aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArik Nemtsov <arik@wizery.com>2014-09-21 12:10:04 -0400
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>2014-11-24 01:30:23 -0500
commita0f6bf2a5b018bcee93e4dece903589a8bb6062b (patch)
tree6013e97f75ac0f5a1e8cebe7f32c534e1a11305e
parentcbd2ae2da6497b507f89849dffd972a474058480 (diff)
iwlwifi: mvm: use private TFD queues for TDLS stations
When adding a TDLS station, allocate 4 new queues for it. Configure them to FW and enable them. On station removal, drain the queues if needed and disable them when empty. Make sure to flush all packets in the private queues of TDLS stations in the mac80211 flush() callback. Signed-off-by: Arik Nemtsov <arikx.nemtsov@intel.com> Reviewed-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c28
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h1
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c94
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.h2
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c7
5 files changed, 121 insertions, 11 deletions
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 3883a86fb719..64e89e89140c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -876,6 +876,7 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
876 iwl_mvm_reset_phy_ctxts(mvm); 876 iwl_mvm_reset_phy_ctxts(mvm);
877 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table)); 877 memset(mvm->fw_key_table, 0, sizeof(mvm->fw_key_table));
878 memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained)); 878 memset(mvm->sta_drained, 0, sizeof(mvm->sta_drained));
879 memset(mvm->tfd_drained, 0, sizeof(mvm->tfd_drained));
879 memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif)); 880 memset(&mvm->last_bt_notif, 0, sizeof(mvm->last_bt_notif));
880 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old)); 881 memset(&mvm->last_bt_notif_old, 0, sizeof(mvm->last_bt_notif_old));
881 memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd)); 882 memset(&mvm->last_bt_ci_cmd, 0, sizeof(mvm->last_bt_ci_cmd));
@@ -3113,31 +3114,44 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
3113 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 3114 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
3114 struct iwl_mvm_vif *mvmvif; 3115 struct iwl_mvm_vif *mvmvif;
3115 struct iwl_mvm_sta *mvmsta; 3116 struct iwl_mvm_sta *mvmsta;
3117 struct ieee80211_sta *sta;
3118 int i;
3119 u32 msk = 0;
3116 3120
3117 if (!vif || vif->type != NL80211_IFTYPE_STATION) 3121 if (!vif || vif->type != NL80211_IFTYPE_STATION)
3118 return; 3122 return;
3119 3123
3120 mutex_lock(&mvm->mutex); 3124 mutex_lock(&mvm->mutex);
3121 mvmvif = iwl_mvm_vif_from_mac80211(vif); 3125 mvmvif = iwl_mvm_vif_from_mac80211(vif);
3122 mvmsta = iwl_mvm_sta_from_staid_protected(mvm, mvmvif->ap_sta_id);
3123 3126
3124 if (WARN_ON_ONCE(!mvmsta)) { 3127 /* flush the AP-station and all TDLS peers */
3125 mutex_unlock(&mvm->mutex); 3128 for (i = 0; i < IWL_MVM_STATION_COUNT; i++) {
3126 return; 3129 sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[i],
3130 lockdep_is_held(&mvm->mutex));
3131 if (IS_ERR_OR_NULL(sta))
3132 continue;
3133
3134 mvmsta = iwl_mvm_sta_from_mac80211(sta);
3135 if (mvmsta->vif != vif)
3136 continue;
3137
3138 /* make sure only TDLS peers or the AP are flushed */
3139 WARN_ON(i != mvmvif->ap_sta_id && !sta->tdls);
3140
3141 msk |= mvmsta->tfd_queue_msk;
3127 } 3142 }
3128 3143
3129 if (drop) { 3144 if (drop) {
3130 if (iwl_mvm_flush_tx_path(mvm, mvmsta->tfd_queue_msk, true)) 3145 if (iwl_mvm_flush_tx_path(mvm, msk, true))
3131 IWL_ERR(mvm, "flush request fail\n"); 3146 IWL_ERR(mvm, "flush request fail\n");
3132 mutex_unlock(&mvm->mutex); 3147 mutex_unlock(&mvm->mutex);
3133 } else { 3148 } else {
3134 u32 tfd_queue_msk = mvmsta->tfd_queue_msk;
3135 mutex_unlock(&mvm->mutex); 3149 mutex_unlock(&mvm->mutex);
3136 3150
3137 /* this can take a while, and we may need/want other operations 3151 /* this can take a while, and we may need/want other operations
3138 * to succeed while doing this, so do it without the mutex held 3152 * to succeed while doing this, so do it without the mutex held
3139 */ 3153 */
3140 iwl_trans_wait_tx_queue_empty(mvm->trans, tfd_queue_msk); 3154 iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
3141 } 3155 }
3142} 3156}
3143 3157
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index 363be83e283e..63d2d453f9dd 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -578,6 +578,7 @@ struct iwl_mvm {
578 struct work_struct sta_drained_wk; 578 struct work_struct sta_drained_wk;
579 unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)]; 579 unsigned long sta_drained[BITS_TO_LONGS(IWL_MVM_STATION_COUNT)];
580 atomic_t pending_frames[IWL_MVM_STATION_COUNT]; 580 atomic_t pending_frames[IWL_MVM_STATION_COUNT];
581 u32 tfd_drained[IWL_MVM_STATION_COUNT];
581 u8 rx_ba_sessions; 582 u8 rx_ba_sessions;
582 583
583 /* configured by mac80211 */ 584 /* configured by mac80211 */
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index 0eb850542af4..15afa9a26c8f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -204,6 +204,56 @@ int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
204 return ret; 204 return ret;
205} 205}
206 206
207static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
208 struct ieee80211_sta *sta)
209{
210 unsigned long used_hw_queues;
211 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
212 u32 ac;
213
214 lockdep_assert_held(&mvm->mutex);
215
216 used_hw_queues = iwl_mvm_get_used_hw_queues(mvm, NULL);
217
218 /* Find available queues, and allocate them to the ACs */
219 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
220 u8 queue = find_first_zero_bit(&used_hw_queues,
221 mvm->first_agg_queue);
222
223 if (queue >= mvm->first_agg_queue) {
224 IWL_ERR(mvm, "Failed to allocate STA queue\n");
225 return -EBUSY;
226 }
227
228 __set_bit(queue, &used_hw_queues);
229 mvmsta->hw_queue[ac] = queue;
230 }
231
232 /* Found a place for all queues - enable them */
233 for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
234 iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
235 iwl_mvm_ac_to_tx_fifo[ac]);
236 mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
237 }
238
239 return 0;
240}
241
242static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
243 struct ieee80211_sta *sta)
244{
245 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
246 unsigned long sta_msk;
247 int i;
248
249 lockdep_assert_held(&mvm->mutex);
250
251 /* disable the TDLS STA-specific queues */
252 sta_msk = mvmsta->tfd_queue_msk;
253 for_each_set_bit(i, &sta_msk, sizeof(sta_msk))
254 iwl_mvm_disable_txq(mvm, i);
255}
256
207int iwl_mvm_add_sta(struct iwl_mvm *mvm, 257int iwl_mvm_add_sta(struct iwl_mvm *mvm,
208 struct ieee80211_vif *vif, 258 struct ieee80211_vif *vif,
209 struct ieee80211_sta *sta) 259 struct ieee80211_sta *sta)
@@ -237,9 +287,17 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
237 atomic_set(&mvm->pending_frames[sta_id], 0); 287 atomic_set(&mvm->pending_frames[sta_id], 0);
238 mvm_sta->tid_disable_agg = 0; 288 mvm_sta->tid_disable_agg = 0;
239 mvm_sta->tfd_queue_msk = 0; 289 mvm_sta->tfd_queue_msk = 0;
240 for (i = 0; i < IEEE80211_NUM_ACS; i++) 290
241 if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE) 291 /* allocate new queues for a TDLS station */
242 mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]); 292 if (sta->tdls) {
293 ret = iwl_mvm_tdls_sta_init(mvm, sta);
294 if (ret)
295 return ret;
296 } else {
297 for (i = 0; i < IEEE80211_NUM_ACS; i++)
298 if (vif->hw_queue[i] != IEEE80211_INVAL_HW_QUEUE)
299 mvm_sta->tfd_queue_msk |= BIT(vif->hw_queue[i]);
300 }
243 301
244 /* for HW restart - reset everything but the sequence number */ 302 /* for HW restart - reset everything but the sequence number */
245 for (i = 0; i < IWL_MAX_TID_COUNT; i++) { 303 for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
@@ -251,7 +309,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
251 309
252 ret = iwl_mvm_sta_send_to_fw(mvm, sta, false); 310 ret = iwl_mvm_sta_send_to_fw(mvm, sta, false);
253 if (ret) 311 if (ret)
254 return ret; 312 goto err;
255 313
256 if (vif->type == NL80211_IFTYPE_STATION) { 314 if (vif->type == NL80211_IFTYPE_STATION) {
257 if (!sta->tdls) { 315 if (!sta->tdls) {
@@ -265,6 +323,10 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
265 rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta); 323 rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
266 324
267 return 0; 325 return 0;
326
327err:
328 iwl_mvm_tdls_sta_deinit(mvm, sta);
329 return ret;
268} 330}
269 331
270int iwl_mvm_update_sta(struct iwl_mvm *mvm, 332int iwl_mvm_update_sta(struct iwl_mvm *mvm,
@@ -398,6 +460,17 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
398 } 460 }
399 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL); 461 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[sta_id], NULL);
400 clear_bit(sta_id, mvm->sta_drained); 462 clear_bit(sta_id, mvm->sta_drained);
463
464 if (mvm->tfd_drained[sta_id]) {
465 unsigned long i, msk = mvm->tfd_drained[sta_id];
466
467 for_each_set_bit(i, &msk, sizeof(msk))
468 iwl_mvm_disable_txq(mvm, i);
469
470 mvm->tfd_drained[sta_id] = 0;
471 IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
472 sta_id, msk);
473 }
401 } 474 }
402 475
403 mutex_unlock(&mvm->mutex); 476 mutex_unlock(&mvm->mutex);
@@ -443,9 +516,22 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
443 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id], 516 rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
444 ERR_PTR(-EBUSY)); 517 ERR_PTR(-EBUSY));
445 spin_unlock_bh(&mvm_sta->lock); 518 spin_unlock_bh(&mvm_sta->lock);
519
520 /* disable TDLS sta queues on drain complete */
521 if (sta->tdls) {
522 mvm->tfd_drained[mvm_sta->sta_id] =
523 mvm_sta->tfd_queue_msk;
524 IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n",
525 mvm_sta->sta_id);
526 }
527
446 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true); 528 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
447 } else { 529 } else {
448 spin_unlock_bh(&mvm_sta->lock); 530 spin_unlock_bh(&mvm_sta->lock);
531
532 if (sta->tdls)
533 iwl_mvm_tdls_sta_deinit(mvm, sta);
534
449 ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id); 535 ret = iwl_mvm_rm_sta_common(mvm, mvm_sta->sta_id);
450 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL); 536 RCU_INIT_POINTER(mvm->fw_id_to_mac_id[mvm_sta->sta_id], NULL);
451 } 537 }
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.h b/drivers/net/wireless/iwlwifi/mvm/sta.h
index 84f37ca9398a..2c869bcb9490 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.h
@@ -288,6 +288,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
288 * struct iwl_mvm_sta - representation of a station in the driver 288 * struct iwl_mvm_sta - representation of a station in the driver
289 * @sta_id: the index of the station in the fw (will be replaced by id_n_color) 289 * @sta_id: the index of the station in the fw (will be replaced by id_n_color)
290 * @tfd_queue_msk: the tfd queues used by the station 290 * @tfd_queue_msk: the tfd queues used by the station
291 * @hw_queue: per-AC mapping of the TFD queues used by station
291 * @mac_id_n_color: the MAC context this station is linked to 292 * @mac_id_n_color: the MAC context this station is linked to
292 * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for 293 * @tid_disable_agg: bitmap: if bit(tid) is set, the fw won't send ampdus for
293 * tid. 294 * tid.
@@ -311,6 +312,7 @@ static inline u16 iwl_mvm_tid_queued(struct iwl_mvm_tid_data *tid_data)
311struct iwl_mvm_sta { 312struct iwl_mvm_sta {
312 u32 sta_id; 313 u32 sta_id;
313 u32 tfd_queue_msk; 314 u32 tfd_queue_msk;
315 u8 hw_queue[IEEE80211_NUM_ACS];
314 u32 mac_id_n_color; 316 u32 mac_id_n_color;
315 u16 tid_disable_agg; 317 u16 tid_disable_agg;
316 u8 max_agg_bufsize; 318 u8 max_agg_bufsize;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index b54708e4d29c..4f15d9decc81 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -424,6 +424,13 @@ int iwl_mvm_tx_skb(struct iwl_mvm *mvm, struct sk_buff *skb,
424 424
425 WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM); 425 WARN_ON_ONCE(info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM);
426 426
427 if (sta->tdls) {
428 /* default to TID 0 for non-QoS packets */
429 u8 tdls_tid = tid == IWL_MAX_TID_COUNT ? 0 : tid;
430
431 txq_id = mvmsta->hw_queue[tid_to_mac80211_ac[tdls_tid]];
432 }
433
427 if (is_ampdu) { 434 if (is_ampdu) {
428 if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON)) 435 if (WARN_ON_ONCE(mvmsta->tid_data[tid].state != IWL_AGG_ON))
429 goto drop_unlock_sta; 436 goto drop_unlock_sta;