Blame SOURCES/0019-Revert-iwlwifi-mvm-support-mac80211-AMSDU.patch

deb259
From 37359a82e85dab864b3aee0058f6deacc6448c21 Mon Sep 17 00:00:00 2001
deb259
From: Eugene Syromiatnikov <esyr@redhat.com>
deb259
Date: Thu, 25 Jul 2019 15:37:39 +0200
deb259
Subject: [PATCH 3/7] Revert "iwlwifi: mvm: support mac80211 AMSDU"
deb259
deb259
This reverts commit 438af9698b0f161286c6e5d24255c3c231988b39.
deb259
---
deb259
 drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c |  33 ----
deb259
 drivers/net/wireless/intel/iwlwifi/mvm/mvm.h      |   3 -
deb259
 drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c    |  14 --
deb259
 drivers/net/wireless/intel/iwlwifi/mvm/rs.c       |  14 --
deb259
 drivers/net/wireless/intel/iwlwifi/mvm/tx.c       | 229 +++++++++++++++++++++-
deb259
 5 files changed, 226 insertions(+), 67 deletions(-)
deb259
deb259
Index: src/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
deb259
===================================================================
deb259
--- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c	2019-07-31 18:50:33.492326106 +0200
deb259
+++ src/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c	2019-07-31 18:50:40.636230724 +0200
deb259
@@ -429,8 +429,6 @@
deb259
 	ieee80211_hw_set(hw, SUPPORTS_VHT_EXT_NSS_BW);
deb259
 	ieee80211_hw_set(hw, BUFF_MMPDU_TXQ);
deb259
 	ieee80211_hw_set(hw, STA_MMPDU_TXQ);
deb259
-	ieee80211_hw_set(hw, TX_AMSDU);
deb259
-	ieee80211_hw_set(hw, TX_FRAG_LIST);
deb259
 
deb259
 	if (iwl_mvm_has_tlc_offload(mvm)) {
deb259
 		ieee80211_hw_set(hw, TX_AMPDU_SETUP_IN_HW);
deb259
@@ -476,7 +474,6 @@
deb259
 
deb259
 	hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
deb259
 	hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
deb259
-	hw->max_tx_fragments = mvm->trans->max_skb_frags;
deb259
 
deb259
 	BUILD_BUG_ON(ARRAY_SIZE(mvm->ciphers) < ARRAY_SIZE(mvm_ciphers) + 6);
deb259
 	memcpy(mvm->ciphers, mvm_ciphers, sizeof(mvm_ciphers));
deb259
@@ -739,7 +736,6 @@
deb259
 	}
deb259
 
deb259
 	hw->netdev_features |= mvm->cfg->features;
deb259
-	hw->netdev_features &= ~(NETIF_F_TSO | NETIF_F_TSO6);
deb259
 	if (!iwl_mvm_is_csum_supported(mvm)) {
deb259
 		hw->netdev_features &= ~(IWL_TX_CSUM_NETIF_FLAGS |
deb259
 					 NETIF_F_RXCSUM);
deb259
@@ -3169,8 +3165,6 @@
deb259
 			iwl_mvm_tdls_check_trigger(mvm, vif, sta->addr,
deb259
 						   NL80211_TDLS_SETUP);
deb259
 		}
deb259
-
deb259
-		sta->max_rc_amsdu_len = 1;
deb259
 	} else if (old_state == IEEE80211_STA_NONE &&
deb259
 		   new_state == IEEE80211_STA_AUTH) {
deb259
 		/*
deb259
@@ -4918,32 +4912,6 @@
deb259
 	mutex_unlock(&mvm->mutex);
deb259
 }
deb259
 
deb259
-static bool iwl_mvm_can_hw_csum(struct sk_buff *skb)
deb259
-{
deb259
-	u8 protocol = ip_hdr(skb)->protocol;
deb259
-
deb259
-	if (!IS_ENABLED(CONFIG_INET))
deb259
-		return false;
deb259
-
deb259
-	return protocol == IPPROTO_TCP || protocol == IPPROTO_UDP;
deb259
-}
deb259
-
deb259
-static bool iwl_mvm_mac_can_aggregate(struct ieee80211_hw *hw,
deb259
-				      struct sk_buff *head,
deb259
-				      struct sk_buff *skb)
deb259
-{
deb259
-	struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
deb259
-
deb259
-	/* For now don't aggregate IPv6 in AMSDU */
deb259
-	if (skb->protocol != htons(ETH_P_IP))
deb259
-		return false;
deb259
-
deb259
-	if (!iwl_mvm_is_csum_supported(mvm))
deb259
-		return true;
deb259
-
deb259
-	return iwl_mvm_can_hw_csum(skb) == iwl_mvm_can_hw_csum(head);
deb259
-}
deb259
-
deb259
 const struct ieee80211_ops iwl_mvm_hw_ops = {
deb259
 	.tx = iwl_mvm_mac_tx,
deb259
 	.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
deb259
@@ -5022,7 +4990,6 @@
deb259
 #endif
deb259
 	.get_survey = iwl_mvm_mac_get_survey,
deb259
 	.sta_statistics = iwl_mvm_mac_sta_statistics,
deb259
-	.can_aggregate_in_amsdu = iwl_mvm_mac_can_aggregate,
deb259
 #ifdef CONFIG_IWLWIFI_DEBUGFS
deb259
 	.sta_add_debugfs = iwl_mvm_sta_add_debugfs,
deb259
 #endif
deb259
Index: src/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
deb259
===================================================================
deb259
--- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h	2019-07-25 15:31:29.301154126 +0200
deb259
+++ src/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h	2019-07-31 18:50:40.637230710 +0200
deb259
@@ -1553,9 +1553,6 @@
deb259
 			    struct ieee80211_tx_info *info,
deb259
 			    struct ieee80211_sta *sta, __le16 fc);
deb259
 void iwl_mvm_mac_itxq_xmit(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
deb259
-unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
deb259
-				    struct ieee80211_sta *sta,
deb259
-				    unsigned int tid);
deb259
 
deb259
 #ifdef CONFIG_IWLWIFI_DEBUG
deb259
 const char *iwl_mvm_get_tx_fail_reason(u32 status);
deb259
Index: src/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c
deb259
===================================================================
deb259
--- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c	2019-06-27 14:54:04.138678277 +0200
deb259
+++ src/drivers/net/wireless/intel/iwlwifi/mvm/rs-fw.c	2019-07-31 18:50:40.638230697 +0200
deb259
@@ -346,26 +346,12 @@
deb259
 
deb259
 	if (flags & IWL_TLC_NOTIF_FLAG_AMSDU) {
deb259
 		u16 size = le32_to_cpu(notif->amsdu_size);
deb259
-		int i;
deb259
 
deb259
 		if (WARN_ON(sta->max_amsdu_len < size))
deb259
 			goto out;
deb259
 
deb259
 		mvmsta->amsdu_enabled = le32_to_cpu(notif->amsdu_enabled);
deb259
 		mvmsta->max_amsdu_len = size;
deb259
-		sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
deb259
-
deb259
-		for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
deb259
-			if (mvmsta->amsdu_enabled & BIT(i))
deb259
-				sta->max_tid_amsdu_len[i] =
deb259
-					iwl_mvm_max_amsdu_size(mvm, sta, i);
deb259
-			else
deb259
-				/*
deb259
-				 * Not so elegant, but this will effectively
deb259
-				 * prevent AMSDU on this TID
deb259
-				 */
deb259
-				sta->max_tid_amsdu_len[i] = 1;
deb259
-		}
deb259
 
deb259
 		IWL_DEBUG_RATE(mvm,
deb259
 			       "AMSDU update. AMSDU size: %d, AMSDU selected size: %d, AMSDU TID bitmap 0x%X\n",
deb259
Index: src/drivers/net/wireless/intel/iwlwifi/mvm/rs.c
deb259
===================================================================
deb259
--- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/rs.c	2019-07-31 18:50:25.238436309 +0200
deb259
+++ src/drivers/net/wireless/intel/iwlwifi/mvm/rs.c	2019-07-31 18:50:40.639230684 +0200
deb259
@@ -1751,7 +1751,6 @@
deb259
 			     enum rs_action scale_action)
deb259
 {
deb259
 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
deb259
-	int i;
deb259
 
deb259
 	/*
deb259
 	 * In case TLC offload is not active amsdu_enabled is either 0xFFFF
deb259
@@ -1765,19 +1764,6 @@
deb259
 		mvmsta->amsdu_enabled = 0xFFFF;
deb259
 
deb259
 	mvmsta->max_amsdu_len = sta->max_amsdu_len;
deb259
-	sta->max_rc_amsdu_len = mvmsta->max_amsdu_len;
deb259
-
deb259
-	for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
deb259
-		if (mvmsta->amsdu_enabled)
deb259
-			sta->max_tid_amsdu_len[i] =
deb259
-				iwl_mvm_max_amsdu_size(mvm, sta, i);
deb259
-		else
deb259
-			/*
deb259
-			 * Not so elegant, but this will effectively
deb259
-			 * prevent AMSDU on this TID
deb259
-			 */
deb259
-			sta->max_tid_amsdu_len[i] = 1;
deb259
-	}
deb259
 }
deb259
 
deb259
 /*
deb259
Index: src/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
deb259
===================================================================
deb259
--- src.orig/drivers/net/wireless/intel/iwlwifi/mvm/tx.c	2019-07-31 18:50:33.494326080 +0200
deb259
+++ src/drivers/net/wireless/intel/iwlwifi/mvm/tx.c	2019-07-31 18:50:40.639230684 +0200
deb259
@@ -785,8 +785,78 @@
deb259
 	return 0;
deb259
 }
deb259
 
deb259
-unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
deb259
-				    struct ieee80211_sta *sta, unsigned int tid)
deb259
+#ifdef CONFIG_INET
deb259
+
deb259
+static int
deb259
+iwl_mvm_tx_tso_segment(struct sk_buff *skb, unsigned int num_subframes,
deb259
+		       netdev_features_t netdev_flags,
deb259
+		       struct sk_buff_head *mpdus_skb)
deb259
+{
deb259
+	struct sk_buff *tmp, *next;
deb259
+	struct ieee80211_hdr *hdr = (void *)skb->data;
deb259
+	char cb[sizeof(skb->cb)];
deb259
+	u16 i = 0;
deb259
+	unsigned int tcp_payload_len;
deb259
+	unsigned int mss = skb_shinfo(skb)->gso_size;
deb259
+	bool ipv4 = (skb->protocol == htons(ETH_P_IP));
deb259
+	u16 ip_base_id = ipv4 ? ntohs(ip_hdr(skb)->id) : 0;
deb259
+
deb259
+	skb_shinfo(skb)->gso_size = num_subframes * mss;
deb259
+	memcpy(cb, skb->cb, sizeof(cb));
deb259
+
deb259
+	next = skb_gso_segment(skb, netdev_flags);
deb259
+	skb_shinfo(skb)->gso_size = mss;
deb259
+	if (WARN_ON_ONCE(IS_ERR(next)))
deb259
+		return -EINVAL;
deb259
+	else if (next)
deb259
+		consume_skb(skb);
deb259
+
deb259
+	while (next) {
deb259
+		tmp = next;
deb259
+		next = tmp->next;
deb259
+
deb259
+		memcpy(tmp->cb, cb, sizeof(tmp->cb));
deb259
+		/*
deb259
+		 * Compute the length of all the data added for the A-MSDU.
deb259
+		 * This will be used to compute the length to write in the TX
deb259
+		 * command. We have: SNAP + IP + TCP for n -1 subframes and
deb259
+		 * ETH header for n subframes.
deb259
+		 */
deb259
+		tcp_payload_len = skb_tail_pointer(tmp) -
deb259
+			skb_transport_header(tmp) -
deb259
+			tcp_hdrlen(tmp) + tmp->data_len;
deb259
+
deb259
+		if (ipv4)
deb259
+			ip_hdr(tmp)->id = htons(ip_base_id + i * num_subframes);
deb259
+
deb259
+		if (tcp_payload_len > mss) {
deb259
+			skb_shinfo(tmp)->gso_size = mss;
deb259
+		} else {
deb259
+			if (ieee80211_is_data_qos(hdr->frame_control)) {
deb259
+				u8 *qc;
deb259
+
deb259
+				if (ipv4)
deb259
+					ip_send_check(ip_hdr(tmp));
deb259
+
deb259
+				qc = ieee80211_get_qos_ctl((void *)tmp->data);
deb259
+				*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
deb259
+			}
deb259
+			skb_shinfo(tmp)->gso_size = 0;
deb259
+		}
deb259
+
deb259
+		tmp->prev = NULL;
deb259
+		tmp->next = NULL;
deb259
+
deb259
+		__skb_queue_tail(mpdus_skb, tmp);
deb259
+		i++;
deb259
+	}
deb259
+
deb259
+	return 0;
deb259
+}
deb259
+
deb259
+static unsigned int iwl_mvm_max_amsdu_size(struct iwl_mvm *mvm,
deb259
+					   struct ieee80211_sta *sta,
deb259
+					   unsigned int tid)
deb259
 {
deb259
 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
deb259
 	enum nl80211_band band = mvmsta->vif->bss_conf.chandef.chan->band;
deb259
@@ -814,6 +884,128 @@
deb259
 		     mvm->fwrt.smem_cfg.lmac[lmac].txfifo_size[txf] - 256);
deb259
 }
deb259
 
deb259
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
deb259
+			  struct ieee80211_tx_info *info,
deb259
+			  struct ieee80211_sta *sta,
deb259
+			  struct sk_buff_head *mpdus_skb)
deb259
+{
deb259
+	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
deb259
+	struct ieee80211_hdr *hdr = (void *)skb->data;
deb259
+	unsigned int mss = skb_shinfo(skb)->gso_size;
deb259
+	unsigned int num_subframes, tcp_payload_len, subf_len, max_amsdu_len;
deb259
+	u16 snap_ip_tcp, pad;
deb259
+	unsigned int dbg_max_amsdu_len;
deb259
+	netdev_features_t netdev_flags = NETIF_F_CSUM_MASK | NETIF_F_SG;
deb259
+	u8 tid;
deb259
+
deb259
+	snap_ip_tcp = 8 + skb_transport_header(skb) - skb_network_header(skb) +
deb259
+		tcp_hdrlen(skb);
deb259
+
deb259
+	dbg_max_amsdu_len = READ_ONCE(mvm->max_amsdu_len);
deb259
+
deb259
+	if (!mvmsta->max_amsdu_len ||
deb259
+	    !ieee80211_is_data_qos(hdr->frame_control) ||
deb259
+	    (!mvmsta->amsdu_enabled && !dbg_max_amsdu_len))
deb259
+		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
deb259
+
deb259
+	/*
deb259
+	 * Do not build AMSDU for IPv6 with extension headers.
deb259
+	 * ask stack to segment and checkum the generated MPDUs for us.
deb259
+	 */
deb259
+	if (skb->protocol == htons(ETH_P_IPV6) &&
deb259
+	    ((struct ipv6hdr *)skb_network_header(skb))->nexthdr !=
deb259
+	    IPPROTO_TCP) {
deb259
+		netdev_flags &= ~NETIF_F_CSUM_MASK;
deb259
+		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
deb259
+	}
deb259
+
deb259
+	tid = ieee80211_get_tid(hdr);
deb259
+	if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
deb259
+		return -EINVAL;
deb259
+
deb259
+	/*
deb259
+	 * No need to lock amsdu_in_ampdu_allowed since it can't be modified
deb259
+	 * during an BA session.
deb259
+	 */
deb259
+	if (info->flags & IEEE80211_TX_CTL_AMPDU &&
deb259
+	    !mvmsta->tid_data[tid].amsdu_in_ampdu_allowed)
deb259
+		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
deb259
+
deb259
+	if (iwl_mvm_vif_low_latency(iwl_mvm_vif_from_mac80211(mvmsta->vif)) ||
deb259
+	    !(mvmsta->amsdu_enabled & BIT(tid)))
deb259
+		return iwl_mvm_tx_tso_segment(skb, 1, netdev_flags, mpdus_skb);
deb259
+
deb259
+	max_amsdu_len = iwl_mvm_max_amsdu_size(mvm, sta, tid);
deb259
+
deb259
+	if (unlikely(dbg_max_amsdu_len))
deb259
+		max_amsdu_len = min_t(unsigned int, max_amsdu_len,
deb259
+				      dbg_max_amsdu_len);
deb259
+
deb259
+	/*
deb259
+	 * Limit A-MSDU in A-MPDU to 4095 bytes when VHT is not
deb259
+	 * supported. This is a spec requirement (IEEE 802.11-2015
deb259
+	 * section 8.7.3 NOTE 3).
deb259
+	 */
deb259
+	if (info->flags & IEEE80211_TX_CTL_AMPDU &&
deb259
+	    !sta->vht_cap.vht_supported)
deb259
+		max_amsdu_len = min_t(unsigned int, max_amsdu_len, 4095);
deb259
+
deb259
+	/* Sub frame header + SNAP + IP header + TCP header + MSS */
deb259
+	subf_len = sizeof(struct ethhdr) + snap_ip_tcp + mss;
deb259
+	pad = (4 - subf_len) & 0x3;
deb259
+
deb259
+	/*
deb259
+	 * If we have N subframes in the A-MSDU, then the A-MSDU's size is
deb259
+	 * N * subf_len + (N - 1) * pad.
deb259
+	 */
deb259
+	num_subframes = (max_amsdu_len + pad) / (subf_len + pad);
deb259
+
deb259
+	if (sta->max_amsdu_subframes &&
deb259
+	    num_subframes > sta->max_amsdu_subframes)
deb259
+		num_subframes = sta->max_amsdu_subframes;
deb259
+
deb259
+	tcp_payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
deb259
+		tcp_hdrlen(skb) + skb->data_len;
deb259
+
deb259
+	/*
deb259
+	 * Make sure we have enough TBs for the A-MSDU:
deb259
+	 *	2 for each subframe
deb259
+	 *	1 more for each fragment
deb259
+	 *	1 more for the potential data in the header
deb259
+	 */
deb259
+	if ((num_subframes * 2 + skb_shinfo(skb)->nr_frags + 1) >
deb259
+	    mvm->trans->max_skb_frags)
deb259
+		num_subframes = 1;
deb259
+
deb259
+	if (num_subframes > 1)
deb259
+		*ieee80211_get_qos_ctl(hdr) |= IEEE80211_QOS_CTL_A_MSDU_PRESENT;
deb259
+
deb259
+	/* This skb fits in one single A-MSDU */
deb259
+	if (num_subframes * mss >= tcp_payload_len) {
deb259
+		__skb_queue_tail(mpdus_skb, skb);
deb259
+		return 0;
deb259
+	}
deb259
+
deb259
+	/*
deb259
+	 * Trick the segmentation function to make it
deb259
+	 * create SKBs that can fit into one A-MSDU.
deb259
+	 */
deb259
+	return iwl_mvm_tx_tso_segment(skb, num_subframes, netdev_flags,
deb259
+				      mpdus_skb);
deb259
+}
deb259
+#else /* CONFIG_INET */
deb259
+static int iwl_mvm_tx_tso(struct iwl_mvm *mvm, struct sk_buff *skb,
deb259
+			  struct ieee80211_tx_info *info,
deb259
+			  struct ieee80211_sta *sta,
deb259
+			  struct sk_buff_head *mpdus_skb)
deb259
+{
deb259
+	/* Impossible to get TSO with CONFIG_INET */
deb259
+	WARN_ON(1);
deb259
+
deb259
+	return -1;
deb259
+}
deb259
+#endif
deb259
+
deb259
 /* Check if there are any timed-out TIDs on a given shared TXQ */
deb259
 static bool iwl_mvm_txq_should_update(struct iwl_mvm *mvm, int txq_id)
deb259
 {
deb259
@@ -1012,6 +1204,9 @@
deb259
 {
deb259
 	struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
deb259
 	struct ieee80211_tx_info info;
deb259
+	struct sk_buff_head mpdus_skbs;
deb259
+	unsigned int payload_len;
deb259
+	int ret;
deb259
 
deb259
 	if (WARN_ON_ONCE(!mvmsta))
deb259
 		return -1;
deb259
@@ -1021,7 +1216,35 @@
deb259
 
deb259
 	memcpy(&info, skb->cb, sizeof(info));
deb259
 
deb259
-	return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
deb259
+	if (!skb_is_gso(skb))
deb259
+		return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
deb259
+
deb259
+	payload_len = skb_tail_pointer(skb) - skb_transport_header(skb) -
deb259
+		tcp_hdrlen(skb) + skb->data_len;
deb259
+
deb259
+	if (payload_len <= skb_shinfo(skb)->gso_size)
deb259
+		return iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
deb259
+
deb259
+	__skb_queue_head_init(&mpdus_skbs);
deb259
+
deb259
+	ret = iwl_mvm_tx_tso(mvm, skb, &info, sta, &mpdus_skbs);
deb259
+	if (ret)
deb259
+		return ret;
deb259
+
deb259
+	if (WARN_ON(skb_queue_empty(&mpdus_skbs)))
deb259
+		return ret;
deb259
+
deb259
+	while (!skb_queue_empty(&mpdus_skbs)) {
deb259
+		skb = __skb_dequeue(&mpdus_skbs);
deb259
+
deb259
+		ret = iwl_mvm_tx_mpdu(mvm, skb, &info, sta);
deb259
+		if (ret) {
deb259
+			__skb_queue_purge(&mpdus_skbs);
deb259
+			return ret;
deb259
+		}
deb259
+	}
deb259
+
deb259
+	return 0;
deb259
 }
deb259
 
deb259
 static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,