[PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
Lucid Duck
lucid_duck at justthetip.ca
Thu Mar 12 10:38:12 PDT 2026
Hi Bryam, Sean,
I tested this on my MT7921AU USB adapter (Alfa AWUS036AXML, Fedora,
kernel 6.18.16, ISED/Canada). The callback itself is clean and with
one fix it gives correct values on all three bands, stable across a
full gauntlet. Nice work.
chanctx channel source (affects all mt7921 phy->chandef readers)
-----------------------------------------------------------------
This one bit me during testing and is worth flagging because it
affects more than just the callback. mt7921 uses the chanctx model,
and mt7921_add_chanctx() stores the context in dev->new_ctx without
updating phy->chandef. So phy->chandef.chan stays stuck on whatever
channel the firmware scanned at probe time -- channel 229 (6 GHz) on
my system. I confirmed via debugfs: "Tx power table (channel 229)"
while actually connected to 2.4 GHz ch6.
Because the callback reads phy->chandef.chan->max_power, it returns
12 dBm on every band. mt76_get_power_bound() has the same issue
internally since it also reads phy->chandef.chan.
The fix that worked for me: read the channel from the VIF chanctx
(falling back to phy->chandef.chan when unassociated) and inline the
SAR + delta math to avoid get_power_bound:
rcu_read_lock();
ctx = rcu_dereference(vif->bss_conf.chanctx_conf);
chan = ctx ? ctx->def.chan : phy->chandef.chan;
rcu_read_unlock();
if (!chan)
return mt76_get_txpower(hw, vif, link_id, dbm);
n_chains = hweight16(phy->chainmask);
delta = mt76_tx_power_path_delta(n_chains);
tx_power = mt76_get_sar_power(phy, chan, chan->max_power * 2);
tx_power -= delta;
tx_power = mt76_get_rate_power_limits(phy, chan, &limits, tx_power);
*dbm = DIV_ROUND_UP(tx_power + delta, 2);
A note on Sean's rate power loop direction
-------------------------------------------
Sean's feedback on both our patches points toward deriving the
reported value from mt76_connac_mcu_rate_txpower_band() -- the loop
that computes per-rate power limits before sending SKU tables to
firmware. That would sidestep the chanctx issue entirely since
txpower_cur gets written at configuration time rather than computed
at query time.
Looking at the code, mt7915 already does this (mt7915/mcu.c:3396):
tx_power = mt76_get_rate_power_limits(...);
mphy->txpower_cur = tx_power;
The connac equivalent calls mt76_get_rate_power_limits() in the same
loop but discards the return value. If that were fixed to match
mt7915, the existing mt76_get_txpower() would report correctly
without a per-driver callback.
That approach would also cover user txpower limits for free --
`iw dev set txpower fixed 1500` currently succeeds but the callback
reports the regulatory ceiling because it starts from chan->max_power.
The rate power loop already reads 2 * phy->hw->conf.power_level
(mt76_connac_mcu.c:2162), so user limits would be reflected
automatically.
Either way, happy to help test whatever direction v3 takes.
Test results (chanctx fix applied)
------------------------------------
Alfa AWUS036AXML (MT7921AU, USB, 2x2 MIMO)
Kernel 6.18.16-200.fc43.x86_64, ISED/Canada
Per-band (10 runs each):
2.4 GHz ch6: 30.00 dBm (ISED: 30) 10/10 PASS
5 GHz ch100: 26.00 dBm (ISED: 26) 10/10 PASS
6 GHz ch5: 12.00 dBm (ISED: 12) 10/10 PASS
Band switching: 18/18 correct
Rapid cycling (20/band): 60/60 PASS
Regdomain (CA/US/CA): 9/9 PASS (5 GHz: 26->24->26)
60-min soak (5 GHz): 61/61 PASS, zero drift
USB torture (module reload, monitor cycling, assoc interrupt):
20/20 PASS
Kernel errors: zero across all phases
Tested-by: Lucid Duck <lucid_duck at justthetip.ca>
More information about the Linux-mediatek
mailing list