mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-25 16:31:13 +00:00
93ae4353cd
ath11k is the upstream driver for Qualcomm 802.11ax radios, both for the internal AHB and PCI based cards. This commit does however only provide PCI support while AHB will follow but its SoC specific so it will require an OpenWrt target first. It differs a bit from ath10k as it requires stuff like QRTR, MHI and QMI helpers. PCI variant requires qrtr-mhi and mhi-bus which backports do provide, however we are dropping those in a patch as they will conflict with support for the AHB variant as that one requires qrtr-smd which in turn requires RPMSG and GLINK and its not feasable to provide those in backports as they are really SoC specific. QRTR and MHI in kernel 5.10 are not usable and backporting the changes is not easy as they have changed drastically from 5.10 to 5.15 ath11k will only be available on targets that use kernel 5.15. Signed-off-by: Robert Marko <robimarko@gmail.com>
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;
|
|
}
|
|
|