diff options
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.patch | 225 |
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; + } + |