The mt7921 driver never updates phy->txpower_cur when TX power rate configuration is sent to firmware. This causes mt76_get_txpower() to report bogus values to userspace (typically 3 dBm) regardless of actual regulatory or SAR limits. User-set txpower limits via iw are also not reflected. Three root causes are addressed: 1. The rate power loop in mt76_connac_mcu_rate_txpower_band() computes the correct bounded TX power for each channel but discards the return value of mt76_get_rate_power_limits(). Fix: capture the return value and store it to phy->txpower_cur when processing the current channel. 2. mt7921 uses the chanctx model but its add_chanctx callback bypasses the common mt76_phy_update_channel(), leaving phy->chandef stale. Fix: update phy->chandef from ctx->def in both add_chanctx and change_chanctx, and trigger the rate power path to refresh txpower_cur. Also trigger on IEEE80211_CONF_CHANGE_CHANNEL in config(), matching mt7915. 3. For chanctx drivers, mac80211 routes user txpower changes through BSS_CHANGED_TXPOWER in bss_info_changed() -- not through IEEE80211_CONF_CHANGE_POWER in config(). hw->conf.power_level is never updated. Fix: handle BSS_CHANGED_TXPOWER in mt7921_bss_info_changed(), bridge bss_conf.txpower to hw->conf.power_level, and re-trigger the rate power path. Tested on Alfa AWUS036AXML (MT7921AU), kernel 6.17.1-300.fc43: Before: iw dev wlan0 info shows "txpower 3.00 dBm" (wrong) After: correct per-band values, user limits reflected Test results (regulatory domain: Canada/CA): - 2.4GHz ch6: 33 dBm (30 dBm limit + 3 dBm 2x2 path delta) - 5GHz ch36: 26 dBm (23 dBm limit + 3 dBm path delta) - 6GHz ch5: 15 dBm (12 dBm limit + 3 dBm path delta) - Band switch: 100 cycles, 0 failures - Module reload: 50 cycles, 0 failures - 2-hour soak: 480 samples, zero drift - Regdomain switching: 10 countries, all correct - User txpower limits: reflected on all bands - Monitor mode: correct on all tested channels Signed-off-by: Lucid Duck --- .../wireless/mediatek/mt76/mt76_connac_mcu.c | 12 +++++++--- .../net/wireless/mediatek/mt76/mt7921/main.c | 22 ++++++++++++++++++- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c index 16db0f208..5856924a9 100644 --- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c +++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.c @@ -2193,14 +2193,20 @@ mt76_connac_mcu_rate_txpower_band(struct mt76_phy *phy, .hw_value = ch_list[idx], .band = band, }; - s8 reg_power, sar_power; + s8 reg_power, sar_power, max_power; reg_power = mt76_connac_get_ch_power(phy, &chan, tx_power); sar_power = mt76_get_sar_power(phy, &chan, reg_power); - mt76_get_rate_power_limits(phy, &chan, limits, - sar_power); + max_power = mt76_get_rate_power_limits(phy, &chan, + limits, + sar_power); + + if (phy->chandef.chan && + phy->chandef.chan->hw_value == ch_list[idx] && + phy->chandef.chan->band == band) + phy->txpower_cur = max_power; tx_power_tlv.last_msg = ch_list[idx] == last_ch; sku_tlbv.channel = ch_list[idx]; diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c b/drivers/net/wireless/mediatek/mt76/mt7921/main.c index 5881040ac..38a59c6f2 100644 --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c @@ -638,7 +638,8 @@ static int mt7921_config(struct ieee80211_hw *hw, int radio_idx, u32 changed) mt792x_mutex_acquire(dev); - if (changed & IEEE80211_CONF_CHANGE_POWER) { + if (changed & (IEEE80211_CONF_CHANGE_POWER | + IEEE80211_CONF_CHANGE_CHANNEL)) { ret = mt7921_set_tx_sar_pwr(hw, NULL); if (ret) goto out; @@ -719,6 +720,14 @@ static void mt7921_bss_info_changed(struct ieee80211_hw *hw, if (changed & BSS_CHANGED_CQM) mt7921_mcu_set_rssimonitor(dev, vif); + if (changed & BSS_CHANGED_TXPOWER) { + int tx_power = info->txpower; + + if (tx_power != INT_MIN && tx_power > 0) + hw->conf.power_level = tx_power; + mt7921_set_tx_sar_pwr(hw, NULL); + } + if (changed & BSS_CHANGED_ASSOC) { mt7921_mcu_sta_update(dev, NULL, vif, true, MT76_STA_INFO_STATE_ASSOC); @@ -1360,8 +1369,15 @@ mt7921_add_chanctx(struct ieee80211_hw *hw, struct ieee80211_chanctx_conf *ctx) { struct mt792x_dev *dev = mt792x_hw_dev(hw); + struct mt76_phy *mphy = hw->priv; dev->new_ctx = ctx; + mphy->chandef = ctx->def; + + mt792x_mutex_acquire(dev); + mt7921_set_tx_sar_pwr(hw, NULL); + mt792x_mutex_release(dev); + return 0; } @@ -1396,6 +1412,10 @@ mt7921_change_chanctx(struct ieee80211_hw *hw, mt7921_mcu_config_sniffer(mvif, ctx); else mt76_connac_mcu_uni_set_chctx(mvif->phy->mt76, &mvif->bss_conf.mt76, ctx); + + phy->mt76->chandef = ctx->def; + mt7921_set_tx_sar_pwr(hw, NULL); + mt792x_mutex_release(phy->dev); } -- 2.51.0