Skip to content

Commit 10b2b20

Browse files
sara-slucacoelho
authored andcommitted
iwlwifi: mvm: add infrastructure for tracking BA session in driver
According to the spec when a BA session is started there is a timeout set for the session in the ADDBA request. If there is not activity on the TA/TID then the session expires and a DELBA is sent. In order to check for the timeout, data must be shared among the rx queues. Add a timer that runs as long as BA session is active for the station and stops aggregation session if needed. This patch also lays the infrastructure for the reordering buffer which will be enabled in the next patches. Signed-off-by: Sara Sharon <[email protected]> Signed-off-by: Luca Coelho <[email protected]>
1 parent d0ff5d2 commit 10b2b20

File tree

6 files changed

+194
-13
lines changed

6 files changed

+194
-13
lines changed

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -255,8 +255,10 @@ struct iwl_mvm_keyinfo {
255255
__le64 hw_tkip_mic_tx_key;
256256
} __packed;
257257

258-
#define IWL_ADD_STA_STATUS_MASK 0xFF
259-
#define IWL_ADD_STA_BAID_MASK 0xFF00
258+
#define IWL_ADD_STA_STATUS_MASK 0xFF
259+
#define IWL_ADD_STA_BAID_VALID_MASK 0x8000
260+
#define IWL_ADD_STA_BAID_MASK 0x7F00
261+
#define IWL_ADD_STA_BAID_SHIFT 8
260262

261263
/**
262264
* struct iwl_mvm_add_sta_cmd_v7 - Add/modify a station in the fw's sta table.

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -848,6 +848,7 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
848848
u16 *ssn = &params->ssn;
849849
u8 buf_size = params->buf_size;
850850
bool amsdu = params->amsdu;
851+
u16 timeout = params->timeout;
851852

852853
IWL_DEBUG_HT(mvm, "A-MPDU action on addr %pM tid %d: action %d\n",
853854
sta->addr, tid, action);
@@ -888,10 +889,12 @@ static int iwl_mvm_mac_ampdu_action(struct ieee80211_hw *hw,
888889
ret = -EINVAL;
889890
break;
890891
}
891-
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size);
892+
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, *ssn, true, buf_size,
893+
timeout);
892894
break;
893895
case IEEE80211_AMPDU_RX_STOP:
894-
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size);
896+
ret = iwl_mvm_sta_rx_agg(mvm, sta, tid, 0, false, buf_size,
897+
timeout);
895898
break;
896899
case IEEE80211_AMPDU_TX_START:
897900
if (!iwl_enable_tx_ampdu(mvm->cfg)) {

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

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -613,6 +613,27 @@ struct iwl_mvm_shared_mem_cfg {
613613
u32 internal_txfifo_size[TX_FIFO_INTERNAL_MAX_NUM];
614614
};
615615

616+
/**
617+
* struct iwl_mvm_baid_data - BA session data
618+
* @sta_id: station id
619+
* @tid: tid of the session
620+
* @baid baid of the session
621+
* @timeout: the timeout set in the addba request
622+
* @last_rx: last rx jiffies, updated only if timeout passed from last update
623+
* @session_timer: timer to check if BA session expired, runs at 2 * timeout
624+
* @mvm: mvm pointer, needed for timer context
625+
*/
626+
struct iwl_mvm_baid_data {
627+
struct rcu_head rcu_head;
628+
u8 sta_id;
629+
u8 tid;
630+
u8 baid;
631+
u16 timeout;
632+
unsigned long last_rx;
633+
struct timer_list session_timer;
634+
struct iwl_mvm *mvm;
635+
};
636+
616637
struct iwl_mvm {
617638
/* for logger access */
618639
struct device *dev;
@@ -922,6 +943,10 @@ struct iwl_mvm {
922943
u32 ciphers[6];
923944
struct iwl_mvm_tof_data tof_data;
924945

946+
struct ieee80211_vif *nan_vif;
947+
#define IWL_MAX_BAID 32
948+
struct iwl_mvm_baid_data __rcu *baid_map[IWL_MAX_BAID];
949+
925950
/*
926951
* Drop beacons from other APs in AP mode when there are no connected
927952
* clients.

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

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -424,6 +424,36 @@ void iwl_mvm_rx_queue_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
424424
}
425425
}
426426

427+
static void iwl_mvm_agg_rx_received(struct iwl_mvm *mvm, u8 baid)
428+
{
429+
unsigned long now = jiffies;
430+
unsigned long timeout;
431+
struct iwl_mvm_baid_data *data;
432+
433+
rcu_read_lock();
434+
435+
data = rcu_dereference(mvm->baid_map[baid]);
436+
if (WARN_ON(!data))
437+
goto out;
438+
439+
if (!data->timeout)
440+
goto out;
441+
442+
timeout = data->timeout;
443+
/*
444+
* Do not update last rx all the time to avoid cache bouncing
445+
* between the rx queues.
446+
* Update it every timeout. Worst case is the session will
447+
* expire after ~ 2 * timeout, which doesn't matter that much.
448+
*/
449+
if (time_before(data->last_rx + TU_TO_JIFFIES(timeout), now))
450+
/* Update is atomic */
451+
data->last_rx = now;
452+
453+
out:
454+
rcu_read_unlock();
455+
}
456+
427457
void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
428458
struct iwl_rx_cmd_buffer *rxb, int queue)
429459
{
@@ -494,6 +524,9 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
494524

495525
if (sta) {
496526
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
527+
u8 baid = (u8)((le32_to_cpu(desc->reorder_data) &
528+
IWL_RX_MPDU_REORDER_BAID_MASK) >>
529+
IWL_RX_MPDU_REORDER_BAID_SHIFT);
497530

498531
/*
499532
* We have tx blocked stations (with CS bit). If we heard
@@ -546,6 +579,8 @@ void iwl_mvm_rx_mpdu_mq(struct iwl_mvm *mvm, struct napi_struct *napi,
546579

547580
*qc &= ~IEEE80211_QOS_CTL_A_MSDU_PRESENT;
548581
}
582+
if (baid != IWL_RX_REORDER_DATA_INVALID_BAID)
583+
iwl_mvm_agg_rx_received(mvm, baid);
549584
}
550585

551586
/*

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

Lines changed: 122 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,39 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
223223
return ret;
224224
}
225225

226+
static void iwl_mvm_rx_agg_session_expired(unsigned long data)
227+
{
228+
struct iwl_mvm_baid_data __rcu **rcu_ptr = (void *)data;
229+
struct iwl_mvm_baid_data *ba_data;
230+
struct ieee80211_sta *sta;
231+
struct iwl_mvm_sta *mvm_sta;
232+
unsigned long timeout;
233+
234+
rcu_read_lock();
235+
236+
ba_data = rcu_dereference(*rcu_ptr);
237+
238+
if (WARN_ON(!ba_data))
239+
goto unlock;
240+
241+
if (!ba_data->timeout)
242+
goto unlock;
243+
244+
timeout = ba_data->last_rx + TU_TO_JIFFIES(ba_data->timeout * 2);
245+
if (time_is_after_jiffies(timeout)) {
246+
mod_timer(&ba_data->session_timer, timeout);
247+
goto unlock;
248+
}
249+
250+
/* Timer expired */
251+
sta = rcu_dereference(ba_data->mvm->fw_id_to_mac_id[ba_data->sta_id]);
252+
mvm_sta = iwl_mvm_sta_from_mac80211(sta);
253+
ieee80211_stop_rx_ba_session_offl(mvm_sta->vif,
254+
sta->addr, ba_data->tid);
255+
unlock:
256+
rcu_read_unlock();
257+
}
258+
226259
static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
227260
struct ieee80211_sta *sta)
228261
{
@@ -1134,11 +1167,22 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
11341167

11351168
#define IWL_MAX_RX_BA_SESSIONS 16
11361169

1170+
static void iwl_mvm_sync_rxq_del_ba(struct iwl_mvm *mvm)
1171+
{
1172+
struct iwl_mvm_internal_rxq_notif data = {
1173+
.type = IWL_MVM_RXQ_EMPTY,
1174+
.sync = 1,
1175+
};
1176+
1177+
iwl_mvm_sync_rx_queues_internal(mvm, &data, sizeof(data));
1178+
}
1179+
11371180
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
1138-
int tid, u16 ssn, bool start, u8 buf_size)
1181+
int tid, u16 ssn, bool start, u8 buf_size, u16 timeout)
11391182
{
11401183
struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
11411184
struct iwl_mvm_add_sta_cmd cmd = {};
1185+
struct iwl_mvm_baid_data *baid_data = NULL;
11421186
int ret;
11431187
u32 status;
11441188

@@ -1149,6 +1193,16 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
11491193
return -ENOSPC;
11501194
}
11511195

1196+
if (iwl_mvm_has_new_rx_api(mvm) && start) {
1197+
/*
1198+
* Allocate here so if allocation fails we can bail out early
1199+
* before starting the BA session in the firmware
1200+
*/
1201+
baid_data = kzalloc(sizeof(*baid_data), GFP_KERNEL);
1202+
if (!baid_data)
1203+
return -ENOMEM;
1204+
}
1205+
11521206
cmd.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color);
11531207
cmd.sta_id = mvm_sta->sta_id;
11541208
cmd.add_modify = STA_MODE_MODIFY;
@@ -1167,7 +1221,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
11671221
iwl_mvm_add_sta_cmd_size(mvm),
11681222
&cmd, &status);
11691223
if (ret)
1170-
return ret;
1224+
goto out_free;
11711225

11721226
switch (status & IWL_ADD_STA_STATUS_MASK) {
11731227
case ADD_STA_SUCCESS:
@@ -1185,14 +1239,74 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
11851239
break;
11861240
}
11871241

1188-
if (!ret) {
1189-
if (start)
1190-
mvm->rx_ba_sessions++;
1191-
else if (mvm->rx_ba_sessions > 0)
1192-
/* check that restart flow didn't zero the counter */
1193-
mvm->rx_ba_sessions--;
1242+
if (ret)
1243+
goto out_free;
1244+
1245+
if (start) {
1246+
u8 baid;
1247+
1248+
mvm->rx_ba_sessions++;
1249+
1250+
if (!iwl_mvm_has_new_rx_api(mvm))
1251+
return 0;
1252+
1253+
if (WARN_ON(!(status & IWL_ADD_STA_BAID_VALID_MASK))) {
1254+
ret = -EINVAL;
1255+
goto out_free;
1256+
}
1257+
baid = (u8)((status & IWL_ADD_STA_BAID_MASK) >>
1258+
IWL_ADD_STA_BAID_SHIFT);
1259+
baid_data->baid = baid;
1260+
baid_data->timeout = timeout;
1261+
baid_data->last_rx = jiffies;
1262+
init_timer(&baid_data->session_timer);
1263+
baid_data->session_timer.function =
1264+
iwl_mvm_rx_agg_session_expired;
1265+
baid_data->session_timer.data =
1266+
(unsigned long)&mvm->baid_map[baid];
1267+
baid_data->mvm = mvm;
1268+
baid_data->tid = tid;
1269+
baid_data->sta_id = mvm_sta->sta_id;
1270+
1271+
mvm_sta->tid_to_baid[tid] = baid;
1272+
if (timeout)
1273+
mod_timer(&baid_data->session_timer,
1274+
TU_TO_EXP_TIME(timeout * 2));
1275+
1276+
/*
1277+
* protect the BA data with RCU to cover a case where our
1278+
* internal RX sync mechanism will timeout (not that it's
1279+
* supposed to happen) and we will free the session data while
1280+
* RX is being processed in parallel
1281+
*/
1282+
WARN_ON(rcu_access_pointer(mvm->baid_map[baid]));
1283+
rcu_assign_pointer(mvm->baid_map[baid], baid_data);
1284+
} else if (mvm->rx_ba_sessions > 0) {
1285+
u8 baid = mvm_sta->tid_to_baid[tid];
1286+
1287+
/* check that restart flow didn't zero the counter */
1288+
mvm->rx_ba_sessions--;
1289+
if (!iwl_mvm_has_new_rx_api(mvm))
1290+
return 0;
1291+
1292+
if (WARN_ON(baid == IWL_RX_REORDER_DATA_INVALID_BAID))
1293+
return -EINVAL;
1294+
1295+
baid_data = rcu_access_pointer(mvm->baid_map[baid]);
1296+
if (WARN_ON(!baid_data))
1297+
return -EINVAL;
1298+
1299+
/* synchronize all rx queues so we can safely delete */
1300+
iwl_mvm_sync_rxq_del_ba(mvm);
1301+
del_timer_sync(&baid_data->session_timer);
1302+
1303+
RCU_INIT_POINTER(mvm->baid_map[baid], NULL);
1304+
kfree_rcu(baid_data, rcu_head);
11941305
}
1306+
return 0;
11951307

1308+
out_free:
1309+
kfree(baid_data);
11961310
return ret;
11971311
}
11981312

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,7 @@ struct iwl_mvm_rxq_dup_data {
373373
* @lock: lock to protect the whole struct. Since %tid_data is access from Tx
374374
* and from Tx response flow, it needs a spinlock.
375375
* @tid_data: per tid data + mgmt. Look at %iwl_mvm_tid_data.
376+
* @tid_to_baid: a simple map of TID to baid
376377
* @reserved_queue: the queue reserved for this STA for DQA purposes
377378
* Every STA has is given one reserved queue to allow it to operate. If no
378379
* such queue can be guaranteed, the STA addition will fail.
@@ -406,6 +407,7 @@ struct iwl_mvm_sta {
406407
bool next_status_eosp;
407408
spinlock_t lock;
408409
struct iwl_mvm_tid_data tid_data[IWL_MAX_TID_COUNT + 1];
410+
u8 tid_to_baid[IWL_MAX_TID_COUNT];
409411
struct iwl_lq_sta lq_sta;
410412
struct ieee80211_vif *vif;
411413
struct iwl_mvm_key_pn __rcu *ptk_pn[4];
@@ -487,7 +489,7 @@ void iwl_mvm_rx_eosp_notif(struct iwl_mvm *mvm,
487489

488490
/* AMPDU */
489491
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
490-
int tid, u16 ssn, bool start, u8 buf_size);
492+
int tid, u16 ssn, bool start, u8 buf_size, u16 timeout);
491493
int iwl_mvm_sta_tx_agg_start(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
492494
struct ieee80211_sta *sta, u16 tid, u16 *ssn);
493495
int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,

0 commit comments

Comments
 (0)