]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blame - releases/4.9.28/iwlwifi-mvm-fix-pending-frame-counter-calculation.patch
fix up queue-5.15/mm-fix-race-between-__split_huge_pmd_locked-and-gup-.patch
[thirdparty/kernel/stable-queue.git] / releases / 4.9.28 / iwlwifi-mvm-fix-pending-frame-counter-calculation.patch
CommitLineData
b74db2ac
GKH
1From 94c3e614df2117626fccfac8f821c66e30556384 Mon Sep 17 00:00:00 2001
2From: Sara Sharon <sara.sharon@intel.com>
3Date: Wed, 7 Dec 2016 15:04:37 +0200
4Subject: iwlwifi: mvm: fix pending frame counter calculation
5
6From: Sara Sharon <sara.sharon@intel.com>
7
8commit 94c3e614df2117626fccfac8f821c66e30556384 upstream.
9
10In DQA mode the check whether to decrement the pending frames
11counter relies on the tid status and not on the txq id.
12This may result in an inconsistent state of the pending frames
13counter in case frame is queued on a non aggregation queue but
14with this TID, and will be followed by a failure to remove the
15station and later on SYSASSERT 0x3421 when trying to remove the
16MAC.
17Such frames are for example bar and qos NDPs.
18Fix it by aligning the condition of incrementing the counter
19with the condition of decrementing it - rely on TID state for
20DQA mode.
21Also, avoid internal error like this affecting station removal
22for DQA mode - since we can know for sure it is an internal
23error.
24
25Fixes: cf961e16620f ("iwlwifi: mvm: support dqa-mode agg on non-shared queue")
26Signed-off-by: Sara Sharon <sara.sharon@intel.com>
27Signed-off-by: Luca Coelho <luciano.coelho@intel.com>
28Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
29
30---
31 drivers/net/wireless/intel/iwlwifi/mvm/sta.c | 31 +++++++++++++++++----------
32 drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 5 +++-
33 2 files changed, 24 insertions(+), 12 deletions(-)
34
35--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
36+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.c
37@@ -1466,6 +1466,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
38 {
39 struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
40 struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
41+ u8 sta_id = mvm_sta->sta_id;
42 int ret;
43
44 lockdep_assert_held(&mvm->mutex);
45@@ -1474,7 +1475,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
46 kfree(mvm_sta->dup_data);
47
48 if ((vif->type == NL80211_IFTYPE_STATION &&
49- mvmvif->ap_sta_id == mvm_sta->sta_id) ||
50+ mvmvif->ap_sta_id == sta_id) ||
51 iwl_mvm_is_dqa_supported(mvm)){
52 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
53 if (ret)
54@@ -1497,6 +1498,15 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
55 iwl_mvm_disable_sta_queues(mvm, vif, mvm_sta);
56
57 /*
58+ * If pending_frames is set at this point - it must be
59+ * driver internal logic error, since queues are empty
60+ * and removed successuly.
61+ * warn on it but set it to 0 anyway to avoid station
62+ * not being removed later in the function
63+ */
64+ WARN_ON(atomic_xchg(&mvm->pending_frames[sta_id], 0));
65+
66+ /*
67 * If no traffic has gone through the reserved TXQ - it
68 * is still marked as IWL_MVM_QUEUE_RESERVED, and
69 * should be manually marked as free again
70@@ -1506,7 +1516,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
71 if (WARN((*status != IWL_MVM_QUEUE_RESERVED) &&
72 (*status != IWL_MVM_QUEUE_FREE),
73 "sta_id %d reserved txq %d status %d",
74- mvm_sta->sta_id, reserved_txq, *status)) {
75+ sta_id, reserved_txq, *status)) {
76 spin_unlock_bh(&mvm->queue_info_lock);
77 return -EINVAL;
78 }
79@@ -1516,7 +1526,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
80 }
81
82 if (vif->type == NL80211_IFTYPE_STATION &&
83- mvmvif->ap_sta_id == mvm_sta->sta_id) {
84+ mvmvif->ap_sta_id == sta_id) {
85 /* if associated - we can't remove the AP STA now */
86 if (vif->bss_conf.assoc)
87 return ret;
88@@ -1525,7 +1535,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
89 mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
90
91 /* clear d0i3_ap_sta_id if no longer relevant */
92- if (mvm->d0i3_ap_sta_id == mvm_sta->sta_id)
93+ if (mvm->d0i3_ap_sta_id == sta_id)
94 mvm->d0i3_ap_sta_id = IWL_MVM_STATION_COUNT;
95 }
96 }
97@@ -1534,7 +1544,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
98 * This shouldn't happen - the TDLS channel switch should be canceled
99 * before the STA is removed.
100 */
101- if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == mvm_sta->sta_id)) {
102+ if (WARN_ON_ONCE(mvm->tdls_cs.peer.sta_id == sta_id)) {
103 mvm->tdls_cs.peer.sta_id = IWL_MVM_STATION_COUNT;
104 cancel_delayed_work(&mvm->tdls_cs.dwork);
105 }
106@@ -1544,21 +1554,20 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
107 * calls the drain worker.
108 */
109 spin_lock_bh(&mvm_sta->lock);
110+
111 /*
112 * There are frames pending on the AC queues for this station.
113 * We need to wait until all the frames are drained...
114 */
115- if (atomic_read(&mvm->pending_frames[mvm_sta->sta_id])) {
116- rcu_assign_pointer(mvm->fw_id_to_mac_id[mvm_sta->sta_id],
117+ if (atomic_read(&mvm->pending_frames[sta_id])) {
118+ rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id],
119 ERR_PTR(-EBUSY));
120 spin_unlock_bh(&mvm_sta->lock);
121
122 /* disable TDLS sta queues on drain complete */
123 if (sta->tdls) {
124- mvm->tfd_drained[mvm_sta->sta_id] =
125- mvm_sta->tfd_queue_msk;
126- IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n",
127- mvm_sta->sta_id);
128+ mvm->tfd_drained[sta_id] = mvm_sta->tfd_queue_msk;
129+ IWL_DEBUG_TDLS(mvm, "Draining TDLS sta %d\n", sta_id);
130 }
131
132 ret = iwl_mvm_drain_sta(mvm, mvm_sta, true);
133--- a/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
134+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tx.c
135@@ -1008,7 +1008,10 @@ static int iwl_mvm_tx_mpdu(struct iwl_mv
136 spin_unlock(&mvmsta->lock);
137
138 /* Increase pending frames count if this isn't AMPDU */
139- if (!is_ampdu)
140+ if ((iwl_mvm_is_dqa_supported(mvm) &&
141+ mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_ON &&
142+ mvmsta->tid_data[tx_cmd->tid_tspec].state != IWL_AGG_STARTING) ||
143+ (!iwl_mvm_is_dqa_supported(mvm) && !is_ampdu))
144 atomic_inc(&mvm->pending_frames[mvmsta->sta_id]);
145
146 return 0;