diff options
author | Sara Sharon <sara.sharon@intel.com> | 2017-03-14 03:50:35 -0400 |
---|---|---|
committer | Kalle Valo <kvalo@codeaurora.org> | 2017-03-16 03:53:39 -0400 |
commit | 9a3fcf912ef7f5c6e18f9af6875dd13f7311f7aa (patch) | |
tree | 6202776b7699c3e862d0b2323936993662875315 | |
parent | 22a0e18eac7a9e986fec76c60fa4a2926d1291e2 (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.c | 5 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 11 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 2 | ||||
-rw-r--r-- | drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 41 |
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); |
551 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, | 551 | int iwl_mvm_drain_sta(struct iwl_mvm *mvm, struct iwl_mvm_sta *mvmsta, |
552 | bool drain); | 552 | bool drain); |
553 | void iwl_mvm_sta_modify_disable_tx(struct iwl_mvm *mvm, | 553 | void 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])) |