Skip to content

Commit 24afba7

Browse files
lkaufman-heegrumbach
authored andcommitted
iwlwifi: mvm: support bss dynamic alloc/dealloc of queues
"DQA" is shorthand for "dynamic queue allocation". This enables on-demand allocation of queues per RA/TID rather than statically allocating per vif, thus allowing a potential benefit of various factors. Please refer to the DOC section this patch adds to sta.h to see a more in-depth explanation of this feature. There are many things to take into consideration when working in DQA mode, and this patch is only one in a series. Note that default operation mode is non-DQA mode, unless the FW indicates that it supports DQA mode. This patch enables support of DQA for a station connected to an AP, and works in a non-aggregated mode. When a frame for an unused RA/TID arrives at the driver, it isn't TXed immediately, but deferred first until a suitable queue is first allocated for it, and then TXed by a worker that both allocates the queues and TXes deferred traffic. When a STA is removed, its queues goes back into the queue pools for reuse as needed. Signed-off-by: Liad Kaufman <[email protected]> Signed-off-by: Emmanuel Grumbach <[email protected]>
1 parent 7ec5471 commit 24afba7

File tree

9 files changed

+481
-16
lines changed

9 files changed

+481
-16
lines changed

drivers/net/wireless/intel/iwlwifi/mvm/d3.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
723723
return -EIO;
724724
}
725725

726-
ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false);
726+
ret = iwl_mvm_sta_send_to_fw(mvm, ap_sta, false, 0);
727727
if (ret)
728728
return ret;
729729
rcu_assign_pointer(mvm->fw_id_to_mac_id[mvmvif->ap_sta_id], ap_sta);

drivers/net/wireless/intel/iwlwifi/mvm/fw-api.h

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,32 @@
8080
#include "fw-api-stats.h"
8181
#include "fw-api-tof.h"
8282

83-
/* Tx queue numbers */
83+
/* Tx queue numbers for non-DQA mode */
8484
enum {
8585
IWL_MVM_OFFCHANNEL_QUEUE = 8,
8686
IWL_MVM_CMD_QUEUE = 9,
8787
};
8888

89+
/*
90+
* DQA queue numbers
91+
*
92+
* @IWL_MVM_DQA_MIN_MGMT_QUEUE: first TXQ in pool for MGMT and non-QOS frames.
93+
* Each MGMT queue is mapped to a single STA
94+
* MGMT frames are frames that return true on ieee80211_is_mgmt()
95+
* @IWL_MVM_DQA_MAX_MGMT_QUEUE: last TXQ in pool for MGMT frames
96+
* @IWL_MVM_DQA_MIN_DATA_QUEUE: first TXQ in pool for DATA frames.
97+
* DATA frames are intended for !ieee80211_is_mgmt() frames, but if
98+
* the MGMT TXQ pool is exhausted, mgmt frames can be sent on DATA queues
99+
* as well
100+
* @IWL_MVM_DQA_MAX_DATA_QUEUE: last TXQ in pool for DATA frames
101+
*/
102+
enum iwl_mvm_dqa_txq {
103+
IWL_MVM_DQA_MIN_MGMT_QUEUE = 5,
104+
IWL_MVM_DQA_MAX_MGMT_QUEUE = 8,
105+
IWL_MVM_DQA_MIN_DATA_QUEUE = 10,
106+
IWL_MVM_DQA_MAX_DATA_QUEUE = 31,
107+
};
108+
89109
enum iwl_mvm_tx_fifo {
90110
IWL_MVM_TX_FIFO_BK = 0,
91111
IWL_MVM_TX_FIFO_BE,

drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -425,12 +425,17 @@ static int iwl_mvm_mac_ctxt_allocate_resources(struct iwl_mvm *mvm,
425425
return 0;
426426
}
427427

428-
/* Find available queues, and allocate them to the ACs */
428+
/*
429+
* Find available queues, and allocate them to the ACs. When in
430+
* DQA-mode they aren't really used, and this is done only so the
431+
* mac80211 ieee80211_check_queues() function won't fail
432+
*/
429433
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
430434
u8 queue = find_first_zero_bit(&used_hw_queues,
431435
mvm->first_agg_queue);
432436

433-
if (queue >= mvm->first_agg_queue) {
437+
if (!iwl_mvm_is_dqa_supported(mvm) &&
438+
queue >= mvm->first_agg_queue) {
434439
IWL_ERR(mvm, "Failed to allocate queue\n");
435440
ret = -EIO;
436441
goto exit_fail;
@@ -495,6 +500,10 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
495500
IWL_MVM_TX_FIFO_MCAST, 0, wdg_timeout);
496501
/* fall through */
497502
default:
503+
/* If DQA is supported - queues will be enabled when needed */
504+
if (iwl_mvm_is_dqa_supported(mvm))
505+
break;
506+
498507
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
499508
iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
500509
vif->hw_queue[ac],
@@ -523,6 +532,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
523532
IWL_MAX_TID_COUNT, 0);
524533
/* fall through */
525534
default:
535+
/*
536+
* If DQA is supported - queues were already disabled, since in
537+
* DQA-mode the queues are a property of the STA and not of the
538+
* vif, and at this point the STA was already deleted
539+
*/
540+
if (iwl_mvm_is_dqa_supported(mvm))
541+
break;
542+
526543
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
527544
iwl_mvm_disable_txq(mvm, vif->hw_queue[ac],
528545
vif->hw_queue[ac],

drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -992,6 +992,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
992992
iwl_mvm_reset_phy_ctxts(mvm);
993993
memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
994994
memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
995+
memset(mvm->sta_deferred_frames, 0, sizeof(mvm->sta_deferred_frames));
995996
memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
996997
memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
997998
memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
@@ -1178,6 +1179,7 @@ static void iwl_mvm_mac_stop(struct ieee80211_hw *hw)
11781179

11791180
flush_work(&mvm->d0i3_exit_work);
11801181
flush_work(&mvm->async_handlers_wk);
1182+
flush_work(&mvm->add_stream_wk);
11811183
cancel_delayed_work_sync(&mvm->fw_dump_wk);
11821184
iwl_mvm_free_fw_dump_desc(mvm);
11831185

@@ -2382,6 +2384,22 @@ iwl_mvm_tdls_check_trigger(struct iwl_mvm *mvm,
23822384
peer_addr, action);
23832385
}
23842386

2387+
static void iwl_mvm_purge_deferred_tx_frames(struct iwl_mvm *mvm,
2388+
struct iwl_mvm_sta *mvm_sta)
2389+
{
2390+
struct iwl_mvm_tid_data *tid_data;
2391+
struct sk_buff *skb;
2392+
int i;
2393+
2394+
spin_lock_bh(&mvm_sta->lock);
2395+
for (i = 0; i <= IWL_MAX_TID_COUNT; i++) {
2396+
tid_data = &mvm_sta->tid_data[i];
2397+
while ((skb = __skb_dequeue(&tid_data->deferred_tx_frames)))
2398+
ieee80211_free_txskb(mvm->hw, skb);
2399+
}
2400+
spin_unlock_bh(&mvm_sta->lock);
2401+
}
2402+
23852403
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
23862404
struct ieee80211_vif *vif,
23872405
struct ieee80211_sta *sta,
@@ -2402,6 +2420,33 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
24022420
/* if a STA is being removed, reuse its ID */
24032421
flush_work(&mvm->sta_drained_wk);
24042422

2423+
/*
2424+
* If we are in a STA removal flow and in DQA mode:
2425+
*
2426+
* This is after the sync_rcu part, so the queues have already been
2427+
* flushed. No more TXs on their way in mac80211's path, and no more in
2428+
* the queues.
2429+
* Also, we won't be getting any new TX frames for this station.
2430+
* What we might have are deferred TX frames that need to be taken care
2431+
* of.
2432+
*
2433+
* Drop any still-queued deferred-frame before removing the STA, and
2434+
* make sure the worker is no longer handling frames for this STA.
2435+
*/
2436+
if (old_state == IEEE80211_STA_NONE &&
2437+
new_state == IEEE80211_STA_NOTEXIST &&
2438+
iwl_mvm_is_dqa_supported(mvm)) {
2439+
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
2440+
2441+
iwl_mvm_purge_deferred_tx_frames(mvm, mvm_sta);
2442+
flush_work(&mvm->add_stream_wk);
2443+
2444+
/*
2445+
* No need to make sure deferred TX indication is off since the
2446+
* worker will already remove it if it was on
2447+
*/
2448+
}
2449+
24052450
mutex_lock(&mvm->mutex);
24062451
if (old_state == IEEE80211_STA_NOTEXIST &&
24072452
new_state == IEEE80211_STA_NONE) {
@@ -3738,6 +3783,10 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
37383783
if (!vif || vif->type != NL80211_IFTYPE_STATION)
37393784
return;
37403785

3786+
/* Make sure we're done with the deferred traffic before flushing */
3787+
if (iwl_mvm_is_dqa_supported(mvm))
3788+
flush_work(&mvm->add_stream_wk);
3789+
37413790
mutex_lock(&mvm->mutex);
37423791
mvmvif = iwl_mvm_vif_from_mac80211(vif);
37433792

drivers/net/wireless/intel/iwlwifi/mvm/mvm.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,10 +665,16 @@ struct iwl_mvm {
665665
/* Map to HW queue */
666666
u32 hw_queue_to_mac80211;
667667
u8 hw_queue_refcount;
668+
/*
669+
* This is to mark that queue is reserved for a STA but not yet
670+
* allocated. This is needed to make sure we have at least one
671+
* available queue to use when adding a new STA
672+
*/
668673
bool setup_reserved;
669674
u16 tid_bitmap; /* Bitmap of the TIDs mapped to this queue */
670675
} queue_info[IWL_MAX_HW_QUEUES];
671676
spinlock_t queue_info_lock; /* For syncing queue mgmt operations */
677+
struct work_struct add_stream_wk; /* To add streams to queues */
672678
atomic_t mac80211_queue_stop_count[IEEE80211_MAX_QUEUES];
673679

674680
const char *nvm_file_name;
@@ -688,6 +694,7 @@ struct iwl_mvm {
688694
struct iwl_rx_phy_info last_phy_info;
689695
struct ieee80211_sta __rcu *fw_id_to_mac_id[IWL_MVM_STATION_COUNT];
690696
struct work_struct sta_drained_wk;
697+
unsigned long sta_deferred_frames[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
691698
unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
692699
atomic_t pending_frames[IWL_MVM_STATION_COUNT];
693700
u32 tfd_drained[IWL_MVM_STATION_COUNT];

drivers/net/wireless/intel/iwlwifi/mvm/ops.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,7 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
579579
INIT_WORK(&mvm->d0i3_exit_work, iwl_mvm_d0i3_exit_work);
580580
INIT_DELAYED_WORK(&mvm->fw_dump_wk, iwl_mvm_fw_error_dump_wk);
581581
INIT_DELAYED_WORK(&mvm->tdls_cs.dwork, iwl_mvm_tdls_ch_switch_work);
582+
INIT_WORK(&mvm->add_stream_wk, iwl_mvm_add_new_dqa_stream_wk);
582583

583584
spin_lock_init(&mvm->d0i3_tx_lock);
584585
spin_lock_init(&mvm->refs_lock);

0 commit comments

Comments
 (0)