226 lines
7.1 KiB
Diff
226 lines
7.1 KiB
Diff
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;
|
|
}
|
|
|