Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH wireless] wifi: mt76: mt7915: move sta_poll from tx_free to mac_work
From: Joshua Klinesmith @ 2026-04-07  3:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
	Joshua Klinesmith

mt7915_mac_sta_poll() performs direct MMIO reads of WTBL entries for
airtime accounting, GI reporting, and RSSI. It is called from
mt7915_mac_tx_free_done(), which runs in NAPI context on every
TX-Free-Done event. The high-frequency WTBL access races with firmware
WTBL operations, causing kernel warnings and panics at
mt7915_mac_wtbl_lmac_addr, followed by MCU message timeouts and
firmware communication breakdown.

Move mt7915_mac_sta_poll() into mt7915_mac_work() at the periodic 5th
tick, under the device mutex. This reduces the access frequency from
thousands of times per second to once every ~5 seconds, serializes it
with other driver operations, and eliminates the NAPI-context WTBL
access that triggers the race.

Vendor driver analysis (mt_wifi.ko from MT7981 firmware) confirms the
vendor's TX-free handler (red_tx_free_handle) performs no WTBL reads
or station polling.

Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Link: https://github.com/openwrt/mt76/issues/1067
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 34a0690c5864..2f307c4caff1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -864,8 +864,6 @@ mt7915_mac_tx_free_done(struct mt7915_dev *dev,
 {
 	struct sk_buff *skb, *tmp;
 
-	mt7915_mac_sta_poll(dev);
-
 	if (wake)
 		mt76_set_tx_blocked(&dev->mt76, false);
 
@@ -2012,6 +2010,7 @@ void mt7915_mac_work(struct work_struct *work)
 	if (++mphy->mac_work_count == 5) {
 		mphy->mac_work_count = 0;
 
+		mt7915_mac_sta_poll(phy->dev);
 		mt7915_mac_update_stats(phy);
 		mt7915_mac_severe_check(phy);
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v3] wifi: mt76: mt7915: set AMSDU parameters for WED v3
From: Joshua Klinesmith @ 2026-04-07  2:58 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
	Joshua Klinesmith

On MT7988 (WED version 3), the WED hardware unconditionally enables the
AMSDU aggregation engine. The engine uses wlan.amsdu_max_subframes and
wlan.amsdu_max_len to configure aggregation limits. The mt7996 driver
sets these to 8 and 1536 respectively, but the mt7915 driver never sets
them, leaving both at zero.

With the AMSDU engine active and zero-valued limits, the TX path is
severely throttled, capping throughput at approximately 6 Mbps on MT7916
PCIe cards attached to MT7988 SoCs.

Set amsdu_max_subframes and amsdu_max_len to the same values used by the
mt7996 driver.

Fixes: b230812b9dda ("net: ethernet: mtk_wed: introduce partial AMSDU offload support for MT7988")
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index 2708b1556f40..f5fa81d3b264 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -719,6 +719,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
 	wed->wlan.reset = mt7915_mmio_wed_reset;
 	wed->wlan.reset_complete = mt76_wed_reset_complete;
 
+	wed->wlan.amsdu_max_subframes = 8;
+	wed->wlan.amsdu_max_len = 1536;
+
 	dev->mt76.rx_token_size = wed->wlan.rx_npkt;
 
 	if (mtk_wed_device_attach(wed))
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless] wifi: ath11k: fix monitor mode frame length by using correct descriptor size
From: Joshua Klinesmith @ 2026-04-07  2:48 UTC (permalink / raw)
  To: linux-wireless; +Cc: ath11k, Joshua Klinesmith

The monitor mode RX path in ath11k_dp_rx_mon_mpdu_pop() and
ath11k_dp_rx_full_mon_mpdu_pop() uses sizeof(struct hal_rx_desc) to
compute the packet buffer offset. This is the size of the union of all
chip-specific descriptors (the maximum), not the actual descriptor size
for the running chip. The later ath11k_dp_rx_msdus_set_payload() then
strips only hw_params.hal_desc_sz bytes (the chip-specific size) from
the front of the skb.

On IPQ8074 and QCN9074, sizeof(struct hal_rx_desc) is 392 but
hal_desc_sz is 384, leaving 8 extra bytes of descriptor data at the
end of every monitor mode frame delivered to userspace. On WCN6855 the
sizes happen to match so the bug is not visible.

The same mismatch in ath11k_dp_mon_set_frag_len() causes incorrect
fragment length calculation for multi-buffer MSDUs, under-counting
intermediate fragments by 8 bytes and over-counting the last fragment.

Fix by using ar->ab->hw_params.hal_desc_sz consistently in both
monitor mpdu_pop functions and passing it through to set_frag_len.

Fixes: d5c65159f289 ("ath11k: driver for Qualcomm IEEE 802.11ax devices")
Link: https://github.com/openwrt/openwrt/issues/16183
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/ath/ath11k/dp_rx.c | 27 ++++++++++++++-----------
 1 file changed, 15 insertions(+), 12 deletions(-)

diff --git a/drivers/net/wireless/ath/ath11k/dp_rx.c b/drivers/net/wireless/ath/ath11k/dp_rx.c
index 85defe11750d..c86ffc203f15 100644
--- a/drivers/net/wireless/ath/ath11k/dp_rx.c
+++ b/drivers/net/wireless/ath/ath11k/dp_rx.c
@@ -4511,10 +4511,11 @@ int ath11k_dp_rx_pdev_alloc(struct ath11k_base *ab, int mac_id)
 	return 0;
 }
 
-static void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len)
+static void ath11k_dp_mon_set_frag_len(u32 *total_len, u32 *frag_len,
+				       u32 hal_desc_sz)
 {
-	if (*total_len >= (DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc))) {
-		*frag_len = DP_RX_BUFFER_SIZE - sizeof(struct hal_rx_desc);
+	if (*total_len >= (DP_RX_BUFFER_SIZE - hal_desc_sz)) {
+		*frag_len = DP_RX_BUFFER_SIZE - hal_desc_sz;
 		*total_len -= *frag_len;
 	} else {
 		*frag_len = *total_len;
@@ -4658,19 +4659,19 @@ static u32 ath11k_dp_rx_mon_comp_ppduid(u32 msdu_ppdu_id, u32 *ppdu_id,
 
 static void ath11k_dp_mon_get_buf_len(struct hal_rx_msdu_desc_info *info,
 				      bool *is_frag, u32 *total_len,
-				      u32 *frag_len, u32 *msdu_cnt)
+				      u32 *frag_len, u32 *msdu_cnt,
+				      u32 hal_desc_sz)
 {
 	if (info->msdu_flags & RX_MSDU_DESC_INFO0_MSDU_CONTINUATION) {
 		if (!*is_frag) {
 			*total_len = info->msdu_len;
 			*is_frag = true;
 		}
-		ath11k_dp_mon_set_frag_len(total_len,
-					   frag_len);
+		ath11k_dp_mon_set_frag_len(total_len, frag_len, hal_desc_sz);
 	} else {
 		if (*is_frag) {
-			ath11k_dp_mon_set_frag_len(total_len,
-						   frag_len);
+			ath11k_dp_mon_set_frag_len(total_len, frag_len,
+						   hal_desc_sz);
 		} else {
 			*frag_len = info->msdu_len;
 		}
@@ -4792,7 +4793,7 @@ u32 ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
 
 			rx_desc = (struct hal_rx_desc *)msdu->data;
 
-			rx_pkt_offset = sizeof(struct hal_rx_desc);
+			rx_pkt_offset = ar->ab->hw_params.hal_desc_sz;
 			l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc);
 
 			if (is_first_msdu) {
@@ -4823,7 +4824,8 @@ u32 ath11k_dp_rx_mon_mpdu_pop(struct ath11k *ar, int mac_id,
 			}
 			ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i],
 						  &is_frag, &total_len,
-						  &frag_len, &msdu_cnt);
+						  &frag_len, &msdu_cnt,
+						  rx_pkt_offset);
 			rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len;
 
 			ath11k_dp_pkt_set_pktlen(msdu, rx_buf_size);
@@ -5424,7 +5426,7 @@ ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar,
 
 			rx_desc = (struct hal_rx_desc *)msdu->data;
 
-			rx_pkt_offset = sizeof(struct hal_rx_desc);
+			rx_pkt_offset = ar->ab->hw_params.hal_desc_sz;
 			l2_hdr_offset = ath11k_dp_rx_h_msdu_end_l3pad(ar->ab, rx_desc);
 
 			if (is_first_msdu) {
@@ -5439,7 +5441,8 @@ ath11k_dp_rx_full_mon_mpdu_pop(struct ath11k *ar,
 
 			ath11k_dp_mon_get_buf_len(&msdu_list.msdu_info[i],
 						  &is_frag, &total_len,
-						  &frag_len, &msdu_cnt);
+						  &frag_len, &msdu_cnt,
+						  rx_pkt_offset);
 
 			rx_buf_size = rx_pkt_offset + l2_hdr_offset + frag_len;
 
-- 
2.43.0


^ permalink raw reply related

* Re: [PATCH ath-next v4 0/6] wifi: ath12k: Enable IPQ5424 AHB WiFi device
From: Baochen Qiang @ 2026-04-07  2:23 UTC (permalink / raw)
  To: Krzysztof Kozlowski, Raj Kumar Bhagat, Johannes Berg, Rob Herring,
	Krzysztof Kozlowski, Conor Dooley, Jeff Johnson
  Cc: linux-wireless, devicetree, linux-kernel, ath12k,
	Saravanakumar Duraisamy, Sowmiya Sree Elavalagan
In-Reply-To: <95face24-deaf-47c4-935d-0b48b5141371@kernel.org>



On 4/4/2026 1:23 PM, Krzysztof Kozlowski wrote:
> On 03/04/2026 11:13, Baochen Qiang wrote:
>>>
>>>  .../bindings/net/wireless/qcom,ipq5332-wifi.yaml   |  1 +
>>>  drivers/net/wireless/ath/ath12k/ahb.c              | 36 +++++----
>>>  drivers/net/wireless/ath/ath12k/ahb.h              |  1 +
>>>  drivers/net/wireless/ath/ath12k/ce.h               | 13 ++-
>>>  drivers/net/wireless/ath/ath12k/core.h             |  1 +
>>>  drivers/net/wireless/ath/ath12k/wifi7/ahb.c        |  8 ++
>>>  drivers/net/wireless/ath/ath12k/wifi7/hal.c        |  7 ++
>>>  drivers/net/wireless/ath/ath12k/wifi7/hal.h        |  3 +
>>>  .../net/wireless/ath/ath12k/wifi7/hal_qcn9274.c    | 88 ++++++++++++++++++++
>>>  .../net/wireless/ath/ath12k/wifi7/hal_qcn9274.h    |  1 +
>>>  drivers/net/wireless/ath/ath12k/wifi7/hw.c         | 93 +++++++++++++++++++++-
>>>  11 files changed, 231 insertions(+), 21 deletions(-)
>>> ---
>>> base-commit: 15551ababf6d4e857f2101366a0c3eaa86dd822c
>>> change-id: 20260331-ath12k-ipq5424-cddb63a46a97
>>>
>>
>> only nit in patch 2/6, so for patches 2-6/6:
>>
>> Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
> 
> It does not work like this. Replying to cover letter causes that all
> patches will get it. Provide detailed review and response to each email
> in such case.

Got it, thank you!

> 
> Best regards,
> Krzysztof


^ permalink raw reply

* [PATCH wireless] wifi: mt76: mt7996: replace direct WTBL access with MCU for station statistics
From: Joshua Klinesmith @ 2026-04-07  2:20 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
	Joshua Klinesmith

Direct MMIO access to WTBL entries for airtime and RSSI statistics in
mt7996_mac_sta_poll() races with firmware, causing warnings at
mt7996_mac_wtbl_lmac_addr, MCU message timeouts, and firmware
communication breakdown. The function was called from
mt7996_mac_tx_free() on every TX-Free-Done event, compounding the
issue with heavy CPU overhead.

Replace the direct WTBL polling with firmware MCU queries:
- Airtime: UNI_ALL_STA_TXRX_AIR_TIME via the existing all_sta_info
  MCU command, with a new handler in mt7996_mcu_rx_all_sta_info_event()
- RSSI: UNI_PER_STA_RSSI via new mt7996_mcu_get_per_sta_info() using
  MCU_WM_UNI_CMD(PER_STA_INFO)

Both queries run from mt7996_mac_work() every 5th tick under dev mutex,
matching the pattern already used for TX rate, admission stats, and
MSDU count reporting.

Remove mt7996_mac_sta_poll() and its airtime_ac tracking array entirely.

Vendor driver analysis (mt_wifi.ko from Xiaomi AX3000T MT7981 firmware)
confirms the RCPI-to-RSSI conversion formula (rcpi - 220) / 2 and that
the vendor never performs direct WTBL reads for statistics.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Link: https://github.com/openwrt/openwrt/issues/21177
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 .../wireless/mediatek/mt76/mt76_connac_mcu.h  |   7 ++
 .../net/wireless/mediatek/mt76/mt7996/mac.c   | 117 +-----------------
 .../net/wireless/mediatek/mt76/mt7996/mcu.c   | 116 +++++++++++++++++
 .../net/wireless/mediatek/mt76/mt7996/mcu.h   |  25 ++++
 .../wireless/mediatek/mt76/mt7996/mt7996.h    |   2 +-
 5 files changed, 151 insertions(+), 116 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 8d59cf43f0e2..14d3ee7defa1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1392,6 +1392,13 @@ enum {
 	UNI_OFFLOAD_OFFLOAD_BMC_RPY_DETECT,
 };
 
+#define PER_STA_INFO_MAX_NUM	90
+
+enum UNI_PER_STA_INFO_TAG {
+	UNI_PER_STA_RSSI,
+	UNI_PER_STA_MAX_NUM
+};
+
 enum UNI_ALL_STA_INFO_TAG {
 	UNI_ALL_STA_TXRX_RATE,
 	UNI_ALL_STA_TX_STAT,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index d4f3ee943b47..3d9648fb6773 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -111,119 +111,6 @@ u32 mt7996_mac_wtbl_lmac_addr(struct mt7996_dev *dev, u16 wcid, u8 dw)
 	return MT_WTBL_LMAC_OFFS(wcid, dw);
 }
 
-static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
-{
-	static const u8 ac_to_tid[] = {
-		[IEEE80211_AC_BE] = 0,
-		[IEEE80211_AC_BK] = 1,
-		[IEEE80211_AC_VI] = 4,
-		[IEEE80211_AC_VO] = 6
-	};
-	struct mt7996_sta_link *msta_link;
-	struct mt76_vif_link *mlink;
-	struct ieee80211_sta *sta;
-	struct mt7996_sta *msta;
-	u32 tx_time[IEEE80211_NUM_ACS], rx_time[IEEE80211_NUM_ACS];
-	LIST_HEAD(sta_poll_list);
-	struct mt76_wcid *wcid;
-	int i;
-
-	spin_lock_bh(&dev->mt76.sta_poll_lock);
-	list_splice_init(&dev->mt76.sta_poll_list, &sta_poll_list);
-	spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
-	rcu_read_lock();
-
-	while (true) {
-		bool clear = false;
-		u32 addr, val;
-		u16 idx;
-		s8 rssi[4];
-
-		spin_lock_bh(&dev->mt76.sta_poll_lock);
-		if (list_empty(&sta_poll_list)) {
-			spin_unlock_bh(&dev->mt76.sta_poll_lock);
-			break;
-		}
-		msta_link = list_first_entry(&sta_poll_list,
-					     struct mt7996_sta_link,
-					     wcid.poll_list);
-		msta = msta_link->sta;
-		wcid = &msta_link->wcid;
-		list_del_init(&wcid->poll_list);
-		spin_unlock_bh(&dev->mt76.sta_poll_lock);
-
-		idx = wcid->idx;
-
-		/* refresh peer's airtime reporting */
-		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 20);
-
-		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-			u32 tx_last = msta_link->airtime_ac[i];
-			u32 rx_last = msta_link->airtime_ac[i + 4];
-
-			msta_link->airtime_ac[i] = mt76_rr(dev, addr);
-			msta_link->airtime_ac[i + 4] = mt76_rr(dev, addr + 4);
-
-			tx_time[i] = msta_link->airtime_ac[i] - tx_last;
-			rx_time[i] = msta_link->airtime_ac[i + 4] - rx_last;
-
-			if ((tx_last | rx_last) & BIT(30))
-				clear = true;
-
-			addr += 8;
-		}
-
-		if (clear) {
-			mt7996_mac_wtbl_update(dev, idx,
-					       MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
-			memset(msta_link->airtime_ac, 0,
-			       sizeof(msta_link->airtime_ac));
-		}
-
-		if (!wcid->sta)
-			continue;
-
-		sta = container_of((void *)msta, struct ieee80211_sta,
-				   drv_priv);
-		for (i = 0; i < IEEE80211_NUM_ACS; i++) {
-			u8 q = mt76_connac_lmac_mapping(i);
-			u32 tx_cur = tx_time[q];
-			u32 rx_cur = rx_time[q];
-			u8 tid = ac_to_tid[i];
-
-			if (!tx_cur && !rx_cur)
-				continue;
-
-			ieee80211_sta_register_airtime(sta, tid, tx_cur, rx_cur);
-		}
-
-		/* get signal strength of resp frames (CTS/BA/ACK) */
-		addr = mt7996_mac_wtbl_lmac_addr(dev, idx, 34);
-		val = mt76_rr(dev, addr);
-
-		rssi[0] = to_rssi(GENMASK(7, 0), val);
-		rssi[1] = to_rssi(GENMASK(15, 8), val);
-		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
-
-		mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]);
-		if (mlink) {
-			struct mt76_phy *mphy = mt76_vif_link_phy(mlink);
-
-			if (mphy)
-				msta_link->ack_signal =
-					mt76_rx_signal(mphy->antenna_mask,
-						       rssi);
-		}
-
-		ewma_avg_signal_add(&msta_link->avg_ack_signal,
-				    -msta_link->ack_signal);
-	}
-
-	rcu_read_unlock();
-}
-
 /* The HW does not translate the mac header to 802.3 for mesh point */
 static int mt7996_reverse_frag0_hdr_trans(struct sk_buff *skb, u16 hdr_gap)
 {
@@ -1424,8 +1311,6 @@ mt7996_mac_tx_free(struct mt7996_dev *dev, void *data, int len)
 		}
 	}
 
-	mt7996_mac_sta_poll(dev);
-
 	if (wake)
 		mt76_set_tx_blocked(&dev->mt76, false);
 
@@ -2947,6 +2832,8 @@ void mt7996_mac_work(struct work_struct *work)
 		mt7996_mac_update_stats(phy);
 
 		mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_RATE);
+		mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_AIR_TIME);
+		mt7996_mcu_get_per_sta_info(phy, UNI_PER_STA_RSSI);
 		if (mtk_wed_device_active(&phy->dev->mt76.mmio.wed)) {
 			mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_ADM_STAT);
 			mt7996_mcu_get_all_sta_info(phy, UNI_ALL_STA_TXRX_MSDU_COUNT);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index c0c042de477b..05b43c16f0d3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -616,6 +616,35 @@ mt7996_mcu_rx_all_sta_info_event(struct mt7996_dev *dev, struct sk_buff *skb)
 			wcid->stats.rx_packets +=
 				le32_to_cpu(res->msdu_cnt[i].rx_msdu_cnt);
 			break;
+		case UNI_ALL_STA_TXRX_AIR_TIME: {
+			static const u8 ac_to_tid[] = {
+				[IEEE80211_AC_BE] = 0,
+				[IEEE80211_AC_BK] = 1,
+				[IEEE80211_AC_VI] = 4,
+				[IEEE80211_AC_VO] = 6
+			};
+			struct ieee80211_sta *sta;
+
+			wlan_idx = le16_to_cpu(res->airtime[i].wlan_idx);
+			wcid = mt76_wcid_ptr(dev, wlan_idx);
+			sta = wcid_to_sta(wcid);
+			if (!sta)
+				break;
+
+			for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+				u8 lmac_ac = mt76_connac_lmac_mapping(ac);
+				u32 tx_cur = le32_to_cpu(res->airtime[i].tx[lmac_ac]);
+				u32 rx_cur = le32_to_cpu(res->airtime[i].rx[lmac_ac]);
+
+				if (!tx_cur && !rx_cur)
+					continue;
+
+				ieee80211_sta_register_airtime(sta,
+							      ac_to_tid[ac],
+							      tx_cur, rx_cur);
+			}
+			break;
+		}
 		default:
 			break;
 		}
@@ -4755,6 +4784,93 @@ int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag)
 				 &req, sizeof(req), false);
 }
 
+int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag)
+{
+	struct mt7996_dev *dev = phy->dev;
+	struct mt7996_mcu_per_sta_info_event *res;
+	struct mt76_wcid *wcid;
+	struct sk_buff *skb;
+	int i, ret, sta_num = 0;
+	struct {
+		u8 _rsv1;
+		u8 unsolicit;
+		u8 _rsv2[2];
+
+		__le16 tag;
+		__le16 len;
+		__le16 sta_num;
+		u8 _rsv3[2];
+		__le16 wlan_idx[PER_STA_INFO_MAX_NUM];
+	} __packed req = {
+		.tag = cpu_to_le16(tag),
+		.len = cpu_to_le16(sizeof(req) - 4),
+	};
+
+	/* Build list of active station WCIDs */
+	rcu_read_lock();
+	for (i = 0; i < mt7996_wtbl_size(dev) && sta_num < PER_STA_INFO_MAX_NUM; i++) {
+		wcid = rcu_dereference(dev->mt76.wcid[i]);
+		if (!wcid || !wcid->sta)
+			continue;
+		req.wlan_idx[sta_num] = cpu_to_le16(i);
+		sta_num++;
+	}
+	rcu_read_unlock();
+
+	if (!sta_num)
+		return 0;
+
+	req.sta_num = cpu_to_le16(sta_num);
+
+	ret = mt76_mcu_send_and_get_msg(&dev->mt76, MCU_WM_UNI_CMD(PER_STA_INFO),
+					&req, sizeof(req), true, &skb);
+	if (ret)
+		return ret;
+
+	res = (struct mt7996_mcu_per_sta_info_event *)skb->data;
+
+	rcu_read_lock();
+	for (i = 0; i < sta_num; i++) {
+		struct mt7996_sta_link *msta_link;
+		struct mt76_vif_link *mlink;
+		struct mt76_phy *mphy;
+		u16 wlan_idx;
+		s8 rssi[4];
+
+		switch (tag) {
+		case UNI_PER_STA_RSSI:
+			wlan_idx = le16_to_cpu(res->rssi[i].wlan_idx);
+			wcid = rcu_dereference(dev->mt76.wcid[wlan_idx]);
+			if (!wcid || !wcid->sta)
+				break;
+
+			msta_link = container_of(wcid, struct mt7996_sta_link, wcid);
+
+			rssi[0] = (res->rssi[i].rcpi[0] - 220) / 2;
+			rssi[1] = (res->rssi[i].rcpi[1] - 220) / 2;
+			rssi[2] = (res->rssi[i].rcpi[2] - 220) / 2;
+			rssi[3] = (res->rssi[i].rcpi[3] - 220) / 2;
+
+			mlink = rcu_dereference(msta_link->sta->vif->mt76.link[wcid->link_id]);
+			if (mlink) {
+				mphy = mt76_vif_link_phy(mlink);
+				if (mphy)
+					msta_link->ack_signal =
+						mt76_rx_signal(mphy->antenna_mask, rssi);
+			}
+
+			ewma_avg_signal_add(&msta_link->avg_ack_signal,
+					    -msta_link->ack_signal);
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	dev_kfree_skb(skb);
+
+	return 0;
+}
+
 int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id)
 {
 	struct {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index e0b83ac9f5e2..b5bad9a76c49 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -220,6 +220,31 @@ struct mt7996_mcu_all_sta_info_event {
 			__le32 tx_msdu_cnt;
 			__le32 rx_msdu_cnt;
 		} __packed, msdu_cnt);
+
+		DECLARE_FLEX_ARRAY(struct {
+			__le16 wlan_idx;
+			u8 rsv[2];
+			__le32 tx[IEEE80211_NUM_ACS];
+			__le32 rx[IEEE80211_NUM_ACS];
+		} __packed, airtime);
+	} __packed;
+} __packed;
+
+struct mt7996_mcu_per_sta_info_event {
+	u8 rsv[4];
+	__le16 tag;
+	__le16 len;
+	u8 more;
+	u8 rsv2;
+	__le16 sta_num;
+	u8 rsv3[4];
+
+	union {
+		DECLARE_FLEX_ARRAY(struct {
+			__le16 wlan_idx;
+			u8 rsv[2];
+			u8 rcpi[4];
+		} __packed, rssi);
 	} __packed;
 } __packed;
 
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 7a884311800e..b523e971f78c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -222,7 +222,6 @@ struct mt7996_sta_link {
 	struct mt7996_sta *sta;
 
 	struct list_head rc_list;
-	u32 airtime_ac[8];
 
 	int ack_signal;
 	struct ewma_avg_signal avg_ack_signal;
@@ -741,6 +740,7 @@ int mt7996_mcu_trigger_assert(struct mt7996_dev *dev);
 void mt7996_mcu_rx_event(struct mt7996_dev *dev, struct sk_buff *skb);
 void mt7996_mcu_exit(struct mt7996_dev *dev);
 int mt7996_mcu_get_all_sta_info(struct mt7996_phy *phy, u16 tag);
+int mt7996_mcu_get_per_sta_info(struct mt7996_phy *phy, u16 tag);
 int mt7996_mcu_wed_rro_reset_sessions(struct mt7996_dev *dev, u16 id);
 int mt7996_mcu_set_sniffer_mode(struct mt7996_phy *phy, bool enabled);
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless] wifi: mt76: mt7915: expose all physical chains via available_antennas
From: Joshua Klinesmith @ 2026-04-07  1:43 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang,
	Joshua Klinesmith

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


^ permalink raw reply related

* Re: [PATCH v3 net-next] net: use get_random_u{16,32,64}() where appropriate
From: Julian Calaby @ 2026-04-07  1:33 UTC (permalink / raw)
  To: David Carlier
  Cc: Jakub Kicinski, David S . Miller, Eric Dumazet, Paolo Abeni,
	Andrew Lunn, Simon Horman, Ilya Dryomov, Johannes Berg,
	Matthieu Baerts, Mat Martineau, Geliang Tang, Aaron Conole,
	Ilya Maximets, Marcelo Ricardo Leitner, Xin Long, Jon Maloy,
	netdev, ceph-devel, linux-wireless, mptcp, dev, linux-sctp,
	tipc-discussion, linux-kernel
In-Reply-To: <20260405154816.4774-1-devnexen@gmail.com>

Hi David,

On Mon, Apr 6, 2026 at 1:50 AM David Carlier <devnexen@gmail.com> wrote:
>
> Use the typed random integer helpers instead of
> get_random_bytes() when filling a single integer variable.
> The helpers return the value directly, require no pointer
> or size argument, and better express intent.
>
> Skipped sites writing into __be16 fields (netdevsim) where
> a direct assignment would trigger sparse endianness warnings.

I don't believe that endian swapping significantly affects the
randomness of the data returned, so either:

1. Do something to silence sparse (casts?)
2. Live with the endian swap overhead if they're not in the hot path.

Other than that,

Reviewed-by: Julian Calaby <julian.calaby@gmail.com>

Thanks,

-- 
Julian Calaby

Email: julian.calaby@gmail.com
Profile: http://www.google.com/profiles/julian.calaby/

^ permalink raw reply

* RE: [PATCH] rtlwifi: rtl8821ae: Remove dead code in rtl8821ae_update_hal_rate_table()
From: Ping-Ke Shih @ 2026-04-07  0:45 UTC (permalink / raw)
  To: Chelsy Ratnawat
  Cc: johannes.berg@intel.com, bhelgaas@google.com,
	linux-wireless@vger.kernel.org
In-Reply-To: <20260403165416.131684-1-chelsyratnawat2001@gmail.com>

Chelsy Ratnawat <chelsyratnawat2001@gmail.com> wrote:
> Sent: Saturday, April 4, 2026 12:54 AM
> The variable 'mimo_ps' is initialized to IEEE80211_SMPS_OFF and never
> modified throughout the function. This makes the condition checking for
> IEEE80211_SMPS_STATIC always evaluate to false, rendering the entire
> if-branch unreachable dead code.
> 
> The error was reported by Coverity Scan.
> 
> Signed-off-by: Chelsy Ratnawat <chelsyratnawat2001@gmail.com>
> ---
>  .../wireless/realtek/rtlwifi/rtl8821ae/hw.c   | 19 +++++++------------
>  1 file changed, 7 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
> b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
> index 3a4a33476205..81d36041a79b 100644
> --- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
> +++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/hw.c
> @@ -3257,7 +3257,6 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
>         u32 ratr_value;
>         u8 ratr_index = 0;
>         u8 b_nmode = mac->ht_enable;
> -       u8 mimo_ps = IEEE80211_SMPS_OFF;
>         u16 shortgi_rate;
>         u32 tmp_ratr_value;
>         u8 curtxbw_40mhz = mac->bw_40;
> @@ -3288,19 +3287,15 @@ static void rtl8821ae_update_hal_rate_table(struct ieee80211_hw *hw,
>         case WIRELESS_MODE_N_24G:
>         case WIRELESS_MODE_N_5G:
>                 b_nmode = 1;
> -               if (mimo_ps == IEEE80211_SMPS_STATIC) {
> -                       ratr_value &= 0x0007F005;
> -               } else {
> -                       u32 ratr_mask;
> +               u32 ratr_mask;

Declare local variable at top of scope or function.

Otherwise, looks fine to me. 

> 
> -                       if (get_rf_type(rtlphy) == RF_1T2R ||
> -                           get_rf_type(rtlphy) == RF_1T1R)
> -                               ratr_mask = 0x000ff005;
> -                       else
> -                               ratr_mask = 0x0f0ff005;
> +               if (get_rf_type(rtlphy) == RF_1T2R ||
> +                   get_rf_type(rtlphy) == RF_1T1R)
> +                       ratr_mask = 0x000ff005;
> +               else
> +                       ratr_mask = 0x0f0ff005;
> 
> -                       ratr_value &= ratr_mask;
> -               }
> +               ratr_value &= ratr_mask;
>                 break;
>         default:
>                 if (rtlphy->rf_type == RF_1T2R)
> --
> 2.43.0


^ permalink raw reply

* RE: wifi: rtw89: rtw8922ae: HWSI bus lockup during RF recalibration on AP bandwidth change
From: Ping-Ke Shih @ 2026-04-07  0:38 UTC (permalink / raw)
  To: Jeffrey Wälti; +Cc: linux-wireless@vger.kernel.org
In-Reply-To: <dFJeMTbWtJdpQXoZpQRv85Z8BumU9LW5xY5D4Hnuri6Zez_Gkk8XL6zNEuCFN1djAEqsTA9-mJb1ygNXX-V72HL4Q3Vit_1JY1-xBHBm5SQ=@waelti.dev>

Jeffrey Wälti <jeffrey@waelti.dev> wrote:
> 
> Jeffrey Wälti <jeffrey@waelti.dev> wrote:
> 
> > Ping-Ke Shih <pkshih@realtek.com> wrote:
> >
> > > Jeffrey Wälti <jeffrey@waelti.dev> wrote:
> > > >
> > > > Ping-Ke Shih <pkshih@realtek.com> wrote:
> > > >
> > > > > Jeffrey Wälti <jeffrey@waelti.dev> wrote:
> > > > > >
> > > > > > <pkshih@realtek.com> wrote:
> > > > > >
> > > > > > >
> > > > > > > Please try to disable power save and ASPM by
> > > > > > > 1) iw wlan0 set power_save off
> > > >
> > > > I'm sorry, this is my first time interacting with the mailing list and I overlooked the other
> instructions.
> > > > It seems like disabling power save gets rid of the issue of Wi-Fi timeouts. I haven't been able
> to
> > > > reproduce the issue with `iw wlan0 set power_save off` yet, even without any of the other fixes
> on kernel
> > > > 6.19.10 and 7.0-rc6.
> > > >
> > > > > > > 2) reference and install
> > > > > > https://github.com/lwfinger/rtw89/blob/main/70-rtw89.conf
> > > > > > >    and then cold reboot.
> > > > >
> > > > > Have you tested with these conditions?
> > > >
> > > > Using this patch eliminates the issue of Bluetooth devices disconnecting, when switching between
> > > > networks.
> > > >
> > > > > [...]
> > > > >
> > > > > > >
> > > > > > > Please help to test the latest kernel 7.0-rc with additional patch [1].
> > > > > > >
> > > > > > > [1]
> > > > > > https://lore.kernel.org/linux-wireless/20260310080146.31113-4-pkshih@realtek
> > > > > > .com/
> > > > >
> > > > > Have you also applied this patch?
> > > >
> > > > I tested kernel 7.0-rc6 with this patch applied on top for ~1 day now and haven't been able to
> reproduce,
> > > > even with power save enabled. However, it is a bit difficult to reliably trigger the issue as
> it seems
> > > > to trigger more on certain networks than others etc.
> > > >
> > > > > > >
> > > > > > > Ping-Ke
> > > > > > >
> > > > > > >
> > > > > >
> > > > > > Thank you for coming back to me so quickly, I just encountered the same thing
> > > > > > with kernel 7.0-rc5.
> > > > > >
> > > > >
> > > > > Please confirm my questions above.
> > > > >
> > > > > Ping-Ke
> > > > >
> > > > >
> > > >
> > > > In summary:
> > > > - Disabling power save seems to stop the timeouts but Bluetooth issues remain
> > > > - Disabling ASPM features fixes the Bluetooth issue
> > > > - kernel 7.0-rc6 with the additional patch fixes Wi-Fi timeouts but not the Bluetooth disconnects
> > > >
> > > > I hope that answers your questions.
> > >
> > > It looks like additional patch can fix the WiFi timeouts problem, and
> > > disabling ASPM feature can fix Bluetooth issue. I think you can keep
> > > (2) + (3) setting as workaround.
> > >
> > > I'd talk with BT coexistence team internally to figure out the cause
> > > of Bluetooth disconnection.
> >
> > As always, thank you very much for coming back to me so quickly and working on a fix. Please do let
> me know if there is any progress on the issue or if you need any more help testing a patch.
> 
> Hi again,
> 
> I'm sorry for coming back to you so quickly once again, but I am sad to report, that I just encountered
> the same issue again with kernel 7.0-rc6 and the custom patch applied. 

What did custom patch you mentioned? The additional patch I mentioned?

> After resume the Wi-Fi connection
> ran at less than 1/100 of the expected speed and wouldn't come back up, until I reconnected to the same
> network. It seems like just the custom patch was not enough to fix the underlying issue, but it did
> fix the HWSI lock up. This is what dmesg tells me.
> 
> [126462.035430] PM: suspend exit
> [126465.615935] wlan0: authenticate with 68:67:c7:2a:20:43 (local address=7c:fa:80:c3:5b:f9)
> [126465.615944] wlan0: send auth to 68:67:c7:2a:20:43 (try 1/3)
> [126465.634818] wlan0: send auth to 68:67:c7:2a:20:43 (try 2/3)
> [126465.654072] wlan0: send auth to 68:67:c7:2a:20:43 (try 3/3)
> [126465.673115] wlan0: authentication with 68:67:c7:2a:20:43 timed out

This said that it failed to TX auth or RX auth. I suggest to disable
Bluetooth entirely to see it can improve. 

> [126466.065780] wlan0: authenticate with 68:67:c7:2a:20:42 (local address=7c:fa:80:c3:5b:f9)
> [126466.065789] wlan0: send auth to 68:67:c7:2a:20:42 (try 1/3)
> [126468.082718] wlan0: send auth to 68:67:c7:2a:20:42 (try 2/3)
> [126470.107802] wlan0: send auth to 68:67:c7:2a:20:42 (try 3/3)
> [126471.070743] wlan0: aborting authentication with 68:67:c7:2a:20:42 by local choice (Reason:
> 3=DEAUTH_LEAVING)
> [126474.858695] wlan0: authenticate with 68:67:c7:2a:20:43 (local address=7c:fa:80:c3:5b:f9)
> [126474.858705] wlan0: send auth to 68:67:c7:2a:20:43 (try 1/3)
> [126474.879430] wlan0: authenticate with 68:67:c7:2a:20:43 (local address=7c:fa:80:c3:5b:f9)
> [126474.879439] wlan0: send auth to 68:67:c7:2a:20:43 (try 1/3)
> [126474.884633] wlan0: authenticated
> [126474.885578] wlan0: associate with 68:67:c7:2a:20:43 (try 1/3)
> [126474.899521] wlan0: RX AssocResp from 68:67:c7:2a:20:43 (capab=0x1011 status=0 aid=20)
> [126475.002744] wlan0: associated
> [126475.002799] wlan0: Limiting TX power to 23 (23 - 0) dBm as advertised by 68:67:c7:2a:20:43
> [126490.802365] ideapad_acpi VPC2004:00: unexpected charge_types: both [Fast] and [Long_Life] are
> enabled
> [126627.760736] ideapad_acpi VPC2004:00: unexpected charge_types: both [Fast] and [Long_Life] are
> enabled
> 
> (Here I decide to manually reconnect to the same network)
> 
> [126737.556015] wlan0: deauthenticating from 68:67:c7:2a:20:43 by local choice (Reason:
> 3=DEAUTH_LEAVING)
> [126738.215678] wlan0: authenticate with 68:67:c7:2a:20:43 (local address=7c:fa:80:c3:5b:f9)
> [126738.215697] wlan0: send auth to 68:67:c7:2a:20:43 (try 1/3)
> [126740.272244] wlan0: send auth to 68:67:c7:2a:20:43 (try 2/3)
> [126740.291264] wlan0: authenticate with 68:67:c7:2a:20:43 (local address=7c:fa:80:c3:5b:f9)
> [126740.291271] wlan0: send auth to 68:67:c7:2a:20:43 (try 1/3)
> [126740.293310] wlan0: authenticated
> [126740.294214] wlan0: associate with 68:67:c7:2a:20:43 (try 1/3)
> [126740.303679] wlan0: RX AssocResp from 68:67:c7:2a:20:43 (capab=0x1011 status=0 aid=21)
> [126740.409430] wlan0: associated
> [126740.409517] wlan0: Limiting TX power to 23 (23 - 0) dBm as advertised by 68:67:c7:2a:20:43
> 
> I will resume testing with the power save function turned off, to check if that still is a working
> workaround for now.

Please test it.

Ping-Ke


^ permalink raw reply

* [PATCH wireless v2] wifi: mt76: mt7915: set AMSDU parameters for WED v3
From: Joshua Klinesmith @ 2026-04-07  0:16 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith

On MT7988 (WED version 3), the WED hardware unconditionally
enables the AMSDU aggregation engine. The engine uses
wlan.amsdu_max_subframes and wlan.amsdu_max_len to configure
aggregation limits. The mt7996 driver sets these to 8 and 1536
respectively, but the mt7915 driver never sets them, leaving
both at zero.

With the AMSDU engine active and zero-valued limits, the TX
path is severely throttled, capping throughput at approximately
6 Mbps on MT7916 PCIe cards attached to MT7988 SoCs.

Set amsdu_max_subframes and amsdu_max_len to the same values
used by the mt7996 driver.

Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index 2708b1556f..f5fa81d3b2 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -719,6 +719,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
 	wed->wlan.reset = mt7915_mmio_wed_reset;
 	wed->wlan.reset_complete = mt76_wed_reset_complete;
 
+	wed->wlan.amsdu_max_subframes = 8;
+	wed->wlan.amsdu_max_len = 1536;
+
 	dev->mt76.rx_token_size = wed->wlan.rx_npkt;
 
 	if (mtk_wed_device_attach(wed))

base-commit: 6cb103122c802fbfc82d1e53cf78667bfc52eb9e
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 4/4] wifi: mt76: mt7925: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-07  0:16 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001600.31234-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 0d94359004..596bc21b02 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -145,7 +145,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 3/4] wifi: mt76: mt7921: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001600.31234-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index 03b4960db7..fa5631b879 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -155,7 +155,7 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 2/4] wifi: mt76: mt7996: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001600.31234-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index d4f3ee943b..a0342012e5 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -205,7 +205,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]);
 		if (mlink) {
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 1/4] wifi: mt76: mt7915: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001600.31234-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cefe56c057..cf72b38c85 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -221,7 +221,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		msta->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 0/4] wifi: mt76: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith

The fourth receive chain RCPI extraction in sta_poll uses
GENMASK(31, 14), an 18-bit mask spanning bits 14-31. It should
be GENMASK(31, 24), an 8-bit mask for the fourth byte, consistent
with the other three chains and with the RCPI3 definitions used
elsewhere in the driver.

On devices with fewer than 4 antenna chains the corrupted value
is masked out by antenna_mask. On 4-chain devices this produces
incorrect ACK signal strength readings.
---
v1 -> v2: Rebased on wireless.git (was mt76-fixes)

Joshua Klinesmith (4):
  wifi: mt76: mt7915: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7996: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7921: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7925: fix RCPI chain 3 mask in sta_poll RSSI extraction

 drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)


base-commit: ce5cc2702bb63ecd1f2066acb7d6e7d19081618d
-- 
2.43.0


^ permalink raw reply

* [PATCH wireless v2 2/2] wifi: mt76: mt7996: clear cipher state on key removal for WED offload
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001531.31207-1-joshuaklinesmith@gmail.com>

Same issue as mt7915: link->mt76.cipher is set on key installation
but never cleared on removal. The WA firmware retains the stale
cipher in BSS_INFO, sets the protection bit on WED-offloaded
frames, and drops all plaintext traffic when encryption is
switched to open/none.

Reset link->mt76.cipher to zero and call mt7996_mcu_add_bss_info()
when the last group key is removed.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index f16135f0b7..d464fc3d90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -249,6 +249,13 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	else if (idx == *wcid_keyidx)
 		*wcid_keyidx = -1;
 
+	if (cmd != SET_KEY && !sta && link->mt76.cipher) {
+		link->mt76.cipher = 0;
+		if (link->phy)
+			mt7996_mcu_add_bss_info(link->phy, vif, link_conf,
+						&link->mt76, msta_link, true);
+	}
+
 	/* only do remove key for BIGTK */
 	if (cmd != SET_KEY && !is_bigtk)
 		return 0;
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 1/2] wifi: mt76: mt7915: clear cipher state on key removal for WED offload
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260407001531.31207-1-joshuaklinesmith@gmail.com>

When switching from WPA-PSK/SAE to open/no encryption, the
DISABLE_KEY path never resets mvif->mt76.cipher back to zero.
The stale cipher value is sent to the WA firmware via BSS_INFO
updates, causing the firmware to keep the protection bit set on
WED-offloaded packets. The hardware then drops all plaintext
frames, resulting in zero throughput.

Reset mvif->mt76.cipher to zero and notify the firmware via
mt7915_mcu_add_bss_info() when the last group key is removed.

Fixes: 3fd2dbd6a1d3 ("mt76: mt7915: update bss_info with cipher after setting the group key")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 90d5e79fbf..6e7442cac4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -414,6 +414,12 @@ static int mt7915_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 	} else {
 		if (idx == *wcid_keyidx)
 			*wcid_keyidx = -1;
+
+		if (!sta && mvif->mt76.cipher) {
+			mvif->mt76.cipher = 0;
+			mt7915_mcu_add_bss_info(phy, vif, true);
+		}
+
 		goto out;
 	}
 
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless v2 0/2] wifi: mt76: clear cipher state on key removal for WED offload
From: Joshua Klinesmith @ 2026-04-07  0:15 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith

When switching WiFi encryption from WPA-PSK/SAE to open/none with
WED hardware offload enabled, throughput drops to zero. The BSS
cipher state is set when group keys are installed but never cleared
when they are removed. The WA firmware retains the stale cipher
value and keeps the protection bit set on WED-offloaded packets,
causing all plaintext frames to be dropped.

Found via reverse engineering of the vendor MediaTek SDK
mt_wifi.ko driver.
---
v1 -> v2: Rebased on wireless.git (was mt76-fixes)

Joshua Klinesmith (2):
  wifi: mt76: mt7915: clear cipher state on key removal for WED offload
  wifi: mt76: mt7996: clear cipher state on key removal for WED offload

 drivers/net/wireless/mediatek/mt76/mt7915/main.c | 6 ++++++
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 7 +++++++
 2 files changed, 13 insertions(+)


base-commit: 45dbf8fcea4dcf28cabcf4a1778e908feadf4c90
-- 
2.43.0


^ permalink raw reply

* [PATCH wireless] wifi: mt76: mt7915: set AMSDU parameters for WED v3
From: Joshua Klinesmith @ 2026-04-06 23:48 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith

On MT7988 (WED version 3), the WED hardware unconditionally
enables the AMSDU aggregation engine. The engine uses
wlan.amsdu_max_subframes and wlan.amsdu_max_len to configure
aggregation limits. The mt7996 driver sets these to 8 and 1536
respectively, but the mt7915 driver never sets them, leaving
both at zero.

With the AMSDU engine active and zero-valued limits, the TX
path is severely throttled, capping throughput at approximately
6 Mbps on MT7916 PCIe cards attached to MT7988 SoCs.

Set amsdu_max_subframes and amsdu_max_len to the same values
used by the mt7996 driver.

Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mmio.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
index 4a82f8e4c1..403466eca6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mmio.c
@@ -719,6 +719,9 @@ int mt7915_mmio_wed_init(struct mt7915_dev *dev, void *pdev_ptr,
 	wed->wlan.reset = mt7915_mmio_wed_reset;
 	wed->wlan.reset_complete = mt76_wed_reset_complete;
 
+	wed->wlan.amsdu_max_subframes = 8;
+	wed->wlan.amsdu_max_len = 1536;
+
 	dev->mt76.rx_token_size = wed->wlan.rx_npkt;
 
 	if (mtk_wed_device_attach(wed))

base-commit: 316da1786e2ac103254d49c0524bdcf72a454401
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless 4/4] wifi: mt76: mt7925: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-06 23:47 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260406234739.29926-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 chips")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 6334019249..85e91ca84f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -144,7 +144,7 @@ static void mt7925_mac_sta_poll(struct mt792x_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless 3/4] wifi: mt76: mt7921: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-06 23:47 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260406234739.29926-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: 163f4d22c118 ("mt76: mt7921: add MAC support")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
index bce26389ab..7a46b50171 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7921/mac.c
@@ -155,7 +155,7 @@ static void mt7921_mac_sta_poll(struct mt792x_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless 2/4] wifi: mt76: mt7996: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-06 23:47 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260406234739.29926-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index ca2305ea7c..ab47118fb1 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -205,7 +205,7 @@ static void mt7996_mac_sta_poll(struct mt7996_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		mlink = rcu_dereference(msta->vif->mt76.link[wcid->link_id]);
 		if (mlink) {
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless 1/4] wifi: mt76: mt7915: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-06 23:47 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260406234739.29926-1-joshuaklinesmith@gmail.com>

The fourth receive chain RCPI uses GENMASK(31, 14), an 18-bit mask
spanning bits 14-31. It should be GENMASK(31, 24), an 8-bit mask
for the fourth byte, consistent with the other three chains and
with the RCPI3 definitions used elsewhere in the driver
(MT_PRXV_RCPI3 and MT_TXS7_F0_RCPI_3 both use GENMASK(31, 24)).

On devices with fewer than 4 antenna chains, the corrupted value
is masked out by antenna_mask in mt76_rx_signal(). On 4-chain
devices, this produces incorrect ACK signal strength readings.

Fixes: e57b7901469f ("mt76: add mac80211 driver for MT7915 PCIe-based chipsets")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index 1c0d310146..946d2bd0d9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -221,7 +221,7 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
 		rssi[0] = to_rssi(GENMASK(7, 0), val);
 		rssi[1] = to_rssi(GENMASK(15, 8), val);
 		rssi[2] = to_rssi(GENMASK(23, 16), val);
-		rssi[3] = to_rssi(GENMASK(31, 14), val);
+		rssi[3] = to_rssi(GENMASK(31, 24), val);
 
 		msta->ack_signal =
 			mt76_rx_signal(msta->vif->phy->mt76->antenna_mask, rssi);
-- 
2.43.0


^ permalink raw reply related

* [PATCH wireless 0/4] wifi: mt76: fix RCPI chain 3 mask in sta_poll RSSI extraction
From: Joshua Klinesmith @ 2026-04-06 23:47 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith

The fourth receive chain RCPI extraction in sta_poll uses
GENMASK(31, 14), an 18-bit mask spanning bits 14-31. It should
be GENMASK(31, 24), an 8-bit mask for the fourth byte, consistent
with the other three chains and with the RCPI3 definitions used
elsewhere in the driver.

On devices with fewer than 4 antenna chains the corrupted value
is masked out by antenna_mask. On 4-chain devices this produces
incorrect ACK signal strength readings.

Joshua Klinesmith (4):
  wifi: mt76: mt7915: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7996: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7921: fix RCPI chain 3 mask in sta_poll RSSI extraction
  wifi: mt76: mt7925: fix RCPI chain 3 mask in sta_poll RSSI extraction

 drivers/net/wireless/mediatek/mt76/mt7915/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7921/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7925/mac.c | 2 +-
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)


base-commit: d863fb7a97fab243b48ce2e5e21243dee5abbcdd
-- 
2.43.0


^ permalink raw reply

* [PATCH wireless 2/2] wifi: mt76: mt7996: clear cipher state on key removal for WED offload
From: Joshua Klinesmith @ 2026-04-06 23:42 UTC (permalink / raw)
  To: linux-wireless
  Cc: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, linux-kernel,
	Joshua Klinesmith, stable
In-Reply-To: <20260406234205.29857-1-joshuaklinesmith@gmail.com>

Same issue as mt7915: link->mt76.cipher is set on key installation
but never cleared on removal. The WA firmware retains the stale
cipher in BSS_INFO, sets the protection bit on WED-offloaded
frames, and drops all plaintext traffic when encryption is
switched to open/none.

Reset link->mt76.cipher to zero and call mt7996_mcu_add_bss_info()
when the last group key is removed.

Fixes: 98686cd21624 ("wifi: mt76: mt7996: add driver for MediaTek Wi-Fi 7 (802.11be) devices")
Cc: stable@vger.kernel.org
Signed-off-by: Joshua Klinesmith <joshuaklinesmith@gmail.com>
---
 drivers/net/wireless/mediatek/mt76/mt7996/main.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index 84f731b387..bf5fda6925 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -235,6 +235,21 @@ mt7996_set_hw_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 		} else {
 			if (idx == *wcid_keyidx)
 				*wcid_keyidx = -1;
+
+			if (!sta && link->mt76.cipher) {
+				struct ieee80211_bss_conf *lc;
+
+				lc = link_conf_dereference_protected(vif,
+								     link_id);
+				if (!lc)
+					lc = &vif->bss_conf;
+
+				link->mt76.cipher = 0;
+				mt7996_mcu_add_bss_info(link->phy, vif, lc,
+							&link->mt76,
+							msta_link, true);
+			}
+
 			continue;
 		}
 
-- 
2.43.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox