f4fedb46ccbb56531198f617e171b911ae90e1a4
[openwrt/staging/blogic.git] /
1 From 3ff51d7416ee1ea2d771051a0ffa1ec8be054768 Mon Sep 17 00:00:00 2001
2 From: Aditya Kumar Singh <quic_adisi@quicinc.com>
3 Date: Wed, 5 Oct 2022 15:24:30 +0530
4 Subject: [PATCH 6/9] wifi: ath11k: fix firmware assert during bandwidth change
5 for peer sta
6
7 Currently, ath11k sends peer assoc command for each peer to
8 firmware when bandwidth changes. Peer assoc command is a
9 bulky command and if many clients are connected, this could
10 lead to firmware buffer getting overflowed leading to a firmware
11 assert.
12
13 However, during bandwidth change, only phymode and bandwidth
14 also can be updated by WMI set peer param command. This makes
15 the overall command light when compared to peer assoc and for
16 multi-client cases, firmware buffer overflow also does not
17 occur.
18
19 Remove sending peer assoc command during sta bandwidth change
20 and instead add sending WMI set peer param command for phymode
21 and bandwidth.
22
23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
24
25 Fixes: f187fe8e3bc65 ("ath11k: fix firmware crash during channel switch")
26 Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
27 Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
28 Link: https://lore.kernel.org/r/20221005095430.19890-1-quic_adisi@quicinc.com
29 ---
30 drivers/net/wireless/ath/ath11k/core.h | 2 +
31 drivers/net/wireless/ath/ath11k/mac.c | 122 +++++++++++++++++--------
32 2 files changed, 87 insertions(+), 37 deletions(-)
33
34 --- a/drivers/net/wireless/ath/ath11k/core.h
35 +++ b/drivers/net/wireless/ath/ath11k/core.h
36 @@ -505,6 +505,8 @@ struct ath11k_sta {
37 u64 ps_start_jiffies;
38 u64 ps_total_duration;
39 bool peer_current_ps_valid;
40 +
41 + u32 bw_prev;
42 };
43
44 #define ATH11K_MIN_5G_FREQ 4150
45 --- a/drivers/net/wireless/ath/ath11k/mac.c
46 +++ b/drivers/net/wireless/ath/ath11k/mac.c
47 @@ -4215,10 +4215,11 @@ static void ath11k_sta_rc_update_wk(stru
48 const u8 *ht_mcs_mask;
49 const u16 *vht_mcs_mask;
50 const u16 *he_mcs_mask;
51 - u32 changed, bw, nss, smps;
52 + u32 changed, bw, nss, smps, bw_prev;
53 int err, num_vht_rates, num_he_rates;
54 const struct cfg80211_bitrate_mask *mask;
55 struct peer_assoc_params peer_arg;
56 + enum wmi_phy_mode peer_phymode;
57
58 arsta = container_of(wk, struct ath11k_sta, update_wk);
59 sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
60 @@ -4239,6 +4240,7 @@ static void ath11k_sta_rc_update_wk(stru
61 arsta->changed = 0;
62
63 bw = arsta->bw;
64 + bw_prev = arsta->bw_prev;
65 nss = arsta->nss;
66 smps = arsta->smps;
67
68 @@ -4252,26 +4254,57 @@ static void ath11k_sta_rc_update_wk(stru
69 ath11k_mac_max_he_nss(he_mcs_mask)));
70
71 if (changed & IEEE80211_RC_BW_CHANGED) {
72 - /* Send peer assoc command before set peer bandwidth param to
73 - * avoid the mismatch between the peer phymode and the peer
74 - * bandwidth.
75 - */
76 - ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true);
77 + /* Get the peer phymode */
78 + ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg);
79 + peer_phymode = peer_arg.peer_phymode;
80 +
81 + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n",
82 + sta->addr, bw, peer_phymode);
83 +
84 + if (bw > bw_prev) {
85 + /* BW is upgraded. In this case we send WMI_PEER_PHYMODE
86 + * followed by WMI_PEER_CHWIDTH
87 + */
88 + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n",
89 + sta->addr, bw, bw_prev);
90 +
91 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
92 + WMI_PEER_PHYMODE, peer_phymode);
93 +
94 + if (err) {
95 + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
96 + sta->addr, peer_phymode, err);
97 + goto err_rc_bw_changed;
98 + }
99
100 - peer_arg.is_assoc = false;
101 - err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
102 - if (err) {
103 - ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n",
104 - sta->addr, arvif->vdev_id, err);
105 - } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
106 err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
107 WMI_PEER_CHWIDTH, bw);
108 +
109 if (err)
110 ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
111 sta->addr, bw, err);
112 } else {
113 - ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
114 - sta->addr, arvif->vdev_id);
115 + /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH
116 + * followed by WMI_PEER_PHYMODE
117 + */
118 + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d,old BW %d\n",
119 + sta->addr, bw, bw_prev);
120 +
121 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
122 + WMI_PEER_CHWIDTH, bw);
123 +
124 + if (err) {
125 + ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
126 + sta->addr, bw, err);
127 + goto err_rc_bw_changed;
128 + }
129 +
130 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
131 + WMI_PEER_PHYMODE, peer_phymode);
132 +
133 + if (err)
134 + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
135 + sta->addr, peer_phymode, err);
136 }
137 }
138
139 @@ -4352,6 +4385,7 @@ static void ath11k_sta_rc_update_wk(stru
140 }
141 }
142
143 +err_rc_bw_changed:
144 mutex_unlock(&ar->conf_mutex);
145 }
146
147 @@ -4505,6 +4539,34 @@ exit:
148 return ret;
149 }
150
151 +static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
152 + struct ieee80211_sta *sta)
153 +{
154 + u32 bw = WMI_PEER_CHWIDTH_20MHZ;
155 +
156 + switch (sta->deflink.bandwidth) {
157 + case IEEE80211_STA_RX_BW_20:
158 + bw = WMI_PEER_CHWIDTH_20MHZ;
159 + break;
160 + case IEEE80211_STA_RX_BW_40:
161 + bw = WMI_PEER_CHWIDTH_40MHZ;
162 + break;
163 + case IEEE80211_STA_RX_BW_80:
164 + bw = WMI_PEER_CHWIDTH_80MHZ;
165 + break;
166 + case IEEE80211_STA_RX_BW_160:
167 + bw = WMI_PEER_CHWIDTH_160MHZ;
168 + break;
169 + default:
170 + ath11k_warn(ar->ab, "Invalid bandwidth %d for %pM\n",
171 + sta->deflink.bandwidth, sta->addr);
172 + bw = WMI_PEER_CHWIDTH_20MHZ;
173 + break;
174 + }
175 +
176 + return bw;
177 +}
178 +
179 static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
180 struct ieee80211_vif *vif,
181 struct ieee80211_sta *sta,
182 @@ -4590,6 +4652,12 @@ static int ath11k_mac_op_sta_state(struc
183 if (ret)
184 ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
185 sta->addr);
186 +
187 + spin_lock_bh(&ar->data_lock);
188 + /* Set arsta bw and prev bw */
189 + arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
190 + arsta->bw_prev = arsta->bw;
191 + spin_unlock_bh(&ar->data_lock);
192 } else if (old_state == IEEE80211_STA_ASSOC &&
193 new_state == IEEE80211_STA_AUTHORIZED) {
194 spin_lock_bh(&ar->ab->base_lock);
195 @@ -4713,28 +4781,8 @@ static void ath11k_mac_op_sta_rc_update(
196 spin_lock_bh(&ar->data_lock);
197
198 if (changed & IEEE80211_RC_BW_CHANGED) {
199 - bw = WMI_PEER_CHWIDTH_20MHZ;
200 -
201 - switch (sta->deflink.bandwidth) {
202 - case IEEE80211_STA_RX_BW_20:
203 - bw = WMI_PEER_CHWIDTH_20MHZ;
204 - break;
205 - case IEEE80211_STA_RX_BW_40:
206 - bw = WMI_PEER_CHWIDTH_40MHZ;
207 - break;
208 - case IEEE80211_STA_RX_BW_80:
209 - bw = WMI_PEER_CHWIDTH_80MHZ;
210 - break;
211 - case IEEE80211_STA_RX_BW_160:
212 - bw = WMI_PEER_CHWIDTH_160MHZ;
213 - break;
214 - default:
215 - ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
216 - sta->deflink.bandwidth, sta->addr);
217 - bw = WMI_PEER_CHWIDTH_20MHZ;
218 - break;
219 - }
220 -
221 + bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
222 + arsta->bw_prev = arsta->bw;
223 arsta->bw = bw;
224 }
225