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
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
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
19 Remove sending peer assoc command during sta bandwidth change
20 and instead add sending WMI set peer param command for phymode
23 Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
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
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(-)
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 {
38 u64 ps_total_duration;
39 bool peer_current_ps_valid;
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;
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
64 + bw_prev = arsta->bw_prev;
68 @@ -4252,26 +4254,57 @@ static void ath11k_sta_rc_update_wk(stru
69 ath11k_mac_max_he_nss(he_mcs_mask)));
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
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;
81 + ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n",
82 + sta->addr, bw, peer_phymode);
85 + /* BW is upgraded. In this case we send WMI_PEER_PHYMODE
86 + * followed by WMI_PEER_CHWIDTH
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);
91 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
92 + WMI_PEER_PHYMODE, peer_phymode);
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;
100 - peer_arg.is_assoc = false;
101 - err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
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);
110 ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
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
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);
121 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
122 + WMI_PEER_CHWIDTH, bw);
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;
130 + err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
131 + WMI_PEER_PHYMODE, peer_phymode);
134 + ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
135 + sta->addr, peer_phymode, err);
139 @@ -4352,6 +4385,7 @@ static void ath11k_sta_rc_update_wk(stru
144 mutex_unlock(&ar->conf_mutex);
147 @@ -4505,6 +4539,34 @@ exit:
151 +static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
152 + struct ieee80211_sta *sta)
154 + u32 bw = WMI_PEER_CHWIDTH_20MHZ;
156 + switch (sta->deflink.bandwidth) {
157 + case IEEE80211_STA_RX_BW_20:
158 + bw = WMI_PEER_CHWIDTH_20MHZ;
160 + case IEEE80211_STA_RX_BW_40:
161 + bw = WMI_PEER_CHWIDTH_40MHZ;
163 + case IEEE80211_STA_RX_BW_80:
164 + bw = WMI_PEER_CHWIDTH_80MHZ;
166 + case IEEE80211_STA_RX_BW_160:
167 + bw = WMI_PEER_CHWIDTH_160MHZ;
170 + ath11k_warn(ar->ab, "Invalid bandwidth %d for %pM\n",
171 + sta->deflink.bandwidth, sta->addr);
172 + bw = WMI_PEER_CHWIDTH_20MHZ;
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
184 ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
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);
198 if (changed & IEEE80211_RC_BW_CHANGED) {
199 - bw = WMI_PEER_CHWIDTH_20MHZ;
201 - switch (sta->deflink.bandwidth) {
202 - case IEEE80211_STA_RX_BW_20:
203 - bw = WMI_PEER_CHWIDTH_20MHZ;
205 - case IEEE80211_STA_RX_BW_40:
206 - bw = WMI_PEER_CHWIDTH_40MHZ;
208 - case IEEE80211_STA_RX_BW_80:
209 - bw = WMI_PEER_CHWIDTH_80MHZ;
211 - case IEEE80211_STA_RX_BW_160:
212 - bw = WMI_PEER_CHWIDTH_160MHZ;
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;
221 + bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
222 + arsta->bw_prev = arsta->bw;