* [PATCH v2 00/10] Convert mac80211 to TXQs only
@ 2025-02-17 8:17 Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 01/10] wifi: mac80211: move rate control setup Alexander Wetzel
` (10 more replies)
0 siblings, 11 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
This series switches all TX handling in mac80211 over to TXQs.
TXQs can take over buffering in many - potentially even all - cases
where we use separate solutions so far.
This reduces the complexity of the TX path and making it simpler to use
TX in mac8021.
These patches continue the work to get rid of the legacy TX path we
started drivers with
https://lore.kernel.org/r/20221009163040.25637-1-alexander@wetzel-home.de
and was inspired by this old discussion on the wireless mailing list:
https://lore.kernel.org/r/1507217947.2387.60.camel@sipsolutions.net/
Changes compared to RFC and v1 are documented in the individual patches,
where applicable.
A quick overview of the patches in the series:
wifi: mac80211: move rate control setup
Broken off from "Add new TX queues to replace legacy TX" as
requested. Moves some exiting code around.
wifi: mac80211: Always provide the MMPDU TXQ
When only using TXQs for TX we akways need this.
Creates and uses MMPDU TXQs even for drivers not supporting
them.
wifi: mac80211: Convert vif->txq to an array
We need some more TXQs for the patch below. Create them.
wifi: mac80211: Add new TX queues to replace legacy TX
This starts the core of the move to TXQs.
Creats all the missing TXQs and updates the support function for
them. It also directly switches traffic to them, when possible.
(Only offchannel is sticking to legacy TX after that.)
wifi: mac80211: Stop using legacy TX path
Drop the legacy TX functions and move offchannel TX to the new
alternate TXQ path named TXQ_NOQUEUE (so far).
With that mac80211 has two TX paths both using TXQ:
- The existing one, which uses the TXQ for queuing and
- TXQ_NOQUEUE. Which just puts frames into a TXQ and
immediately sends out the frame by also calling drv_tx() for
it. There never can be more than one frame in any of these
TXQs. They never see a wake_tx_queue call by the driver or
mac80211.
wifi: mac80211: Call ieee80211_tx_h_select_key only once
A optimization which could be without the patches, too. Would
just be done differently. (Not required)
wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK
Rename the flag used to select the NOQUEU TX path to make its
use more obvious.
wifi: mac80211: Simplify AMPDU handling
Uses TXQs to buffer frames when AMPDU is started/stopped.
wifi: mac80211: Migrate TX to kthread
Moves all TX operation except TXQ_NOQUEUE to a new kthread.
This hooks into the existing txq scheduling and uses
local->active_txqs to determine which TXQs need to run.
wifi: mac80211: Cleanup *ieee80211_wake_txq* naming
Rename a few functions.
drivers/net/wireless/ath/ath10k/mac.c | 8 +-
drivers/net/wireless/ath/ath9k/ath9k.h | 2 +-
.../net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +-
.../net/wireless/mediatek/mt76/mt7603/main.c | 3 +-
.../net/wireless/mediatek/mt76/mt7615/main.c | 5 +-
.../net/wireless/mediatek/mt76/mt76x02_util.c | 3 +-
.../net/wireless/mediatek/mt76/mt7915/main.c | 6 +-
.../net/wireless/mediatek/mt76/mt7921/main.c | 5 +-
.../net/wireless/mediatek/mt76/mt7925/main.c | 5 +-
.../net/wireless/mediatek/mt76/mt7996/main.c | 5 +-
drivers/net/wireless/realtek/rtw88/mac80211.c | 4 +-
drivers/net/wireless/realtek/rtw88/main.c | 2 +-
drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +-
include/net/mac80211.h | 60 +-
net/mac80211/agg-tx.c | 129 +---
net/mac80211/cfg.c | 8 +-
net/mac80211/debugfs_netdev.c | 46 +-
net/mac80211/debugfs_sta.c | 2 -
net/mac80211/driver-ops.h | 28 +-
net/mac80211/ieee80211_i.h | 32 +-
net/mac80211/iface.c | 144 ++--
net/mac80211/main.c | 9 +-
net/mac80211/mesh.c | 13 +-
net/mac80211/mlme.c | 2 +-
net/mac80211/offchannel.c | 2 +-
net/mac80211/rx.c | 11 +-
net/mac80211/scan.c | 2 +-
net/mac80211/sta_info.c | 6 +-
net/mac80211/sta_info.h | 30 +-
net/mac80211/tx.c | 616 ++++--------------
net/mac80211/util.c | 162 +++--
31 files changed, 534 insertions(+), 824 deletions(-)
--
2.48.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v2 01/10] wifi: mac80211: move rate control setup
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 02/10] wifi: mac80211: Always provide the MMPDU TXQ Alexander Wetzel
` (9 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
Move setting up the rate control into ieee80211_sdata_init() to ensure
rates are also set up for the virtual monitor interface.
Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
---
net/mac80211/iface.c | 51 ++++++++++++++++++++++----------------------
1 file changed, 26 insertions(+), 25 deletions(-)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 77d0078616fb..e01beda8c414 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1118,6 +1118,31 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
* MLD connection, we get a separate allocation for it.
*/
ieee80211_link_init(sdata, -1, &sdata->deflink, &sdata->vif.bss_conf);
+
+ for (int i = 0; i < NUM_NL80211_BANDS; i++) {
+ struct ieee80211_supported_band *sband;
+
+ sband = local->hw.wiphy->bands[i];
+ sdata->rc_rateidx_mask[i] =
+ sband ? (1 << sband->n_bitrates) - 1 : 0;
+ if (sband) {
+ __le16 cap;
+ u16 *vht_rate_mask;
+
+ memcpy(sdata->rc_rateidx_mcs_mask[i],
+ sband->ht_cap.mcs.rx_mask,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
+
+ cap = sband->vht_cap.vht_mcs.rx_mcs_map;
+ vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i];
+ ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask);
+ } else {
+ memset(sdata->rc_rateidx_mcs_mask[i], 0,
+ sizeof(sdata->rc_rateidx_mcs_mask[i]));
+ memset(sdata->rc_rateidx_vht_mcs_mask[i], 0,
+ sizeof(sdata->rc_rateidx_vht_mcs_mask[i]));
+ }
+ }
}
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
@@ -2076,7 +2101,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
struct net_device *ndev = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
struct txq_info *txqi;
- int ret, i;
+ int ret;
ASSERT_RTNL();
lockdep_assert_wiphy(local->hw.wiphy);
@@ -2165,30 +2190,6 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
wiphy_delayed_work_init(&sdata->dec_tailroom_needed_wk,
ieee80211_delayed_tailroom_dec);
- for (i = 0; i < NUM_NL80211_BANDS; i++) {
- struct ieee80211_supported_band *sband;
- sband = local->hw.wiphy->bands[i];
- sdata->rc_rateidx_mask[i] =
- sband ? (1 << sband->n_bitrates) - 1 : 0;
- if (sband) {
- __le16 cap;
- u16 *vht_rate_mask;
-
- memcpy(sdata->rc_rateidx_mcs_mask[i],
- sband->ht_cap.mcs.rx_mask,
- sizeof(sdata->rc_rateidx_mcs_mask[i]));
-
- cap = sband->vht_cap.vht_mcs.rx_mcs_map;
- vht_rate_mask = sdata->rc_rateidx_vht_mcs_mask[i];
- ieee80211_get_vht_mask_from_cap(cap, vht_rate_mask);
- } else {
- memset(sdata->rc_rateidx_mcs_mask[i], 0,
- sizeof(sdata->rc_rateidx_mcs_mask[i]));
- memset(sdata->rc_rateidx_vht_mcs_mask[i], 0,
- sizeof(sdata->rc_rateidx_vht_mcs_mask[i]));
- }
- }
-
ieee80211_set_default_queues(sdata);
/* setup type-dependent data */
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 02/10] wifi: mac80211: Always provide the MMPDU TXQ
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 01/10] wifi: mac80211: move rate control setup Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 03/10] wifi: mac80211: Convert vif->txq to an array Alexander Wetzel
` (8 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
From: Alexander Wetzel <alexander@wetzel-home.de>
Always providing and use the MMPDU TX queue to prepare to move all TX
into TXQs.
For drivers not supporting the MMPDU TXQ, mac80211 will handle it
internally.
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
net/mac80211/driver-ops.h | 12 ++++++++++++
net/mac80211/sta_info.c | 1 -
net/mac80211/tx.c | 19 ++-----------------
3 files changed, 14 insertions(+), 18 deletions(-)
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 307587c8a003..992fa2957621 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1364,6 +1364,18 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
return;
trace_drv_wake_tx_queue(local, sdata, txq);
+
+ /* Driver support for MPDU TXQ support is optional */
+ if (unlikely(txq->txq.tid == IEEE80211_NUM_TIDS &&
+ ((sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !ieee80211_hw_check(&sdata->local->hw, STA_MMPDU_TXQ)) ||
+ (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ !ieee80211_hw_check(&sdata->local->hw,
+ BUFF_MMPDU_TXQ))))) {
+ ieee80211_handle_wake_tx_queue(&local->hw, &txq->txq);
+ return;
+ }
+
local->ops->wake_tx_queue(&local->hw, &txq->txq);
}
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index f83268fa9f92..3ba03b6142cc 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -638,7 +638,6 @@ __sta_info_alloc(struct ieee80211_sub_if_data *sdata,
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
struct txq_info *txq = txq_data + i * size;
- /* might not do anything for the (bufferable) MMPDU TXQ */
ieee80211_txq_init(sdata, sta, txq, i);
}
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 20179db88c4a..914fba53d7f1 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1311,10 +1311,6 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
ieee80211_is_bufferable_mmpdu(skb) ||
vif->type == NL80211_IFTYPE_STATION) &&
sta && sta->uploaded) {
- /*
- * This will be NULL if the driver didn't set the
- * opt-in hardware flag.
- */
txq = sta->sta.txq[IEEE80211_NUM_TIDS];
}
} else if (sta) {
@@ -1521,21 +1517,10 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
return;
}
- if (tid == IEEE80211_NUM_TIDS) {
- if (sdata->vif.type == NL80211_IFTYPE_STATION) {
- /* Drivers need to opt in to the management MPDU TXQ */
- if (!ieee80211_hw_check(&sdata->local->hw,
- STA_MMPDU_TXQ))
- return;
- } else if (!ieee80211_hw_check(&sdata->local->hw,
- BUFF_MMPDU_TXQ)) {
- /* Drivers need to opt in to the bufferable MMPDU TXQ */
- return;
- }
+ if (tid == IEEE80211_NUM_TIDS)
txqi->txq.ac = IEEE80211_AC_VO;
- } else {
+ else
txqi->txq.ac = ieee80211_ac_from_tid(tid);
- }
txqi->txq.sta = &sta->sta;
txqi->txq.tid = tid;
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 03/10] wifi: mac80211: Convert vif->txq to an array
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 01/10] wifi: mac80211: move rate control setup Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 02/10] wifi: mac80211: Always provide the MMPDU TXQ Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 04/10] wifi: mac80211: Add new TX queues to replace legacy TX Alexander Wetzel
` (7 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
From: Alexander Wetzel <alexander@wetzel-home.de>
Mac80211 needs additional TX queues to handle all TX within TXQs.
Convert vif->txq to an array, allowing other patches to extend vif TXQs.
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
drivers/net/wireless/ath/ath10k/mac.c | 8 ++++----
drivers/net/wireless/ath/ath9k/ath9k.h | 2 +-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +++---
drivers/net/wireless/mediatek/mt76/mt7603/main.c | 3 ++-
drivers/net/wireless/mediatek/mt76/mt7615/main.c | 5 +++--
drivers/net/wireless/mediatek/mt76/mt76x02_util.c | 3 ++-
drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 +++---
drivers/net/wireless/mediatek/mt76/mt7921/main.c | 5 +++--
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 5 +++--
drivers/net/wireless/mediatek/mt76/mt7996/main.c | 5 +++--
drivers/net/wireless/realtek/rtw88/mac80211.c | 4 ++--
drivers/net/wireless/realtek/rtw88/main.c | 2 +-
drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +-
include/net/mac80211.h | 15 +++++++++++++--
net/mac80211/cfg.c | 8 ++++++--
net/mac80211/debugfs_netdev.c | 4 ++--
net/mac80211/iface.c | 6 ++++--
net/mac80211/tx.c | 8 ++++----
net/mac80211/util.c | 7 ++++---
19 files changed, 64 insertions(+), 40 deletions(-)
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index c61b95a928da..53df2a9102a7 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4297,7 +4297,7 @@ struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
if (peer->sta)
return peer->sta->txq[tid];
else if (peer->vif)
- return peer->vif->txq;
+ return peer->vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
else
return NULL;
}
@@ -5539,7 +5539,7 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
mutex_lock(&ar->conf_mutex);
memset(arvif, 0, sizeof(*arvif));
- ath10k_mac_txq_init(vif->txq);
+ ath10k_mac_txq_init(vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
arvif->ar = ar;
arvif->vif = vif;
@@ -5985,7 +5985,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
spin_unlock_bh(&ar->data_lock);
ath10k_peer_cleanup(ar, arvif->vdev_id);
- ath10k_mac_txq_unref(ar, vif->txq);
+ ath10k_mac_txq_unref(ar, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
if (vif->type == NL80211_IFTYPE_MONITOR) {
ar->monitor_arvif = NULL;
@@ -6002,7 +6002,7 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
ath10k_mac_vif_tx_unlock_all(arvif);
spin_unlock_bh(&ar->htt.tx_lock);
- ath10k_mac_txq_unref(ar, vif->txq);
+ ath10k_mac_txq_unref(ar, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
out:
mutex_unlock(&ar->conf_mutex);
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index a728cc0387df..d681a9a2f377 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -437,7 +437,7 @@ ath_node_to_tid(struct ath_node *an, u8 tidno)
if (sta)
txq = sta->txq[tidno % ARRAY_SIZE(sta->txq)];
else
- txq = vif->txq;
+ txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
return (struct ath_atx_tid *) txq->drv_priv;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index 014777c9cc5d..df7bc70f6744 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -1597,12 +1597,12 @@ int iwl_mvm_post_channel_switch(struct ieee80211_hw *hw,
}
} else if (vif->type == NL80211_IFTYPE_AP && mvmvif->csa_blocks_tx) {
struct iwl_mvm_txq *mvmtxq =
- iwl_mvm_txq_from_mac80211(vif->txq);
+ iwl_mvm_txq_from_mac80211(vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
clear_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
local_bh_disable();
- iwl_mvm_mac_itxq_xmit(hw, vif->txq);
+ iwl_mvm_mac_itxq_xmit(hw, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
ieee80211_iterate_stations_atomic(hw, iwl_mvm_post_csa_tx, hw);
local_bh_enable();
@@ -5712,7 +5712,7 @@ int iwl_mvm_pre_channel_switch(struct iwl_mvm *mvm,
break;
mvmvif->csa_blocks_tx = true;
- mvmtxq = iwl_mvm_txq_from_mac80211(vif->txq);
+ mvmtxq = iwl_mvm_txq_from_mac80211(vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
set_bit(IWL_MVM_TXQ_STATE_STOP_AP_CSA, &mvmtxq->state);
ieee80211_iterate_stations_atomic(mvm->hw,
iwl_mvm_csa_block_txqs,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7603/main.c b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
index 3e8b1ec76169..6f385e2a77ad 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7603/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7603/main.c
@@ -35,6 +35,7 @@ mt7603_stop(struct ieee80211_hw *hw, bool suspend)
static int
mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt7603_vif *mvif = (struct mt7603_vif *)vif->drv_priv;
struct mt7603_dev *dev = hw->priv;
struct mt76_txq *mtxq;
@@ -73,7 +74,7 @@ mt7603_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
eth_broadcast_addr(bc_addr);
mt7603_wtbl_init(dev, idx, mvif->idx, bc_addr);
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 2e7b05eeef7a..81ab5d8b7c8e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -179,6 +179,7 @@ static int get_omac_idx(enum nl80211_iftype type, u64 mask)
static int mt7615_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
struct mt7615_dev *dev = mt7615_hw_dev(hw);
struct mt7615_phy *phy = mt7615_hw_phy(hw);
@@ -231,8 +232,8 @@ static int mt7615_add_interface(struct ieee80211_hw *hw,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.wcid);
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ if (txq) {
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
index 4fb30589fa7a..c02639af7df0 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
+++ b/drivers/net/wireless/mediatek/mt76/mt76x02_util.c
@@ -280,6 +280,7 @@ static void
mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
unsigned int idx)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt76x02_vif *mvif = (struct mt76x02_vif *)vif->drv_priv;
struct mt76_txq *mtxq;
@@ -289,7 +290,7 @@ mt76x02_vif_init(struct mt76x02_dev *dev, struct ieee80211_vif *vif,
mvif->group_wcid.idx = MT_VIF_WCID(idx);
mt76_wcid_init(&mvif->group_wcid, 0);
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ mtxq = (struct mt76_txq *)txq->drv_priv;
rcu_assign_pointer(dev->mt76.wcid[MT_VIF_WCID(idx)], &mvif->group_wcid);
mtxq->wcid = MT_VIF_WCID(idx);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 3aa31c5cefa6..020d74b573ec 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -204,6 +204,7 @@ static void mt7915_init_bitrate_mask(struct ieee80211_vif *vif)
static int mt7915_add_interface(struct ieee80211_hw *hw,
struct ieee80211_vif *vif)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
@@ -259,9 +260,8 @@ static int mt7915_add_interface(struct ieee80211_hw *hw,
mt7915_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
-
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ if (txq) {
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
index 13e58c328aff..625e0268f81c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
@@ -292,6 +292,7 @@ static void mt7921_stop(struct ieee80211_hw *hw, bool suspend)
static int
mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
struct mt792x_dev *dev = mt792x_hw_dev(hw);
struct mt792x_phy *phy = mt792x_hw_phy(hw);
@@ -334,8 +335,8 @@ mt7921_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
ewma_rssi_init(&mvif->bss_conf.rssi);
rcu_assign_pointer(dev->mt76.wcid[idx], &mvif->sta.deflink.wcid);
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ if (txq) {
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 98daf80ac131..c776f33705ab 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -356,6 +356,7 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev,
{
struct mt792x_bss_conf *mconf = mt792x_link_conf_to_mconf(link_conf);
struct ieee80211_vif *vif = link_conf->vif;
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt792x_vif *mvif = mconf->vif;
struct mt76_txq *mtxq;
int idx, ret = 0;
@@ -398,8 +399,8 @@ static int mt7925_mac_link_bss_add(struct mt792x_dev *dev,
if (ret)
goto out;
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ if (txq) {
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 69dd565d8319..77ea8878e197 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -229,6 +229,7 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf,
struct mt76_vif_link *mlink)
{
+ struct ieee80211_txq *txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct mt7996_vif_link *link = container_of(mlink, struct mt7996_vif_link, mt76);
struct mt7996_phy *phy = mphy->priv;
struct mt7996_dev *dev = phy->dev;
@@ -267,8 +268,8 @@ int mt7996_vif_link_add(struct mt76_phy *mphy, struct ieee80211_vif *vif,
mt7996_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
- if (vif->txq) {
- mtxq = (struct mt76_txq *)vif->txq->drv_priv;
+ if (txq) {
+ mtxq = (struct mt76_txq *)txq->drv_priv;
mtxq->wcid = idx;
}
diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c b/drivers/net/wireless/realtek/rtw88/mac80211.c
index 026fbf4ad9cc..f689e37c4f7d 100644
--- a/drivers/net/wireless/realtek/rtw88/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
@@ -162,7 +162,7 @@ static int rtw_ops_add_interface(struct ieee80211_hw *hw,
rtwvif->stats.rx_cnt = 0;
rtwvif->scan_req = NULL;
memset(&rtwvif->bfee, 0, sizeof(struct rtw_bfee));
- rtw_txq_init(rtwdev, vif->txq);
+ rtw_txq_init(rtwdev, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
INIT_LIST_HEAD(&rtwvif->rsvd_page_list);
mutex_lock(&rtwdev->mutex);
@@ -239,7 +239,7 @@ static void rtw_ops_remove_interface(struct ieee80211_hw *hw,
rtw_leave_lps_deep(rtwdev);
- rtw_txq_cleanup(rtwdev, vif->txq);
+ rtw_txq_cleanup(rtwdev, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
rtw_remove_rsvd_page(rtwdev, rtwvif);
eth_zero_addr(rtwvif->mac_addr);
diff --git a/drivers/net/wireless/realtek/rtw88/main.c b/drivers/net/wireless/realtek/rtw88/main.c
index e4f9b744f24d..8ba10a1dfcce 100644
--- a/drivers/net/wireless/realtek/rtw88/main.c
+++ b/drivers/net/wireless/realtek/rtw88/main.c
@@ -626,7 +626,7 @@ static void rtw_reset_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
rtw_bf_disassoc(rtwdev, vif, NULL);
rtw_vif_assoc_changed(rtwvif, NULL);
- rtw_txq_cleanup(rtwdev, vif->txq);
+ rtw_txq_cleanup(rtwdev, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
rtw_release_macid(rtwdev, rtwvif->mac_id);
}
diff --git a/drivers/net/wireless/realtek/rtw89/mac80211.c b/drivers/net/wireless/realtek/rtw89/mac80211.c
index 778ca8589284..c36afe809255 100644
--- a/drivers/net/wireless/realtek/rtw89/mac80211.c
+++ b/drivers/net/wireless/realtek/rtw89/mac80211.c
@@ -181,7 +181,7 @@ static int rtw89_ops_add_interface(struct ieee80211_hw *hw,
rtw89_init_vif(rtwdev, rtwvif, mac_id, port);
- rtw89_core_txq_init(rtwdev, vif->txq);
+ rtw89_core_txq_init(rtwdev, vif->txq[IEEE80211_VIF_TXQ_MULTICAST]);
if (!rtw89_rtwvif_in_list(rtwdev, rtwvif)) {
list_add_tail(&rtwvif->list, &rtwdev->rtwvifs_list);
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 22d32419e8a0..11552c872f2a 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -1966,6 +1966,17 @@ enum ieee80211_neg_ttlm_res {
NEG_TTLM_RES_SUGGEST_PREFERRED
};
+/**
+ * enum ieee80211_vif_txq - per-vif intermediate queues (txqi)
+ *
+ * @IEEE80211_VIF_TXQ_MULTICAST: queue for broadcast/multicast data frames.
+ * @IEEE80211_VIF_TXQ_NUM: max number of available vif TXQs.
+ */
+enum ieee80211_vif_txq {
+ IEEE80211_VIF_TXQ_MULTICAST,
+ IEEE80211_VIF_TXQ_NUM,
+};
+
/**
* struct ieee80211_vif - per-interface data
*
@@ -2020,7 +2031,7 @@ enum ieee80211_neg_ttlm_res {
* for this interface.
* @drv_priv: data area for driver use, will always be aligned to
* sizeof(void \*).
- * @txq: the multicast data TX queue
+ * @txq: per-vif iTXQs (see enum ieee80211_vif_txq for available queues)
* @offload_flags: 802.3 -> 802.11 enapsulation offload flags, see
* &enum ieee80211_offload_flags.
* @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
@@ -2039,7 +2050,7 @@ struct ieee80211_vif {
u8 cab_queue;
u8 hw_queue[IEEE80211_NUM_ACS];
- struct ieee80211_txq *txq;
+ struct ieee80211_txq *txq[IEEE80211_VIF_TXQ_NUM];
netdev_features_t netdev_features;
u32 driver_flags;
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 5785fe30adaa..805dd0a799bc 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4634,12 +4634,16 @@ static int ieee80211_get_txq_stats(struct wiphy *wiphy,
rcu_read_lock();
if (wdev) {
+ struct ieee80211_txq *txq;
+
sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
- if (!sdata->vif.txq) {
+ txq = sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST];
+
+ if (!txq) {
ret = 1;
goto out;
}
- ieee80211_fill_txq_stats(txqstats, to_txq_info(sdata->vif.txq));
+ ieee80211_fill_txq_stats(txqstats, to_txq_info(txq));
} else {
/* phy stats */
txqstats->filled |= BIT(NL80211_TXQ_STATS_BACKLOG_PACKETS) |
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 54c479910d05..73de4c6d420e 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -619,10 +619,10 @@ static ssize_t ieee80211_if_fmt_aqm(
struct txq_info *txqi;
int len;
- if (!sdata->vif.txq)
+ if (!sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST])
return 0;
- txqi = to_txq_info(sdata->vif.txq);
+ txqi = to_txq_info(sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST]);
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e01beda8c414..c6966836817f 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -2238,6 +2238,8 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
{
+ struct ieee80211_txq *txq = sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST];
+
ASSERT_RTNL();
lockdep_assert_wiphy(sdata->local->hw.wiphy);
@@ -2245,8 +2247,8 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
- if (sdata->vif.txq)
- ieee80211_txq_purge(sdata->local, to_txq_info(sdata->vif.txq));
+ if (txq)
+ ieee80211_txq_purge(sdata->local, to_txq_info(txq));
synchronize_rcu();
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 914fba53d7f1..e0a63668c785 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1321,7 +1321,7 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
txq = sta->sta.txq[tid];
} else {
- txq = vif->txq;
+ txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
}
if (!txq)
@@ -1485,10 +1485,10 @@ void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
ap = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
- if (!ap->vif.txq)
+ if (!ap->vif.txq[IEEE80211_VIF_TXQ_MULTICAST])
return;
- txqi = to_txq_info(ap->vif.txq);
+ txqi = to_txq_info(ap->vif.txq[IEEE80211_VIF_TXQ_MULTICAST]);
tin = &txqi->tin;
spin_lock_bh(&fq->lock);
@@ -1510,7 +1510,7 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
txqi->txq.vif = &sdata->vif;
if (!sta) {
- sdata->vif.txq = &txqi->txq;
+ sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST] = &txqi->txq;
txqi->txq.tid = 0;
txqi->txq.ac = IEEE80211_AC_BE;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7f02bd5891eb..9f99128d6219 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -324,6 +324,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_vif *vif = &sdata->vif;
+ struct ieee80211_txq *txq_mc = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct fq *fq = &local->fq;
struct ps_data *ps = NULL;
struct txq_info *txqi;
@@ -364,13 +365,13 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
}
}
- if (!vif->txq)
+ if (!txq_mc)
goto out;
- txqi = to_txq_info(vif->txq);
+ txqi = to_txq_info(txq_mc);
if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
- (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
+ (ps && atomic_read(&ps->num_sta_ps)) || ac != txq_mc->ac)
goto out;
spin_unlock(&fq->lock);
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 04/10] wifi: mac80211: Add new TX queues to replace legacy TX
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (2 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 03/10] wifi: mac80211: Convert vif->txq to an array Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path Alexander Wetzel
` (6 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
From: Alexander Wetzel <alexander@wetzel-home.de>
Add new mac80211 internal TX queues (TXQs) for cases which can't be
handled with the existing queues:
1) per-vif fallback queue for all non-bufferable frames
2) per-vif "noqueue" helper queue
3) per-sta "noqueue" helper queue for sta
The "noqueue" queues are intended for frames which can't be queued but
still use the queue/dequeue functions to prepare the frames. This is
intended to be used for offchannel, disassoc and null-func PS frames in
another patch. For now these frames continue to use the legacy TX path.
All other frames previously using the legacy TX path are switched over
to the new per-vif fallback queue, including TX on monitor interfaces.
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
Changes compared to v1:
- fix wrong indents in drv_wake_tx_queue()
- format fix to a comment in __ieee80211_wake_txq
Changes compared to RFC v1:
- incorporated nits and comment change requests from feedback.
- some additional comment updates
- using unsigned long for qsr in ieee80211_tx_dequeue()
- renamed IEEE80211_TXQ_NOQUEUE to IEEE80211_TID_NOQUEUE. (We use it as
a "special" tid, after all)
- fixed checks in drv_wake_tx_queue() and get rid of the checkpatch
warning.
---
include/net/mac80211.h | 37 ++++++++---
net/mac80211/debugfs_netdev.c | 46 ++++++++------
net/mac80211/driver-ops.h | 25 +++++---
net/mac80211/ieee80211_i.h | 18 ++++++
net/mac80211/iface.c | 93 +++++++++++++++++++--------
net/mac80211/tx.c | 115 +++++++++++++++++-----------------
net/mac80211/util.c | 76 +++++++++++++---------
7 files changed, 263 insertions(+), 147 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 11552c872f2a..320082546b29 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -97,9 +97,14 @@
* linking it to ieee80211_handle_wake_tx_queue() or implementing a custom
* handler.
*
- * Intermediate queues (struct ieee80211_txq) are kept per-sta per-tid, with
- * another per-sta for non-data/non-mgmt and bufferable management frames, and
- * a single per-vif queue for multicast data frames.
+ * Intermediate queues (struct ieee80211_txq) are kept for:
+ * - per-sta per-tid
+ * - per-sta for non-data/non-mgmt and bufferable management frames
+ * - per-sta "noqueue" helper queue for sta (mac80211 internal only)
+ * - per-vif queue for broadcast/multicast data frames
+ * - per-vif fallback queue (mac80211 internal only)
+ * - per-vif "noqueue" helper queue (mac80211 internal only)
+ * The "mac80211 internal only" queues must be ignored by drivers.
*
* The driver is expected to initialize its private per-queue data for stations
* and interfaces in the .add_interface and .sta_add ops.
@@ -1970,10 +1975,19 @@ enum ieee80211_neg_ttlm_res {
* enum ieee80211_vif_txq - per-vif intermediate queues (txqi)
*
* @IEEE80211_VIF_TXQ_MULTICAST: queue for broadcast/multicast data frames.
+ * @IEEE80211_VIF_TXQ_FALLBACK: last resort queue for frames unable to use any
+ * other queue.
+ * @IEEE80211_VIF_TXQ_NOQUEUE: "queue" for non-sta frames which must be
+ * send out immediately, like offchannel, null-func and disassoc frames.
+ * (Queued frames will be transmitted by the queueing process and not wait
+ * for a queue run like normal iTXQs.)
* @IEEE80211_VIF_TXQ_NUM: max number of available vif TXQs.
+ *
*/
enum ieee80211_vif_txq {
IEEE80211_VIF_TXQ_MULTICAST,
+ IEEE80211_VIF_TXQ_FALLBACK,
+ IEEE80211_VIF_TXQ_NOQUEUE,
IEEE80211_VIF_TXQ_NUM,
};
@@ -2465,6 +2479,12 @@ struct ieee80211_link_sta {
struct ieee80211_sta_txpwr txpwr;
};
+/* To identify the NOQUEUE iTXQs vif->txq[IEEE80211_VIF_TXQ_NOQUEUE] and
+ * sta->txq[IEEE80211_TID_NOQUEUE] we set the tid for these queues to
+ * IEEE80211_TID_NOQUEUE (IEEE80211_NUM_TIDS + 1)
+ */
+#define IEEE80211_TID_NOQUEUE (IEEE80211_NUM_TIDS + 1)
+
/**
* struct ieee80211_sta - station table entry
*
@@ -2503,8 +2523,10 @@ struct ieee80211_link_sta {
* For non MLO STA it will point to the deflink data. For MLO STA
* ieee80211_sta_recalc_aggregates() must be called to update it.
* @support_p2p_ps: indicates whether the STA supports P2P PS mechanism or not.
- * @txq: per-TID data TX queues; note that the last entry (%IEEE80211_NUM_TIDS)
- * is used for non-data frames
+ * @txq: per-TID data TX queues; note that the last two queues are not for TIDs:
+ * %IEEE80211_NUM_TIDS is used for non-data frames and
+ * %IEEE80211_TID_NOQUEUE is for frames which can't wait in any of the
+ * other queues and must be send out immediately.
* @deflink: This holds the default link STA information, for non MLO STA all link
* specific STA information is accessed through @deflink or through
* link[0] which points to address of @deflink. For MLO Link STA
@@ -2538,7 +2560,7 @@ struct ieee80211_sta {
bool support_p2p_ps;
- struct ieee80211_txq *txq[IEEE80211_NUM_TIDS + 1];
+ struct ieee80211_txq *txq[IEEE80211_TID_NOQUEUE + 1];
u16 valid_links;
struct ieee80211_link_sta deflink;
@@ -2600,7 +2622,8 @@ struct ieee80211_tx_control {
* @vif: &struct ieee80211_vif pointer from the add_interface callback.
* @sta: station table entry, %NULL for per-vif queue
* @tid: the TID for this queue (unused for per-vif queue),
- * %IEEE80211_NUM_TIDS for non-data (if enabled)
+ * %IEEE80211_NUM_TIDS for non-data (if enabled) and
+ * %IEEE80211_TID_NOQUEUE for non-queueable frames.
* @ac: the AC for this queue
* @drv_priv: driver private area, sized by hw->txq_data_size
*
diff --git a/net/mac80211/debugfs_netdev.c b/net/mac80211/debugfs_netdev.c
index 73de4c6d420e..9de7e3303a2b 100644
--- a/net/mac80211/debugfs_netdev.c
+++ b/net/mac80211/debugfs_netdev.c
@@ -619,28 +619,38 @@ static ssize_t ieee80211_if_fmt_aqm(
struct txq_info *txqi;
int len;
- if (!sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST])
- return 0;
-
- txqi = to_txq_info(sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST]);
+ len = scnprintf(buf,
+ buflen,
+ "id ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets flags\n");
spin_lock_bh(&local->fq.lock);
rcu_read_lock();
- len = scnprintf(buf,
- buflen,
- "ac backlog-bytes backlog-packets new-flows drops marks overlimit collisions tx-bytes tx-packets\n"
- "%u %u %u %u %u %u %u %u %u %u\n",
- txqi->txq.ac,
- txqi->tin.backlog_bytes,
- txqi->tin.backlog_packets,
- txqi->tin.flows,
- txqi->cstats.drop_count,
- txqi->cstats.ecn_mark,
- txqi->tin.overlimit,
- txqi->tin.collisions,
- txqi->tin.tx_bytes,
- txqi->tin.tx_packets);
+ for (int i = 0; i < IEEE80211_VIF_TXQ_NUM; i++) {
+ if (!sdata->vif.txq[i])
+ break;
+
+ txqi = to_txq_info(sdata->vif.txq[i]);
+ len += scnprintf(buf + len,
+ buflen - len,
+ "%u %u %u %u %u %u %u %u %u %u %u 0x%lx(%s%s%s%s)\n",
+ txqi->txq.tid,
+ txqi->txq.ac,
+ txqi->tin.backlog_bytes,
+ txqi->tin.backlog_packets,
+ txqi->tin.flows,
+ txqi->cstats.drop_count,
+ txqi->cstats.ecn_mark,
+ txqi->tin.overlimit,
+ txqi->tin.collisions,
+ txqi->tin.tx_bytes,
+ txqi->tin.tx_packets,
+ txqi->flags,
+ test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
+ test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
+ test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "",
+ test_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ? " DIRTY" : "");
+ }
rcu_read_unlock();
spin_unlock_bh(&local->fq.lock);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index 992fa2957621..d5419eb06224 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1360,22 +1360,27 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
return;
}
- if (!check_sdata_in_driver(sdata))
- return;
-
trace_drv_wake_tx_queue(local, sdata, txq);
- /* Driver support for MPDU TXQ support is optional */
- if (unlikely(txq->txq.tid == IEEE80211_NUM_TIDS &&
- ((sdata->vif.type == NL80211_IFTYPE_STATION &&
- !ieee80211_hw_check(&sdata->local->hw, STA_MMPDU_TXQ)) ||
- (sdata->vif.type != NL80211_IFTYPE_STATION &&
- !ieee80211_hw_check(&sdata->local->hw,
- BUFF_MMPDU_TXQ))))) {
+ /*
+ * Driver support for MPDU TXQ support is optional.
+ * IEEE80211_NUM_TIDS (fallback) TXQs are mac80211 internal and not
+ * intended to be handled by the drivers.
+ */
+ if (WARN_ON(txq->txq.tid == IEEE80211_TID_NOQUEUE) ||
+ (txq->txq.tid == IEEE80211_NUM_TIDS &&
+ (!txq->txq.sta ||
+ (sdata->vif.type == NL80211_IFTYPE_STATION &&
+ !ieee80211_hw_check(&sdata->local->hw, STA_MMPDU_TXQ)) ||
+ (sdata->vif.type != NL80211_IFTYPE_STATION &&
+ !ieee80211_hw_check(&sdata->local->hw, BUFF_MMPDU_TXQ))))) {
ieee80211_handle_wake_tx_queue(&local->hw, &txq->txq);
return;
}
+ if (WARN_ON_ONCE(!check_sdata_in_driver(sdata)))
+ return;
+
local->ops->wake_tx_queue(&local->hw, &txq->txq);
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index f23be8b5d0d8..feda302d3a4c 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1640,6 +1640,24 @@ IEEE80211_WDEV_TO_SUB_IF(struct wireless_dev *wdev)
return container_of(wdev, struct ieee80211_sub_if_data, wdev);
}
+static inline struct ieee80211_sub_if_data *
+ieee80211_get_tx_sdata(struct ieee80211_sub_if_data *sdata)
+{
+ if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
+ sdata = container_of(sdata->bss,
+ struct ieee80211_sub_if_data, u.ap);
+ /*
+ * local->monitor_sdata can only be set without
+ * IEEE80211_HW_NO_VIRTUAL_MONITOR, no need to check it here.
+ */
+ else if (unlikely(sdata->vif.type == NL80211_IFTYPE_MONITOR) &&
+ sdata->local->monitor_sdata &&
+ !(sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE))
+ sdata = rcu_dereference(sdata->local->monitor_sdata);
+
+ return sdata;
+}
+
static inline struct ieee80211_supported_band *
ieee80211_get_sband(struct ieee80211_sub_if_data *sdata)
{
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index c6966836817f..0437e87ec8f2 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -1145,9 +1145,36 @@ static void ieee80211_sdata_init(struct ieee80211_local *local,
}
}
+static void ieee80211_vif_txq_init(struct ieee80211_sub_if_data *sdata,
+ int txq_offset, int txq_size, int num_queues)
+{
+ void *buffer = (char *)sdata + txq_offset;
+
+ /* IEEE80211_VIF_TXQ_FALLBACK */
+ ieee80211_txq_init(sdata, NULL, buffer, IEEE80211_NUM_TIDS);
+
+ if (num_queues == 1)
+ return;
+
+ /* IEEE80211_VIF_TXQ_NOQUEUE */
+ buffer += txq_size;
+ ieee80211_txq_init(sdata, NULL, buffer, IEEE80211_TID_NOQUEUE);
+
+ if (num_queues == 2)
+ return;
+
+ /* IEEE80211_VIF_TXQ_MULTICAST */
+ buffer += txq_size;
+ ieee80211_txq_init(sdata, NULL, buffer, 0);
+}
+
int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
{
struct ieee80211_sub_if_data *sdata;
+ int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
+ sizeof(void *));
+ int txq_size = ALIGN(sizeof(struct txq_info) + local->hw.txq_data_size,
+ sizeof(void *));
int ret;
ASSERT_RTNL();
@@ -1157,7 +1184,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR))
return 0;
- sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size, GFP_KERNEL);
+ sdata = kzalloc(size + txq_size, GFP_KERNEL);
if (!sdata)
return -ENOMEM;
@@ -1169,7 +1196,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
sdata->wdev.wiphy = local->hw.wiphy;
ieee80211_sdata_init(local, sdata);
-
+ ieee80211_vif_txq_init(sdata, size, txq_size, 1);
ieee80211_set_default_queues(sdata);
if (ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
@@ -2100,7 +2127,11 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
{
struct net_device *ndev = NULL;
struct ieee80211_sub_if_data *sdata = NULL;
- struct txq_info *txqi;
+ int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
+ sizeof(void *));
+ int txq_size = ALIGN(sizeof(struct txq_info) + local->hw.txq_data_size,
+ sizeof(void *));
+ int num_txqs = 2;
int ret;
ASSERT_RTNL();
@@ -2109,8 +2140,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
if (type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN) {
struct wireless_dev *wdev;
- sdata = kzalloc(sizeof(*sdata) + local->hw.vif_data_size,
- GFP_KERNEL);
+ sdata = kzalloc(size + 2 * txq_size, GFP_KERNEL);
if (!sdata)
return -ENOMEM;
wdev = &sdata->wdev;
@@ -2121,17 +2151,14 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
memcpy(sdata->vif.addr, wdev->address, ETH_ALEN);
ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
} else {
- int size = ALIGN(sizeof(*sdata) + local->hw.vif_data_size,
- sizeof(void *));
- int txq_size = 0;
-
- if (type != NL80211_IFTYPE_AP_VLAN &&
- (type != NL80211_IFTYPE_MONITOR ||
- (params->flags & MONITOR_FLAG_ACTIVE)))
- txq_size += sizeof(struct txq_info) +
- local->hw.txq_data_size;
+ if (type == NL80211_IFTYPE_AP_VLAN)
+ num_txqs = 0;
+ else if (type == NL80211_IFTYPE_MONITOR)
+ num_txqs = 1;
+ else
+ num_txqs = 3;
- ndev = alloc_netdev_mqs(size + txq_size,
+ ndev = alloc_netdev_mqs(size + num_txqs * txq_size,
name, name_assign_type,
ieee80211_if_setup, 1, 1);
if (!ndev)
@@ -2170,14 +2197,12 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
ether_addr_copy(sdata->vif.bss_conf.addr, sdata->vif.addr);
memcpy(sdata->name, ndev->name, IFNAMSIZ);
- if (txq_size) {
- txqi = netdev_priv(ndev) + size;
- ieee80211_txq_init(sdata, NULL, txqi, 0);
- }
-
sdata->dev = ndev;
}
+ if (num_txqs)
+ ieee80211_vif_txq_init(sdata, size, txq_size, num_txqs);
+
/* initialise type-independent data */
sdata->wdev.wiphy = local->hw.wiphy;
@@ -2236,10 +2261,27 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
return 0;
}
-void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
+static void ieee80211_purge_txqs(struct ieee80211_sub_if_data *sdata)
{
- struct ieee80211_txq *txq = sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST];
+ struct sta_info *sta;
+
+ list_for_each_entry(sta, &sdata->local->sta_list, list) {
+ if (sdata != sta->sdata)
+ continue;
+ ieee80211_purge_sta_txqs(sta);
+ }
+
+ for (int i = IEEE80211_VIF_TXQ_MULTICAST;
+ i <= IEEE80211_VIF_TXQ_FALLBACK;
+ i++) {
+ if (sdata->vif.txq[i])
+ ieee80211_txq_purge(sdata->local,
+ to_txq_info(sdata->vif.txq[i]));
+ }
+}
+void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
+{
ASSERT_RTNL();
lockdep_assert_wiphy(sdata->local->hw.wiphy);
@@ -2247,9 +2289,7 @@ void ieee80211_if_remove(struct ieee80211_sub_if_data *sdata)
list_del_rcu(&sdata->list);
mutex_unlock(&sdata->local->iflist_mtx);
- if (txq)
- ieee80211_txq_purge(sdata->local, to_txq_info(txq));
-
+ ieee80211_purge_txqs(sdata);
synchronize_rcu();
cfg80211_unregister_wdev(&sdata->wdev);
@@ -2299,6 +2339,8 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
list_for_each_entry_safe(sdata, tmp, &unreg_list, list) {
bool netdev = sdata->dev;
+ ieee80211_purge_txqs(sdata);
+
/*
* Remove IP addresses explicitly, since the notifier will
* skip the callbacks if wdev->registered is false, since
@@ -2317,6 +2359,7 @@ void ieee80211_remove_interfaces(struct ieee80211_local *local)
if (!netdev)
kfree(sdata);
}
+ synchronize_rcu();
}
static int netdev_notify(struct notifier_block *nb,
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e0a63668c785..600c34fe10ad 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1301,31 +1301,37 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_txq *txq = NULL;
- if ((info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM) ||
- (info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK))
+ /* Offchannel queue can't be used, yet */
return NULL;
- if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
- unlikely(!ieee80211_is_data_present(hdr->frame_control))) {
+ if (unlikely(vif->type == NL80211_IFTYPE_MONITOR ||
+ info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM ||
+ info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE))
+ goto out;
+
+ if (unlikely(!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) &&
+ !ieee80211_is_data_present(hdr->frame_control))) {
if ((!ieee80211_is_mgmt(hdr->frame_control) ||
ieee80211_is_bufferable_mmpdu(skb) ||
vif->type == NL80211_IFTYPE_STATION) &&
sta && sta->uploaded) {
txq = sta->sta.txq[IEEE80211_NUM_TIDS];
}
- } else if (sta) {
+ } else if (likely(sta)) {
u8 tid = skb->priority & IEEE80211_QOS_CTL_TID_MASK;
- if (!sta->uploaded)
- return NULL;
+ if (unlikely(!sta->uploaded))
+ goto out;
txq = sta->sta.txq[tid];
} else {
txq = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
}
+out:
if (!txq)
- return NULL;
+ txq = vif->txq[IEEE80211_VIF_TXQ_FALLBACK];
return to_txq_info(txq);
}
@@ -1447,12 +1453,13 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local,
spin_lock_bh(&fq->lock);
/*
- * For management frames, don't really apply codel etc.,
+ * For management frames (tid set to IEEE80211_NUM_TIDS
+ * or IEEE80211_TID_NOQUEUE), don't really apply codel etc.,
* we don't want to apply any shaping or anything we just
- * want to simplify the driver API by having them on the
- * txqi.
+ * want to simplify the driver API and mac80211 internal
+ * handling by having them on the txqi.
*/
- if (unlikely(txqi->txq.tid == IEEE80211_NUM_TIDS)) {
+ if (unlikely(txqi->txq.tid >= IEEE80211_NUM_TIDS)) {
IEEE80211_SKB_CB(skb)->control.flags |=
IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
__skb_queue_tail(&txqi->frags, skb);
@@ -1510,14 +1517,26 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata,
txqi->txq.vif = &sdata->vif;
if (!sta) {
- sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST] = &txqi->txq;
- txqi->txq.tid = 0;
- txqi->txq.ac = IEEE80211_AC_BE;
+ if (tid == IEEE80211_TID_NOQUEUE) {
+ sdata->vif.txq[IEEE80211_VIF_TXQ_NOQUEUE] =
+ &txqi->txq;
+ txqi->txq.ac = IEEE80211_AC_VO;
+ } else if (tid == IEEE80211_NUM_TIDS) {
+ sdata->vif.txq[IEEE80211_VIF_TXQ_FALLBACK] =
+ &txqi->txq;
+ txqi->txq.ac = IEEE80211_AC_VO;
+ } else {
+ sdata->vif.txq[IEEE80211_VIF_TXQ_MULTICAST] =
+ &txqi->txq;
+ txqi->txq.ac = IEEE80211_AC_BE;
+ }
+ txqi->txq.tid = tid;
return;
}
- if (tid == IEEE80211_NUM_TIDS)
+ /* for %IEEE80211_NUM_TIDS and %IEEE80211_TID_NOQUEUE */
+ if (tid >= IEEE80211_NUM_TIDS)
txqi->txq.ac = IEEE80211_AC_VO;
else
txqi->txq.ac = ieee80211_ac_from_tid(tid);
@@ -1629,16 +1648,13 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
struct sta_info *sta,
struct sk_buff *skb)
{
- struct ieee80211_vif *vif;
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct ieee80211_vif *vif = &sdata->vif;
struct txq_info *txqi;
- if (sdata->vif.type == NL80211_IFTYPE_MONITOR)
- return false;
-
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
+ info->control.vif = vif;
+ sdata = ieee80211_get_tx_sdata(sdata);
vif = &sdata->vif;
txqi = ieee80211_get_txq(local, vif, sta, skb);
@@ -3795,7 +3811,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_local *local = hw_to_local(hw);
struct txq_info *txqi = container_of(txq, struct txq_info, txq);
struct ieee80211_hdr *hdr;
- struct sk_buff *skb = NULL;
+ struct sk_buff *skb;
struct fq *fq = &local->fq;
struct fq_tin *tin = &txqi->tin;
struct ieee80211_tx_info *info;
@@ -3804,7 +3820,7 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
struct ieee80211_vif *vif = txq->vif;
int q = vif->hw_queue[txq->ac];
unsigned long flags;
- bool q_stopped;
+ unsigned long qsr;
WARN_ON_ONCE(softirq_count() == 0);
@@ -3813,10 +3829,22 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
begin:
spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- q_stopped = local->queue_stop_reasons[q];
+ qsr = local->queue_stop_reasons[q];
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- if (unlikely(q_stopped)) {
+ if (unlikely(qsr &&
+ (txq->tid != IEEE80211_TID_NOQUEUE ||
+ (qsr & ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL))))) {
+ /*
+ * Drop noqueue (includes off-channel) frames if queues are
+ * stopped for any other reason than off-channel operation.
+ */
+ if (WARN_ONCE(txq->tid == IEEE80211_TID_NOQUEUE,
+ "mac80211: Drop noqueue TX. qsr=%lu\n", qsr)) {
+ ieee80211_txq_purge(local, txqi);
+ return NULL;
+ }
+
/* mark for waking later */
set_bit(IEEE80211_TXQ_DIRTY, &txqi->flags);
return NULL;
@@ -3937,36 +3965,6 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
}
}
- switch (tx.sdata->vif.type) {
- case NL80211_IFTYPE_MONITOR:
- if ((tx.sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
- ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
- vif = &tx.sdata->vif;
- break;
- }
- tx.sdata = rcu_dereference(local->monitor_sdata);
- if (tx.sdata &&
- ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
- vif = &tx.sdata->vif;
- info->hw_queue =
- vif->hw_queue[skb_get_queue_mapping(skb)];
- } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
- ieee80211_free_txskb(&local->hw, skb);
- goto begin;
- } else {
- info->control.vif = NULL;
- return skb;
- }
- break;
- case NL80211_IFTYPE_AP_VLAN:
- tx.sdata = container_of(tx.sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
- fallthrough;
- default:
- vif = &tx.sdata->vif;
- break;
- }
-
encap_out:
info->control.vif = vif;
@@ -4144,7 +4142,7 @@ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
if (!txq->sta)
return true;
- if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
+ if (unlikely(txq->tid >= IEEE80211_NUM_TIDS))
return true;
sta = container_of(txq->sta, struct sta_info, sta);
@@ -4637,7 +4635,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
struct ieee80211_sub_if_data, u.ap);
info->flags |= IEEE80211_TX_CTL_HW_80211_ENCAP;
- info->control.vif = &sdata->vif;
if (key)
info->control.hw_key = &key->conf;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 9f99128d6219..5e76829ecc6b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -320,65 +320,85 @@ void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue);
+__releases(&local->fq->lock)
+__acquires(&local->fq->lock)
+static void __ieee80211_wake_txq(struct ieee80211_local *local,
+ struct ieee80211_txq *txq)
+{
+ struct txq_info *txqi = to_txq_info(txq);
+ struct fq *fq = &local->fq;
+
+ if (WARN_ON(!txq))
+ return;
+ if (test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags)) {
+ /* ieee80211_tx_dequeue() also takes fq->lock */
+ spin_unlock(&fq->lock);
+ drv_wake_tx_queue(local, txqi);
+ spin_lock(&fq->lock);
+ }
+}
+
static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
{
struct ieee80211_local *local = sdata->local;
- struct ieee80211_vif *vif = &sdata->vif;
- struct ieee80211_txq *txq_mc = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
struct fq *fq = &local->fq;
struct ps_data *ps = NULL;
- struct txq_info *txqi;
struct sta_info *sta;
+ struct ieee80211_vif *vif;
+ struct ieee80211_txq *txq_mc, *txq_fb;
int i;
local_bh_disable();
spin_lock(&fq->lock);
+ if (WARN_ON(!sdata))
+ goto out;
if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
goto out;
+ sdata = ieee80211_get_tx_sdata(sdata);
+ vif = &sdata->vif;
+ txq_mc = vif->txq[IEEE80211_VIF_TXQ_MULTICAST];
+ txq_fb = vif->txq[IEEE80211_VIF_TXQ_FALLBACK];
+
if (sdata->vif.type == NL80211_IFTYPE_AP)
ps = &sdata->bss->ps;
+ /*
+ * Start with vif TXQs.
+ * Don't check IEEE80211_TID_NOQUEUE for IEEE80211_VIF_TXQ_NOQUEUE.
+ * It can't get dirty or queue frames
+ */
+
+ if (ac == txq_fb->ac)
+ __ieee80211_wake_txq(local, txq_fb);
+
+ if (txq_mc && ac == txq_mc->ac &&
+ (!ps || !atomic_read(&ps->num_sta_ps)))
+ __ieee80211_wake_txq(local, txq_mc);
+
+ /* STA TXQs */
list_for_each_entry_rcu(sta, &local->sta_list, list) {
if (sdata != sta->sdata)
continue;
- for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
+ /*
+ * Don't check IEEE80211_TID_NOQUEUE for sta's
+ * They can't get dirty or queue frames
+ */
+ for (i = 0; i <= IEEE80211_NUM_TIDS; i++) {
struct ieee80211_txq *txq = sta->sta.txq[i];
if (!txq)
continue;
- txqi = to_txq_info(txq);
-
if (ac != txq->ac)
continue;
- if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY,
- &txqi->flags))
- continue;
-
- spin_unlock(&fq->lock);
- drv_wake_tx_queue(local, txqi);
- spin_lock(&fq->lock);
+ /* releases and retakes fq->lock */
+ __ieee80211_wake_txq(local, txq);
}
}
-
- if (!txq_mc)
- goto out;
-
- txqi = to_txq_info(txq_mc);
-
- if (!test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags) ||
- (ps && atomic_read(&ps->num_sta_ps)) || ac != txq_mc->ac)
- goto out;
-
- spin_unlock(&fq->lock);
-
- drv_wake_tx_queue(local, txqi);
- local_bh_enable();
- return;
out:
spin_unlock(&fq->lock);
local_bh_enable();
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (3 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 04/10] wifi: mac80211: Add new TX queues to replace legacy TX Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 22:33 ` kernel test robot
2025-02-17 8:17 ` [PATCH v2 06/10] wifi: mac80211: Call ieee80211_tx_h_select_key only once Alexander Wetzel
` (5 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
From: Alexander Wetzel <alexander@wetzel-home.de>
Stop using the legacy TX path within mac80211 and start using TXQs to
handle the not queueable offchannel, disassoc and null-func PS frames.
ieee80211_tx() will queue these frames into either the per-vif or
per-sta helper TXQ. But instead of scheduling a queue run the frame will
immediately be dequeued again and handed over to the driver.
With that functionality mac80211 is now only using TXQs to send frames.
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
Changes compared to v1:
- Use WARN_ON_ONE() instead WARN() in ieee80211_tx()
---
net/mac80211/tx.c | 307 +++++++-------------------------------------
net/mac80211/util.c | 12 +-
2 files changed, 55 insertions(+), 264 deletions(-)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 600c34fe10ad..db66deae69a4 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1301,9 +1301,13 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_txq *txq = NULL;
- if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK))
- /* Offchannel queue can't be used, yet */
- return NULL;
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
+ if (sta)
+ txq = sta->sta.txq[IEEE80211_TID_NOQUEUE];
+ else
+ txq = vif->txq[IEEE80211_VIF_TXQ_NOQUEUE];
+ goto out;
+ }
if (unlikely(vif->type == NL80211_IFTYPE_MONITOR ||
info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM ||
@@ -1643,10 +1647,10 @@ void ieee80211_txq_teardown_flows(struct ieee80211_local *local)
spin_unlock_bh(&fq->lock);
}
-static bool ieee80211_queue_skb(struct ieee80211_local *local,
- struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta,
- struct sk_buff *skb)
+static struct txq_info *ieee80211_queue_skb(struct ieee80211_local *local,
+ struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta,
+ struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = &sdata->vif;
@@ -1658,143 +1662,12 @@ static bool ieee80211_queue_skb(struct ieee80211_local *local,
vif = &sdata->vif;
txqi = ieee80211_get_txq(local, vif, sta, skb);
- if (!txqi)
- return false;
-
ieee80211_txq_enqueue(local, txqi, skb);
- schedule_and_wake_txq(local, txqi);
-
- return true;
-}
-
-static bool ieee80211_tx_frags(struct ieee80211_local *local,
- struct ieee80211_vif *vif,
- struct sta_info *sta,
- struct sk_buff_head *skbs,
- bool txpending)
-{
- struct ieee80211_tx_control control = {};
- struct sk_buff *skb, *tmp;
- unsigned long flags;
-
- skb_queue_walk_safe(skbs, skb, tmp) {
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- int q = info->hw_queue;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
- if (WARN_ON_ONCE(q >= local->hw.queues)) {
- __skb_unlink(skb, skbs);
- ieee80211_free_txskb(&local->hw, skb);
- continue;
- }
-#endif
-
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- if (local->queue_stop_reasons[q] ||
- (!txpending && !skb_queue_empty(&local->pending[q]))) {
- if (unlikely(info->flags &
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
- if (local->queue_stop_reasons[q] &
- ~BIT(IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL)) {
- /*
- * Drop off-channel frames if queues
- * are stopped for any reason other
- * than off-channel operation. Never
- * queue them.
- */
- spin_unlock_irqrestore(
- &local->queue_stop_reason_lock,
- flags);
- ieee80211_purge_tx_queue(&local->hw,
- skbs);
- return true;
- }
- } else {
-
- /*
- * Since queue is stopped, queue up frames for
- * later transmission from the tx-pending
- * tasklet when the queue is woken again.
- */
- if (txpending)
- skb_queue_splice_init(skbs,
- &local->pending[q]);
- else
- skb_queue_splice_tail_init(skbs,
- &local->pending[q]);
-
- spin_unlock_irqrestore(&local->queue_stop_reason_lock,
- flags);
- return false;
- }
- }
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- info->control.vif = vif;
- control.sta = sta ? &sta->sta : NULL;
-
- __skb_unlink(skb, skbs);
- drv_tx(local, &control, skb);
- }
-
- return true;
-}
-
-/*
- * Returns false if the frame couldn't be transmitted but was queued instead.
- */
-static bool __ieee80211_tx(struct ieee80211_local *local,
- struct sk_buff_head *skbs, struct sta_info *sta,
- bool txpending)
-{
- struct ieee80211_tx_info *info;
- struct ieee80211_sub_if_data *sdata;
- struct ieee80211_vif *vif;
- struct sk_buff *skb;
- bool result;
-
- if (WARN_ON(skb_queue_empty(skbs)))
- return true;
-
- skb = skb_peek(skbs);
- info = IEEE80211_SKB_CB(skb);
- sdata = vif_to_sdata(info->control.vif);
- if (sta && !sta->uploaded)
- sta = NULL;
-
- switch (sdata->vif.type) {
- case NL80211_IFTYPE_MONITOR:
- if ((sdata->u.mntr.flags & MONITOR_FLAG_ACTIVE) ||
- ieee80211_hw_check(&local->hw, NO_VIRTUAL_MONITOR)) {
- vif = &sdata->vif;
- break;
- }
- sdata = rcu_dereference(local->monitor_sdata);
- if (sdata && ieee80211_hw_check(&local->hw, WANT_MONITOR_VIF)) {
- vif = &sdata->vif;
- info->hw_queue =
- vif->hw_queue[skb_get_queue_mapping(skb)];
- } else if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL)) {
- ieee80211_purge_tx_queue(&local->hw, skbs);
- return true;
- } else
- vif = NULL;
- break;
- case NL80211_IFTYPE_AP_VLAN:
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
- fallthrough;
- default:
- vif = &sdata->vif;
- break;
- }
-
- result = ieee80211_tx_frags(local, vif, sta, skbs, txpending);
-
- WARN_ON_ONCE(!skb_queue_empty(skbs));
+ if (likely(txqi->txq.tid != IEEE80211_TID_NOQUEUE))
+ schedule_and_wake_txq(local, txqi);
- return result;
+ return txqi;
}
/*
@@ -1929,22 +1802,20 @@ bool ieee80211_tx_prepare_skb(struct ieee80211_hw *hw,
}
EXPORT_SYMBOL(ieee80211_tx_prepare_skb);
-/*
- * Returns false if the frame couldn't be transmitted but was queued instead.
- */
-static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
- struct sta_info *sta, struct sk_buff *skb,
- bool txpending)
+static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
+ struct sta_info *sta, struct sk_buff *skb)
{
struct ieee80211_local *local = sdata->local;
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- bool result = true;
+ bool noqueue = info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ struct ieee80211_tx_control control;
+ struct txq_info *txqi;
if (unlikely(skb->len < 10)) {
dev_kfree_skb(skb);
- return true;
+ return;
}
/* initialises tx */
@@ -1952,9 +1823,9 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
if (unlikely(res_prepare == TX_DROP)) {
ieee80211_free_txskb(&local->hw, skb);
- return true;
+ return;
} else if (unlikely(res_prepare == TX_QUEUED)) {
- return true;
+ return;
}
/* set up hw_queue value early */
@@ -1964,15 +1835,23 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata,
sdata->vif.hw_queue[skb_get_queue_mapping(skb)];
if (invoke_tx_handlers_early(&tx))
- return true;
+ return;
- if (ieee80211_queue_skb(local, sdata, tx.sta, tx.skb))
- return true;
+ txqi = ieee80211_queue_skb(local, sdata, tx.sta, tx.skb);
+
+ if (likely(!noqueue))
+ return;
- if (!invoke_tx_handlers_late(&tx))
- result = __ieee80211_tx(local, &tx.skbs, tx.sta, txpending);
+ /* Noqueue frames bypass the normal TX and go out immediately */
- return result;
+ if (sta && sta->uploaded)
+ control.sta = txqi->txq.sta;
+ else
+ control.sta = NULL;
+
+ skb = ieee80211_tx_dequeue(&local->hw, &txqi->txq);
+ if (!WARN_ON_ONCE(!skb))
+ drv_tx(local, &control, skb);
}
/* device xmit handlers */
@@ -2062,7 +1941,7 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
}
ieee80211_set_qos_hdr(sdata, skb);
- ieee80211_tx(sdata, sta, skb, false);
+ ieee80211_tx(sdata, sta, skb);
}
static bool ieee80211_validate_radiotap_len(struct sk_buff *skb)
@@ -3676,7 +3555,6 @@ void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
struct ieee80211_tx_info *info;
struct ieee80211_tx_data tx;
- ieee80211_tx_result r;
int hw_headroom = sdata->local->hw.extra_tx_headroom;
int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2);
@@ -3732,22 +3610,7 @@ void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
tx.sta = sta;
tx.key = fast_tx->key;
- if (ieee80211_queue_skb(local, sdata, sta, skb))
- return;
-
- tx.skb = skb;
- r = ieee80211_xmit_fast_finish(sdata, sta, fast_tx->pn_offs,
- fast_tx->key, &tx);
- tx.skb = NULL;
- if (r == TX_DROP)
- goto free;
-
- if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
- sdata = container_of(sdata->bss,
- struct ieee80211_sub_if_data, u.ap);
-
- __skb_queue_tail(&tx.skbs, skb);
- ieee80211_tx_frags(local, &sdata->vif, sta, &tx.skbs, false);
+ ieee80211_queue_skb(local, sdata, sta, skb);
return;
free:
@@ -4522,65 +4385,6 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
return NETDEV_TX_OK;
}
-
-
-static bool __ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, struct sta_info *sta,
- bool txpending)
-{
- struct ieee80211_local *local = sdata->local;
- struct ieee80211_tx_control control = {};
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *pubsta = NULL;
- unsigned long flags;
- int q = info->hw_queue;
-
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
-
- if (local->queue_stop_reasons[q] ||
- (!txpending && !skb_queue_empty(&local->pending[q]))) {
- if (txpending)
- skb_queue_head(&local->pending[q], skb);
- else
- skb_queue_tail(&local->pending[q], skb);
-
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- return false;
- }
-
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-
- if (sta && sta->uploaded)
- pubsta = &sta->sta;
-
- control.sta = pubsta;
-
- drv_tx(local, &control, skb);
-
- return true;
-}
-
-static bool ieee80211_tx_8023(struct ieee80211_sub_if_data *sdata,
- struct sk_buff *skb, struct sta_info *sta,
- bool txpending)
-{
- struct ieee80211_local *local = sdata->local;
- struct sk_buff *next;
- bool ret = true;
-
- if (ieee80211_queue_skb(local, sdata, sta, skb))
- return true;
-
- skb_list_walk_safe(skb, skb, next) {
- skb_mark_not_on_list(skb);
- if (!__ieee80211_tx_8023(sdata, skb, sta, txpending))
- ret = false;
- }
-
- return ret;
-}
-
static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
struct net_device *dev, struct sta_info *sta,
struct ieee80211_key *key, struct sk_buff *skb)
@@ -4659,8 +4463,7 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
sta->deflink.tx_stats.bytes[queue] += len;
ieee80211_tpt_led_trig_tx(local, len);
-
- ieee80211_tx_8023(sdata, skb, sta, false);
+ ieee80211_queue_skb(local, sdata, sta, skb);
return;
@@ -4767,19 +4570,13 @@ void ieee80211_clear_tx_pending(struct ieee80211_local *local)
}
}
-/*
- * Returns false if the frame couldn't be transmitted but was queued instead,
- * which in this case means re-queued -- take as an indication to stop sending
- * more pending frames.
- */
-static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
+static void ieee80211_tx_pending_skb(struct ieee80211_local *local,
struct sk_buff *skb)
{
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_sub_if_data *sdata;
struct sta_info *sta;
struct ieee80211_hdr *hdr;
- bool result;
struct ieee80211_chanctx_conf *chanctx_conf;
sdata = vif_to_sdata(info->control.vif);
@@ -4791,34 +4588,25 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
if (unlikely(!chanctx_conf)) {
dev_kfree_skb(skb);
- return true;
+ return;
}
info->band = chanctx_conf->def.chan->band;
}
- result = ieee80211_tx(sdata, NULL, skb, true);
+ ieee80211_tx(sdata, NULL, skb);
} else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
dev_kfree_skb(skb);
- return true;
+ return;
}
if (IS_ERR(sta) || (sta && !sta->uploaded))
sta = NULL;
- result = ieee80211_tx_8023(sdata, skb, sta, true);
+ ieee80211_queue_skb(local, sdata, sta, skb);
} else {
- struct sk_buff_head skbs;
-
- __skb_queue_head_init(&skbs);
- __skb_queue_tail(&skbs, skb);
-
- hdr = (struct ieee80211_hdr *)skb->data;
sta = sta_info_get(sdata, hdr->addr1);
-
- result = __ieee80211_tx(local, &skbs, sta, true);
+ ieee80211_tx(sdata, sta, skb);
}
-
- return result;
}
/*
@@ -4830,7 +4618,6 @@ void ieee80211_tx_pending(struct tasklet_struct *t)
tx_pending_tasklet);
unsigned long flags;
int i;
- bool txok;
rcu_read_lock();
@@ -4856,11 +4643,9 @@ void ieee80211_tx_pending(struct tasklet_struct *t)
spin_unlock_irqrestore(&local->queue_stop_reason_lock,
flags);
- txok = ieee80211_tx_pending_skb(local, skb);
+ ieee80211_tx_pending_skb(local, skb);
spin_lock_irqsave(&local->queue_stop_reason_lock,
flags);
- if (!txok)
- break;
}
}
spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 5e76829ecc6b..4a130d2ffcb9 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -353,8 +353,6 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
if (WARN_ON(!sdata))
goto out;
- if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
- goto out;
sdata = ieee80211_get_tx_sdata(sdata);
vif = &sdata->vif;
@@ -429,6 +427,9 @@ _ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
for (ac = 0; ac < n_acs; ac++) {
int ac_queue = sdata->vif.hw_queue[ac];
+ if (unlikely(!ieee80211_sdata_running(sdata)))
+ continue;
+
if (ac_queue == i ||
sdata->vif.cab_queue == i)
__ieee80211_wake_txqs(sdata, ac);
@@ -1190,8 +1191,13 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
if (sdata->vif.type != NL80211_IFTYPE_STATION ||
!(sdata->u.mgd.flags & IEEE80211_STA_MFP_ENABLED))
+ /*
+ * Use offchannel txq and tx to avoid raceing
+ * the frame with tearing down sta txq's
+ */
IEEE80211_SKB_CB(skb)->flags |=
- IEEE80211_TX_INTFL_DONT_ENCRYPT;
+ IEEE80211_TX_INTFL_DONT_ENCRYPT |
+ IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
ieee80211_tx_skb(sdata, skb);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 06/10] wifi: mac80211: Call ieee80211_tx_h_select_key only once
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (4 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 07/10] wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK Alexander Wetzel
` (4 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
ieee80211_tx_dequeue() already calls ieee80211_tx_h_select_key() when
needed. Move it from invoke_tx_handlers_early() to invoke_tx_handlers()
to avoid calling it twice for TXQs.
Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
---
net/mac80211/tx.c | 12 +++++++++++-
1 file changed, 11 insertions(+), 1 deletion(-)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index db66deae69a4..7c269d8e5dcf 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1693,7 +1693,6 @@ static int invoke_tx_handlers_early(struct ieee80211_tx_data *tx)
CALL_TXH(ieee80211_tx_h_check_assoc);
CALL_TXH(ieee80211_tx_h_ps_buf);
CALL_TXH(ieee80211_tx_h_check_control_port_protocol);
- CALL_TXH(ieee80211_tx_h_select_key);
txh_done:
if (unlikely(res == TX_DROP)) {
@@ -1761,6 +1760,17 @@ static int invoke_tx_handlers(struct ieee80211_tx_data *tx)
if (r)
return r;
+
+ r = ieee80211_tx_h_select_key(tx);
+ if (unlikely(r != TX_CONTINUE)) {
+ I802_DEBUG_INC(tx->local->tx_handlers_drop);
+ if (tx->skb)
+ ieee80211_free_txskb(&tx->local->hw, tx->skb);
+ else
+ ieee80211_purge_tx_queue(&tx->local->hw, &tx->skbs);
+ return -1;
+ }
+
return invoke_tx_handlers_late(tx);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 07/10] wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (5 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 06/10] wifi: mac80211: Call ieee80211_tx_h_select_key only once Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling Alexander Wetzel
` (3 subsequent siblings)
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
To make it clear that IEEE80211_TX_INTFL_OFFCHAN_TX_OK is now selecting
the alternate TX path in mac80211 - which immediately sends the frame -
the flag is renamed to IEEE80211_TX_INTFL_NOQUEUE_TX.
Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
---
include/net/mac80211.h | 8 ++++----
net/mac80211/mlme.c | 2 +-
net/mac80211/offchannel.c | 2 +-
net/mac80211/rx.c | 2 +-
net/mac80211/scan.c | 2 +-
net/mac80211/tx.c | 6 +++---
net/mac80211/util.c | 2 +-
7 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 320082546b29..ceea27e58cd9 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -898,9 +898,9 @@ struct ieee80211_bss_conf {
* @IEEE80211_TX_CTL_RATE_CTRL_PROBE: internal to mac80211, can be
* set by rate control algorithms to indicate probe rate, will
* be cleared for fragmented frames (except on the last fragment)
- * @IEEE80211_TX_INTFL_OFFCHAN_TX_OK: Internal to mac80211. Used to indicate
- * that a frame can be transmitted while the queues are stopped for
- * off-channel operation.
+ * @IEEE80211_TX_INTFL_NOQUEUE_TX: Internal to mac80211. Indicates that a frame
+ * can't be queued and must be transmitted immediately. Frames with this
+ * flag ignore offchannel queue stops and bypass wake_tx_queue().
* @IEEE80211_TX_CTL_HW_80211_ENCAP: This frame uses hardware encapsulation
* (header conversion)
* @IEEE80211_TX_INTFL_RETRIED: completely internal to mac80211,
@@ -970,7 +970,7 @@ enum mac80211_tx_info_flags {
IEEE80211_TX_STAT_AMPDU = BIT(10),
IEEE80211_TX_STAT_AMPDU_NO_BACK = BIT(11),
IEEE80211_TX_CTL_RATE_CTRL_PROBE = BIT(12),
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK = BIT(13),
+ IEEE80211_TX_INTFL_NOQUEUE_TX = BIT(13),
IEEE80211_TX_CTL_HW_80211_ENCAP = BIT(14),
IEEE80211_TX_INTFL_RETRIED = BIT(15),
IEEE80211_TX_INTFL_DONT_ENCRYPT = BIT(16),
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 4e8f0a5f6251..87a3ff6fa286 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2295,7 +2295,7 @@ void ieee80211_send_nullfunc(struct ieee80211_local *local,
nullfunc->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_INTFL_DONT_ENCRYPT |
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ IEEE80211_TX_INTFL_NOQUEUE_TX;
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS))
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
diff --git a/net/mac80211/offchannel.c b/net/mac80211/offchannel.c
index 29fab7ae47b4..85c27df0f423 100644
--- a/net/mac80211/offchannel.c
+++ b/net/mac80211/offchannel.c
@@ -1026,7 +1026,7 @@ int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
}
IEEE80211_SKB_CB(skb)->flags |= IEEE80211_TX_CTL_TX_OFFCHAN |
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ IEEE80211_TX_INTFL_NOQUEUE_TX;
if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
IEEE80211_SKB_CB(skb)->hw_queue =
local->hw.offchannel_tx_hw_queue;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index f40e2ea1b09a..042e12f08842 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -3998,7 +3998,7 @@ ieee80211_rx_h_action_return(struct ieee80211_rx_data *rx)
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(nskb);
info->flags = IEEE80211_TX_CTL_TX_OFFCHAN |
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK |
+ IEEE80211_TX_INTFL_NOQUEUE_TX |
IEEE80211_TX_CTL_NO_CCK_RATE;
if (ieee80211_hw_check(&local->hw, QUEUE_CONTROL))
info->hw_queue =
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index cb7079071885..00d37260f292 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -668,7 +668,7 @@ static void ieee80211_scan_state_send_probe(struct ieee80211_local *local,
scan_req = rcu_dereference_protected(local->scan_req,
lockdep_is_held(&local->hw.wiphy->mtx));
- tx_flags = IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ tx_flags = IEEE80211_TX_INTFL_NOQUEUE_TX;
if (scan_req->no_cck)
tx_flags |= IEEE80211_TX_CTL_NO_CCK_RATE;
if (scan_req->flags & NL80211_SCAN_FLAG_MIN_PREQ_CONTENT)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 7c269d8e5dcf..17836327c1fe 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -230,7 +230,7 @@ ieee80211_tx_h_dynamic_ps(struct ieee80211_tx_data *tx)
if (tx->sdata->vif.type != NL80211_IFTYPE_STATION)
return TX_CONTINUE;
- if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK))
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_NOQUEUE_TX))
return TX_CONTINUE;
ifmgd = &tx->sdata->u.mgd;
@@ -1301,7 +1301,7 @@ static struct txq_info *ieee80211_get_txq(struct ieee80211_local *local,
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_txq *txq = NULL;
- if (unlikely(info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK)) {
+ if (unlikely(info->flags & IEEE80211_TX_INTFL_NOQUEUE_TX)) {
if (sta)
txq = sta->sta.txq[IEEE80211_TID_NOQUEUE];
else
@@ -1819,7 +1819,7 @@ static void ieee80211_tx(struct ieee80211_sub_if_data *sdata,
struct ieee80211_tx_data tx;
ieee80211_tx_result res_prepare;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- bool noqueue = info->flags & IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ bool noqueue = info->flags & IEEE80211_TX_INTFL_NOQUEUE_TX;
struct ieee80211_tx_control control;
struct txq_info *txqi;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 4a130d2ffcb9..ecbc79d3015e 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1197,7 +1197,7 @@ void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
*/
IEEE80211_SKB_CB(skb)->flags |=
IEEE80211_TX_INTFL_DONT_ENCRYPT |
- IEEE80211_TX_INTFL_OFFCHAN_TX_OK;
+ IEEE80211_TX_INTFL_NOQUEUE_TX;
ieee80211_tx_skb(sdata, skb);
}
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (6 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 07/10] wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 16:30 ` kernel test robot
2025-02-17 8:17 ` [PATCH v2 09/10] wifi: mac80211: Migrate TX to kthread Alexander Wetzel
` (2 subsequent siblings)
10 siblings, 1 reply; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
From: Alexander Wetzel <alexander@wetzel-home.de>
With all drivers now using TXQ we can simplify the AMPDU handling
and avoid stopping the queues when enabling or disabling it.
Move AMPDU handling fully into ieee80211_tx_dequeue() and use the
flag %IEEE80211_TXQ_AMPDU to detect if AMPDU is operational.
Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
---
net/mac80211/agg-tx.c | 127 ++-----------------------------
net/mac80211/debugfs_sta.c | 2 -
net/mac80211/ieee80211_i.h | 5 +-
net/mac80211/main.c | 1 -
net/mac80211/mesh.c | 13 +---
net/mac80211/rx.c | 9 +--
net/mac80211/sta_info.c | 3 -
net/mac80211/sta_info.h | 30 ++++----
net/mac80211/tx.c | 149 ++++---------------------------------
9 files changed, 38 insertions(+), 301 deletions(-)
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index 63a5e48291ac..e9168e8ba133 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -138,45 +138,6 @@ void ieee80211_assign_tid_tx(struct sta_info *sta, int tid,
rcu_assign_pointer(sta->ampdu_mlme.tid_tx[tid], tid_tx);
}
-/*
- * When multiple aggregation sessions on multiple stations
- * are being created/destroyed simultaneously, we need to
- * refcount the global queue stop caused by that in order
- * to not get into a situation where one of the aggregation
- * setup or teardown re-enables queues before the other is
- * ready to handle that.
- *
- * These two functions take care of this issue by keeping
- * a global "agg_queue_stop" refcount.
- */
-static void __acquires(agg_queue)
-ieee80211_stop_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
-{
- int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
-
- /* we do refcounting here, so don't use the queue reason refcounting */
-
- if (atomic_inc_return(&sdata->local->agg_queue_stop[queue]) == 1)
- ieee80211_stop_queue_by_reason(
- &sdata->local->hw, queue,
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
- false);
- __acquire(agg_queue);
-}
-
-static void __releases(agg_queue)
-ieee80211_wake_queue_agg(struct ieee80211_sub_if_data *sdata, int tid)
-{
- int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
-
- if (atomic_dec_return(&sdata->local->agg_queue_stop[queue]) == 0)
- ieee80211_wake_queue_by_reason(
- &sdata->local->hw, queue,
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
- false);
- __release(agg_queue);
-}
-
static void
ieee80211_agg_stop_txq(struct sta_info *sta, int tid)
{
@@ -224,40 +185,6 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
local_bh_enable();
}
-/*
- * splice packets from the STA's pending to the local pending,
- * requires a call to ieee80211_agg_splice_finish later
- */
-static void __acquires(agg_queue)
-ieee80211_agg_splice_packets(struct ieee80211_sub_if_data *sdata,
- struct tid_ampdu_tx *tid_tx, u16 tid)
-{
- struct ieee80211_local *local = sdata->local;
- int queue = sdata->vif.hw_queue[ieee80211_ac_from_tid(tid)];
- unsigned long flags;
-
- ieee80211_stop_queue_agg(sdata, tid);
-
- if (WARN(!tid_tx,
- "TID %d gone but expected when splicing aggregates from the pending queue\n",
- tid))
- return;
-
- if (!skb_queue_empty(&tid_tx->pending)) {
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- /* copy over remaining packets */
- skb_queue_splice_tail_init(&tid_tx->pending,
- &local->pending[queue]);
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
- }
-}
-
-static void __releases(agg_queue)
-ieee80211_agg_splice_finish(struct ieee80211_sub_if_data *sdata, u16 tid)
-{
- ieee80211_wake_queue_agg(sdata, tid);
-}
-
static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
{
struct tid_ampdu_tx *tid_tx;
@@ -267,23 +194,8 @@ static void ieee80211_remove_tid_tx(struct sta_info *sta, int tid)
tid_tx = rcu_dereference_protected_tid_tx(sta, tid);
- /*
- * When we get here, the TX path will not be lockless any more wrt.
- * aggregation, since the OPERATIONAL bit has long been cleared.
- * Thus it will block on getting the lock, if it occurs. So if we
- * stop the queue now, we will not get any more packets, and any
- * that might be being processed will wait for us here, thereby
- * guaranteeing that no packets go to the tid_tx pending queue any
- * more.
- */
-
- ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
-
/* future packets must not find the tid_tx struct any more */
ieee80211_assign_tid_tx(sta, tid, NULL);
-
- ieee80211_agg_splice_finish(sta->sdata, tid);
-
kfree_rcu(tid_tx, rcu_head);
}
@@ -355,6 +267,10 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
set_bit(HT_AGG_STATE_STOPPING, &tid_tx->state);
+ /*
+ * After this packets are no longer handed through
+ * to the driver
+ */
ieee80211_agg_stop_txq(sta, tid);
spin_unlock_bh(&sta->lock);
@@ -365,13 +281,6 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
del_timer_sync(&tid_tx->addba_resp_timer);
del_timer_sync(&tid_tx->session_timer);
- /*
- * After this packets are no longer handed right through
- * to the driver but are put onto tid_tx->pending instead,
- * with locking to ensure proper access.
- */
- clear_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
-
/*
* There might be a few packets being processed right now (on
* another CPU) that have already gotten past the aggregation
@@ -395,12 +304,7 @@ int __ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
ret = drv_ampdu_action(local, sta->sdata, ¶ms);
/* HW shall not deny going back to legacy */
- if (WARN_ON(ret)) {
- /*
- * We may have pending packets get stuck in this case...
- * Not bothering with a workaround for now.
- */
- }
+ WARN_ON(ret);
/*
* In the case of AGG_STOP_DESTROY_STA, the driver won't
@@ -537,9 +441,7 @@ void ieee80211_tx_ba_session_handle_start(struct sta_info *sta, int tid)
"BA request denied - HW unavailable for %pM tid %d\n",
sta->sta.addr, tid);
spin_lock_bh(&sta->lock);
- ieee80211_agg_splice_packets(sdata, tid_tx, tid);
ieee80211_assign_tid_tx(sta, tid, NULL);
- ieee80211_agg_splice_finish(sdata, tid);
spin_unlock_bh(&sta->lock);
ieee80211_agg_start_txq(sta, tid, false);
@@ -713,7 +615,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
goto err_unlock_sta;
}
- skb_queue_head_init(&tid_tx->pending);
__set_bit(HT_AGG_STATE_WANT_START, &tid_tx->state);
tid_tx->timeout = timeout;
@@ -768,24 +669,6 @@ static void ieee80211_agg_tx_operational(struct ieee80211_local *local,
sta->sta.addr, tid);
drv_ampdu_action(local, sta->sdata, ¶ms);
-
- /*
- * synchronize with TX path, while splicing the TX path
- * should block so it won't put more packets onto pending.
- */
- spin_lock_bh(&sta->lock);
-
- ieee80211_agg_splice_packets(sta->sdata, tid_tx, tid);
- /*
- * Now mark as operational. This will be visible
- * in the TX path, and lets it go lock-free in
- * the common case.
- */
- set_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state);
- ieee80211_agg_splice_finish(sta->sdata, tid);
-
- spin_unlock_bh(&sta->lock);
-
ieee80211_agg_start_txq(sta, tid, true);
}
diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c
index a67a9d316008..890c01d848e5 100644
--- a/net/mac80211/debugfs_sta.c
+++ b/net/mac80211/debugfs_sta.c
@@ -343,8 +343,6 @@ static ssize_t sta_agg_status_do_read(struct wiphy *wiphy, struct file *file,
p += scnprintf(p, bufsz + buf - p, "\t\t%x", !!tid_tx);
p += scnprintf(p, bufsz + buf - p, "\t%#.2x",
tid_tx ? tid_tx->dialog_token : 0);
- p += scnprintf(p, bufsz + buf - p, "\t%03d",
- tid_tx ? skb_queue_len(&tid_tx->pending) : 0);
p += scnprintf(p, bufsz + buf - p, "\n");
}
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index feda302d3a4c..37b81354f289 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1265,7 +1265,6 @@ enum queue_stop_reason {
IEEE80211_QUEUE_STOP_REASON_DRIVER,
IEEE80211_QUEUE_STOP_REASON_PS,
IEEE80211_QUEUE_STOP_REASON_CSA,
- IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
IEEE80211_QUEUE_STOP_REASON_SKB_ADD,
IEEE80211_QUEUE_STOP_REASON_OFFCHANNEL,
@@ -1483,8 +1482,6 @@ struct ieee80211_local {
struct tasklet_struct tx_pending_tasklet;
struct tasklet_struct wake_txqs_tasklet;
- atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
-
/* number of interfaces with allmulti RX */
atomic_t iff_allmultis;
@@ -2127,7 +2124,7 @@ int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_fast_tx *fast_tx,
- struct sk_buff *skb, bool ampdu,
+ struct sk_buff *skb,
const u8 *da, const u8 *sa);
void ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb);
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 741e6c7edcb7..230c15dd3c4d 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -999,7 +999,6 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
for (i = 0; i < IEEE80211_MAX_QUEUES; i++) {
skb_queue_head_init(&local->pending[i]);
- atomic_set(&local->agg_queue_stop[i], 0);
}
tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending);
tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 974081324aa4..4fc91fe743c6 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -753,11 +753,9 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct ieee80211_mesh_fast_tx *entry;
struct ieee80211s_hdr *meshhdr;
u8 sa[ETH_ALEN] __aligned(2);
- struct tid_ampdu_tx *tid_tx;
struct sta_info *sta;
bool copy_sa = false;
u16 ethertype;
- u8 tid;
if (ctrl_flags & IEEE80211_TX_CTRL_SKIP_MPATH_LOOKUP)
return false;
@@ -799,15 +797,6 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
if (!sta)
return false;
- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- if (tid_tx) {
- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
- return false;
- if (tid_tx->timeout)
- tid_tx->last_tx = jiffies;
- }
-
skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
return true;
@@ -832,7 +821,7 @@ bool ieee80211_mesh_xmit_fast(struct ieee80211_sub_if_data *sdata,
ether_addr_copy(meshhdr->eaddr2, sa);
skb_push(skb, 2 * ETH_ALEN);
- __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
+ __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb,
entry->mpath->dst, sdata->vif.addr);
return true;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 042e12f08842..7cbd2409ca1a 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -2801,13 +2801,6 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- if (tid_tx) {
- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
- return false;
-
- if (tid_tx->timeout)
- tid_tx->last_tx = jiffies;
- }
ieee80211_aggr_check(sdata, sta, skb);
@@ -2821,7 +2814,7 @@ ieee80211_rx_mesh_fast_forward(struct ieee80211_sub_if_data *sdata,
skb->dev = sdata->dev;
memcpy(ð, skb->data, ETH_HLEN - 2);
skb_pull(skb, 2);
- __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb, tid_tx,
+ __ieee80211_xmit_fast(sdata, sta, &entry->fast_tx, skb,
eth.h_dest, eth.h_source);
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_unicast);
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 3ba03b6142cc..2a3785cd7aae 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -178,9 +178,6 @@ static void __cleanup_single_sta(struct sta_info *sta)
for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
kfree(sta->ampdu_mlme.tid_start_tx[i]);
tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
- if (!tid_tx)
- continue;
- ieee80211_purge_tx_queue(&local->hw, &tid_tx->pending);
kfree(tid_tx);
}
}
diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h
index 07b7ec39a52f..01c07368e9ea 100644
--- a/net/mac80211/sta_info.h
+++ b/net/mac80211/sta_info.h
@@ -113,15 +113,17 @@ enum ieee80211_sta_info_flags {
#define HT_AGG_BURST_RETRIES 3
#define HT_AGG_RETRIES_PERIOD (15 * HZ)
-#define HT_AGG_STATE_DRV_READY 0
-#define HT_AGG_STATE_RESPONSE_RECEIVED 1
-#define HT_AGG_STATE_OPERATIONAL 2
-#define HT_AGG_STATE_STOPPING 3
-#define HT_AGG_STATE_WANT_START 4
-#define HT_AGG_STATE_WANT_STOP 5
-#define HT_AGG_STATE_START_CB 6
-#define HT_AGG_STATE_STOP_CB 7
-#define HT_AGG_STATE_SENT_ADDBA 8
+/* TXQs using aggregation have %IEEE80211_TXQ_AMPDU set */
+enum ieee80211_ht_agg_state {
+ HT_AGG_STATE_DRV_READY,
+ HT_AGG_STATE_RESPONSE_RECEIVED,
+ HT_AGG_STATE_STOPPING,
+ HT_AGG_STATE_WANT_START,
+ HT_AGG_STATE_WANT_STOP,
+ HT_AGG_STATE_START_CB,
+ HT_AGG_STATE_STOP_CB,
+ HT_AGG_STATE_SENT_ADDBA,
+};
DECLARE_EWMA(avg_signal, 10, 8)
enum ieee80211_agg_stop_reason {
@@ -157,7 +159,6 @@ struct sta_info;
* @rcu_head: rcu head for freeing structure
* @session_timer: check if we keep Tx-ing on the TID (by timeout value)
* @addba_resp_timer: timer for peer's response to addba request
- * @pending: pending frames queue -- use sta's spinlock to protect
* @sta: station we are attached to
* @dialog_token: dialog token for aggregation session
* @timeout: session timeout value to be filled in ADDBA requests
@@ -176,16 +177,15 @@ struct sta_info;
* the array holding it must hold the aggregation mutex.
*
* The TX path can access it under RCU lock-free if, and
- * only if, the state has the flag %HT_AGG_STATE_OPERATIONAL
- * set. Otherwise, the TX path must also acquire the spinlock
- * and re-check the state, see comments in the tx code
- * touching it.
+ * only if, the aggregation is operational (txq has the flag
+ * %IEEE80211_TXQ_AMPDU set). Otherwise, the TX path must also
+ * acquire the spinlock and re-check the state, see comments
+ * in the tx code touching it.
*/
struct tid_ampdu_tx {
struct rcu_head rcu_head;
struct timer_list session_timer;
struct timer_list addba_resp_timer;
- struct sk_buff_head pending;
struct sta_info *sta;
unsigned long state;
unsigned long last_tx;
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 17836327c1fe..e50a33918e37 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1102,77 +1102,6 @@ ieee80211_tx_h_calculate_duration(struct ieee80211_tx_data *tx)
/* actual transmit path */
-static bool ieee80211_tx_prep_agg(struct ieee80211_tx_data *tx,
- struct sk_buff *skb,
- struct ieee80211_tx_info *info,
- struct tid_ampdu_tx *tid_tx,
- int tid)
-{
- bool queued = false;
- bool reset_agg_timer = false;
- struct sk_buff *purge_skb = NULL;
-
- if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
- reset_agg_timer = true;
- } else if (test_bit(HT_AGG_STATE_WANT_START, &tid_tx->state)) {
- /*
- * nothing -- this aggregation session is being started
- * but that might still fail with the driver
- */
- } else if (!tx->sta->sta.txq[tid]) {
- spin_lock(&tx->sta->lock);
- /*
- * Need to re-check now, because we may get here
- *
- * 1) in the window during which the setup is actually
- * already done, but not marked yet because not all
- * packets are spliced over to the driver pending
- * queue yet -- if this happened we acquire the lock
- * either before or after the splice happens, but
- * need to recheck which of these cases happened.
- *
- * 2) during session teardown, if the OPERATIONAL bit
- * was cleared due to the teardown but the pointer
- * hasn't been assigned NULL yet (or we loaded it
- * before it was assigned) -- in this case it may
- * now be NULL which means we should just let the
- * packet pass through because splicing the frames
- * back is already done.
- */
- tid_tx = rcu_dereference_protected_tid_tx(tx->sta, tid);
-
- if (!tid_tx) {
- /* do nothing, let packet pass through */
- } else if (test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
- reset_agg_timer = true;
- } else {
- queued = true;
- if (info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER) {
- clear_sta_flag(tx->sta, WLAN_STA_SP);
- ps_dbg(tx->sta->sdata,
- "STA %pM aid %d: SP frame queued, close the SP w/o telling the peer\n",
- tx->sta->sta.addr, tx->sta->sta.aid);
- }
- info->control.vif = &tx->sdata->vif;
- info->control.flags |= IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
- info->flags &= ~IEEE80211_TX_TEMPORARY_FLAGS;
- __skb_queue_tail(&tid_tx->pending, skb);
- if (skb_queue_len(&tid_tx->pending) > STA_MAX_TX_BUFFER)
- purge_skb = __skb_dequeue(&tid_tx->pending);
- }
- spin_unlock(&tx->sta->lock);
-
- if (purge_skb)
- ieee80211_free_txskb(&tx->local->hw, purge_skb);
- }
-
- /* reset session timer */
- if (reset_agg_timer)
- tid_tx->last_tx = jiffies;
-
- return queued;
-}
-
void ieee80211_aggr_check(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta, struct sk_buff *skb)
{
@@ -1209,7 +1138,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
struct ieee80211_hdr *hdr;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
bool aggr_check = false;
- int tid;
memset(tx, 0, sizeof(*tx));
tx->skb = skb;
@@ -1243,30 +1171,6 @@ ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
}
}
- if (tx->sta && ieee80211_is_data_qos(hdr->frame_control) &&
- !ieee80211_is_qos_nullfunc(hdr->frame_control) &&
- ieee80211_hw_check(&local->hw, AMPDU_AGGREGATION) &&
- !ieee80211_hw_check(&local->hw, TX_AMPDU_SETUP_IN_HW)) {
- struct tid_ampdu_tx *tid_tx;
-
- tid = ieee80211_get_tid(hdr);
- tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
- if (!tid_tx && aggr_check) {
- ieee80211_aggr_check(sdata, tx->sta, skb);
- tid_tx = rcu_dereference(tx->sta->ampdu_mlme.tid_tx[tid]);
- }
-
- if (tid_tx) {
- bool queued;
-
- queued = ieee80211_tx_prep_agg(tx, skb, info,
- tid_tx, tid);
-
- if (unlikely(queued))
- return TX_QUEUED;
- }
- }
-
if (is_multicast_ether_addr(hdr->addr1)) {
tx->flags &= ~IEEE80211_TX_UNICAST;
info->flags |= IEEE80211_TX_CTL_NO_ACK;
@@ -3558,7 +3462,7 @@ ieee80211_tx_skb_fixup(struct sk_buff *skb, netdev_features_t features)
void __ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sta_info *sta,
struct ieee80211_fast_tx *fast_tx,
- struct sk_buff *skb, bool ampdu,
+ struct sk_buff *skb,
const u8 *da, const u8 *sa)
{
struct ieee80211_local *local = sdata->local;
@@ -3633,11 +3537,8 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
struct sk_buff *skb)
{
u16 ethertype = (skb->data[12] << 8) | skb->data[13];
- struct ieee80211_hdr *hdr = (void *)fast_tx->hdr;
- struct tid_ampdu_tx *tid_tx = NULL;
struct sk_buff *next;
struct ethhdr eth;
- u8 tid = IEEE80211_NUM_TIDS;
/* control port protocol needs a lot of special handling */
if (cpu_to_be16(ethertype) == sdata->control_port_protocol)
@@ -3651,17 +3552,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
if (skb->sk && skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)
return false;
- if (hdr->frame_control & cpu_to_le16(IEEE80211_STYPE_QOS_DATA)) {
- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- if (tid_tx) {
- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state))
- return false;
- if (tid_tx->timeout)
- tid_tx->last_tx = jiffies;
- }
- }
-
memcpy(ð, skb->data, ETH_HLEN - 2);
/* after this point (skb is modified) we cannot return false */
@@ -3671,7 +3561,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata,
skb_list_walk_safe(skb, skb, next) {
skb_mark_not_on_list(skb);
- __ieee80211_xmit_fast(sdata, sta, fast_tx, skb, tid_tx,
+ __ieee80211_xmit_fast(sdata, sta, fast_tx, skb,
eth.h_dest, eth.h_source);
}
@@ -3786,9 +3676,19 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw,
goto begin;
}
- if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags))
- info->flags |= (IEEE80211_TX_CTL_AMPDU |
- IEEE80211_TX_CTL_DONTFRAG);
+ ieee80211_aggr_check(tx.sdata, tx.sta, skb);
+
+ if (test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags)) {
+ struct tid_ampdu_tx *tid_tx;
+
+ tid_tx = rcu_dereference(tx.sta->ampdu_mlme.tid_tx[txq->tid]);
+ if (!WARN_ON_ONCE(!tid_tx)) {
+ tid_tx->last_tx = jiffies;
+
+ info->flags |= (IEEE80211_TX_CTL_AMPDU |
+ IEEE80211_TX_CTL_DONTFRAG);
+ }
+ }
if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
if (!ieee80211_hw_check(&local->hw, HAS_RATE_CONTROL)) {
@@ -4156,7 +4056,6 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
sta = NULL;
skb_set_queue_mapping(skb, ieee80211_select_queue(sdata, sta, skb));
- ieee80211_aggr_check(sdata, sta, skb);
if (sta) {
struct ieee80211_fast_tx *fast_tx;
@@ -4401,11 +4300,9 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
{
struct ieee80211_tx_info *info;
struct ieee80211_local *local = sdata->local;
- struct tid_ampdu_tx *tid_tx;
struct sk_buff *seg, *next;
unsigned int skbs = 0, len = 0;
u16 queue;
- u8 tid;
queue = ieee80211_select_queue(sdata, sta, skb);
skb_set_queue_mapping(skb, queue);
@@ -4419,22 +4316,6 @@ static void ieee80211_8023_xmit(struct ieee80211_sub_if_data *sdata,
return;
ieee80211_aggr_check(sdata, sta, skb);
-
- tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
- tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[tid]);
- if (tid_tx) {
- if (!test_bit(HT_AGG_STATE_OPERATIONAL, &tid_tx->state)) {
- /* fall back to non-offload slow path */
- __ieee80211_subif_start_xmit(skb, dev, 0,
- IEEE80211_TX_CTRL_MLO_LINK_UNSPEC,
- NULL);
- return;
- }
-
- if (tid_tx->timeout)
- tid_tx->last_tx = jiffies;
- }
-
skb = ieee80211_tx_skb_fixup(skb, ieee80211_sdata_netdev_features(sdata));
if (!skb)
return;
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 09/10] wifi: mac80211: Migrate TX to kthread
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (7 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 10/10] wifi: mac80211: Cleanup *ieee80211_wake_txq* naming Alexander Wetzel
2025-02-19 19:19 ` [PATCH v2 00/10] Convert mac80211 to TXQs only James Prestwood
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
Use a per-phy kthread to handle all TX operations except
IEEE80211_TX_INTFL_NOQUEUE_TX.
Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
---
Changes compared to RFC v1:
- using guard() in ac_has_active_txq
---
net/mac80211/agg-tx.c | 2 +-
net/mac80211/driver-ops.h | 7 ----
net/mac80211/ieee80211_i.h | 9 ++---
net/mac80211/main.c | 8 ++--
net/mac80211/sta_info.c | 2 +-
net/mac80211/tx.c | 14 ++++++-
net/mac80211/util.c | 75 +++++++++++++++++++++++++++-----------
7 files changed, 76 insertions(+), 41 deletions(-)
diff --git a/net/mac80211/agg-tx.c b/net/mac80211/agg-tx.c
index e9168e8ba133..1646cb6b440f 100644
--- a/net/mac80211/agg-tx.c
+++ b/net/mac80211/agg-tx.c
@@ -180,7 +180,7 @@ ieee80211_agg_start_txq(struct sta_info *sta, int tid, bool enable)
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
local_bh_disable();
rcu_read_lock();
- schedule_and_wake_txq(sta->sdata->local, txqi);
+ ieee80211_schedule_txq(&sta->sdata->local->hw, &txqi->txq);
rcu_read_unlock();
local_bh_enable();
}
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index d5419eb06224..6d1489a39f99 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -1384,13 +1384,6 @@ static inline void drv_wake_tx_queue(struct ieee80211_local *local,
local->ops->wake_tx_queue(&local->hw, &txq->txq);
}
-static inline void schedule_and_wake_txq(struct ieee80211_local *local,
- struct txq_info *txqi)
-{
- ieee80211_schedule_txq(&local->hw, &txqi->txq);
- drv_wake_tx_queue(local, txqi);
-}
-
static inline int drv_can_aggregate_in_amsdu(struct ieee80211_local *local,
struct sk_buff *head,
struct sk_buff *skb)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 37b81354f289..acfdc5089d0f 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1358,9 +1358,7 @@ struct ieee80211_local {
spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
struct list_head active_txqs[IEEE80211_NUM_ACS];
u16 schedule_round[IEEE80211_NUM_ACS];
-
- /* serializes ieee80211_handle_wake_tx_queue */
- spinlock_t handle_wake_tx_queue_lock;
+ bool txq_scheduler_used;
u16 airtime_flags;
u32 aql_txq_limit_low[IEEE80211_NUM_ACS];
@@ -1480,7 +1478,8 @@ struct ieee80211_local {
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
struct tasklet_struct tx_pending_tasklet;
- struct tasklet_struct wake_txqs_tasklet;
+ struct task_struct *mac80211_tsk;
+ wait_queue_head_t mac80211_tsk_wq;
/* number of interfaces with allmulti RX */
atomic_t iff_allmultis;
@@ -2555,7 +2554,7 @@ void ieee80211_txq_remove_vlan(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata);
void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
struct txq_info *txqi);
-void ieee80211_wake_txqs(struct tasklet_struct *t);
+int mac80211_thread(void *data);
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
u16 transaction, u16 auth_alg, u16 status,
const u8 *extra, size_t extra_len, const u8 *bssid,
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 230c15dd3c4d..a08d97e6f50c 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -972,8 +972,6 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
local->aql_threshold = IEEE80211_AQL_THRESHOLD;
atomic_set(&local->aql_total_pending_airtime, 0);
- spin_lock_init(&local->handle_wake_tx_queue_lock);
-
INIT_LIST_HEAD(&local->chanctx_list);
wiphy_delayed_work_init(&local->scan_work, ieee80211_scan_work);
@@ -1001,9 +999,12 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len,
skb_queue_head_init(&local->pending[i]);
}
tasklet_setup(&local->tx_pending_tasklet, ieee80211_tx_pending);
- tasklet_setup(&local->wake_txqs_tasklet, ieee80211_wake_txqs);
tasklet_setup(&local->tasklet, ieee80211_tasklet_handler);
+ init_waitqueue_head(&local->mac80211_tsk_wq);
+ local->mac80211_tsk = kthread_run(mac80211_thread, local,
+ "mac80211-%s", wiphy_name(wiphy));
+
skb_queue_head_init(&local->skb_queue);
skb_queue_head_init(&local->skb_queue_unreliable);
@@ -1660,6 +1661,7 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
+ kthread_stop(local->mac80211_tsk);
tasklet_kill(&local->tx_pending_tasklet);
tasklet_kill(&local->tasklet);
diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c
index 2a3785cd7aae..60a154b0f8b9 100644
--- a/net/mac80211/sta_info.c
+++ b/net/mac80211/sta_info.c
@@ -1735,7 +1735,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
if (!sta->sta.txq[i] || !txq_has_queue(sta->sta.txq[i]))
continue;
- schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
+ ieee80211_schedule_txq(&local->hw, sta->sta.txq[i]);
}
skb_queue_head_init(&pending);
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index e50a33918e37..4d5d641b2b6b 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -1569,7 +1569,7 @@ static struct txq_info *ieee80211_queue_skb(struct ieee80211_local *local,
ieee80211_txq_enqueue(local, txqi, skb);
if (likely(txqi->txq.tid != IEEE80211_TID_NOQUEUE))
- schedule_and_wake_txq(local, txqi);
+ ieee80211_schedule_txq(&local->hw, &txqi->txq);
return txqi;
}
@@ -3826,6 +3826,11 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
found_eligible_txq = false;
}
+ if (test_bit(IEEE80211_TXQ_DIRTY, &txqi->flags)) {
+ list_del_init(&txqi->schedule_order);
+ goto begin;
+ }
+
if (!head)
head = txqi;
@@ -3892,8 +3897,9 @@ void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
&local->active_txqs[txq->ac]);
if (has_queue)
ieee80211_txq_set_active(txqi);
- }
+ wake_up_interruptible(&local->mac80211_tsk_wq);
+ }
spin_unlock_bh(&local->active_txq_lock[txq->ac]);
}
EXPORT_SYMBOL(__ieee80211_schedule_txq);
@@ -4009,6 +4015,8 @@ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
{
struct ieee80211_local *local = hw_to_local(hw);
+ local->txq_scheduler_used = true;
+
spin_lock_bh(&local->active_txq_lock[ac]);
if (ieee80211_txq_schedule_airtime_check(local, ac)) {
@@ -4035,6 +4043,8 @@ void __ieee80211_subif_start_xmit(struct sk_buff *skb,
struct sk_buff *next;
int len = skb->len;
+ skb->dev = dev;
+
if (unlikely(!ieee80211_sdata_running(sdata) || skb->len < ETH_HLEN)) {
kfree_skb(skb);
return;
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ecbc79d3015e..7125a5004776 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -307,16 +307,14 @@ void ieee80211_handle_wake_tx_queue(struct ieee80211_hw *hw,
struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
struct ieee80211_txq *queue;
- spin_lock(&local->handle_wake_tx_queue_lock);
-
/* Use ieee80211_next_txq() for airtime fairness accounting */
ieee80211_txq_schedule_start(hw, txq->ac);
- while ((queue = ieee80211_next_txq(hw, txq->ac))) {
+ queue = ieee80211_next_txq(hw, txq->ac);
+ if (queue) {
wake_tx_push_queue(local, sdata, queue);
ieee80211_return_txq(hw, queue, false);
}
ieee80211_txq_schedule_end(hw, txq->ac);
- spin_unlock(&local->handle_wake_tx_queue_lock);
}
EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue);
@@ -328,12 +326,10 @@ static void __ieee80211_wake_txq(struct ieee80211_local *local,
struct txq_info *txqi = to_txq_info(txq);
struct fq *fq = &local->fq;
- if (WARN_ON(!txq))
- return;
if (test_and_clear_bit(IEEE80211_TXQ_DIRTY, &txqi->flags)) {
/* ieee80211_tx_dequeue() also takes fq->lock */
spin_unlock(&fq->lock);
- drv_wake_tx_queue(local, txqi);
+ ieee80211_schedule_txq(&local->hw, txq);
spin_lock(&fq->lock);
}
}
@@ -441,17 +437,6 @@ _ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
rcu_read_unlock();
}
-void ieee80211_wake_txqs(struct tasklet_struct *t)
-{
- struct ieee80211_local *local = from_tasklet(local, t,
- wake_txqs_tasklet);
- unsigned long flags;
-
- spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
- _ieee80211_wake_txqs(local, &flags);
- spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
-}
-
static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
enum queue_stop_reason reason,
bool refcounted,
@@ -493,10 +478,56 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
* release someone's lock, but it is fine because all the callers of
* __ieee80211_wake_queue call it right before releasing the lock.
*/
- if (reason == IEEE80211_QUEUE_STOP_REASON_DRIVER)
- tasklet_schedule(&local->wake_txqs_tasklet);
- else
- _ieee80211_wake_txqs(local, flags);
+ _ieee80211_wake_txqs(local, flags);
+}
+
+static int ac_has_active_txq(struct ieee80211_local *local)
+{
+ for (int ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ guard(spinlock)(&local->active_txq_lock[ac]);
+
+ if (!list_empty(&local->active_txqs[ac]))
+ return ac;
+ }
+ return IEEE80211_NUM_ACS;
+}
+
+int mac80211_thread(void *data)
+{
+ struct ieee80211_local *local = data;
+ struct txq_info *txqi, *tmp;
+ unsigned int ac = IEEE80211_NUM_ACS;
+
+ while (1) {
+ wait_event_interruptible(local->mac80211_tsk_wq,
+ (ac = ac_has_active_txq(local))
+ != IEEE80211_NUM_ACS);
+ if (kthread_should_stop())
+ break;
+
+ rcu_read_lock();
+
+ list_for_each_entry_safe(txqi, tmp,
+ &local->active_txqs[ac],
+ schedule_order) {
+ local->txq_scheduler_used = false;
+ local_bh_disable();
+ drv_wake_tx_queue(local, txqi);
+ local_bh_enable();
+ if (!local->txq_scheduler_used) {
+ /* Driver is not using
+ * ieee80211_txq_schedule_start().
+ * Take over cleaning up the schedule.
+ */
+ spin_lock_bh(&local->active_txq_lock[ac]);
+ list_del_init(&txqi->schedule_order);
+ spin_unlock_bh(&local->active_txq_lock[ac]);
+ }
+ }
+
+ rcu_read_unlock();
+ }
+ return 0;
}
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v2 10/10] wifi: mac80211: Cleanup *ieee80211_wake_txq* naming
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (8 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 09/10] wifi: mac80211: Migrate TX to kthread Alexander Wetzel
@ 2025-02-17 8:17 ` Alexander Wetzel
2025-02-19 19:19 ` [PATCH v2 00/10] Convert mac80211 to TXQs only James Prestwood
10 siblings, 0 replies; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-17 8:17 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg, Alexander Wetzel
ieee80211_wake_txq() and ieee80211_wake_txqs() are not used.
Rename:
_ieee80211_wake_txqs() -> ieee80211_wake_txqs()
__ieee80211_wake_txqs() -> _ieee80211_wake_txqs()
__ieee80211_wake_txq() -> ieee80211_wake_txq()
Signed-off-by: Alexander Wetzel <Alexander@wetzel-home.de>
---
net/mac80211/iface.c | 2 +-
net/mac80211/util.c | 20 ++++++++++----------
2 files changed, 11 insertions(+), 11 deletions(-)
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0437e87ec8f2..2a2aaec68d58 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -467,7 +467,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
lockdep_assert_wiphy(local->hw.wiphy);
clear_bit(SDATA_STATE_RUNNING, &sdata->state);
- synchronize_rcu(); /* flush _ieee80211_wake_txqs() */
+ synchronize_rcu(); /* flush ieee80211_wake_txqs() */
cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
if (cancel_scan)
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 7125a5004776..e85ecbda9afa 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -320,8 +320,8 @@ EXPORT_SYMBOL(ieee80211_handle_wake_tx_queue);
__releases(&local->fq->lock)
__acquires(&local->fq->lock)
-static void __ieee80211_wake_txq(struct ieee80211_local *local,
- struct ieee80211_txq *txq)
+static void ieee80211_wake_txq(struct ieee80211_local *local,
+ struct ieee80211_txq *txq)
{
struct txq_info *txqi = to_txq_info(txq);
struct fq *fq = &local->fq;
@@ -334,7 +334,7 @@ static void __ieee80211_wake_txq(struct ieee80211_local *local,
}
}
-static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
+static void _ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
{
struct ieee80211_local *local = sdata->local;
struct fq *fq = &local->fq;
@@ -365,11 +365,11 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
*/
if (ac == txq_fb->ac)
- __ieee80211_wake_txq(local, txq_fb);
+ ieee80211_wake_txq(local, txq_fb);
if (txq_mc && ac == txq_mc->ac &&
(!ps || !atomic_read(&ps->num_sta_ps)))
- __ieee80211_wake_txq(local, txq_mc);
+ ieee80211_wake_txq(local, txq_mc);
/* STA TXQs */
list_for_each_entry_rcu(sta, &local->sta_list, list) {
@@ -390,7 +390,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
continue;
/* releases and retakes fq->lock */
- __ieee80211_wake_txq(local, txq);
+ ieee80211_wake_txq(local, txq);
}
}
out:
@@ -401,7 +401,7 @@ static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
static void
__releases(&local->queue_stop_reason_lock)
__acquires(&local->queue_stop_reason_lock)
-_ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
+ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
{
struct ieee80211_sub_if_data *sdata;
int n_acs = IEEE80211_NUM_ACS;
@@ -428,7 +428,7 @@ _ieee80211_wake_txqs(struct ieee80211_local *local, unsigned long *flags)
if (ac_queue == i ||
sdata->vif.cab_queue == i)
- __ieee80211_wake_txqs(sdata, ac);
+ _ieee80211_wake_txqs(sdata, ac);
}
}
spin_lock_irqsave(&local->queue_stop_reason_lock, *flags);
@@ -472,13 +472,13 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
tasklet_schedule(&local->tx_pending_tasklet);
/*
- * Calling _ieee80211_wake_txqs here can be a problem because it may
+ * Calling ieee80211_wake_txqs here can be a problem because it may
* release queue_stop_reason_lock which has been taken by
* __ieee80211_wake_queue's caller. It is certainly not very nice to
* release someone's lock, but it is fine because all the callers of
* __ieee80211_wake_queue call it right before releasing the lock.
*/
- _ieee80211_wake_txqs(local, flags);
+ ieee80211_wake_txqs(local, flags);
}
static int ac_has_active_txq(struct ieee80211_local *local)
--
2.48.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling
2025-02-17 8:17 ` [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling Alexander Wetzel
@ 2025-02-17 16:30 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2025-02-17 16:30 UTC (permalink / raw)
To: Alexander Wetzel, linux-wireless
Cc: oe-kbuild-all, Johannes Berg, Alexander Wetzel
Hi Alexander,
kernel test robot noticed the following build warnings:
[auto build test WARNING on wireless-next/main]
[also build test WARNING on wireless/main ath/ath-next linus/master v6.14-rc3 next-20250217]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexander-Wetzel/wifi-mac80211-move-rate-control-setup/20250217-162046
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
patch link: https://lore.kernel.org/r/20250217081721.45110-9-Alexander%40wetzel-home.de
patch subject: [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling
config: i386-buildonly-randconfig-004-20250217 (https://download.01.org/0day-ci/archive/20250218/202502180007.MFwMk2L7-lkp@intel.com/config)
compiler: gcc-12 (Debian 12.2.0-14) 12.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250218/202502180007.MFwMk2L7-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502180007.MFwMk2L7-lkp@intel.com/
All warnings (new ones prefixed by >>):
net/mac80211/tx.c: In function 'ieee80211_tx_prepare':
>> net/mac80211/tx.c:1140:14: warning: variable 'aggr_check' set but not used [-Wunused-but-set-variable]
1140 | bool aggr_check = false;
| ^~~~~~~~~~
--
net/mac80211/rx.c: In function 'ieee80211_rx_mesh_fast_forward':
>> net/mac80211/rx.c:2778:30: warning: variable 'tid_tx' set but not used [-Wunused-but-set-variable]
2778 | struct tid_ampdu_tx *tid_tx;
| ^~~~~~
vim +/aggr_check +1140 net/mac80211/tx.c
1a7915501ca94a Felix Fietkau 2021-06-29 1126
58d4185e36913d Johannes Berg 2007-09-26 1127 /*
58d4185e36913d Johannes Berg 2007-09-26 1128 * initialises @tx
7c10770f995820 Johannes Berg 2015-03-20 1129 * pass %NULL for the station if unknown, a valid pointer if known
7c10770f995820 Johannes Berg 2015-03-20 1130 * or an ERR_PTR() if the station is known not to exist
58d4185e36913d Johannes Berg 2007-09-26 1131 */
9ae54c8463691b Johannes Berg 2008-01-31 1132 static ieee80211_tx_result
3b8d81e020f77c Johannes Berg 2009-06-17 1133 ieee80211_tx_prepare(struct ieee80211_sub_if_data *sdata,
3b8d81e020f77c Johannes Berg 2009-06-17 1134 struct ieee80211_tx_data *tx,
7c10770f995820 Johannes Berg 2015-03-20 1135 struct sta_info *sta, struct sk_buff *skb)
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1136 {
3b8d81e020f77c Johannes Berg 2009-06-17 1137 struct ieee80211_local *local = sdata->local;
58d4185e36913d Johannes Berg 2007-09-26 1138 struct ieee80211_hdr *hdr;
e039fa4a4195ac Johannes Berg 2008-05-15 1139 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
1a7915501ca94a Felix Fietkau 2021-06-29 @1140 bool aggr_check = false;
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1141
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1142 memset(tx, 0, sizeof(*tx));
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1143 tx->skb = skb;
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1144 tx->local = local;
3b8d81e020f77c Johannes Berg 2009-06-17 1145 tx->sdata = sdata;
252b86c43225d0 Johannes Berg 2011-11-16 1146 __skb_queue_head_init(&tx->skbs);
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1147
cd8ffc800ce18e Johannes Berg 2009-03-23 1148 /*
cd8ffc800ce18e Johannes Berg 2009-03-23 1149 * If this flag is set to true anywhere, and we get here,
cd8ffc800ce18e Johannes Berg 2009-03-23 1150 * we are doing the needed processing, so remove the flag
cd8ffc800ce18e Johannes Berg 2009-03-23 1151 * now.
cd8ffc800ce18e Johannes Berg 2009-03-23 1152 */
cc20ff2c6b5d3e Felix Fietkau 2020-09-08 1153 info->control.flags &= ~IEEE80211_TX_INTCFL_NEED_TXPROCESSING;
cd8ffc800ce18e Johannes Berg 2009-03-23 1154
58d4185e36913d Johannes Berg 2007-09-26 1155 hdr = (struct ieee80211_hdr *) skb->data;
58d4185e36913d Johannes Berg 2007-09-26 1156
7c10770f995820 Johannes Berg 2015-03-20 1157 if (likely(sta)) {
7c10770f995820 Johannes Berg 2015-03-20 1158 if (!IS_ERR(sta))
7c10770f995820 Johannes Berg 2015-03-20 1159 tx->sta = sta;
7c10770f995820 Johannes Berg 2015-03-20 1160 } else {
3f0e0b220f8007 Felix Fietkau 2010-01-08 1161 if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
f14543ee4d0681 Felix Fietkau 2009-11-10 1162 tx->sta = rcu_dereference(sdata->u.vlan.sta);
7c10770f995820 Johannes Berg 2015-03-20 1163 if (!tx->sta && sdata->wdev.use_4addr)
3f0e0b220f8007 Felix Fietkau 2010-01-08 1164 return TX_DROP;
10cb8e617560fc Markus Theil 2021-02-06 1165 } else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
b4d57adb727ec7 Felix Fietkau 2010-01-31 1166 tx->sta = sta_info_get_bss(sdata, hdr->addr1);
3f0e0b220f8007 Felix Fietkau 2010-01-08 1167 }
1a7915501ca94a Felix Fietkau 2021-06-29 1168 if (!tx->sta && !is_multicast_ether_addr(hdr->addr1)) {
abe60632f311d5 Johannes Berg 2009-11-25 1169 tx->sta = sta_info_get(sdata, hdr->addr1);
1a7915501ca94a Felix Fietkau 2021-06-29 1170 aggr_check = true;
1a7915501ca94a Felix Fietkau 2021-06-29 1171 }
7c10770f995820 Johannes Berg 2015-03-20 1172 }
58d4185e36913d Johannes Berg 2007-09-26 1173
badffb725c86cc Jiri Slaby 2007-08-28 1174 if (is_multicast_ether_addr(hdr->addr1)) {
5cf121c3cdb955 Johannes Berg 2008-02-25 1175 tx->flags &= ~IEEE80211_TX_UNICAST;
e039fa4a4195ac Johannes Berg 2008-05-15 1176 info->flags |= IEEE80211_TX_CTL_NO_ACK;
6fd67e937ece53 Simon Wunderlich 2011-11-18 1177 } else
5cf121c3cdb955 Johannes Berg 2008-02-25 1178 tx->flags |= IEEE80211_TX_UNICAST;
58d4185e36913d Johannes Berg 2007-09-26 1179
a26eb27ab43014 Johannes Berg 2011-10-07 1180 if (!(info->flags & IEEE80211_TX_CTL_DONTFRAG)) {
a26eb27ab43014 Johannes Berg 2011-10-07 1181 if (!(tx->flags & IEEE80211_TX_UNICAST) ||
a26eb27ab43014 Johannes Berg 2011-10-07 1182 skb->len + FCS_LEN <= local->hw.wiphy->frag_threshold ||
a26eb27ab43014 Johannes Berg 2011-10-07 1183 info->flags & IEEE80211_TX_CTL_AMPDU)
a26eb27ab43014 Johannes Berg 2011-10-07 1184 info->flags |= IEEE80211_TX_CTL_DONTFRAG;
58d4185e36913d Johannes Berg 2007-09-26 1185 }
58d4185e36913d Johannes Berg 2007-09-26 1186
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1187 if (!tx->sta)
e039fa4a4195ac Johannes Berg 2008-05-15 1188 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
f7418bc10d8402 Felix Fietkau 2015-09-24 1189 else if (test_and_clear_sta_flag(tx->sta, WLAN_STA_CLEAR_PS_FILT)) {
e039fa4a4195ac Johannes Berg 2008-05-15 1190 info->flags |= IEEE80211_TX_CTL_CLEAR_PS_FILT;
f7418bc10d8402 Felix Fietkau 2015-09-24 1191 ieee80211_check_fast_xmit(tx->sta);
f7418bc10d8402 Felix Fietkau 2015-09-24 1192 }
58d4185e36913d Johannes Berg 2007-09-26 1193
e039fa4a4195ac Johannes Berg 2008-05-15 1194 info->flags |= IEEE80211_TX_CTL_FIRST_FRAGMENT;
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1195
9ae54c8463691b Johannes Berg 2008-01-31 1196 return TX_CONTINUE;
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1197 }
e2ebc74d7e3d71 Johannes Berg 2007-07-27 1198
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path
2025-02-17 8:17 ` [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path Alexander Wetzel
@ 2025-02-17 22:33 ` kernel test robot
0 siblings, 0 replies; 16+ messages in thread
From: kernel test robot @ 2025-02-17 22:33 UTC (permalink / raw)
To: Alexander Wetzel, linux-wireless
Cc: llvm, oe-kbuild-all, Johannes Berg, Alexander Wetzel
Hi Alexander,
kernel test robot noticed the following build warnings:
[auto build test WARNING on wireless-next/main]
[also build test WARNING on wireless/main ath/ath-next linus/master v6.14-rc3 next-20250217]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Alexander-Wetzel/wifi-mac80211-move-rate-control-setup/20250217-162046
base: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
patch link: https://lore.kernel.org/r/20250217081721.45110-6-Alexander%40wetzel-home.de
patch subject: [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path
config: x86_64-buildonly-randconfig-003-20250218 (https://download.01.org/0day-ci/archive/20250218/202502180650.CWCCOFGJ-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250218/202502180650.CWCCOFGJ-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202502180650.CWCCOFGJ-lkp@intel.com/
All warnings (new ones prefixed by >>):
In file included from net/mac80211/tx.c:15:
In file included from include/linux/skbuff.h:17:
In file included from include/linux/bvec.h:10:
In file included from include/linux/highmem.h:8:
In file included from include/linux/cacheflush.h:5:
In file included from arch/x86/include/asm/cacheflush.h:5:
In file included from include/linux/mm.h:2224:
include/linux/vmstat.h:504:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
504 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
505 | item];
| ~~~~
include/linux/vmstat.h:511:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
511 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
512 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
include/linux/vmstat.h:524:43: warning: arithmetic between different enumeration types ('enum zone_stat_item' and 'enum numa_stat_item') [-Wenum-enum-conversion]
524 | return vmstat_text[NR_VM_ZONE_STAT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~ ^
525 | NR_VM_NUMA_EVENT_ITEMS +
| ~~~~~~~~~~~~~~~~~~~~~~
>> net/mac80211/tx.c:4607:29: warning: variable 'hdr' is uninitialized when used here [-Wuninitialized]
4607 | sta = sta_info_get(sdata, hdr->addr1);
| ^~~
net/mac80211/tx.c:4579:27: note: initialize the variable 'hdr' to silence this warning
4579 | struct ieee80211_hdr *hdr;
| ^
| = NULL
4 warnings generated.
vim +/hdr +4607 net/mac80211/tx.c
e2ebc74d7e3d716 Johannes Berg 2007-07-27 4572
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4573 static void ieee80211_tx_pending_skb(struct ieee80211_local *local,
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4574 struct sk_buff *skb)
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4575 {
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4576 struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4577 struct ieee80211_sub_if_data *sdata;
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4578 struct sta_info *sta;
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4579 struct ieee80211_hdr *hdr;
55de908ab292c03 Johannes Berg 2012-07-26 4580 struct ieee80211_chanctx_conf *chanctx_conf;
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4581
5061b0c2b9066de Johannes Berg 2009-07-14 4582 sdata = vif_to_sdata(info->control.vif);
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4583
cc20ff2c6b5d3e2 Felix Fietkau 2020-09-08 4584 if (info->control.flags & IEEE80211_TX_INTCFL_NEED_TXPROCESSING) {
eef25a6679adb3c Johannes Berg 2022-06-01 4585 /* update band only for non-MLD */
f1871abd27641c0 Ilan Peer 2023-06-08 4586 if (!ieee80211_vif_is_mld(&sdata->vif)) {
eef25a6679adb3c Johannes Berg 2022-06-01 4587 chanctx_conf =
eef25a6679adb3c Johannes Berg 2022-06-01 4588 rcu_dereference(sdata->vif.bss_conf.chanctx_conf);
55de908ab292c03 Johannes Berg 2012-07-26 4589 if (unlikely(!chanctx_conf)) {
55de908ab292c03 Johannes Berg 2012-07-26 4590 dev_kfree_skb(skb);
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4591 return;
55de908ab292c03 Johannes Berg 2012-07-26 4592 }
73c4e195e6396ee Johannes Berg 2014-11-09 4593 info->band = chanctx_conf->def.chan->band;
eef25a6679adb3c Johannes Berg 2022-06-01 4594 }
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4595 ieee80211_tx(sdata, NULL, skb);
cc20ff2c6b5d3e2 Felix Fietkau 2020-09-08 4596 } else if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
50ff477a8639fa1 John Crispin 2019-11-25 4597 if (ieee80211_lookup_ra_sta(sdata, skb, &sta)) {
50ff477a8639fa1 John Crispin 2019-11-25 4598 dev_kfree_skb(skb);
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4599 return;
50ff477a8639fa1 John Crispin 2019-11-25 4600 }
50ff477a8639fa1 John Crispin 2019-11-25 4601
50ff477a8639fa1 John Crispin 2019-11-25 4602 if (IS_ERR(sta) || (sta && !sta->uploaded))
50ff477a8639fa1 John Crispin 2019-11-25 4603 sta = NULL;
50ff477a8639fa1 John Crispin 2019-11-25 4604
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4605 ieee80211_queue_skb(local, sdata, sta, skb);
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4606 } else {
abe60632f311d51 Johannes Berg 2009-11-25 @4607 sta = sta_info_get(sdata, hdr->addr1);
e8f495b5a04f5a6 Alexander Wetzel 2025-02-17 4608 ieee80211_tx(sdata, sta, skb);
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4609 }
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4610 }
cd8ffc800ce18e5 Johannes Berg 2009-03-23 4611
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 00/10] Convert mac80211 to TXQs only
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
` (9 preceding siblings ...)
2025-02-17 8:17 ` [PATCH v2 10/10] wifi: mac80211: Cleanup *ieee80211_wake_txq* naming Alexander Wetzel
@ 2025-02-19 19:19 ` James Prestwood
2025-02-19 21:27 ` Alexander Wetzel
10 siblings, 1 reply; 16+ messages in thread
From: James Prestwood @ 2025-02-19 19:19 UTC (permalink / raw)
To: Alexander Wetzel, linux-wireless; +Cc: Johannes Berg, ath10k, Remi Pommarel
Hi Alexander,
On 2/17/25 12:17 AM, Alexander Wetzel wrote:
> This series switches all TX handling in mac80211 over to TXQs.
> TXQs can take over buffering in many - potentially even all - cases
> where we use separate solutions so far.
> This reduces the complexity of the TX path and making it simpler to use
> TX in mac8021.
>
> These patches continue the work to get rid of the legacy TX path we
> started drivers with
> https://lore.kernel.org/r/20221009163040.25637-1-alexander@wetzel-home.de
>
> and was inspired by this old discussion on the wireless mailing list:
> https://lore.kernel.org/r/1507217947.2387.60.camel@sipsolutions.net/
>
> Changes compared to RFC and v1 are documented in the individual patches,
> where applicable.
>
> A quick overview of the patches in the series:
> wifi: mac80211: move rate control setup
> Broken off from "Add new TX queues to replace legacy TX" as
> requested. Moves some exiting code around.
>
> wifi: mac80211: Always provide the MMPDU TXQ
> When only using TXQs for TX we akways need this.
> Creates and uses MMPDU TXQs even for drivers not supporting
> them.
>
> wifi: mac80211: Convert vif->txq to an array
> We need some more TXQs for the patch below. Create them.
>
> wifi: mac80211: Add new TX queues to replace legacy TX
> This starts the core of the move to TXQs.
> Creats all the missing TXQs and updates the support function for
> them. It also directly switches traffic to them, when possible.
> (Only offchannel is sticking to legacy TX after that.)
>
> wifi: mac80211: Stop using legacy TX path
> Drop the legacy TX functions and move offchannel TX to the new
> alternate TXQ path named TXQ_NOQUEUE (so far).
> With that mac80211 has two TX paths both using TXQ:
> - The existing one, which uses the TXQ for queuing and
> - TXQ_NOQUEUE. Which just puts frames into a TXQ and
> immediately sends out the frame by also calling drv_tx() for
> it. There never can be more than one frame in any of these
> TXQs. They never see a wake_tx_queue call by the driver or
> mac80211.
>
> wifi: mac80211: Call ieee80211_tx_h_select_key only once
> A optimization which could be without the patches, too. Would
> just be done differently. (Not required)
>
> wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK
> Rename the flag used to select the NOQUEU TX path to make its
> use more obvious.
>
> wifi: mac80211: Simplify AMPDU handling
> Uses TXQs to buffer frames when AMPDU is started/stopped.
>
> wifi: mac80211: Migrate TX to kthread
> Moves all TX operation except TXQ_NOQUEUE to a new kthread.
> This hooks into the existing txq scheduling and uses
> local->active_txqs to determine which TXQs need to run.
>
> wifi: mac80211: Cleanup *ieee80211_wake_txq* naming
> Rename a few functions.
>
> drivers/net/wireless/ath/ath10k/mac.c | 8 +-
> drivers/net/wireless/ath/ath9k/ath9k.h | 2 +-
> .../net/wireless/intel/iwlwifi/mvm/mac80211.c | 6 +-
> .../net/wireless/mediatek/mt76/mt7603/main.c | 3 +-
> .../net/wireless/mediatek/mt76/mt7615/main.c | 5 +-
> .../net/wireless/mediatek/mt76/mt76x02_util.c | 3 +-
> .../net/wireless/mediatek/mt76/mt7915/main.c | 6 +-
> .../net/wireless/mediatek/mt76/mt7921/main.c | 5 +-
> .../net/wireless/mediatek/mt76/mt7925/main.c | 5 +-
> .../net/wireless/mediatek/mt76/mt7996/main.c | 5 +-
> drivers/net/wireless/realtek/rtw88/mac80211.c | 4 +-
> drivers/net/wireless/realtek/rtw88/main.c | 2 +-
> drivers/net/wireless/realtek/rtw89/mac80211.c | 2 +-
> include/net/mac80211.h | 60 +-
> net/mac80211/agg-tx.c | 129 +---
> net/mac80211/cfg.c | 8 +-
> net/mac80211/debugfs_netdev.c | 46 +-
> net/mac80211/debugfs_sta.c | 2 -
> net/mac80211/driver-ops.h | 28 +-
> net/mac80211/ieee80211_i.h | 32 +-
> net/mac80211/iface.c | 144 ++--
> net/mac80211/main.c | 9 +-
> net/mac80211/mesh.c | 13 +-
> net/mac80211/mlme.c | 2 +-
> net/mac80211/offchannel.c | 2 +-
> net/mac80211/rx.c | 11 +-
> net/mac80211/scan.c | 2 +-
> net/mac80211/sta_info.c | 6 +-
> net/mac80211/sta_info.h | 30 +-
> net/mac80211/tx.c | 616 ++++--------------
> net/mac80211/util.c | 162 +++--
> 31 files changed, 534 insertions(+), 824 deletions(-)
>
Trying to get some clarity if this might fix a regression [1] with
ath10k where upon roaming the TX queue hangs on flush for ~4-10 seconds.
I was hopeful for another set [2] but it looks like this only effected
AP mode and with that applied I still notice the behavior.
In the worse case we see two failures, which add up to about 10 seconds
of delays, more often its just the single "failed to flush transmit queue"
Feb 19 14:15:59 kernel: ath10k_pci 0000:02:00.0: failed to flush sta txq
(sta 6a:3a:0e:22:45:08 skip 0 ar-state 1): 0
Feb 19 14:16:04 kernel: ath10k_pci 0000:02:00.0: failed to flush
transmit queue (skip 0 ar-state 1): 0
Crossing my fingers this set will have some positive effect here
[1]
https://lore.kernel.org/all/CA+Xfe4FjUmzM5mvPxGbpJsF3SvSdE5_wgxvgFJ0bsdrKODVXCQ@mail.gmail.com/
[2]
https://lore.kernel.org/linux-wireless/cover.1732293922.git.repk@triplefau.lt/
Thanks,
James
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 00/10] Convert mac80211 to TXQs only
2025-02-19 19:19 ` [PATCH v2 00/10] Convert mac80211 to TXQs only James Prestwood
@ 2025-02-19 21:27 ` Alexander Wetzel
2025-02-20 13:56 ` James Prestwood
0 siblings, 1 reply; 16+ messages in thread
From: Alexander Wetzel @ 2025-02-19 21:27 UTC (permalink / raw)
To: James Prestwood, linux-wireless; +Cc: Johannes Berg, ath10k, Remi Pommarel
On 19.02.25 20:19, James Prestwood wrote:
...
>>
> Trying to get some clarity if this might fix a regression [1] with
> ath10k where upon roaming the TX queue hangs on flush for ~4-10 seconds.
> I was hopeful for another set [2] but it looks like this only effected
> AP mode and with that applied I still notice the behavior.
>
> In the worse case we see two failures, which add up to about 10 seconds
> of delays, more often its just the single "failed to flush transmit queue"
>
> Feb 19 14:15:59 kernel: ath10k_pci 0000:02:00.0: failed to flush sta txq
> (sta 6a:3a:0e:22:45:08 skip 0 ar-state 1): 0
> Feb 19 14:16:04 kernel: ath10k_pci 0000:02:00.0: failed to flush
> transmit queue (skip 0 ar-state 1): 0
>
> Crossing my fingers this set will have some positive effect here
>
I had a quick look at ath10k driver and the error message you have. The
patch series here will probably not help with that. From driver
perspective nothing relevant should be different...
> [1] https://lore.kernel.org/all/
> CA+Xfe4FjUmzM5mvPxGbpJsF3SvSdE5_wgxvgFJ0bsdrKODVXCQ@mail.gmail.com/
> [2] https://lore.kernel.org/linux-wireless/
> cover.1732293922.git.repk@triplefau.lt/
>
> Thanks,
>
> James
>
^ permalink raw reply [flat|nested] 16+ messages in thread
* Re: [PATCH v2 00/10] Convert mac80211 to TXQs only
2025-02-19 21:27 ` Alexander Wetzel
@ 2025-02-20 13:56 ` James Prestwood
0 siblings, 0 replies; 16+ messages in thread
From: James Prestwood @ 2025-02-20 13:56 UTC (permalink / raw)
To: Alexander Wetzel, linux-wireless; +Cc: Johannes Berg, ath10k, Remi Pommarel
Hi,
On 2/19/25 1:27 PM, Alexander Wetzel wrote:
> On 19.02.25 20:19, James Prestwood wrote:
> ...
>>>
>> Trying to get some clarity if this might fix a regression [1] with
>> ath10k where upon roaming the TX queue hangs on flush for ~4-10
>> seconds. I was hopeful for another set [2] but it looks like this
>> only effected AP mode and with that applied I still notice the behavior.
>>
>> In the worse case we see two failures, which add up to about 10
>> seconds of delays, more often its just the single "failed to flush
>> transmit queue"
>>
>> Feb 19 14:15:59 kernel: ath10k_pci 0000:02:00.0: failed to flush sta
>> txq (sta 6a:3a:0e:22:45:08 skip 0 ar-state 1): 0
>> Feb 19 14:16:04 kernel: ath10k_pci 0000:02:00.0: failed to flush
>> transmit queue (skip 0 ar-state 1): 0
>>
>> Crossing my fingers this set will have some positive effect here
>>
>
> I had a quick look at ath10k driver and the error message you have.
> The patch series here will probably not help with that. From driver
> perspective nothing relevant should be different...
Well thank you for looking at least, I appreciate that.
>
>
>> [1] https://lore.kernel.org/all/
>> CA+Xfe4FjUmzM5mvPxGbpJsF3SvSdE5_wgxvgFJ0bsdrKODVXCQ@mail.gmail.com/
>> [2] https://lore.kernel.org/linux-wireless/
>> cover.1732293922.git.repk@triplefau.lt/
>>
>> Thanks,
>>
>> James
>>
>
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2025-02-20 13:56 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-17 8:17 [PATCH v2 00/10] Convert mac80211 to TXQs only Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 01/10] wifi: mac80211: move rate control setup Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 02/10] wifi: mac80211: Always provide the MMPDU TXQ Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 03/10] wifi: mac80211: Convert vif->txq to an array Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 04/10] wifi: mac80211: Add new TX queues to replace legacy TX Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 05/10] wifi: mac80211: Stop using legacy TX path Alexander Wetzel
2025-02-17 22:33 ` kernel test robot
2025-02-17 8:17 ` [PATCH v2 06/10] wifi: mac80211: Call ieee80211_tx_h_select_key only once Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 07/10] wifi: mac80211: Rename IEEE80211_TX_INTFL_OFFCHAN_TX_OK Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 08/10] wifi: mac80211: Simplify AMPDU handling Alexander Wetzel
2025-02-17 16:30 ` kernel test robot
2025-02-17 8:17 ` [PATCH v2 09/10] wifi: mac80211: Migrate TX to kthread Alexander Wetzel
2025-02-17 8:17 ` [PATCH v2 10/10] wifi: mac80211: Cleanup *ieee80211_wake_txq* naming Alexander Wetzel
2025-02-19 19:19 ` [PATCH v2 00/10] Convert mac80211 to TXQs only James Prestwood
2025-02-19 21:27 ` Alexander Wetzel
2025-02-20 13:56 ` James Prestwood
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).