Currently, ath12k_bss_assoc() sets HE MU mode with WMI_VDEV_PARAM_SET_HEMU_MODE before ath12k_wmi_send_peer_assoc_cmd(), but has no equivalent step for EHT. This means firmware can process peer assoc without EHT beamformee/OFDMA mode state matching the current peer and bandwidth, which can leave incorrect beamforming/OFDMA state for 11be links. Fix this by adding ath12k_mac_vif_recalc_sta_eht_txbf() to compute the EHT MU mode bitmask from local and peer EHT capabilities and link bandwidth, and sending WMI_VDEV_PARAM_SET_EHT_MU_MODE before peer assoc, mirroring the existing HE flow. Also send WMI_VDEV_PARAM_SET_EHT_MU_MODE with zero for non-EHT associations to clear stale EHT mode left from a previous association on the same vdev. Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c7-00108-QCAHMTSWPL_V1.0_V2.0_SILICONZ_UPSTREAM-3 Signed-off-by: Hangtian Zhu --- drivers/net/wireless/ath/ath12k/mac.c | 91 +++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/drivers/net/wireless/ath/ath12k/mac.c b/drivers/net/wireless/ath/ath12k/mac.c index d4116ba0da08..bc463f759d6e 100644 --- a/drivers/net/wireless/ath/ath12k/mac.c +++ b/drivers/net/wireless/ath/ath12k/mac.c @@ -3780,6 +3780,79 @@ static int ath12k_mac_vif_recalc_sta_he_txbf(struct ath12k *ar, return 0; } +static int ath12k_mac_vif_recalc_sta_eht_txbf(struct ath12k *ar, + struct ath12k_link_vif *arvif, + struct ieee80211_link_sta *link_sta, + u32 *ehtmode) +{ + const struct ieee80211_sta_eht_cap *peer_eht_cap; + const struct ieee80211_sta_eht_cap *own_eht_cap; + const struct ieee80211_sband_iftype_data *iftd; + struct ieee80211_vif *vif = arvif->ahvif->vif; + struct ieee80211_bss_conf *link_conf; + struct cfg80211_chan_def def; + enum nl80211_band band; + u8 mu_bformer; + + *ehtmode = 0; + + if (vif->type != NL80211_IFTYPE_STATION) + return -EINVAL; + + link_conf = ath12k_mac_get_link_bss_conf(arvif); + if (!link_conf) { + ath12k_warn(ar->ab, "unable to access bss link conf in recalc eht txbf conf\n"); + return -EINVAL; + } + + if (!link_conf->eht_support || !link_sta->eht_cap.has_eht) + return 0; + + if (WARN_ON(ath12k_mac_vif_link_chan(vif, arvif->link_id, &def))) + return -EINVAL; + + band = def.chan->band; + iftd = ieee80211_get_sband_iftype_data(&ar->mac.sbands[band], vif->type); + if (!iftd) { + ath12k_dbg(ar->ab, ATH12K_DBG_MAC, + "unable to access iftype data in recalc eht txbf conf\n"); + return 0; + } + + own_eht_cap = &iftd->eht_cap; + peer_eht_cap = &link_sta->eht_cap; + + if (!own_eht_cap->has_eht) + return 0; + + *ehtmode |= u32_encode_bits(EHT_DL_MUOFDMA_ENABLE, EHT_MODE_DL_OFDMA) | + u32_encode_bits(EHT_UL_MUOFDMA_ENABLE, EHT_MODE_UL_OFDMA); + + if ((own_eht_cap->eht_cap_elem.phy_cap_info[0] & + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMEE) && + (peer_eht_cap->eht_cap_elem.phy_cap_info[0] & + IEEE80211_EHT_PHY_CAP0_SU_BEAMFORMER)) + *ehtmode |= u32_encode_bits(EHT_SU_BFEE_ENABLE, EHT_MODE_SU_TX_BFEE); + + switch (link_sta->bandwidth) { + case IEEE80211_STA_RX_BW_320: + mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_320MHZ; + break; + case IEEE80211_STA_RX_BW_160: + mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_160MHZ; + break; + default: + mu_bformer = IEEE80211_EHT_PHY_CAP7_MU_BEAMFORMER_80MHZ; + break; + } + + if (u32_get_bits(*ehtmode, EHT_MODE_SU_TX_BFEE) && + (peer_eht_cap->eht_cap_elem.phy_cap_info[7] & mu_bformer)) + *ehtmode |= u32_encode_bits(EHT_MU_BFEE_ENABLE, EHT_MODE_MU_TX_BFEE); + + return 0; +} + static int ath12k_mac_set_eht_txbf_conf(struct ath12k_link_vif *arvif) { struct ath12k_vif *ahvif = arvif->ahvif; @@ -3923,6 +3996,7 @@ static void ath12k_bss_assoc(struct ath12k *ar, struct ath12k_sta *ahsta; struct ath12k_dp_link_peer *peer; bool is_auth = false; + u32 ehtmode = 0; u32 hemode = 0; int ret; struct ath12k_dp *dp = ath12k_ab_to_dp(ar->ab); @@ -3977,6 +4051,14 @@ static void ath12k_bss_assoc(struct ath12k *ar, return; } + ret = ath12k_mac_vif_recalc_sta_eht_txbf(ar, arvif, link_sta, &ehtmode); + if (ret) { + ath12k_warn(ar->ab, "failed to recalc eht txbf for vdev %i on bss %pM: %d\n", + arvif->vdev_id, bss_conf->bssid, ret); + rcu_read_unlock(); + return; + } + rcu_read_unlock(); /* keep this before ath12k_wmi_send_peer_assoc_cmd() */ @@ -3988,6 +4070,15 @@ static void ath12k_bss_assoc(struct ath12k *ar, return; } + ret = ath12k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id, + WMI_VDEV_PARAM_SET_EHT_MU_MODE, + ehtmode); + if (ret) { + ath12k_warn(ar->ab, "failed to submit vdev param eht txbf 0x%x: %d\n", + ehtmode, ret); + return; + } + peer_arg->is_assoc = true; ret = ath12k_mac_peer_assoc(ar, peer_arg); base-commit: c3bace8584ca707e34ba837f65c2e9d566af4c2c -- 2.25.1