aboutsummaryrefslogtreecommitdiffstats
path: root/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch')
-rw-r--r--package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch225
1 files changed, 225 insertions, 0 deletions
diff --git a/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch b/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch
new file mode 100644
index 0000000000..f4fedb46cc
--- /dev/null
+++ b/package/kernel/mac80211/patches/ath11k/0006-wifi-ath11k-fix-firmware-assert-during-bandwidth-cha.patch
@@ -0,0 +1,225 @@
+From 3ff51d7416ee1ea2d771051a0ffa1ec8be054768 Mon Sep 17 00:00:00 2001
+From: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Date: Wed, 5 Oct 2022 15:24:30 +0530
+Subject: [PATCH 6/9] wifi: ath11k: fix firmware assert during bandwidth change
+ for peer sta
+
+Currently, ath11k sends peer assoc command for each peer to
+firmware when bandwidth changes. Peer assoc command is a
+bulky command and if many clients are connected, this could
+lead to firmware buffer getting overflowed leading to a firmware
+assert.
+
+However, during bandwidth change, only phymode and bandwidth
+also can be updated by WMI set peer param command. This makes
+the overall command light when compared to peer assoc and for
+multi-client cases, firmware buffer overflow also does not
+occur.
+
+Remove sending peer assoc command during sta bandwidth change
+and instead add sending WMI set peer param command for phymode
+and bandwidth.
+
+Tested-on: QCN9074 hw1.0 PCI WLAN.HK.2.5.0.1-01100-QCAHKSWPL_SILICONZ-1
+
+Fixes: f187fe8e3bc65 ("ath11k: fix firmware crash during channel switch")
+Signed-off-by: Aditya Kumar Singh <quic_adisi@quicinc.com>
+Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
+Link: https://lore.kernel.org/r/20221005095430.19890-1-quic_adisi@quicinc.com
+---
+ drivers/net/wireless/ath/ath11k/core.h | 2 +
+ drivers/net/wireless/ath/ath11k/mac.c | 122 +++++++++++++++++--------
+ 2 files changed, 87 insertions(+), 37 deletions(-)
+
+--- a/drivers/net/wireless/ath/ath11k/core.h
++++ b/drivers/net/wireless/ath/ath11k/core.h
+@@ -505,6 +505,8 @@ struct ath11k_sta {
+ u64 ps_start_jiffies;
+ u64 ps_total_duration;
+ bool peer_current_ps_valid;
++
++ u32 bw_prev;
+ };
+
+ #define ATH11K_MIN_5G_FREQ 4150
+--- a/drivers/net/wireless/ath/ath11k/mac.c
++++ b/drivers/net/wireless/ath/ath11k/mac.c
+@@ -4215,10 +4215,11 @@ static void ath11k_sta_rc_update_wk(stru
+ const u8 *ht_mcs_mask;
+ const u16 *vht_mcs_mask;
+ const u16 *he_mcs_mask;
+- u32 changed, bw, nss, smps;
++ u32 changed, bw, nss, smps, bw_prev;
+ int err, num_vht_rates, num_he_rates;
+ const struct cfg80211_bitrate_mask *mask;
+ struct peer_assoc_params peer_arg;
++ enum wmi_phy_mode peer_phymode;
+
+ arsta = container_of(wk, struct ath11k_sta, update_wk);
+ sta = container_of((void *)arsta, struct ieee80211_sta, drv_priv);
+@@ -4239,6 +4240,7 @@ static void ath11k_sta_rc_update_wk(stru
+ arsta->changed = 0;
+
+ bw = arsta->bw;
++ bw_prev = arsta->bw_prev;
+ nss = arsta->nss;
+ smps = arsta->smps;
+
+@@ -4252,26 +4254,57 @@ static void ath11k_sta_rc_update_wk(stru
+ ath11k_mac_max_he_nss(he_mcs_mask)));
+
+ if (changed & IEEE80211_RC_BW_CHANGED) {
+- /* Send peer assoc command before set peer bandwidth param to
+- * avoid the mismatch between the peer phymode and the peer
+- * bandwidth.
+- */
+- ath11k_peer_assoc_prepare(ar, arvif->vif, sta, &peer_arg, true);
++ /* Get the peer phymode */
++ ath11k_peer_assoc_h_phymode(ar, arvif->vif, sta, &peer_arg);
++ peer_phymode = peer_arg.peer_phymode;
++
++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac update sta %pM peer bw %d phymode %d\n",
++ sta->addr, bw, peer_phymode);
++
++ if (bw > bw_prev) {
++ /* BW is upgraded. In this case we send WMI_PEER_PHYMODE
++ * followed by WMI_PEER_CHWIDTH
++ */
++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW upgrade for sta %pM new BW %d, old BW %d\n",
++ sta->addr, bw, bw_prev);
++
++ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
++ WMI_PEER_PHYMODE, peer_phymode);
++
++ if (err) {
++ ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
++ sta->addr, peer_phymode, err);
++ goto err_rc_bw_changed;
++ }
+
+- peer_arg.is_assoc = false;
+- err = ath11k_wmi_send_peer_assoc_cmd(ar, &peer_arg);
+- if (err) {
+- ath11k_warn(ar->ab, "failed to send peer assoc for STA %pM vdev %i: %d\n",
+- sta->addr, arvif->vdev_id, err);
+- } else if (wait_for_completion_timeout(&ar->peer_assoc_done, 1 * HZ)) {
+ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
+ WMI_PEER_CHWIDTH, bw);
++
+ if (err)
+ ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
+ sta->addr, bw, err);
+ } else {
+- ath11k_warn(ar->ab, "failed to get peer assoc conf event for %pM vdev %i\n",
+- sta->addr, arvif->vdev_id);
++ /* BW is downgraded. In this case we send WMI_PEER_CHWIDTH
++ * followed by WMI_PEER_PHYMODE
++ */
++ ath11k_dbg(ar->ab, ATH11K_DBG_MAC, "mac BW downgrade for sta %pM new BW %d,old BW %d\n",
++ sta->addr, bw, bw_prev);
++
++ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
++ WMI_PEER_CHWIDTH, bw);
++
++ if (err) {
++ ath11k_warn(ar->ab, "failed to update STA %pM peer bw %d: %d\n",
++ sta->addr, bw, err);
++ goto err_rc_bw_changed;
++ }
++
++ err = ath11k_wmi_set_peer_param(ar, sta->addr, arvif->vdev_id,
++ WMI_PEER_PHYMODE, peer_phymode);
++
++ if (err)
++ ath11k_warn(ar->ab, "failed to update STA %pM peer phymode %d: %d\n",
++ sta->addr, peer_phymode, err);
+ }
+ }
+
+@@ -4352,6 +4385,7 @@ static void ath11k_sta_rc_update_wk(stru
+ }
+ }
+
++err_rc_bw_changed:
+ mutex_unlock(&ar->conf_mutex);
+ }
+
+@@ -4505,6 +4539,34 @@ exit:
+ return ret;
+ }
+
++static u32 ath11k_mac_ieee80211_sta_bw_to_wmi(struct ath11k *ar,
++ struct ieee80211_sta *sta)
++{
++ u32 bw = WMI_PEER_CHWIDTH_20MHZ;
++
++ switch (sta->deflink.bandwidth) {
++ case IEEE80211_STA_RX_BW_20:
++ bw = WMI_PEER_CHWIDTH_20MHZ;
++ break;
++ case IEEE80211_STA_RX_BW_40:
++ bw = WMI_PEER_CHWIDTH_40MHZ;
++ break;
++ case IEEE80211_STA_RX_BW_80:
++ bw = WMI_PEER_CHWIDTH_80MHZ;
++ break;
++ case IEEE80211_STA_RX_BW_160:
++ bw = WMI_PEER_CHWIDTH_160MHZ;
++ break;
++ default:
++ ath11k_warn(ar->ab, "Invalid bandwidth %d for %pM\n",
++ sta->deflink.bandwidth, sta->addr);
++ bw = WMI_PEER_CHWIDTH_20MHZ;
++ break;
++ }
++
++ return bw;
++}
++
+ static int ath11k_mac_op_sta_state(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+@@ -4590,6 +4652,12 @@ static int ath11k_mac_op_sta_state(struc
+ if (ret)
+ ath11k_warn(ar->ab, "Failed to associate station: %pM\n",
+ sta->addr);
++
++ spin_lock_bh(&ar->data_lock);
++ /* Set arsta bw and prev bw */
++ arsta->bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
++ arsta->bw_prev = arsta->bw;
++ spin_unlock_bh(&ar->data_lock);
+ } else if (old_state == IEEE80211_STA_ASSOC &&
+ new_state == IEEE80211_STA_AUTHORIZED) {
+ spin_lock_bh(&ar->ab->base_lock);
+@@ -4713,28 +4781,8 @@ static void ath11k_mac_op_sta_rc_update(
+ spin_lock_bh(&ar->data_lock);
+
+ if (changed & IEEE80211_RC_BW_CHANGED) {
+- bw = WMI_PEER_CHWIDTH_20MHZ;
+-
+- switch (sta->deflink.bandwidth) {
+- case IEEE80211_STA_RX_BW_20:
+- bw = WMI_PEER_CHWIDTH_20MHZ;
+- break;
+- case IEEE80211_STA_RX_BW_40:
+- bw = WMI_PEER_CHWIDTH_40MHZ;
+- break;
+- case IEEE80211_STA_RX_BW_80:
+- bw = WMI_PEER_CHWIDTH_80MHZ;
+- break;
+- case IEEE80211_STA_RX_BW_160:
+- bw = WMI_PEER_CHWIDTH_160MHZ;
+- break;
+- default:
+- ath11k_warn(ar->ab, "Invalid bandwidth %d in rc update for %pM\n",
+- sta->deflink.bandwidth, sta->addr);
+- bw = WMI_PEER_CHWIDTH_20MHZ;
+- break;
+- }
+-
++ bw = ath11k_mac_ieee80211_sta_bw_to_wmi(ar, sta);
++ arsta->bw_prev = arsta->bw;
+ arsta->bw = bw;
+ }
+