diff mbox series

rtl8xxxu: Fix the handling of TX A-MPDU aggregation

Message ID 20210630160151.28227-1-chris.chiu@canonical.com
State Superseded
Headers show
Series rtl8xxxu: Fix the handling of TX A-MPDU aggregation | expand

Commit Message

Chris Chiu June 30, 2021, 4:01 p.m. UTC
From: Chris Chiu <chris.chiu@canonical.com>

The TX A-MPDU aggregation is not handled in the driver since the
ieee80211_start_tx_ba_session has never been started properly.
Start and stop the TX BA session by tracking the TX aggregation
status of each TID. Fix the ampdu_action and the tx descriptor
accordingly with the given TID.

Signed-off-by: Chris Chiu <chris.chiu@canonical.com>
---
 .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h  |  2 ++
 .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 33 ++++++++++++++-----
 2 files changed, 26 insertions(+), 9 deletions(-)

Comments

Chris Chiu July 12, 2021, 6:18 a.m. UTC | #1
On Thu, Jul 1, 2021 at 12:02 AM <chris.chiu@canonical.com> wrote:
>

> From: Chris Chiu <chris.chiu@canonical.com>

>

> The TX A-MPDU aggregation is not handled in the driver since the

> ieee80211_start_tx_ba_session has never been started properly.

> Start and stop the TX BA session by tracking the TX aggregation

> status of each TID. Fix the ampdu_action and the tx descriptor

> accordingly with the given TID.

>

> Signed-off-by: Chris Chiu <chris.chiu@canonical.com>

> ---

>  .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h  |  2 ++

>  .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 33 ++++++++++++++-----

>  2 files changed, 26 insertions(+), 9 deletions(-)

>

> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> index d1a566cc0c9e..3f7ff84f2056 100644

> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> @@ -1383,6 +1383,8 @@ struct rtl8xxxu_priv {

>         u8 no_pape:1;

>         u8 int_buf[USB_INTR_CONTENT_LENGTH];

>         u8 rssi_level;

> +       bool tx_aggr_started[IEEE80211_NUM_TIDS];

> +       DECLARE_BITMAP(tid_bitmap, IEEE80211_NUM_TIDS);

>         /*

>          * Only one virtual interface permitted because only STA mode

>          * is supported and no iface_combinations are provided.

> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c

> index 9ff09cf7eb62..03c6ed7efe06 100644

> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c

> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c

> @@ -4805,6 +4805,8 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,

>         struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);

>         struct rtl8xxxu_priv *priv = hw->priv;

>         struct device *dev = &priv->udev->dev;

> +       u8 *qc = ieee80211_get_qos_ctl(hdr);

> +       u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;

>         u32 rate;

>         u16 rate_flags = tx_info->control.rates[0].flags;

>         u16 seq_number;

> @@ -4828,7 +4830,7 @@ rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,

>

>         tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT);

>

> -       if (ampdu_enable)

> +       if (ampdu_enable && test_bit(tid, priv->tid_bitmap))

>                 tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_ENABLE);

>         else

>                 tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_BREAK);

> @@ -4876,6 +4878,8 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,

>         struct rtl8xxxu_priv *priv = hw->priv;

>         struct device *dev = &priv->udev->dev;

>         struct rtl8xxxu_txdesc40 *tx_desc40;

> +       u8 *qc = ieee80211_get_qos_ctl(hdr);

> +       u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;

>         u32 rate;

>         u16 rate_flags = tx_info->control.rates[0].flags;

>         u16 seq_number;

> @@ -4902,7 +4906,7 @@ rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,

>

>         tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC40_SEQ_SHIFT);

>

> -       if (ampdu_enable)

> +       if (ampdu_enable && test_bit(tid, priv->tid_bitmap))

>                 tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE);

>         else

>                 tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK);

> @@ -5015,12 +5019,19 @@ static void rtl8xxxu_tx(struct ieee80211_hw *hw,

>         if (ieee80211_is_data_qos(hdr->frame_control) && sta) {

>                 if (sta->ht_cap.ht_supported) {

>                         u32 ampdu, val32;

> +                       u8 *qc = ieee80211_get_qos_ctl(hdr);

> +                       u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;

>

>                         ampdu = (u32)sta->ht_cap.ampdu_density;

>                         val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;

>                         tx_desc->txdw2 |= cpu_to_le32(val32);

>

>                         ampdu_enable = true;

> +

> +                       if (!priv->tx_aggr_started[tid] &&

> +                               !(skb->protocol == cpu_to_be16(ETH_P_PAE)))

> +                               if (!ieee80211_start_tx_ba_session(sta, tid, 0))

> +                                       priv->tx_aggr_started[tid] = true;

>                 }

>         }

>

> @@ -6089,6 +6100,7 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

>         struct device *dev = &priv->udev->dev;

>         u8 ampdu_factor, ampdu_density;

>         struct ieee80211_sta *sta = params->sta;

> +       u16 tid = params->tid;

>         enum ieee80211_ampdu_mlme_action action = params->action;

>

>         switch (action) {

> @@ -6101,17 +6113,20 @@ rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,

>                 dev_dbg(dev,

>                         "Changed HT: ampdu_factor %02x, ampdu_density %02x\n",

>                         ampdu_factor, ampdu_density);

> -               break;

> +               return IEEE80211_AMPDU_TX_START_IMMEDIATE;

> +       case IEEE80211_AMPDU_TX_STOP_CONT:

>         case IEEE80211_AMPDU_TX_STOP_FLUSH:

> -               dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);

> -               rtl8xxxu_set_ampdu_factor(priv, 0);

> -               rtl8xxxu_set_ampdu_min_space(priv, 0);

> -               break;

>         case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:

> -               dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",

> -                        __func__);

> +               dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP\n", __func__);

>                 rtl8xxxu_set_ampdu_factor(priv, 0);

>                 rtl8xxxu_set_ampdu_min_space(priv, 0);

> +               priv->tx_aggr_started[tid] = false;

> +               clear_bit(tid, priv->tid_bitmap);

> +               ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);

> +               break;

> +       case IEEE80211_AMPDU_TX_OPERATIONAL:

> +               dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_OPERATIONAL\n", __func__);

> +               set_bit(tid, priv->tid_bitmap);

>                 break;

>         case IEEE80211_AMPDU_RX_START:

>                 dev_dbg(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);

> --

> 2.20.1

>


Gentle ping. Any suggestion is welcome. Thanks

Chris
Kalle Valo July 30, 2021, 7:54 a.m. UTC | #2
Chris Chiu <chris.chiu@canonical.com> writes:

> Any comments for this patch? Thanks 


Please don't send HTML mails, our lists drop those.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
Kalle Valo Aug. 1, 2021, 10:42 a.m. UTC | #3
chris.chiu@canonical.com writes:

> From: Chris Chiu <chris.chiu@canonical.com>

>

> The TX A-MPDU aggregation is not handled in the driver since the

> ieee80211_start_tx_ba_session has never been started properly.

> Start and stop the TX BA session by tracking the TX aggregation

> status of each TID. Fix the ampdu_action and the tx descriptor

> accordingly with the given TID.

>

> Signed-off-by: Chris Chiu <chris.chiu@canonical.com>

> ---

>  .../net/wireless/realtek/rtl8xxxu/rtl8xxxu.h  |  2 ++

>  .../wireless/realtek/rtl8xxxu/rtl8xxxu_core.c | 33 ++++++++++++++-----

>  2 files changed, 26 insertions(+), 9 deletions(-)

>

> diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> index d1a566cc0c9e..3f7ff84f2056 100644

> --- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> +++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h

> @@ -1383,6 +1383,8 @@ struct rtl8xxxu_priv {

>  	u8 no_pape:1;

>  	u8 int_buf[USB_INTR_CONTENT_LENGTH];

>  	u8 rssi_level;

> +	bool tx_aggr_started[IEEE80211_NUM_TIDS];


Why do you use bool of arrays? That looks racy to me. Wouldn't
DECLARE_BITMAP() be safer, like tid_bitmap uses?

> +	DECLARE_BITMAP(tid_bitmap, IEEE80211_NUM_TIDS);


I would rename this to a more descriptive name, like tid_tx_operational.

-- 
https://patchwork.kernel.org/project/linux-wireless/list/

https://wireless.wiki.kernel.org/en/developers/documentation/submittingpatches
diff mbox series

Patch

diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
index d1a566cc0c9e..3f7ff84f2056 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
@@ -1383,6 +1383,8 @@  struct rtl8xxxu_priv {
 	u8 no_pape:1;
 	u8 int_buf[USB_INTR_CONTENT_LENGTH];
 	u8 rssi_level;
+	bool tx_aggr_started[IEEE80211_NUM_TIDS];
+	DECLARE_BITMAP(tid_bitmap, IEEE80211_NUM_TIDS);
 	/*
 	 * Only one virtual interface permitted because only STA mode
 	 * is supported and no iface_combinations are provided.
diff --git a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
index 9ff09cf7eb62..03c6ed7efe06 100644
--- a/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
+++ b/drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_core.c
@@ -4805,6 +4805,8 @@  rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
 	struct ieee80211_rate *tx_rate = ieee80211_get_tx_rate(hw, tx_info);
 	struct rtl8xxxu_priv *priv = hw->priv;
 	struct device *dev = &priv->udev->dev;
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
+	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 	u32 rate;
 	u16 rate_flags = tx_info->control.rates[0].flags;
 	u16 seq_number;
@@ -4828,7 +4830,7 @@  rtl8xxxu_fill_txdesc_v1(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
 
 	tx_desc->txdw3 = cpu_to_le32((u32)seq_number << TXDESC32_SEQ_SHIFT);
 
-	if (ampdu_enable)
+	if (ampdu_enable && test_bit(tid, priv->tid_bitmap))
 		tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_ENABLE);
 	else
 		tx_desc->txdw1 |= cpu_to_le32(TXDESC32_AGG_BREAK);
@@ -4876,6 +4878,8 @@  rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
 	struct rtl8xxxu_priv *priv = hw->priv;
 	struct device *dev = &priv->udev->dev;
 	struct rtl8xxxu_txdesc40 *tx_desc40;
+	u8 *qc = ieee80211_get_qos_ctl(hdr);
+	u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 	u32 rate;
 	u16 rate_flags = tx_info->control.rates[0].flags;
 	u16 seq_number;
@@ -4902,7 +4906,7 @@  rtl8xxxu_fill_txdesc_v2(struct ieee80211_hw *hw, struct ieee80211_hdr *hdr,
 
 	tx_desc40->txdw9 = cpu_to_le32((u32)seq_number << TXDESC40_SEQ_SHIFT);
 
-	if (ampdu_enable)
+	if (ampdu_enable && test_bit(tid, priv->tid_bitmap))
 		tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_ENABLE);
 	else
 		tx_desc40->txdw2 |= cpu_to_le32(TXDESC40_AGG_BREAK);
@@ -5015,12 +5019,19 @@  static void rtl8xxxu_tx(struct ieee80211_hw *hw,
 	if (ieee80211_is_data_qos(hdr->frame_control) && sta) {
 		if (sta->ht_cap.ht_supported) {
 			u32 ampdu, val32;
+			u8 *qc = ieee80211_get_qos_ctl(hdr);
+			u8 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
 
 			ampdu = (u32)sta->ht_cap.ampdu_density;
 			val32 = ampdu << TXDESC_AMPDU_DENSITY_SHIFT;
 			tx_desc->txdw2 |= cpu_to_le32(val32);
 
 			ampdu_enable = true;
+
+			if (!priv->tx_aggr_started[tid] &&
+				!(skb->protocol == cpu_to_be16(ETH_P_PAE)))
+				if (!ieee80211_start_tx_ba_session(sta, tid, 0))
+					priv->tx_aggr_started[tid] = true;
 		}
 	}
 
@@ -6089,6 +6100,7 @@  rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	struct device *dev = &priv->udev->dev;
 	u8 ampdu_factor, ampdu_density;
 	struct ieee80211_sta *sta = params->sta;
+	u16 tid = params->tid;
 	enum ieee80211_ampdu_mlme_action action = params->action;
 
 	switch (action) {
@@ -6101,17 +6113,20 @@  rtl8xxxu_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 		dev_dbg(dev,
 			"Changed HT: ampdu_factor %02x, ampdu_density %02x\n",
 			ampdu_factor, ampdu_density);
-		break;
+		return IEEE80211_AMPDU_TX_START_IMMEDIATE;
+	case IEEE80211_AMPDU_TX_STOP_CONT:
 	case IEEE80211_AMPDU_TX_STOP_FLUSH:
-		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH\n", __func__);
-		rtl8xxxu_set_ampdu_factor(priv, 0);
-		rtl8xxxu_set_ampdu_min_space(priv, 0);
-		break;
 	case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
-		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP_FLUSH_CONT\n",
-			 __func__);
+		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_STOP\n", __func__);
 		rtl8xxxu_set_ampdu_factor(priv, 0);
 		rtl8xxxu_set_ampdu_min_space(priv, 0);
+		priv->tx_aggr_started[tid] = false;
+		clear_bit(tid, priv->tid_bitmap);
+		ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+		break;
+	case IEEE80211_AMPDU_TX_OPERATIONAL:
+		dev_dbg(dev, "%s: IEEE80211_AMPDU_TX_OPERATIONAL\n", __func__);
+		set_bit(tid, priv->tid_bitmap);
 		break;
 	case IEEE80211_AMPDU_RX_START:
 		dev_dbg(dev, "%s: IEEE80211_AMPDU_RX_START\n", __func__);