aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSara Sharon <sara.sharon@intel.com>2017-03-14 03:50:35 -0400
committerKalle Valo <kvalo@codeaurora.org>2017-03-16 03:53:39 -0400
commit9a3fcf912ef7f5c6e18f9af6875dd13f7311f7aa (patch)
tree6202776b7699c3e862d0b2323936993662875315
parent22a0e18eac7a9e986fec76c60fa4a2926d1291e2 (diff)
iwlwifi: mvm: cleanup pending frames in DQA mode
When a station is asleep, the fw will set it as "asleep". All queues that are used only by one station will be stopped by the fw. In pre-DQA mode this was relevant for aggregation queues. However, in DQA mode a queue is owned by one station only, so all queues will be stopped. As a result, we don't expect to get filtered frames back to mac80211 and don't have to maintain the entire pending_frames state logic, the same way as we do in aggregations. The correct behavior is to align DQA behavior with the aggregation queue behaviour pre-DQA: - Don't count pending frames. - Let mac80211 know we have frames in these queues so that it can properly handle trigger frames. When a trigger frame is received, mac80211 tells the driver to send frames from the queues using release_buffered_frames. The driver will tell the fw to let frames out even if the station is asleep. This is done by iwl_mvm_sta_modify_sleep_tx_count. Reported-and-tested-by: Jens Axboe <axboe@kernel.dk> Reported-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Sara Sharon <sara.sharon@intel.com> Signed-off-by: Luca Coelho <luciano.coelho@intel.com> Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c5
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.c11
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/sta.h2
-rw-r--r--drivers/net/wireless/intel/iwlwifi/mvm/tx.c41
4 files changed, 28 insertions, 31 deletions
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
index d37b1695c64e..6927caecd48e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
@@ -2319,7 +2319,7 @@ iwl_mvm_mac_release_buffered_frames(struct ieee80211_hw *hw,
2319{ 2319{
2320 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw); 2320 struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
2321 2321
2322 /* Called when we need to transmit (a) frame(s) from agg queue */ 2322 /* Called when we need to transmit (a) frame(s) from agg or dqa queue */
2323 2323
2324 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames, 2324 iwl_mvm_sta_modify_sleep_tx_count(mvm, sta, reason, num_frames,
2325 tids, more_data, true); 2325 tids, more_data, true);
@@ -2338,7 +2338,8 @@ static void __iwl_mvm_mac_sta_notify(struct ieee80211_hw *hw,
2338 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) { 2338 for (tid = 0; tid < IWL_MAX_TID_COUNT; tid++) {
2339 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid]; 2339 struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
2340 2340
2341 if (tid_data->state != IWL_AGG_ON && 2341 if (!iwl_mvm_is_dqa_supported(mvm) &&
2342 tid_data->state != IWL_AGG_ON &&
2342 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA) 2343 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA)
2343 continue; 2344 continue;
2344 2345
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
index bd1dcc863d8f..b51a2853cc80 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
@@ -3135,7 +3135,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
3135 struct ieee80211_sta *sta, 3135 struct ieee80211_sta *sta,
3136 enum ieee80211_frame_release_type reason, 3136 enum ieee80211_frame_release_type reason,
3137 u16 cnt, u16 tids, bool more_data, 3137 u16 cnt, u16 tids, bool more_data,
3138 bool agg) 3138 bool single_sta_queue)
3139{ 3139{
3140 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta); 3140 struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
3141 struct iwl_mvm_add_sta_cmd cmd = { 3141 struct iwl_mvm_add_sta_cmd cmd = {
@@ -3155,14 +3155,14 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
3155 for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT) 3155 for_each_set_bit(tid, &_tids, IWL_MAX_TID_COUNT)
3156 cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]); 3156 cmd.awake_acs |= BIT(tid_to_ucode_ac[tid]);
3157 3157
3158 /* If we're releasing frames from aggregation queues then check if the 3158 /* If we're releasing frames from aggregation or dqa queues then check
3159 * all queues combined that we're releasing frames from have 3159 * if all the queues that we're releasing frames from, combined, have:
3160 * - more frames than the service period, in which case more_data 3160 * - more frames than the service period, in which case more_data
3161 * needs to be set 3161 * needs to be set
3162 * - fewer than 'cnt' frames, in which case we need to adjust the 3162 * - fewer than 'cnt' frames, in which case we need to adjust the
3163 * firmware command (but do that unconditionally) 3163 * firmware command (but do that unconditionally)
3164 */ 3164 */
3165 if (agg) { 3165 if (single_sta_queue) {
3166 int remaining = cnt; 3166 int remaining = cnt;
3167 int sleep_tx_count; 3167 int sleep_tx_count;
3168 3168
@@ -3172,7 +3172,8 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
3172 u16 n_queued; 3172 u16 n_queued;
3173 3173
3174 tid_data = &mvmsta->tid_data[tid]; 3174 tid_data = &mvmsta->tid_data[tid];
3175 if (WARN(tid_data->state != IWL_AGG_ON && 3175 if (WARN(!iwl_mvm_is_dqa_supported(mvm) &&
3176 tid_data->state != IWL_AGG_ON &&
3176 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA, 3177 tid_data->state != IWL_EMPTYING_HW_QUEUE_DELBA,
3177 "TID %d state is %d\n", 3178 "TID %d state is %d\n",
3178 tid, tid_data->state)) { 3179 tid, tid_data->state)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index 4be34f902278..1927ce607798 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -547,7 +547,7 @@ void iwl_mvm_sta_modify_sleep_tx_count(struct iwl_mvm *mvm,
547 struct ieee80211_sta *sta, 547 struct ieee80211_sta *sta,
548 enum ieee80211_frame_release_type reason, 548 enum ieee80211_frame_release_type reason,
549 u16 cnt, u16 tids, bool more_data, 549 u16 cnt, u16 tids, bool more_data,
550 bool agg); 550 bool single_sta_queue);
551int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, 551int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta,
552 bool drain); 552 bool drain);
553void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, 553void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
index dd2b4a300819..3f37075f4cde 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
@@ -7,7 +7,7 @@
7 * 7 *
8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 8 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 9 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
10 * Copyright(c) 2016 Intel Deutschland GmbH 10 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
11 * 11 *
12 * This program is free software; you can redistribute it and/or modify 12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of version 2 of the GNU General Public License as 13 * it under the terms of version 2 of the GNU General Public License as
@@ -34,6 +34,7 @@
34 * 34 *
35 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved. 35 * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH 36 * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
37 * Copyright(c) 2016 - 2017 Intel Deutschland GmbH
37 * All rights reserved. 38 * All rights reserved.
38 * 39 *
39 * Redistribution and use in source and binary forms, with or without 40 * Redistribution and use in source and binary forms, with or without
@@ -628,8 +629,10 @@ int iwl_mvm_tx_skb_non_sta(struct iwl_mvm *mvm, struct sk_buff *skb)
628 * values. 629 * values.
629 * Note that we don't need to make sure it isn't agg'd, since we're 630 * Note that we don't need to make sure it isn't agg'd, since we're
630 * TXing non-sta 631 * TXing non-sta
632 * For DQA mode - we shouldn't increase it though
631 */ 633 */
632 atomic_inc(&mvm->pending_frames[sta_id]); 634 if (!iwl_mvm_is_dqa_supported(mvm))
635 atomic_inc(&mvm->pending_frames[sta_id]);
633 636
634 return 0; 637 return 0;
635} 638}
@@ -1005,11 +1008,8 @@ static int iwl_mvm_tx_mpdu(struct iwl_mvm *mvm, struct sk_buff *skb,
1005 1008
1006 spin_unlock(&mvmsta->lock); 1009 spin_unlock(&mvmsta->lock);
1007 1010
1008 /* Increase pending frames count if this isn't AMPDU */ 1011 /* Increase pending frames count if this isn't AMPDU or DQA queue */
1009 if ((iwl_mvm_is_dqa_supported(mvm) && 1012 if (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu)
1010 mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_ON &&
1011 mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_STARTING) ||
1012 (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu))
1013 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]); 1013 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
1014 1014
1015 return 0; 1015 return 0;
@@ -1079,12 +1079,13 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
1079 lockdep_assert_held(&mvmsta->lock); 1079 lockdep_assert_held(&mvmsta->lock);
1080 1080
1081 if ((tid_data->state == IWL_AGG_ON || 1081 if ((tid_data->state == IWL_AGG_ON ||
1082 tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA) && 1082 tid_data->state == IWL_EMPTYING_HW_QUEUE_DELBA ||
1083 iwl_mvm_is_dqa_supported(mvm)) &&
1083 iwl_mvm_tid_queued(tid_data) == 0) { 1084 iwl_mvm_tid_queued(tid_data) == 0) {
1084 /* 1085 /*
1085 * Now that this aggregation queue is empty tell mac80211 so it 1086 * Now that this aggregation or DQA queue is empty tell
1086 * knows we no longer have frames buffered for the station on 1087 * mac80211 so it knows we no longer have frames buffered for
1087 * this TID (for the TIM bitmap calculation.) 1088 * the station on this TID (for the TIM bitmap calculation.)
1088 */ 1089 */
1089 ieee80211_sta_set_buffered(sta, tid, false); 1090 ieee80211_sta_set_buffered(sta, tid, false);
1090 } 1091 }
@@ -1257,7 +1258,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
1257 u8 skb_freed = 0; 1258 u8 skb_freed = 0;
1258 u16 next_reclaimed, seq_ctl; 1259 u16 next_reclaimed, seq_ctl;
1259 bool is_ndp = false; 1260 bool is_ndp = false;
1260 bool txq_agg = false; /* Is this TXQ aggregated */
1261 1261
1262 __skb_queue_head_init(&skbs); 1262 __skb_queue_head_init(&skbs);
1263 1263
@@ -1283,6 +1283,10 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
1283 info->flags |= IEEE80211_TX_STAT_ACK; 1283 info->flags |= IEEE80211_TX_STAT_ACK;
1284 break; 1284 break;
1285 case TX_STATUS_FAIL_DEST_PS: 1285 case TX_STATUS_FAIL_DEST_PS:
1286 /* In DQA, the FW should have stopped the queue and not
1287 * return this status
1288 */
1289 WARN_ON(iwl_mvm_is_dqa_supported(mvm));
1286 info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 1290 info->flags |= IEEE80211_TX_STAT_TX_FILTERED;
1287 break; 1291 break;
1288 default: 1292 default:
@@ -1387,15 +1391,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
1387 bool send_eosp_ndp = false; 1391 bool send_eosp_ndp = false;
1388 1392
1389 spin_lock_bh(&mvmsta->lock); 1393 spin_lock_bh(&mvmsta->lock);
1390 if (iwl_mvm_is_dqa_supported(mvm)) {
1391 enum iwl_mvm_agg_state state;
1392
1393 state = mvmsta->tid_data[tid].state;
1394 txq_agg = (state == IWL_AGG_ON ||
1395 state == IWL_EMPTYING_HW_QUEUE_DELBA);
1396 } else {
1397 txq_agg = txq_id >= mvm->first_agg_queue;
1398 }
1399 1394
1400 if (!is_ndp) { 1395 if (!is_ndp) {
1401 tid_data->next_reclaimed = next_reclaimed; 1396 tid_data->next_reclaimed = next_reclaimed;
@@ -1452,11 +1447,11 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
1452 * If the txq is not an AMPDU queue, there is no chance we freed 1447 * If the txq is not an AMPDU queue, there is no chance we freed
1453 * several skbs. Check that out... 1448 * several skbs. Check that out...
1454 */ 1449 */
1455 if (txq_agg) 1450 if (iwl_mvm_is_dqa_supported(mvm) || txq_id >= mvm->first_agg_queue)
1456 goto out; 1451 goto out;
1457 1452
1458 /* We can't free more than one frame at once on a shared queue */ 1453 /* We can't free more than one frame at once on a shared queue */
1459 WARN_ON(!iwl_mvm_is_dqa_supported(mvm) && (skb_freed > 1)); 1454 WARN_ON(skb_freed > 1);
1460 1455
1461 /* If we have still frames for this STA nothing to do here */ 1456 /* If we have still frames for this STA nothing to do here */
1462 if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id])) 1457 if (!atomic_sub_and_test(skb_freed, &mvm->pending_frames[sta_id]))