Takashi Iwai 115ed5
From 1a89bb2cec93bc7a4e384387b382d08ce14cc354 Mon Sep 17 00:00:00 2001
Takashi Iwai 115ed5
From: Chris Chiu <chris.chiu@canonical.com>
Takashi Iwai 115ed5
Date: Wed, 4 Aug 2021 23:13:25 +0800
Takashi Iwai 115ed5
Subject: [PATCH] rtl8xxxu: Fix the handling of TX A-MPDU aggregation
Takashi Iwai 115ed5
Git-commit: 95a581ab3592082c60a08090aabe09ac7d0bd650
Takashi Iwai 115ed5
Patch-mainline: v5.15-rc1
Takashi Iwai 115ed5
References: stable-5.14.6
Takashi Iwai 115ed5
Takashi Iwai 115ed5
[ Upstream commit 95a581ab3592082c60a08090aabe09ac7d0bd650 ]
Takashi Iwai 115ed5
Takashi Iwai 115ed5
The TX A-MPDU aggregation is not handled in the driver since the
Takashi Iwai 115ed5
ieee80211_start_tx_ba_session has never been started properly.
Takashi Iwai 115ed5
Start and stop the TX BA session by tracking the TX aggregation
Takashi Iwai 115ed5
status of each TID. Fix the ampdu_action and the tx descriptor
Takashi Iwai 115ed5
accordingly with the given TID.
Takashi Iwai 115ed5
Takashi Iwai 115ed5
Signed-off-by: Chris Chiu <chris.chiu@canonical.com>
Takashi Iwai 115ed5
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
Takashi Iwai 115ed5
Link: https://lore.kernel.org/r/20210804151325.86600-1-chris.chiu@canonical.com
Takashi Iwai 115ed5
Signed-off-by: Sasha Levin <sashal@kernel.org>
Takashi Iwai 115ed5
Acked-by: Takashi Iwai <tiwai@suse.de>
Takashi Iwai 115ed5
Takashi Iwai 115ed5
---
Takashi Iwai 115ed5
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h  |  2 ++
Takashi Iwai 115ed5
 .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 33 ++++++++++++++-----
Takashi Iwai 115ed5
 2 files changed, 26 insertions(+), 9 deletions(-)
Takashi Iwai 115ed5
Takashi Iwai 115ed5
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
Takashi Iwai 115ed5
index 01735776345a..7ddce3c3f0c4 100644
Takashi Iwai 115ed5
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
Takashi Iwai 115ed5
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
Takashi Iwai 115ed5
@@ -1378,6 +1378,8 @@ struct rtl8xxxu_priv {
Takashi Iwai 115ed5
 	u8 no_pape:1;
Takashi Iwai 115ed5
 	u8 int_buf[USB_INTR_CONTENT_LENGTH];
Takashi Iwai 115ed5
 	u8 rssi_level;
Takashi Iwai 115ed5
+	DECLARE_BITMAP(tx_aggr_started, IEEE80211_NUM_TIDS);
Takashi Iwai 115ed5
+	DECLARE_BITMAP(tid_tx_operational, IEEE80211_NUM_TIDS);
Takashi Iwai 115ed5
 	/*
Takashi Iwai 115ed5
 	 * Only one virtual interface permitted because only STA mode
Takashi Iwai 115ed5
 	 * is supported and no iface_combinations are provided.
Takashi Iwai 115ed5
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
Takashi Iwai 115ed5
index ac1061caacd6..3285a91efb91 100644
Takashi Iwai 115ed5
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
Takashi Iwai 115ed5
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
Takashi Iwai 115ed5
@@ -4805,6 +4805,8 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
Takashi Iwai 115ed5
 	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
Takashi Iwai 115ed5
 	struct rtl8xxxu_priv *priv = hw->priv;
Takashi Iwai 115ed5
 	struct device *dev = &priv->udev->dev;
Takashi Iwai 115ed5
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
Takashi Iwai 115ed5
+	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
Takashi Iwai 115ed5
 	u32 rate;
Takashi Iwai 115ed5
 	u16 rate_flags = tx_info->control.rates[0].flags;
Takashi Iwai 115ed5
 	u16 seq_number;
Takashi Iwai 115ed5
@@ -4828,7 +4830,7 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
 	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT);
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
-	if (ampdu_enable)
Takashi Iwai 115ed5
+	if (ampdu_enable && test_bit(tid, priv->tid_tx_operational))
Takashi Iwai 115ed5
 		tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_ENABLE);
Takashi Iwai 115ed5
 	else
Takashi Iwai 115ed5
 		tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_BREAK);
Takashi Iwai 115ed5
@@ -4876,6 +4878,8 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
Takashi Iwai 115ed5
 	struct rtl8xxxu_priv *priv = hw->priv;
Takashi Iwai 115ed5
 	struct device *dev = &priv->udev->dev;
Takashi Iwai 115ed5
 	struct rtl8xxxu_txdesc40 *tx_desc40;
Takashi Iwai 115ed5
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
Takashi Iwai 115ed5
+	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
Takashi Iwai 115ed5
 	u32 rate;
Takashi Iwai 115ed5
 	u16 rate_flags = tx_info->control.rates[0].flags;
Takashi Iwai 115ed5
 	u16 seq_number;
Takashi Iwai 115ed5
@@ -4902,7 +4906,7 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
 	tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC40_SEQ_SHIFT);
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
-	if (ampdu_enable)
Takashi Iwai 115ed5
+	if (ampdu_enable && test_bit(tid, priv->tid_tx_operational))
Takashi Iwai 115ed5
 		tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE);
Takashi Iwai 115ed5
 	else
Takashi Iwai 115ed5
 		tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK);
Takashi Iwai 115ed5
@@ -5015,12 +5019,19 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,
Takashi Iwai 115ed5
 	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
Takashi Iwai 115ed5
 		if (sta->ht_cap.ht_supported) {
Takashi Iwai 115ed5
 			u32 ampdu, val32;
Takashi Iwai 115ed5
+			u8 *qc = ieee80211_get_qos_ctl(hdr);
Takashi Iwai 115ed5
+			u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
 			ampdu = (u32)sta->ht_cap.ampdu_density;
Takashi Iwai 115ed5
 			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
Takashi Iwai 115ed5
 			tx_desc->txdw2 |= cpu_to_le32(val32);
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
 			ampdu_enable = true;
Takashi Iwai 115ed5
+
Takashi Iwai 115ed5
+			if (!test_bit(tid, priv->tx_aggr_started) &&
Takashi Iwai 115ed5
+			    !(skb->protocol == cpu_to_be16(ETH_P_PAE)))
Takashi Iwai 115ed5
+				if (!ieee80211_start_tx_ba_session(sta, tid, 0))
Takashi Iwai 115ed5
+					set_bit(tid, priv->tx_aggr_started);
Takashi Iwai 115ed5
 		}
Takashi Iwai 115ed5
 	}
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
@@ -6096,6 +6107,7 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Takashi Iwai 115ed5
 	struct device *dev = &priv->udev->dev;
Takashi Iwai 115ed5
 	u8 ampdu_factor, ampdu_density;
Takashi Iwai 115ed5
 	struct ieee80211_sta *sta = params->sta;
Takashi Iwai 115ed5
+	u16 tid = params->tid;
Takashi Iwai 115ed5
 	enum ieee80211_ampdu_mlme_action action = params->action;
Takashi Iwai 115ed5
 
Takashi Iwai 115ed5
 	switch (action) {
Takashi Iwai 115ed5
@@ -6108,17 +6120,20 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
Takashi Iwai 115ed5
 		dev_dbg(dev,
Takashi Iwai 115ed5
 			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
Takashi Iwai 115ed5
 			ampdu_factor, ampdu_density);
Takashi Iwai 115ed5
-		break;
Takashi Iwai 115ed5
+		return IEEE80211_AMPDU_TX_START_IMMEDIATE;
Takashi Iwai 115ed5
+	case IEEE80211_AMPDU_TX_STOP_CONT:
Takashi Iwai 115ed5
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
Takashi Iwai 115ed5
-		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
Takashi Iwai 115ed5
-		rtl8xxxu_set_ampdu_factor(priv, 0);
Takashi Iwai 115ed5
-		rtl8xxxu_set_ampdu_min_space(priv, 0);
Takashi Iwai 115ed5
-		break;
Takashi Iwai 115ed5
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
Takashi Iwai 115ed5
-		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
Takashi Iwai 115ed5
-			 __func__);
Takashi Iwai 115ed5
+		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP\n", __func__);
Takashi Iwai 115ed5
 		rtl8xxxu_set_ampdu_factor(priv, 0);
Takashi Iwai 115ed5
 		rtl8xxxu_set_ampdu_min_space(priv, 0);
Takashi Iwai 115ed5
+		clear_bit(tid, priv->tx_aggr_started);
Takashi Iwai 115ed5
+		clear_bit(tid, priv->tid_tx_operational);
Takashi Iwai 115ed5
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
Takashi Iwai 115ed5
+		break;
Takashi Iwai 115ed5
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
Takashi Iwai 115ed5
+		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_OPERATIONAL\n", __func__);
Takashi Iwai 115ed5
+		set_bit(tid, priv->tid_tx_operational);
Takashi Iwai 115ed5
 		break;
Takashi Iwai 115ed5
 	case IEEE80211_AMPDU_RX_START:
Takashi Iwai 115ed5
 		dev_dbg(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);
Takashi Iwai 115ed5
-- 
Takashi Iwai 115ed5
2.26.2
Takashi Iwai 115ed5