2021-06-30 16:03:21

by Chris Chiu

[permalink] [raw]
Subject: [PATCH] rtl8xxxu: Fix the handling of TX A-MPDU aggregation

From: Chris Chiu <[email protected]>

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 <[email protected]>
---
.../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


2021-07-12 06:30:47

by Chris Chiu

[permalink] [raw]
Subject: Re: [PATCH] rtl8xxxu: Fix the handling of TX A-MPDU aggregation

On Thu, Jul 1, 2021 at 12:02 AM <[email protected]> wrote:
>
> From: Chris Chiu <[email protected]>
>
> 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 <[email protected]>
> ---
> .../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

2021-08-01 10:42:50

by Kalle Valo

[permalink] [raw]
Subject: Re: [PATCH] rtl8xxxu: Fix the handling of TX A-MPDU aggregation

[email protected] writes:

> From: Chris Chiu <[email protected]>
>
> 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 <[email protected]>
> ---
> .../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