[PATCH 2/2] wifi: mt76: mt7996: clamp EHT beamforming NSS
From: Jiale Yao
Date: Mon Oct 19 2026 - 05:38:13 EST
From: Jiale Yao <jiale.yao@xxxxxxxxxxx>
An EHT peer can advertise zero receive spatial streams for an MCS
range. The beamforming setup decrements that value, causing an
underflow and sending an invalid column count to firmware.
Clamp the converted NSS value to zero for 80, 160, and 320 MHz
beamforming configurations.
Fixes: ba01944adee9 ("wifi: mt76: mt7996: add EHT beamforming support")
Signed-off-by: Jiale Yao <jiale.yao@xxxxxxxxxxx>
---
drivers/net/wireless/mediatek/mt76/mt7996/mcu.c | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index e6243dd33c31..29b67248fad7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1969,7 +1969,7 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
struct ieee80211_eht_cap_elem_fixed *pe = &pc->eht_cap_elem;
struct ieee80211_eht_mcs_nss_supp *eht_nss = &pc->eht_mcs_nss_supp;
u8 nss_mcs = u8_get_bits(eht_nss->bw._80.rx_tx_mcs9_max_nss,
- IEEE80211_EHT_MCS_NSS_RX) - 1;
+ IEEE80211_EHT_MCS_NSS_RX);
const struct ieee80211_eht_cap_elem_fixed *ve;
const struct ieee80211_sta_eht_cap *vc;
u8 snd_dim, sts;
@@ -1988,6 +1988,7 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_80MHZ_MASK, ve->phy_cap_info[2]);
sts = EHT_PHY(CAP0_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[0]) +
(EHT_PHY(CAP1_BEAMFORMEE_SS_80MHZ_MASK, pe->phy_cap_info[1]) << 1);
+ nss_mcs = nss_mcs ? nss_mcs - 1 : 0;
bf->nrow = min_t(u8, snd_dim, sts);
bf->ncol = min_t(u8, nss_mcs, bf->nrow);
bf->ibf_ncol = explicit ? min_t(u8, MT7996_IBF_MAX_NC, bf->ncol) :
@@ -2001,7 +2002,8 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
snd_dim = EHT_PHY(CAP2_SOUNDING_DIM_160MHZ_MASK, ve->phy_cap_info[2]);
sts = EHT_PHY(CAP1_BEAMFORMEE_SS_160MHZ_MASK, pe->phy_cap_info[1]);
nss_mcs = u8_get_bits(eht_nss->bw._160.rx_tx_mcs9_max_nss,
- IEEE80211_EHT_MCS_NSS_RX) - 1;
+ IEEE80211_EHT_MCS_NSS_RX);
+ nss_mcs = nss_mcs ? nss_mcs - 1 : 0;
bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts);
bf->ncol_gt_bw80 = nss_mcs;
@@ -2012,7 +2014,8 @@ mt7996_mcu_sta_bfer_eht(struct ieee80211_link_sta *link_sta,
ve->phy_cap_info[3]) << 1);
sts = EHT_PHY(CAP1_BEAMFORMEE_SS_320MHZ_MASK, pe->phy_cap_info[1]);
nss_mcs = u8_get_bits(eht_nss->bw._320.rx_tx_mcs9_max_nss,
- IEEE80211_EHT_MCS_NSS_RX) - 1;
+ IEEE80211_EHT_MCS_NSS_RX);
+ nss_mcs = nss_mcs ? nss_mcs - 1 : 0;
bf->nrow_gt_bw80 = min_t(u8, snd_dim, sts) << 4;
bf->ncol_gt_bw80 = nss_mcs << 4;
--
2.34.1