From: Joshua Klinesmith <joshuaklinesmith@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: nbd@nbd.name, lorenzo@kernel.org, ryder.lee@mediatek.com,
shayne.chen@mediatek.com, sean.wang@mediatek.com,
Joshua Klinesmith <joshuaklinesmith@gmail.com>
Subject: [PATCH wireless] wifi: mt76: mt7915: expose all physical chains via available_antennas
Date: Mon, 6 Apr 2026 21:43:55 -0400 [thread overview]
Message-ID: <20260407014355.45896-1-joshuaklinesmith@gmail.com> (raw)
On MT7916/MT7981 3T3R variants with 2 spatial streams on the 5 GHz
band, wiphy->available_antennas_{tx,rx} is set from antenna_mask which
is derived from NSS, reporting only 2 available antennas. This
contradicts get_antenna() which already returns the full 3-chain
chainmask, causing a mismatch visible in "iw list":
Available Antennas: TX 0x3 RX 0x3
Configured Antennas: TX 0x1c RX 0x1c
Station signal reporting also only includes 2 per-chain RSSI values
instead of all 3.
Set available_antennas from chainmask instead of antenna_mask, matching
the approach used by the mt7996 driver. Save the original antenna_mask
at EEPROM parse time so set_antenna can cap it to preserve correct
HT/VHT/HE stream capability announcements. The existing 3T3R special
case in set_antenna becomes unnecessary with all chains exposed.
Update RX status chain reporting and ACK signal aggregation to use
the physical chain count so all receive chains contribute. Vendor
driver analysis confirms the hardware populates all RCPI fields in
the P-RXV unconditionally.
Fixes: a7ec8bcf0003 ("wifi: mt76: mt7915: rework eeprom tx paths and streams init")
Link: https://github.com/openwrt/openwrt/issues/19323
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
.../net/wireless/mediatek/mt76/mt7915/eeprom.c | 1 +
drivers/net/wireless/mediatek/mt76/mt7915/init.c | 4 ++--
drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 5 +++--
drivers/net/wireless/mediatek/mt76/mt7915/main.c | 15 ++++-----------
.../net/wireless/mediatek/mt76/mt7915/mt7915.h | 2 ++
5 files changed, 12 insertions(+), 15 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
index eb92cbf1a284..db6788a7ebc3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/eeprom.c
@@ -260,6 +260,7 @@ void mt7915_eeprom_parse_hw_cap(struct mt7915_dev *dev,
if (band)
mphy->chainmask <<= dev->chainshift;
mphy->antenna_mask = BIT(nss) - 1;
+ phy->orig_antenna_mask = mphy->antenna_mask;
dev->chainmask |= mphy->chainmask;
dev->chainshift = hweight8(dev->mphy.chainmask);
}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/init.c b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
index 22443cbc74ad..ffcd3871e289 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/init.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/init.c
@@ -470,8 +470,8 @@ mt7915_init_wiphy(struct mt7915_phy *phy)
mt7915_set_stream_he_caps(phy);
mt7915_init_txpower(phy);
- wiphy->available_antennas_rx = phy->mt76->antenna_mask;
- wiphy->available_antennas_tx = phy->mt76->antenna_mask;
+ wiphy->available_antennas_rx = phy->mt76->chainmask;
+ wiphy->available_antennas_tx = phy->mt76->chainmask;
/* init led callbacks */
if (IS_ENABLED(CONFIG_MT76_LEDS)) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cefe56c05731..34a0690c5864 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -224,7 +224,8 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
rssi[3] = to_rssi(GENMASK(31, 14), val);
msta->ack_signal =
- mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
+ mt76_rx_signal(BIT(hweight16(msta->vif->phy->mt76->chainmask)) - 1,
+ rssi);
ewma_avg_signal_add(&msta->avg_ack_signal, -msta->ack_signal);
}
@@ -450,7 +451,7 @@ mt7915_mac_fill_rx(struct mt7915_dev *dev, struct sk_buff *skb,
if (v0 & MT_PRXV_HT_AD_CODE)
status->enc_flags |= RX_ENC_FLAG_LDPC;
- status->chains = mphy->antenna_mask;
+ status->chains = BIT(hweight16(mphy->chainmask)) - 1;
status->chain_signal[0] = to_rssi(MT_PRXV_RCPI0, v1);
status->chain_signal[1] = to_rssi(MT_PRXV_RCPI1, v1);
status->chain_signal[2] = to_rssi(MT_PRXV_RCPI2, v1);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 90d5e79fbf74..a47b9cca3b46 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -1121,23 +1121,16 @@ mt7915_set_antenna(struct ieee80211_hw *hw, int radio_idx, u32 tx_ant, u32 rx_an
{
struct mt7915_dev *dev = mt7915_hw_dev(hw);
struct mt7915_phy *phy = mt7915_hw_phy(hw);
- int max_nss = hweight8(hw->wiphy->available_antennas_tx);
- u8 chainshift = dev->chainshift;
u8 band = phy->mt76->band_idx;
+ u8 shift = dev->chainshift * band;
- if (!tx_ant || tx_ant != rx_ant || ffs(tx_ant) > max_nss)
+ if (!tx_ant || tx_ant != rx_ant)
return -EINVAL;
mutex_lock(&dev->mt76.mutex);
- phy->mt76->antenna_mask = tx_ant;
-
- /* handle a variant of mt7916/mt7981 which has 3T3R but nss2 on 5 GHz band */
- if ((is_mt7916(&dev->mt76) || is_mt7981(&dev->mt76)) &&
- band && hweight8(tx_ant) == max_nss)
- phy->mt76->chainmask = (dev->chainmask >> chainshift) << chainshift;
- else
- phy->mt76->chainmask = tx_ant << (chainshift * band);
+ phy->mt76->chainmask = tx_ant;
+ phy->mt76->antenna_mask = (tx_ant >> shift) & phy->orig_antenna_mask;
mt76_set_stream_caps(phy->mt76, true);
mt7915_set_stream_vht_txbf_caps(phy);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index b5c06201b707..69fdedaa61fb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -208,6 +208,8 @@ struct mt7915_phy {
u8 throttle_state;
u32 throttle_temp[2]; /* 0: critical high, 1: maximum */
+ u8 orig_antenna_mask;
+
u32 rxfilter;
u64 omac_mask;
--
2.43.0
reply other threads:[~2026-04-07 1:44 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260407014355.45896-1-joshuaklinesmith@gmail.com \
--to=joshuaklinesmith@gmail.com \
--cc=linux-wireless@vger.kernel.org \
--cc=lorenzo@kernel.org \
--cc=nbd@nbd.name \
--cc=ryder.lee@mediatek.com \
--cc=sean.wang@mediatek.com \
--cc=shayne.chen@mediatek.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox