* Re: [PATCH rtw-next 1/9] wifi: rtw89: phy: add chip_ops to calculate RX gain from efuse to support PS mode
From: Ping-Ke Shih @ 2026-01-22 3:31 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: echuang, phhuang, kevin_yang
In-Reply-To: <20260117044157.2392958-2-pkshih@realtek.com>
Ping-Ke Shih <pkshih@realtek.com> wrote:
> In PS mode, it needs to restore RX gain settings while waking up. Add to
> get RX gain values from chip specific ops, and pass these data to firmware
> when going to enter PS mode.
>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
9 patch(es) applied to rtw-next branch of rtw.git, thanks.
32f6bf1872cb wifi: rtw89: phy: add chip_ops to calculate RX gain from efuse to support PS mode
496a0752fe50 wifi: rtw89: phy: handle C2H event for PS mode report
20380a039ddd wifi: rtw89: phy: add H2C command to send detail RX gain and link parameters for PS mode
bcd23ebfef1c wifi: rtw89: phy: update edcca log parsing for RTL8922D
4809013c088c wifi: rtw89: phy: add firmware element of digital TX power compensation
5fe702e4b2cd wifi: rtw89: phy: update TSSI flow for RTL8922D
9cc1a84c53d4 wifi: rtw89: mac: clear DTOP disable excluding CID7090 variant for RTL8922D
1945c83dc5ce wifi: rtw89: mac: set force MBA duration to 0
8da7e88682d5 wifi: rtw89: 8922a: add digital compensation for 2GHz
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* Re: [PATCH v2] wifi: rtw89: debug: Fix memory leak in __print_txpwr_map()
From: Ping-Ke Shih @ 2026-01-22 2:02 UTC (permalink / raw)
To: Zilin Guan, pkshih
Cc: kevin_yang, linux-wireless, linux-kernel, jianhao.xu, Zilin Guan
In-Reply-To: <20260116130834.1413924-1-zilin@seu.edu.cn>
Zilin Guan <zilin@seu.edu.cn> wrote:
> In __print_txpwr_map(), memory is allocated to bufp via vzalloc().
> If max_valid_addr is 0, the function returns -EOPNOTSUPP immediately
> without freeing bufp, leading to a memory leak.
>
> Since the validation of max_valid_addr does not depend on the allocated
> memory, fix this by moving the vzalloc() call after the check.
>
> Compile tested only. Issue found using a prototype static analysis tool
> and code review.
>
> Fixes: 036042e15770 ("wifi: rtw89: debug: txpwr table supports Wi-Fi 7 chips")
> Suggested-by: Zong-Zhe Yang <kevin_yang@realtek.com>
> Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
> Reviewed-by: Zong-Zhe Yang <kevin_yang@realtek.com>
1 patch(es) applied to rtw-next branch of rtw.git, thanks.
6070a44051b1 wifi: rtw89: debug: Fix memory leak in __print_txpwr_map()
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* Re: [PATCH rtw-next] wifi: rtw89: Add default ID 28de:2432 for RTL8832CU
From: Ping-Ke Shih @ 2026-01-22 1:57 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: isaiah
In-Reply-To: <20260114014906.21829-1-pkshih@realtek.com>
Ping-Ke Shih <pkshih@realtek.com> wrote:
> From: Shin-Yi Lin <isaiah@realtek.com>
>
> Add 28de:2432 for RTL8832CU-based adapters that use this default ID.
>
> Signed-off-by: Shin-Yi Lin <isaiah@realtek.com>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
1 patch(es) applied to rtw-next branch of rtw.git, thanks.
5f65ebf9aaf0 wifi: rtw89: Add default ID 28de:2432 for RTL8832CU
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* Re: [PATCH rtw-next 01/12] wifi: rtw89: mac: clear global interrupt right after power-on
From: Ping-Ke Shih @ 2026-01-22 1:54 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: echuang, phhuang
In-Reply-To: <20260114013950.19704-2-pkshih@realtek.com>
Ping-Ke Shih <pkshih@realtek.com> wrote:
> The global interrupt indicator is always persistent, and firmware will
> handle it right after boot. To prevent this unnecessary handling, clear
> the indicator before downloading firmware.
>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
12 patch(es) applied to rtw-next branch of rtw.git, thanks.
e497fc05e9f5 wifi: rtw89: mac: clear global interrupt right after power-on
1e3c50e0b491 wifi: rtw89: phy: add {read,write}_rf_v3 for RTL8922D
3b99dac7bf91 wifi: rtw89: phy: add ops rtw89_phy_gen_be_v1 for RTL8922D
fc31826cbc24 wifi: rtw89: phy: abstract start address and EHT of PHY status bitmap
0e8818a309f7 wifi: rtw89: phy: extend register to read history 2 of PHY env_monitor
ace51dc80334 wifi: rtw89: phy: abstract BB wrap registers to share initial flow
d6cc6e12c15b wifi: rtw89: phy: update bb wrapper TPU init
51cc8220f8ce wifi: rtw89: phy: update BB wrapper RFSI
ee866bb4aa78 wifi: rtw89: phy: write BB wrapper registers with flush
a0343cdc7767 wifi: rtw89: phy: refine initial flow of BB wrapper
76bada91a41a wifi: rtw89: phy: fix incorrect power limit by mac_id
6f6d7a325fbd wifi: rtw89: fix unable to receive probe responses under MLO connection
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* Re: [PATCH 2/2] wifi: rtw88: add WQ_PERCPU to alloc_workqueue users
From: Ping-Ke Shih @ 2026-01-22 1:29 UTC (permalink / raw)
To: Marco Crivellari, linux-kernel, linux-wireless
Cc: Tejun Heo, Lai Jiangshan, Frederic Weisbecker,
Sebastian Andrzej Siewior, Marco Crivellari, Michal Hocko,
Ping-Ke Shih
In-Reply-To: <20251113160605.381777-3-marco.crivellari@suse.com>
Marco Crivellari <marco.crivellari@suse.com> wrote:
> Currently if a user enqueues a work item using schedule_delayed_work() the
> used wq is "system_wq" (per-cpu wq) while queue_delayed_work() use
> WORK_CPU_UNBOUND (used when a cpu is not specified). The same applies to
> schedule_work() that is using system_wq and queue_work(), that makes use
> again of WORK_CPU_UNBOUND.
>
> This lack of consistency cannot be addressed without refactoring the API.
> For more details see the Link tag below.
>
> alloc_workqueue() treats all queues as per-CPU by default, while unbound
> workqueues must opt-in via WQ_UNBOUND.
>
> This default is suboptimal: most workloads benefit from unbound queues,
> allowing the scheduler to place worker threads where they’re needed and
> reducing noise when CPUs are isolated.
>
> This continues the effort to refactor workqueue APIs, which began with
> the introduction of new workqueues and a new alloc_workqueue flag in:
>
> commit 128ea9f6ccfb ("workqueue: Add system_percpu_wq and system_dfl_wq")
> commit 930c2ea566af ("workqueue: Add new WQ_PERCPU flag")
>
> This change adds a new WQ_PERCPU flag to explicitly request
> alloc_workqueue() to be per-cpu when WQ_UNBOUND has not been specified.
>
> With the introduction of the WQ_PERCPU flag (equivalent to !WQ_UNBOUND),
> any alloc_workqueue() caller that doesn’t explicitly specify WQ_UNBOUND
> must now use WQ_PERCPU.
>
> Once migration is complete, WQ_UNBOUND can be removed and unbound will
> become the implicit default.
>
> Suggested-by: Tejun Heo <tj@kernel.org>
> Signed-off-by: Marco Crivellari <marco.crivellari@suse.com>
> Link: https://lore.kernel.org/all/20250221112003.1dSuoGyc@linutronix.de/
1 patch(es) applied to rtw-next branch of rtw.git, thanks.
f65ca6c51179 wifi: rtw88: add WQ_PERCPU to alloc_workqueue users
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* Setting txpower and antenna with radio-idx is broken.
From: Ben Greear @ 2026-01-22 0:24 UTC (permalink / raw)
To: linux-wireless
I took a look at net/wireless/nl80211.c, and noticed that
radio_idx is only assigned in a branch of code that will return.
So trying to pass it on to the set_antenna or set_txpower logic
can never happen. I'm not sure how this was supposed to work,
maybe just not return after nl80211_set_wiphy_radio(info, rdev, radio_idx); ?
This is in today's linus kernel...
Thanks,
Ben
--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc http://www.candelatech.com
^ permalink raw reply
* [PATCH 3/3] wifi: mt76: mt7996: add support for ERP CTS & HT protection
From: Ryder Lee @ 2026-01-21 17:41 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, linux-mediatek, Ryder Lee, Money Wang
In-Reply-To: <edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com>
This patch adds support for handling BSS_CHANGED_ERP_CTS_PROT and
BSS_CHANGED_HT.
With this change, when the Wi-Fi driver needs to adjust its behavior for
compatibility or performance, especially concerning older 11g/n devices,
by enabling or disabling CTS protection frames, often for hidden SSIDs or
to manage legacy clients.
It also introduces debugfs options to manually control protection mode,
allowing users to select betweenno protection, RTS/CTS, and CTS-to-self.
Reviewed-by: Money Wang <money.wang@mediatek.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
.../wireless/mediatek/mt76/mt76_connac_mcu.h | 1 +
.../net/wireless/mediatek/mt76/mt7996/main.c | 4 ++
.../net/wireless/mediatek/mt76/mt7996/mcu.c | 46 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7996/mcu.h | 6 +++
.../wireless/mediatek/mt76/mt7996/mt7996.h | 2 +
5 files changed, 59 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
index 8d59cf43f..f44977f90 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76_connac_mcu.h
@@ -1363,6 +1363,7 @@ enum {
UNI_BSS_INFO_BASIC = 0,
UNI_BSS_INFO_RA = 1,
UNI_BSS_INFO_RLM = 2,
+ UNI_BSS_INFO_PROTECT_INFO = 3,
UNI_BSS_INFO_BSS_COLOR = 4,
UNI_BSS_INFO_HE_BASIC = 5,
UNI_BSS_INFO_11V_MBSSID = 6,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/main.c b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
index beed795ed..db76f1f5d 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/main.c
@@ -864,6 +864,10 @@ mt7996_link_info_changed(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
!!(changed & BSS_CHANGED_BSSID));
}
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7996_mcu_set_protection(phy, link, info->ht_operation_mode,
+ info->use_cts_prot);
+
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = info->use_short_slot ? 9 : 20;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
index 14a88ef79..3d103c66a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.c
@@ -1170,6 +1170,52 @@ int mt7996_mcu_add_bss_info(struct mt7996_phy *phy, struct ieee80211_vif *vif,
MCU_WMWA_UNI_CMD(BSS_INFO_UPDATE), true);
}
+int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link,
+ u8 ht_mode, bool use_cts_prot)
+{
+ struct mt7996_dev *dev = phy->dev;
+ struct bss_prot_tlv *prot;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ enum {
+ PROT_NONMEMBER = BIT(1),
+ PROT_20MHZ = BIT(2),
+ PROT_NONHT_MIXED = BIT(3),
+ PROT_LEGACY_ERP = BIT(5),
+ PROT_NONGF_STA = BIT(7),
+ };
+
+ skb = __mt7996_mcu_alloc_bss_req(&dev->mt76, &link->mt76,
+ MT7996_BSS_UPDATE_MAX_SIZE);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt7996_mcu_add_uni_tlv(skb, UNI_BSS_INFO_PROTECT_INFO,
+ sizeof(*prot));
+ prot = (struct bss_prot_tlv *)tlv;
+
+ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ prot->prot_mode = cpu_to_le32(PROT_20MHZ);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED);
+ break;
+ }
+
+ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
+ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA);
+
+ if (use_cts_prot)
+ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_WM_UNI_CMD(BSS_INFO_UPDATE), true);
+}
+
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
index e0b83ac9f..3a4a7ec3c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mcu.h
@@ -474,6 +474,12 @@ struct bss_mld_tlv {
u8 __rsv[2];
} __packed;
+struct bss_prot_tlv {
+ __le16 tag;
+ __le16 len;
+ __le32 prot_mode;
+} __packed;
+
struct sta_rec_ht_uni {
__le16 tag;
__le16 len;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index 7a8843118..d9370b56f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -719,6 +719,8 @@ int mt7996_mcu_set_radar_th(struct mt7996_dev *dev, int index,
const struct mt7996_dfs_pattern *pattern);
int mt7996_mcu_set_radio_en(struct mt7996_phy *phy, bool enable);
int mt7996_mcu_set_rts_thresh(struct mt7996_phy *phy, u32 val);
+int mt7996_mcu_set_protection(struct mt7996_phy *phy, struct mt7996_vif_link *link,
+ u8 ht_mode, bool use_cts_prot);
int mt7996_mcu_set_timing(struct mt7996_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_bss_conf *link_conf);
int mt7996_mcu_get_chan_mib_info(struct mt7996_phy *phy, bool chan_switch);
--
2.45.2
^ permalink raw reply related
* [PATCH 1/3] wifi: mt76: mt7615: fix use_cts_prot support
From: Ryder Lee @ 2026-01-21 17:41 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, linux-mediatek, Ryder Lee
Driver should not directly write WTBL to prevent overwritten issues.
With this fix, when driver needs to adjust its behavior for compatibility,
especially concerning older 11g/n devices, by enabling or disabling CTS
protection frames, often for hidden SSIDs or to manage legacy clients.
Fixes: e34235ccc5e3 ("wifi: mt76: mt7615: enable use_cts_prot support")
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7615/mac.c | 15 ------
.../net/wireless/mediatek/mt76/mt7615/main.c | 7 +--
.../net/wireless/mediatek/mt76/mt7615/mcu.c | 47 +++++++++++++++++++
.../wireless/mediatek/mt76/mt7615/mt7615.h | 5 +-
.../net/wireless/mediatek/mt76/mt7615/regs.h | 2 -
5 files changed, 53 insertions(+), 23 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
index bd56cdb02..d3478390f 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mac.c
@@ -1167,21 +1167,6 @@ void mt7615_mac_set_rates(struct mt7615_phy *phy, struct mt7615_sta *sta,
}
EXPORT_SYMBOL_GPL(mt7615_mac_set_rates);
-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
- u32 addr;
-
- addr = mt7615_mac_wtbl_addr(dev, mvif->sta.wcid.idx) + 3 * 4;
-
- if (enable)
- mt76_set(dev, addr, MT_WTBL_W3_RTS);
- else
- mt76_clear(dev, addr, MT_WTBL_W3_RTS);
-}
-EXPORT_SYMBOL_GPL(mt7615_mac_enable_rtscts);
-
static int
mt7615_mac_wtbl_update_key(struct mt7615_dev *dev, struct mt76_wcid *wcid,
struct ieee80211_key_conf *key,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/main.c b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
index 727266892..fc619acbb 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/main.c
@@ -583,9 +583,6 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
}
}
- if (changed & BSS_CHANGED_ERP_CTS_PROT)
- mt7615_mac_enable_rtscts(dev, vif, info->use_cts_prot);
-
if (changed & BSS_CHANGED_BEACON_ENABLED && info->enable_beacon) {
mt7615_mcu_add_bss_info(phy, vif, NULL, true);
mt7615_mcu_sta_add(phy, vif, NULL, true);
@@ -598,6 +595,10 @@ static void mt7615_bss_info_changed(struct ieee80211_hw *hw,
BSS_CHANGED_BEACON_ENABLED))
mt7615_mcu_add_beacon(dev, hw, vif, info->enable_beacon);
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7615_mcu_set_protection(phy, vif, info->ht_operation_mode,
+ info->use_cts_prot);
+
if (changed & BSS_CHANGED_PS)
mt76_connac_mcu_set_vif_ps(&dev->mt76, vif);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
index fc0054f8b..ff57ede87 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mcu.c
@@ -2564,3 +2564,50 @@ int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
return mt76_mcu_send_msg(&dev->mt76, MCU_CE_CMD(SET_ROC),
&req, sizeof(req), false);
}
+
+int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot)
+{
+ struct mt7615_dev *dev = phy->dev;
+ struct {
+ u8 prot_idx;
+ u8 band;
+ u8 rsv[2];
+
+ bool long_nav;
+ bool prot_mm;
+ bool prot_gf;
+ bool prot_bw40;
+ bool prot_rifs;
+ bool prot_bw80;
+ bool prot_bw160;
+ u8 prot_erp_mask;
+ } __packed req = {
+ .prot_idx = 0x2,
+ .band = phy != &dev->phy,
+ };
+
+ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ req.prot_mm = true;
+ req.prot_gf = true;
+ fallthrough;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ req.prot_bw40 = true;
+ break;
+ }
+
+ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
+ req.prot_gf = true;
+
+ if (use_cts_prot) {
+ struct mt7615_vif *mvif = (struct mt7615_vif *)vif->drv_priv;
+ u8 i = mvif->mt76.omac_idx > HW_BSSID_MAX ? HW_BSSID_0 : mvif->mt76.omac_idx;
+
+ req.prot_erp_mask = BIT(i);
+ }
+
+ return mt76_mcu_send_msg(&dev->mt76, MCU_EXT_CMD(PROTECT_CTRL), &req,
+ sizeof(req), true);
+}
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
index c93fd245c..391928405 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/mt7615.h
@@ -467,8 +467,6 @@ void mt7615_mac_reset_counters(struct mt7615_phy *phy);
void mt7615_mac_cca_stats_reset(struct mt7615_phy *phy);
void mt7615_mac_set_scs(struct mt7615_phy *phy, bool enable);
void mt7615_mac_enable_nf(struct mt7615_dev *dev, bool ext_phy);
-void mt7615_mac_enable_rtscts(struct mt7615_dev *dev,
- struct ieee80211_vif *vif, bool enable);
void mt7615_mac_sta_poll(struct mt7615_dev *dev);
int mt7615_mac_write_txwi(struct mt7615_dev *dev, __le32 *txwi,
struct sk_buff *skb, struct mt76_wcid *wcid,
@@ -523,7 +521,8 @@ int mt7615_mcu_set_sku_en(struct mt7615_phy *phy, bool enable);
int mt7615_mcu_apply_rx_dcoc(struct mt7615_phy *phy);
int mt7615_mcu_apply_tx_dpd(struct mt7615_phy *phy);
int mt7615_dfs_init_radar_detector(struct mt7615_phy *phy);
-
+int mt7615_mcu_set_protection(struct mt7615_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot);
int mt7615_mcu_set_roc(struct mt7615_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_channel *chan, int duration);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
index eb3c24d51..e4133e918 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7615/regs.h
@@ -455,8 +455,6 @@ enum mt7615_reg_base {
#define MT_WTBL_RIUCR3_RATE6 GENMASK(19, 8)
#define MT_WTBL_RIUCR3_RATE7 GENMASK(31, 20)
-#define MT_WTBL_W3_RTS BIT(22)
-
#define MT_WTBL_W5_CHANGE_BW_RATE GENMASK(7, 5)
#define MT_WTBL_W5_SHORT_GI_20 BIT(8)
#define MT_WTBL_W5_SHORT_GI_40 BIT(9)
--
2.45.2
^ permalink raw reply related
* [PATCH 2/3] wifi: mt76: mt7915: fix use_cts_prot support
From: Ryder Lee @ 2026-01-21 17:41 UTC (permalink / raw)
To: Felix Fietkau; +Cc: linux-wireless, linux-mediatek, Ryder Lee
In-Reply-To: <edb87088b0111b32fafc6c4179f54a5286dd37d8.1768879119.git.ryder.lee@mediatek.com>
With this fix, when driver needs to adjust its behavior for compatibility,
especially concerning older 11g/n devices, by enabling or disabling CTS
protection frames, often for hidden SSIDs or to manage legacy clients.
Fixes: 150b91419d3d ("wifi: mt76: mt7915: enable use_cts_prot support")
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
.../net/wireless/mediatek/mt76/mt7915/mac.c | 13 ----
.../net/wireless/mediatek/mt76/mt7915/main.c | 7 ++-
.../net/wireless/mediatek/mt76/mt7915/mcu.c | 62 +++++++++++++++++++
.../net/wireless/mediatek/mt76/mt7915/mcu.h | 11 ++++
.../wireless/mediatek/mt76/mt7915/mt7915.h | 4 ++
5 files changed, 81 insertions(+), 16 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
index cefe56c05..cec2c4208 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mac.c
@@ -232,19 +232,6 @@ static void mt7915_mac_sta_poll(struct mt7915_dev *dev)
rcu_read_unlock();
}
-void mt7915_mac_enable_rtscts(struct mt7915_dev *dev,
- struct ieee80211_vif *vif, bool enable)
-{
- struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
- u32 addr;
-
- addr = mt7915_mac_wtbl_lmac_addr(dev, mvif->sta.wcid.idx, 5);
- if (enable)
- mt76_set(dev, addr, BIT(5));
- else
- mt76_clear(dev, addr, BIT(5));
-}
-
static void
mt7915_wed_check_ppe(struct mt7915_dev *dev, struct mt76_queue *q,
struct mt7915_sta *msta, struct sk_buff *skb,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/main.c b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
index 90d5e79fb..089229161 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/main.c
@@ -68,7 +68,7 @@ int mt7915_run(struct ieee80211_hw *hw)
if (ret)
goto out;
- ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, 0x92b,
+ ret = mt76_connac_mcu_set_rts_thresh(&dev->mt76, MT7915_RTS_LEN_THRES,
phy->mt76->band_idx);
if (ret)
goto out;
@@ -633,8 +633,9 @@ static void mt7915_bss_info_changed(struct ieee80211_hw *hw,
if (set_sta == 1)
mt7915_mcu_add_sta(dev, vif, NULL, CONN_STATE_PORT_SECURE, false);
- if (changed & BSS_CHANGED_ERP_CTS_PROT)
- mt7915_mac_enable_rtscts(dev, vif, info->use_cts_prot);
+ if (changed & BSS_CHANGED_HT || changed & BSS_CHANGED_ERP_CTS_PROT)
+ mt7915_mcu_set_protection(phy, vif, info->ht_operation_mode,
+ info->use_cts_prot);
if (changed & BSS_CHANGED_ERP_SLOT) {
int slottime = 9;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
index 00bff4d3a..95b8f34a7 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.c
@@ -3954,6 +3954,68 @@ int mt7915_mcu_get_rx_rate(struct mt7915_phy *phy, struct ieee80211_vif *vif,
return ret;
}
+int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot)
+{
+ struct mt7915_dev *dev = phy->dev;
+ int len = sizeof(struct sta_req_hdr) + sizeof(struct bss_info_prot);
+ struct mt7915_vif *mvif = (struct mt7915_vif *)vif->drv_priv;
+ struct bss_info_prot *prot;
+ struct sk_buff *skb;
+ struct tlv *tlv;
+ enum {
+ PROT_NONMEMBER = BIT(1),
+ PROT_20MHZ = BIT(2),
+ PROT_NONHT_MIXED = BIT(3),
+ PROT_LEGACY_ERP = BIT(5),
+ PROT_NONGF_STA = BIT(7),
+ };
+ u32 rts_threshold;
+
+ skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mvif->mt76,
+ NULL, len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ tlv = mt76_connac_mcu_add_tlv(skb, BSS_INFO_PROTECT_INFO,
+ sizeof(*prot));
+ prot = (struct bss_info_prot *)tlv;
+
+ switch (ht_mode & IEEE80211_HT_OP_MODE_PROTECTION) {
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONMEMBER:
+ prot->prot_mode = cpu_to_le32(PROT_NONMEMBER);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+ prot->prot_mode = cpu_to_le32(PROT_20MHZ);
+ break;
+ case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+ prot->prot_mode = cpu_to_le32(PROT_NONHT_MIXED);
+ break;
+ }
+
+ if (ht_mode & IEEE80211_HT_OP_MODE_NON_GF_STA_PRSNT)
+ prot->prot_mode |= cpu_to_le32(PROT_NONGF_STA);
+
+ if (use_cts_prot)
+ prot->prot_mode |= cpu_to_le32(PROT_LEGACY_ERP);
+
+ /* reuse current RTS setting */
+ rts_threshold = phy->mt76->hw->wiphy->rts_threshold;
+ if (rts_threshold == (u32)-1)
+ prot->rts_len_thres = cpu_to_le32(MT7915_RTS_LEN_THRES);
+ else
+ prot->rts_len_thres = cpu_to_le32(rts_threshold);
+
+ prot->rts_pkt_thres = 0x2;
+
+ prot->he_rts_thres = cpu_to_le16(vif->bss_conf.frame_time_rts_th);
+ if (!prot->he_rts_thres)
+ prot->he_rts_thres = cpu_to_le16(DEFAULT_HE_DURATION_RTS_THRES);
+
+ return mt76_mcu_skb_send_msg(&dev->mt76, skb,
+ MCU_EXT_CMD(BSS_INFO_UPDATE), true);
+}
+
int mt7915_mcu_update_bss_color(struct mt7915_dev *dev, struct ieee80211_vif *vif,
struct cfg80211_he_bss_color *he_bss_color)
{
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
index 3af11a075..22f73a5ed 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mcu.h
@@ -399,6 +399,17 @@ struct bss_info_inband_discovery {
__le16 prob_rsp_len;
} __packed __aligned(4);
+struct bss_info_prot {
+ __le16 tag;
+ __le16 len;
+ __le32 prot_type;
+ __le32 prot_mode;
+ __le32 rts_len_thres;
+ __le16 he_rts_thres;
+ u8 rts_pkt_thres;
+ u8 rsv[5];
+} __packed;
+
enum {
BSS_INFO_BCN_CSA,
BSS_INFO_BCN_BCC,
diff --git a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
index b5c06201b..bf1d915a3 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7915/mt7915.h
@@ -84,6 +84,8 @@
#define MT7915_CRIT_TEMP 110
#define MT7915_MAX_TEMP 120
+#define MT7915_RTS_LEN_THRES 0x92b
+
struct mt7915_vif;
struct mt7915_sta;
struct mt7915_dfs_pulse;
@@ -473,6 +475,8 @@ int mt7915_mcu_add_inband_discov(struct mt7915_dev *dev, struct ieee80211_vif *v
u32 changed);
int mt7915_mcu_add_beacon(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
int enable, u32 changed);
+int mt7915_mcu_set_protection(struct mt7915_phy *phy, struct ieee80211_vif *vif,
+ u8 ht_mode, bool use_cts_prot);
int mt7915_mcu_add_obss_spr(struct mt7915_phy *phy, struct ieee80211_vif *vif,
struct ieee80211_he_obss_pd *he_obss_pd);
int mt7915_mcu_add_rate_ctrl(struct mt7915_dev *dev, struct ieee80211_vif *vif,
--
2.45.2
^ permalink raw reply related
* pull-request: iwlwifi-next-2026-01-21
From: Korenblit, Miriam Rachel @ 2026-01-21 12:40 UTC (permalink / raw)
To: Linux Wireless
The following changes since commit 1e1dd9eeaab3908746d1dce5db6b0c29e0d28d6d:
wifi: mac80211: mark iface work SKBs as consumed (2026-01-19 10:22:35 +0100)
are available in the Git repository at:
https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/ tags/iwlwifi-next-2026-01-21
for you to fetch changes up to 66af8ac52d10ea229d5755b8700e2fe86fc037f7:
wifi: iwlwifi: rename struct iwl_mcc_allowed_ap_type_cmd::offset_map (2026-01-21 14:23:03 +0200)
----------------------------------------------------------------
iwlwifi features. Notably:
- Partial NAN support - without DATA
- Initial UHR support
- UNII-9 support
- EHT code cleanup in iwlmvm
----------------------------------------------------------------
Ally Heev (1):
wifi: iwlwifi: mld: remove unused variable in d3.c
Benjamin Berg (2):
wifi: iwlwifi: mld: decode VHT information for sniffer
wifi: iwlwifi: mld: change cluster_id type to u8 array
Daniel Gabay (2):
wifi: iwlwifi: mld: Remove wrong channel flags in scan cmd
wifi: iwlwifi: mvm: Remove few redundant 6 GHz scan chan params
Emmanuel Grumbach (8):
wifi: iwlwifi: mld: trigger a dump upon notification if needed
wifi: iwlwifi: move lari helper functions to the op_mode
wifi: iwlwifi: move iwl_get_lari_config_bitmap to the op_mode
wifi: iwlwifi: acpi: cache the DSM functions
wifi: iwlwifi: uefi: cache the DSM functions
wifi: iwlwifi: split bios_value_u32 to separate the header
wifi: iwlwifi: support V13 of iwl_lari_config_change_cmd
wifi: iwlwifi: rename struct iwl_mcc_allowed_ap_type_cmd::offset_map
Ilan Peer (6):
wifi: iwlwifi: mld: Add support for NAN
wifi: iwlwifi: mld: Handle rate selection for NAN interface
wifi: iwlwifi: mld: Declare support for NAN capabilities
wifi: iwlwifi: mld: Extend the NAN configuration
wifi: iwlwifi: mld: Support changing NAN configuration
wifi: iwlwifi: mld: Advertise support for multicast RX registration
Johannes Berg (7):
wifi: iwlwifi: fix 22000 series SMEM parsing
wifi: iwlwifi: adjust LINK context NPCA API
wifi: iwlwifi: add UHR TLC mode
wifi: iwlwifi: fw: api: add UHR data definitions
wifi: iwlwifi: mld: fix HE SIG-B MCS/DCM/compression
wifi: iwlwifi: fw: api: add HE type for UHR ELR
wifi: iwlwifi: cfg: remove iwl_be221_name
Miri Korenblit (6):
wifi: iwlwifi: mvm: check the validity of noa_len
wifi: iwlwifi: mld: support TLC command version 6
wifi: iwlwifi: cfg: move the MODULE_FIRMWARE to the per-rf file
wifi: iwlwifi: mld: fix chandef start calculation
wifi: iwlwifi: mld: add an helper to update an EMLSR blocker
wifi: iwlwifi: mld: prevent EMLSR when NAN is active
Nidhish A N (3):
wifi: iwlwifi: mld: Fix primary link selection logic
wifi: iwlwifi: mvm: Cleanup MLO code
wifi: iwlwifi: mvm: Remove link_id from time_events
Pagadala Yesu Anjaneyulu (2):
wifi: iwlwifi: fw: fix documentation reference for ap_type field
wifi: iwlwifi: mld: refactor AP power type setting
drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 12 -
drivers/net/wireless/intel/iwlwifi/cfg/rf-fm.c | 12 +
drivers/net/wireless/intel/iwlwifi/cfg/rf-pe.c | 1 -
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 117 +++++---
.../net/wireless/intel/iwlwifi/fw/api/mac-cfg.h | 159 ++++++++++-
.../net/wireless/intel/iwlwifi/fw/api/nvm-reg.h | 34 ++-
drivers/net/wireless/intel/iwlwifi/fw/api/power.h | 2 +-
drivers/net/wireless/intel/iwlwifi/fw/api/rs.h | 41 ++-
drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 95 ++++++-
drivers/net/wireless/intel/iwlwifi/fw/file.h | 2 +
drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 206 +-------------
drivers/net/wireless/intel/iwlwifi/fw/regulatory.h | 9 +-
drivers/net/wireless/intel/iwlwifi/fw/runtime.h | 17 +-
drivers/net/wireless/intel/iwlwifi/fw/smem.c | 8 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 72 +++--
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 2 +-
drivers/net/wireless/intel/iwlwifi/iwl-config.h | 1 -
drivers/net/wireless/intel/iwlwifi/mld/Makefile | 2 +-
drivers/net/wireless/intel/iwlwifi/mld/d3.c | 2 -
drivers/net/wireless/intel/iwlwifi/mld/debugfs.c | 6 +-
drivers/net/wireless/intel/iwlwifi/mld/iface.c | 21 +-
drivers/net/wireless/intel/iwlwifi/mld/iface.h | 2 +
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 114 ++++++--
drivers/net/wireless/intel/iwlwifi/mld/mld.c | 3 +
drivers/net/wireless/intel/iwlwifi/mld/mld.h | 3 +
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 59 ++--
drivers/net/wireless/intel/iwlwifi/mld/mlo.h | 5 +
drivers/net/wireless/intel/iwlwifi/mld/nan.c | 299 +++++++++++++++++++++
drivers/net/wireless/intel/iwlwifi/mld/nan.h | 28 ++
drivers/net/wireless/intel/iwlwifi/mld/notif.c | 13 +
drivers/net/wireless/intel/iwlwifi/mld/notif.h | 1 +
drivers/net/wireless/intel/iwlwifi/mld/power.c | 37 ++-
.../net/wireless/intel/iwlwifi/mld/regulatory.c | 66 ++++-
drivers/net/wireless/intel/iwlwifi/mld/rx.c | 142 +++++++++-
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 12 +-
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 3 +-
drivers/net/wireless/intel/iwlwifi/mld/tlc.c | 85 +++++-
drivers/net/wireless/intel/iwlwifi/mld/tx.c | 11 +
drivers/net/wireless/intel/iwlwifi/mvm/d3.c | 51 +---
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 202 +++++++++++++-
drivers/net/wireless/intel/iwlwifi/mvm/link.c | 22 --
drivers/net/wireless/intel/iwlwifi/mvm/mac-ctxt.c | 25 +-
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c | 68 +----
drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c | 6 +-
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac.c | 29 --
.../net/wireless/intel/iwlwifi/mvm/mld-mac80211.c | 193 +------------
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c | 28 +-
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 60 +----
drivers/net/wireless/intel/iwlwifi/mvm/rxmq.c | 8 -
drivers/net/wireless/intel/iwlwifi/mvm/scan.c | 18 +-
drivers/net/wireless/intel/iwlwifi/mvm/tdls.c | 4 +-
.../net/wireless/intel/iwlwifi/mvm/time-event.c | 39 +--
.../net/wireless/intel/iwlwifi/mvm/time-event.h | 4 +-
drivers/net/wireless/intel/iwlwifi/mvm/tx.c | 51 +---
drivers/net/wireless/intel/iwlwifi/mvm/utils.c | 4 -
55 files changed, 1591 insertions(+), 925 deletions(-)
create mode 100644 drivers/net/wireless/intel/iwlwifi/mld/nan.c
create mode 100644 drivers/net/wireless/intel/iwlwifi/mld/nan.h
^ permalink raw reply
* [PATCH v2] iwlwifi: pcie: support shutdown operation
From: Li Chen @ 2026-01-21 11:39 UTC (permalink / raw)
To: Miri Korenblit, Johannes Berg, Emmanuel Grumbach,
Yedidya Benshimol, linux-wireless, linux-kernel
Cc: Li Chen
Kexec reboot does not reset PCI devices. If iwlwifi is left running,
the next kernel can time out during probe, breaking networking after
kexec:
kernel: iwlwifi 0000:06:00.0: Host monitor block 0x22 vector 0x0
kernel: iwlwifi 0000:06:00.0: value [iter 0]: 0x00000000
kernel: iwlwifi 0000:06:00.0: probe with driver iwlwifi failed with error -110
Register a dedicated PCI shutdown callback:
run the normal teardown path and then disable the PCI function and
transition it to D3hot so the next kernel can re-initialize it reliably.
Signed-off-by: Li Chen <me@linux.beauty>
---
Changes in v2:
- Don't reuse the ->remove callback for shutdown.
- Disable the PCI function and set D3hot after teardown.
drivers/net/wireless/intel/iwlwifi/pcie/drv.c | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
index dc99e7ac4726..e950aab5a39d 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/drv.c
@@ -1192,6 +1192,21 @@ static void iwl_pci_remove(struct pci_dev *pdev)
iwl_pcie_gen1_2_remove(trans);
}
+static void iwl_pci_shutdown(struct pci_dev *pdev)
+{
+ struct iwl_trans *trans = pci_get_drvdata(pdev);
+
+ if (trans) {
+ iwl_pcie_gen1_2_remove(trans);
+ pci_set_drvdata(pdev, NULL);
+ }
+
+ pci_save_state(pdev);
+ pci_clear_master(pdev);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+}
+
#ifdef CONFIG_PM_SLEEP
static int iwl_pci_suspend(struct device *device)
@@ -1325,6 +1340,7 @@ static struct pci_driver iwl_pci_driver = {
.id_table = iwl_hw_card_ids,
.probe = iwl_pci_probe,
.remove = iwl_pci_remove,
+ .shutdown = iwl_pci_shutdown,
.driver.pm = IWL_PM_OPS,
.driver.coredump = iwl_pci_dump,
};
--
2.52.0
^ permalink raw reply related
* [PATCH v4 ath-current 2/2] dt-bindings: net: wireless: ath11k-pci: deprecate 'firmware-name' property
From: Miaoqing Pan @ 2026-01-21 9:50 UTC (permalink / raw)
To: jjohnson, johannes, robh, krzk+dt, conor+dt
Cc: ath11k, linux-wireless, linux-kernel, devicetree, jonas.gorski,
krzk, Miaoqing Pan
In-Reply-To: <20260121095055.3683957-1-miaoqing.pan@oss.qualcomm.com>
The firmware-name property was originally introduced to allow end-users
and integrators to select use-case-specific firmware for the WCN6855.
However, specifying firmware for an M.2 WLAN module in the Device Tree
is not appropriate. Instead, this functionality will be handled within
the ath11k driver. Therefore, the firmware-name property is now
deprecated.
Acked-by: Rob Herring (Arm) <robh@kernel.org>
Signed-off-by: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
---
.../devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
index e34d42a30192..0162e365798b 100644
--- a/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
+++ b/Documentation/devicetree/bindings/net/wireless/qcom,ath11k-pci.yaml
@@ -37,6 +37,7 @@ properties:
firmware-name:
maxItems: 1
+ deprecated: true
description:
If present, a board or platform specific string used to lookup
usecase-specific firmware files for the device.
--
2.34.1
^ permalink raw reply related
* [PATCH v4 ath-current 1/2] wifi: ath11k: add usecase firmware handling based on device compatible
From: Miaoqing Pan @ 2026-01-21 9:50 UTC (permalink / raw)
To: jjohnson, johannes, robh, krzk+dt, conor+dt
Cc: ath11k, linux-wireless, linux-kernel, devicetree, jonas.gorski,
krzk, Miaoqing Pan
In-Reply-To: <20260121095055.3683957-1-miaoqing.pan@oss.qualcomm.com>
For M.2 WLAN chips, there is no suitable DTS node to specify the
firmware-name property. In addition, assigning firmware for the
M.2 PCIe interface causes chips that do not use usecase specific
firmware to fail. Therefore, abandoning the approach of specifying
firmware in DTS. As an alternative, propose a static lookup table
mapping device compatible to firmware names. Currently, only WCN6855
HW2.1 requires this.
However, support for the firmware-name property is retained to keep
the ABI backwards compatible.
For details on usecase specific firmware, see:
https://lore.kernel.org/all/20250522013444.1301330-3-miaoqing.pan@oss.qualcomm.com/.
Tested-on: WCN6855 hw2.1 PCI WLAN.HSP.1.1-04685-QCAHSPSWPL_V1_V2_SILICONZ_IOE-1
Fixes: edbbc647c4f3 ("wifi: ath11k: support usercase-specific firmware overrides")
Signed-off-by: Miaoqing Pan <miaoqing.pan@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath11k/core.c | 27 ++++++++++++++++++++++++++
drivers/net/wireless/ath/ath11k/core.h | 4 ++++
2 files changed, 31 insertions(+)
diff --git a/drivers/net/wireless/ath/ath11k/core.c b/drivers/net/wireless/ath/ath11k/core.c
index de84906d1b27..3f6f4db5b7ee 100644
--- a/drivers/net/wireless/ath/ath11k/core.c
+++ b/drivers/net/wireless/ath/ath11k/core.c
@@ -1044,6 +1044,33 @@ static const struct dmi_system_id ath11k_pm_quirk_table[] = {
{}
};
+static const struct __ath11k_core_usecase_firmware_table {
+ u32 hw_rev;
+ const char *compatible;
+ const char *firmware_name;
+} ath11k_core_usecase_firmware_table[] = {
+ { ATH11K_HW_WCN6855_HW21, "qcom,lemans-evk", "nfa765"},
+ { ATH11K_HW_WCN6855_HW21, "qcom,monaco-evk", "nfa765"},
+ { ATH11K_HW_WCN6855_HW21, "qcom,hamoa-iot-evk", "nfa765"},
+ { /* Sentinel */ }
+};
+
+const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab)
+{
+ const struct __ath11k_core_usecase_firmware_table *entry = NULL;
+
+ entry = ath11k_core_usecase_firmware_table;
+ while (entry->compatible) {
+ if (ab->hw_rev == entry->hw_rev &&
+ of_machine_is_compatible(entry->compatible))
+ return entry->firmware_name;
+ entry++;
+ }
+
+ return NULL;
+}
+EXPORT_SYMBOL(ath11k_core_get_usecase_firmware);
+
void ath11k_fw_stats_pdevs_free(struct list_head *head)
{
struct ath11k_fw_stats_pdev *i, *tmp;
diff --git a/drivers/net/wireless/ath/ath11k/core.h b/drivers/net/wireless/ath/ath11k/core.h
index 3f41e6569a78..a0d725923ef2 100644
--- a/drivers/net/wireless/ath/ath11k/core.h
+++ b/drivers/net/wireless/ath/ath11k/core.h
@@ -1292,6 +1292,7 @@ bool ath11k_core_coldboot_cal_support(struct ath11k_base *ab);
const struct firmware *ath11k_core_firmware_request(struct ath11k_base *ab,
const char *filename);
+const char *ath11k_core_get_usecase_firmware(struct ath11k_base *ab);
static inline const char *ath11k_scan_state_str(enum ath11k_scan_state state)
{
@@ -1346,6 +1347,9 @@ static inline void ath11k_core_create_firmware_path(struct ath11k_base *ab,
of_property_read_string(ab->dev->of_node, "firmware-name", &fw_name);
+ if (!fw_name)
+ fw_name = ath11k_core_get_usecase_firmware(ab);
+
if (fw_name && strncmp(filename, "board", 5))
snprintf(buf, buf_len, "%s/%s/%s/%s", ATH11K_FW_DIR,
ab->hw_params.fw.dir, fw_name, filename);
--
2.34.1
^ permalink raw reply related
* [PATCH v4 ath-current 0/2] wifi: ath11k: add usecase firmware handling based on device compatible
From: Miaoqing Pan @ 2026-01-21 9:50 UTC (permalink / raw)
To: jjohnson, johannes, robh, krzk+dt, conor+dt
Cc: ath11k, linux-wireless, linux-kernel, devicetree, jonas.gorski,
krzk, Miaoqing Pan
The 'firmware-name' property was introduced to allow end-users and
integrators to select use-case-specific firmware for the WCN6855.
But for M.2 WLAN chips, there is no suitable DTS node to specify
the 'firmware-name' property. In addition, assigning firmware for
the M.2 PCIe interface causes chips that do not use use-case-specific
firmware to fail. Therefore, abandoning the approach of specifying
firmware in DTS. As an alternative, propose a static lookup table
mapping device compatible to firmware names.
---
v2:
- Drops `firmware-name` from completely.
- Updates the commit message to clearly state that the property is
obsolete and the change is ABI-breaking but safe for upstream.
v3:
- Deprecate 'firmware-name' property instead of obsolete.
- Keep the ABI backwards compatible.
v4:
- Use of_machine_is_compatible() to simplify the code.
- Add back Acked-by tag.
---
Miaoqing Pan (2):
wifi: ath11k: add usecase firmware handling based on device compatible
dt-bindings: net: wireless: ath11k-pci: deprecate 'firmware-name'
property
.../net/wireless/qcom,ath11k-pci.yaml | 1 +
drivers/net/wireless/ath/ath11k/core.c | 27 +++++++++++++++++++
drivers/net/wireless/ath/ath11k/core.h | 4 +++
3 files changed, 32 insertions(+)
base-commit: d8e1f4a193101a72235416f189b01131a57e26e9
--
2.34.1
^ permalink raw reply
* Re: [PATCH v2] wifi: p54: Fix memory leak in p54_beacon_update()
From: Zilin Guan @ 2026-01-21 9:05 UTC (permalink / raw)
To: chunkeey
Cc: jianhao.xu, johannes.berg, johannes, linux-kernel, linux-wireless,
quic_rdevanat, zilin
In-Reply-To: <71ec168e-423b-4269-88b9-56e08c1d8110@gmail.com>
On Tue, Jan 20, 2026 at 09:25:15PM +0100, Christian Lamparter wrote:
> Ok, from what I remember, this return basically is/was and likely will be a dead-code path.
> So adding something there is only there to "look" good for the static analysis tools.
> But many commits like these have been merged before. As long as it is mentioned that
> static analysis was the reason for this. Yeah sure why not.
>
>
> Reason being why this is dead-code is that in order for the path to trigger, mac80211's
> ieee80211_beacon_get must have prepared an invalid beacon (with an invalid TIM Element)
> to start with... And looking at ieee80211_beacon_add_tim_pvb, it still looks to me like
> the IE length can't be less than 3 ever. But, I've been wrong before, if you do see please
> correct me. (If not, you don't neet to really bother with the Fixes-Tag)
>
>
> Cheers,
> Christian
Hi Christian,
Thanks for the detailed review.
I agree with your analysis. I checked the code and confirmed that mac80211
guarantees a minimum TIM length of 4 bytes for non-S1G devices.
I appreciate you accepting this patch to silence the static analysis warning.
Best regards,
Zilin Guan
^ permalink raw reply
* mt7996 AP Stops Beaconing after Channel Switch with 6.17+
From: Alex Gavin @ 2026-01-21 4:16 UTC (permalink / raw)
To: nbd, lorenzo, ryder.lee, shayne.chen, sean.wang, deren.wu
Cc: linux-mediatek, linux-wireless, hostap, greearb, chad
Hi there. When performing an AP channel switch using a mt7996 radio,
6.17+ kernels and latest hostapd (both vanilla), the AP stops beaconing
shortly after switching channels. The issue occurs regardless of band
and notably does not occur when using other radios like the mt7915 with
the same kernel and hostapd.
The following command is used to trigger the channel switch from the
hostapd CLI. Running the 'update_beacon' command after restores the AP
back to beaconing state on the new channel. Config file used available
here [1].
chan_switch 3 5745 sec_channel_offset=1 center_freq1=5775 bandwidth=80 he
Interestingly, the CSA count matches the number of beacons sent on the
new channel before stopping. In each of these beacons on the new
channel, the destination MAC is sent with the first octet modified,
which looks a lot like the CSA count decrementing.
For example with CSA count set to three (edited for readability) using a
5 GHz AP initially configured to 5180 MHz switching to 5745 MHz a packet
capture shows the following:
$ tshark -r capture.pcapng
xx:_:xx -> Broadcast 5180MHz ... Beacon frame <- non-CSA
xx:_:xx -> Broadcast 5180MHz ... Beacon frame <- CSA 3
xx:_:xx -> Broadcast 5180MHz ... Beacon frame <- CSA 2
xx:_:xx -> Broadcast 5180MHz ... Beacon frame <- CSA 1
xx:_:xx -> 03:ff:ff:ff:ff:ff 5745MHz ... Beacon frame <- new channel
xx:_:xx -> 02:ff:ff:ff:ff:ff 5745MHz ... Beacon frame
xx:_:xx -> 01:ff:ff:ff:ff:ff 5745MHz ... Beacon frame
(nothing)
This has made for interesting 'spelunking' through the channel switching
and beacon configuration infrastructure. However, I'm not confident I
can come up with a fix in any sort of reasonable timeframe. I'd be happy
to test any proposed fix and/or share any further information needed
(e.g. 'trace-cmd' output).
[1]
https://codeberg.org/a-gavin/hostap-confs/src/branch/main/wpa2/hostapd_5GHz-wpa2.conf
^ permalink raw reply
* [wireless:for-next] BUILD SUCCESS 50b359896fe55d0443ed550e1fabba71d242031a
From: kernel test robot @ 2026-01-21 1:37 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git for-next
branch HEAD: 50b359896fe55d0443ed550e1fabba71d242031a wifi: cfg80211: ignore link disabled flag from userspace
elapsed time: 940m
configs tested: 316
configs skipped: 5
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allmodconfig gcc-15.2.0
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-22
arc allyesconfig gcc-15.2.0
arc defconfig gcc-15.2.0
arc randconfig-001-20260120 gcc-10.5.0
arc randconfig-001-20260121 clang-18
arc randconfig-002-20260120 gcc-8.5.0
arc randconfig-002-20260121 clang-18
arc vdk_hs38_smp_defconfig clang-22
arm allnoconfig clang-22
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm allyesconfig gcc-15.2.0
arm assabet_defconfig clang-22
arm collie_defconfig gcc-15.2.0
arm defconfig clang-22
arm defconfig gcc-15.2.0
arm gemini_defconfig gcc-15.2.0
arm mv78xx0_defconfig gcc-15.2.0
arm orion5x_defconfig gcc-15.2.0
arm randconfig-001-20260120 clang-22
arm randconfig-001-20260121 clang-18
arm randconfig-002-20260120 gcc-13.4.0
arm randconfig-002-20260121 clang-18
arm randconfig-003-20260120 clang-22
arm randconfig-003-20260121 clang-18
arm randconfig-004-20260120 clang-22
arm randconfig-004-20260121 clang-18
arm stm32_defconfig clang-22
arm64 allmodconfig clang-19
arm64 allmodconfig clang-22
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260120 gcc-12.5.0
arm64 randconfig-001-20260121 gcc-15.2.0
arm64 randconfig-002-20260120 gcc-8.5.0
arm64 randconfig-002-20260121 gcc-15.2.0
arm64 randconfig-003-20260120 clang-22
arm64 randconfig-003-20260121 gcc-15.2.0
arm64 randconfig-004-20260120 clang-22
arm64 randconfig-004-20260121 gcc-15.2.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260120 gcc-15.2.0
csky randconfig-001-20260121 gcc-15.2.0
csky randconfig-002-20260120 gcc-15.2.0
csky randconfig-002-20260121 gcc-15.2.0
hexagon allmodconfig clang-17
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig clang-22
hexagon allnoconfig gcc-15.2.0
hexagon defconfig clang-22
hexagon defconfig gcc-15.2.0
hexagon randconfig-001-20260120 clang-22
hexagon randconfig-001-20260121 gcc-15.2.0
hexagon randconfig-002-20260120 clang-22
hexagon randconfig-002-20260121 gcc-15.2.0
i386 allmodconfig clang-20
i386 allmodconfig gcc-14
i386 allnoconfig gcc-14
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 allyesconfig gcc-14
i386 buildonly-randconfig-001-20260120 gcc-14
i386 buildonly-randconfig-001-20260121 clang-20
i386 buildonly-randconfig-002-20260120 gcc-14
i386 buildonly-randconfig-002-20260121 clang-20
i386 buildonly-randconfig-003-20260120 gcc-14
i386 buildonly-randconfig-003-20260121 clang-20
i386 buildonly-randconfig-004-20260120 clang-20
i386 buildonly-randconfig-004-20260121 clang-20
i386 buildonly-randconfig-005-20260120 gcc-14
i386 buildonly-randconfig-005-20260121 clang-20
i386 buildonly-randconfig-006-20260120 gcc-14
i386 buildonly-randconfig-006-20260121 clang-20
i386 defconfig clang-20
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260120 gcc-14
i386 randconfig-001-20260121 clang-20
i386 randconfig-002-20260120 gcc-12
i386 randconfig-002-20260121 clang-20
i386 randconfig-003-20260120 clang-20
i386 randconfig-003-20260121 clang-20
i386 randconfig-004-20260120 clang-20
i386 randconfig-004-20260121 clang-20
i386 randconfig-005-20260120 clang-20
i386 randconfig-005-20260121 clang-20
i386 randconfig-006-20260120 clang-20
i386 randconfig-006-20260121 clang-20
i386 randconfig-007-20260120 gcc-14
i386 randconfig-007-20260121 clang-20
i386 randconfig-011-20260120 clang-20
i386 randconfig-011-20260121 gcc-14
i386 randconfig-012-20260120 gcc-14
i386 randconfig-012-20260121 gcc-14
i386 randconfig-013-20260120 clang-20
i386 randconfig-013-20260121 gcc-14
i386 randconfig-014-20260120 clang-20
i386 randconfig-014-20260121 gcc-14
i386 randconfig-015-20260120 clang-20
i386 randconfig-015-20260121 gcc-14
i386 randconfig-016-20260120 clang-20
i386 randconfig-016-20260121 gcc-14
i386 randconfig-017-20260120 clang-20
i386 randconfig-017-20260121 gcc-14
loongarch allmodconfig clang-19
loongarch allmodconfig clang-22
loongarch allnoconfig clang-22
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch loongson64_defconfig gcc-15.2.0
loongarch randconfig-001-20260120 gcc-12.5.0
loongarch randconfig-001-20260121 gcc-15.2.0
loongarch randconfig-002-20260120 gcc-15.2.0
loongarch randconfig-002-20260121 gcc-15.2.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k allyesconfig gcc-15.2.0
m68k apollo_defconfig clang-22
m68k defconfig clang-19
m68k defconfig gcc-15.2.0
m68k m5307c3_defconfig gcc-15.2.0
m68k mvme16x_defconfig gcc-15.2.0
m68k sun3_defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
microblaze defconfig gcc-15.2.0
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
mips fuloong2e_defconfig gcc-15.2.0
mips malta_qemu_32r6_defconfig gcc-15.2.0
mips rt305x_defconfig gcc-15.2.0
nios2 allmodconfig clang-22
nios2 allmodconfig gcc-11.5.0
nios2 allnoconfig clang-22
nios2 allnoconfig gcc-11.5.0
nios2 defconfig clang-19
nios2 defconfig gcc-11.5.0
nios2 randconfig-001-20260120 gcc-11.5.0
nios2 randconfig-001-20260121 gcc-15.2.0
nios2 randconfig-002-20260120 gcc-11.5.0
nios2 randconfig-002-20260121 gcc-15.2.0
openrisc allmodconfig clang-22
openrisc allmodconfig gcc-15.2.0
openrisc allnoconfig clang-22
openrisc allnoconfig gcc-15.2.0
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-22
parisc allnoconfig gcc-15.2.0
parisc allyesconfig clang-19
parisc allyesconfig gcc-15.2.0
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260120 gcc-8.5.0
parisc randconfig-001-20260121 gcc-9.5.0
parisc randconfig-002-20260120 gcc-9.5.0
parisc randconfig-002-20260121 gcc-9.5.0
parisc64 defconfig clang-19
parisc64 defconfig gcc-15.2.0
powerpc adder875_defconfig gcc-15.2.0
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-22
powerpc allnoconfig gcc-15.2.0
powerpc holly_defconfig clang-22
powerpc linkstation_defconfig gcc-15.2.0
powerpc mpc8313_rdb_defconfig gcc-15.2.0
powerpc powernv_defconfig gcc-15.2.0
powerpc randconfig-001-20260120 clang-19
powerpc randconfig-001-20260121 gcc-9.5.0
powerpc randconfig-002-20260120 gcc-10.5.0
powerpc randconfig-002-20260121 gcc-9.5.0
powerpc tqm8560_defconfig clang-22
powerpc64 randconfig-001-20260120 gcc-12.5.0
powerpc64 randconfig-001-20260121 gcc-9.5.0
powerpc64 randconfig-002-20260120 clang-22
powerpc64 randconfig-002-20260121 gcc-9.5.0
riscv allmodconfig clang-22
riscv allnoconfig clang-22
riscv allnoconfig gcc-15.2.0
riscv allyesconfig clang-16
riscv defconfig clang-22
riscv defconfig gcc-15.2.0
riscv randconfig-001-20260120 gcc-13.4.0
riscv randconfig-001-20260121 clang-16
riscv randconfig-002-20260120 gcc-10.5.0
riscv randconfig-002-20260121 clang-16
s390 allmodconfig clang-18
s390 allmodconfig clang-19
s390 allnoconfig clang-22
s390 allyesconfig gcc-15.2.0
s390 defconfig clang-22
s390 defconfig gcc-15.2.0
s390 randconfig-001-20260120 gcc-15.2.0
s390 randconfig-001-20260121 clang-16
s390 randconfig-002-20260120 clang-22
s390 randconfig-002-20260121 clang-16
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-22
sh allnoconfig gcc-15.2.0
sh allyesconfig clang-19
sh allyesconfig gcc-15.2.0
sh apsh4a3a_defconfig gcc-15.2.0
sh defconfig gcc-14
sh edosk7760_defconfig clang-22
sh edosk7760_defconfig gcc-15.2.0
sh r7780mp_defconfig gcc-15.2.0
sh randconfig-001-20260120 gcc-15.2.0
sh randconfig-001-20260121 clang-16
sh randconfig-002-20260120 gcc-11.5.0
sh randconfig-002-20260121 clang-16
sh rsk7201_defconfig gcc-15.2.0
sh se7343_defconfig gcc-15.2.0
sh se7705_defconfig gcc-15.2.0
sparc alldefconfig clang-22
sparc alldefconfig gcc-15.2.0
sparc allnoconfig clang-22
sparc allnoconfig gcc-15.2.0
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260120 gcc-8.5.0
sparc randconfig-001-20260121 gcc-8.5.0
sparc randconfig-002-20260120 gcc-8.5.0
sparc randconfig-002-20260121 gcc-8.5.0
sparc sparc64_defconfig gcc-15.2.0
sparc64 allmodconfig clang-22
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260120 clang-22
sparc64 randconfig-001-20260121 gcc-8.5.0
sparc64 randconfig-002-20260120 clang-20
sparc64 randconfig-002-20260121 gcc-8.5.0
um allmodconfig clang-19
um allnoconfig clang-22
um allyesconfig gcc-14
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260120 gcc-14
um randconfig-001-20260121 gcc-8.5.0
um randconfig-002-20260120 gcc-14
um randconfig-002-20260121 gcc-8.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-20
x86_64 allnoconfig clang-22
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260120 gcc-14
x86_64 buildonly-randconfig-001-20260121 clang-20
x86_64 buildonly-randconfig-002-20260120 gcc-14
x86_64 buildonly-randconfig-002-20260121 clang-20
x86_64 buildonly-randconfig-003-20260120 gcc-14
x86_64 buildonly-randconfig-003-20260121 clang-20
x86_64 buildonly-randconfig-004-20260120 clang-20
x86_64 buildonly-randconfig-004-20260121 clang-20
x86_64 buildonly-randconfig-005-20260120 gcc-14
x86_64 buildonly-randconfig-005-20260121 clang-20
x86_64 buildonly-randconfig-006-20260120 gcc-14
x86_64 buildonly-randconfig-006-20260121 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001-20260121 clang-20
x86_64 randconfig-002-20260121 clang-20
x86_64 randconfig-002-20260121 gcc-14
x86_64 randconfig-003-20260121 clang-20
x86_64 randconfig-003-20260121 gcc-14
x86_64 randconfig-004-20260121 clang-20
x86_64 randconfig-004-20260121 gcc-14
x86_64 randconfig-005-20260121 clang-20
x86_64 randconfig-006-20260121 clang-20
x86_64 randconfig-011-20260120 clang-20
x86_64 randconfig-011-20260121 gcc-14
x86_64 randconfig-012-20260120 gcc-12
x86_64 randconfig-012-20260121 gcc-14
x86_64 randconfig-013-20260120 clang-20
x86_64 randconfig-013-20260121 gcc-14
x86_64 randconfig-014-20260120 gcc-14
x86_64 randconfig-014-20260121 gcc-14
x86_64 randconfig-015-20260120 clang-20
x86_64 randconfig-015-20260121 gcc-14
x86_64 randconfig-016-20260120 gcc-14
x86_64 randconfig-016-20260121 gcc-14
x86_64 randconfig-071-20260120 gcc-14
x86_64 randconfig-071-20260121 clang-20
x86_64 randconfig-072-20260120 gcc-14
x86_64 randconfig-072-20260121 clang-20
x86_64 randconfig-073-20260120 clang-20
x86_64 randconfig-073-20260121 clang-20
x86_64 randconfig-074-20260120 gcc-14
x86_64 randconfig-074-20260121 clang-20
x86_64 randconfig-075-20260120 clang-20
x86_64 randconfig-075-20260121 clang-20
x86_64 randconfig-076-20260120 clang-20
x86_64 randconfig-076-20260121 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-22
xtensa allnoconfig gcc-15.2.0
xtensa allyesconfig clang-22
xtensa allyesconfig gcc-15.2.0
xtensa randconfig-001-20260120 gcc-13.4.0
xtensa randconfig-001-20260121 gcc-8.5.0
xtensa randconfig-002-20260120 gcc-8.5.0
xtensa randconfig-002-20260121 gcc-8.5.0
xtensa smp_lx200_defconfig gcc-15.2.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v2] wifi: p54: Fix memory leak in p54_beacon_update()
From: Christian Lamparter @ 2026-01-20 20:25 UTC (permalink / raw)
To: Zilin Guan
Cc: quic_rdevanat, johannes.berg, linux-wireless, linux-kernel,
johannes, jianhao.xu
In-Reply-To: <20260120130144.2662132-1-zilin@seu.edu.cn>
Hi,
I'm sorry for not seeing this sooner. Yes, 24hrs are passed.
On 1/20/26 2:01 PM, Zilin Guan wrote:
> In p54_beacon_update(), beacon is allocated via ieee80211_beacon_get().
> If p54_beacon_format_ie_tim() fails, the function returns immediately
> without freeing the allocated beacon skb, leading to a memory leak.
>
> Since no other references to this memory exist, it must be freed locally
> before returning the error. Fix this by freeing the buffer using
> dev_kfree_skb_any() in the error path.
>
> Compile tested only. Issue found using a prototype static analysis tool
> and code review.
Ok, from what I remember, this return basically is/was and likely will be a dead-code path.
So adding something there is only there to "look" good for the static analysis tools.
But many commits like these have been merged before. As long as it is mentioned that
static analysis was the reason for this. Yeah sure why not.
Reason being why this is dead-code is that in order for the path to trigger, mac80211's
ieee80211_beacon_get must have prepared an invalid beacon (with an invalid TIM Element)
to start with... And looking at ieee80211_beacon_add_tim_pvb, it still looks to me like
the IE length can't be less than 3 ever. But, I've been wrong before, if you do see please
correct me. (If not, you don't neet to really bother with the Fixes-Tag)
Cheers,
Christian
>
> Fixes: e5ea92a7528d ("p54: AP & Ad-hoc testing")
> Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
> ---
> Changes in v2:
> - Correct the Fixes tag to point to the commit that introduced this issue.
>
> drivers/net/wireless/intersil/p54/main.c | 4 +++-
> 1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/intersil/p54/main.c b/drivers/net/wireless/intersil/p54/main.c
> index 2ec3655f1a9c..57a62108cbc3 100644
> --- a/drivers/net/wireless/intersil/p54/main.c
> +++ b/drivers/net/wireless/intersil/p54/main.c
> @@ -143,8 +143,10 @@ static int p54_beacon_update(struct p54_common *priv,
> if (!beacon)
> return -ENOMEM;
> ret = p54_beacon_format_ie_tim(beacon);
> - if (ret)
> + if (ret) {
> + dev_kfree_skb_any(beacon);
> return ret;
> + }
Hmm
>
> /*
> * During operation, the firmware takes care of beaconing.
^ permalink raw reply
* [PATCH 13/13] wifi: mt76: mt7925: fix double wcid initialization race condition
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
Remove duplicate mt76_wcid_init() call in mt7925_mac_link_sta_add that
occurs after the wcid is already published via rcu_assign_pointer().
The wcid is correctly initialized at line 1023 after allocation.
However, a second mt76_wcid_init() call at line 1036 reinitializes
the wcid after it has been published to RCU readers, which can cause:
- List head corruption (tx_list, poll_list) if concurrent code is
already using the wcid
- Memory leaks from reinitializing the pktid IDR
- Race conditions where readers see partially initialized state
This appears to be a refactoring error where the duplicate call was
left behind.
Fixes: TBD ("wifi: mt76: mt7925: add MLO support")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 4b7c13485497..acce21ad3a29 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1033,7 +1033,6 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
wcid = &mlink->wcid;
ewma_signal_init(&wcid->rssi);
rcu_assign_pointer(dev->mt76.wcid[wcid->idx], wcid);
- mt76_wcid_init(wcid, 0);
ewma_avg_signal_init(&mlink->avg_ack_signal);
memset(mlink->airtime_ac, 0,
sizeof(msta->deflink.airtime_ac));
--
2.52.0
^ permalink raw reply related
* [PATCH 12/13] wifi: mt76: mt7925: fix ROC deadlocks and race conditions
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
Fix multiple interrelated issues in the remain-on-channel (ROC) handling
that cause deadlocks, race conditions, and resource leaks.
Problems fixed:
1. Deadlock in sta removal ROC abort path:
When a station is removed while a ROC operation is in progress, the
driver would call mt7925_roc_abort_sync() which waits for ROC completion.
However, the ROC work itself needs to acquire mt792x_mutex which is
already held during station removal, causing a deadlock.
Fix: Use async ROC abort (mt76_connac_mcu_abort_roc) when called from
paths that already hold the mutex, and add MT76_STATE_ROC_ABORT flag
to coordinate between the abort and the ROC timer.
2. ROC timer race during suspend:
The ROC timer could fire after the device started suspending but before
the ROC was properly aborted, causing undefined behavior.
Fix: Delete ROC timer synchronously before suspend and check device
state before processing ROC timeout.
3. ROC rate limiting for MLO auth failures:
Rapid ROC requests during MLO authentication can overwhelm the firmware,
causing authentication timeouts. The MT7925 firmware has limited ROC
handling capacity.
Fix: Add rate limiting infrastructure with configurable minimum interval
between ROC requests. Track last ROC completion time and defer new
requests if they arrive too quickly.
4. WCID leak in ROC cleanup:
When ROC operations are aborted, the associated WCID resources were
not being properly released, causing resource exhaustion over time.
Fix: Ensure WCID cleanup happens in all ROC termination paths.
5. Async ROC abort race condition:
The async ROC abort could race with normal ROC completion, causing
double-free or use-after-free of ROC resources.
Fix: Use MT76_STATE_ROC_ABORT flag and proper synchronization to
prevent races between async abort and normal completion paths.
These fixes work together to provide robust ROC handling that doesn't
deadlock, properly releases resources, and handles edge cases during
suspend and MLO operations.
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt76.h | 1 +
.../net/wireless/mediatek/mt76/mt7925/main.c | 175 ++++++++++++++++--
drivers/net/wireless/mediatek/mt76/mt792x.h | 7 +
3 files changed, 171 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt76.h b/drivers/net/wireless/mediatek/mt76/mt76.h
index d05e83ea1cac..91f9dd95c89e 100644
--- a/drivers/net/wireless/mediatek/mt76/mt76.h
+++ b/drivers/net/wireless/mediatek/mt76/mt76.h
@@ -511,6 +511,7 @@ enum {
MT76_STATE_POWER_OFF,
MT76_STATE_SUSPEND,
MT76_STATE_ROC,
+ MT76_STATE_ROC_ABORT,
MT76_STATE_PM,
MT76_STATE_WED_RESET,
};
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 82c81c22e39c..4b7c13485497 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -453,6 +453,24 @@ static void mt7925_roc_iter(void *priv, u8 *mac,
mt7925_mcu_abort_roc(phy, &mvif->bss_conf, phy->roc_token_id);
}
+/* Async ROC abort - safe to call while holding mutex.
+ * Sets abort flag and lets roc_work handle cleanup without blocking.
+ * This prevents deadlock when called from sta_remove path which holds mutex.
+ */
+static void mt7925_roc_abort_async(struct mt792x_dev *dev)
+{
+ struct mt792x_phy *phy = &dev->phy;
+
+ /* Set abort flag - roc_work checks this before acquiring mutex */
+ set_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state);
+
+ /* Stop timer and schedule work to handle cleanup.
+ * Must schedule work since timer may not have fired yet.
+ */
+ timer_delete(&phy->roc_timer);
+ ieee80211_queue_work(phy->mt76->hw, &phy->roc_work);
+}
+
void mt7925_roc_abort_sync(struct mt792x_dev *dev)
{
struct mt792x_phy *phy = &dev->phy;
@@ -477,6 +495,17 @@ void mt7925_roc_work(struct work_struct *work)
phy = (struct mt792x_phy *)container_of(work, struct mt792x_phy,
roc_work);
+ /* Check abort flag BEFORE acquiring mutex to prevent deadlock.
+ * If abort is requested while we're in the sta_remove path (which
+ * holds the mutex), we must not try to acquire it or we'll deadlock.
+ * Clear the flags and only notify mac80211 if ROC was actually active.
+ */
+ if (test_and_clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state)) {
+ if (test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
+ ieee80211_remain_on_channel_expired(phy->mt76->hw);
+ return;
+ }
+
if (!test_and_clear_bit(MT76_STATE_ROC, &phy->mt76->state))
return;
@@ -504,14 +533,93 @@ static int mt7925_abort_roc(struct mt792x_phy *phy,
return err;
}
+/* ROC rate limiting constants - exponential backoff to prevent MCU overload
+ * when upper layers trigger rapid reconnection cycles (e.g., MLO auth failures).
+ * Max backoff ~1.6s, resets after 10s of no timeouts.
+ */
+#define MT7925_ROC_BACKOFF_BASE_MS 100
+#define MT7925_ROC_BACKOFF_MAX_MS 1600
+#define MT7925_ROC_TIMEOUT_RESET_MS 10000
+#define MT7925_ROC_TIMEOUT_WARN_THRESH 5
+
+/* Check if ROC should be throttled due to recent timeouts.
+ * Returns delay in jiffies if throttling, 0 if OK to proceed.
+ */
+static unsigned long mt7925_roc_throttle_check(struct mt792x_phy *phy)
+{
+ unsigned long now = jiffies;
+
+ /* Reset timeout counter if it's been a while since last timeout */
+ if (phy->roc_timeout_count &&
+ time_after(now, phy->roc_last_timeout +
+ msecs_to_jiffies(MT7925_ROC_TIMEOUT_RESET_MS))) {
+ phy->roc_timeout_count = 0;
+ phy->roc_backoff_until = 0;
+ }
+
+ /* Check if we're still in backoff period */
+ if (phy->roc_backoff_until && time_before(now, phy->roc_backoff_until))
+ return phy->roc_backoff_until - now;
+
+ return 0;
+}
+
+/* Record ROC timeout and calculate backoff period */
+static void mt7925_roc_record_timeout(struct mt792x_phy *phy)
+{
+ unsigned int backoff_ms;
+
+ phy->roc_last_timeout = jiffies;
+ phy->roc_timeout_count++;
+
+ /* Exponential backoff: 100ms, 200ms, 400ms, 800ms, 1600ms (capped) */
+ backoff_ms = MT7925_ROC_BACKOFF_BASE_MS <<
+ min_t(u8, phy->roc_timeout_count - 1, 4);
+ if (backoff_ms > MT7925_ROC_BACKOFF_MAX_MS)
+ backoff_ms = MT7925_ROC_BACKOFF_MAX_MS;
+
+ phy->roc_backoff_until = jiffies + msecs_to_jiffies(backoff_ms);
+
+ /* Warn if we're seeing repeated timeouts - likely upper layer issue */
+ if (phy->roc_timeout_count == MT7925_ROC_TIMEOUT_WARN_THRESH)
+ dev_warn(phy->dev->mt76.dev,
+ "mt7925: %u consecutive ROC timeouts, possible mac80211/wpa_supplicant issue (MLO key race?)\n",
+ phy->roc_timeout_count);
+}
+
+/* Clear timeout tracking on successful ROC */
+static void mt7925_roc_clear_timeout(struct mt792x_phy *phy)
+{
+ phy->roc_timeout_count = 0;
+ phy->roc_backoff_until = 0;
+}
+
static int mt7925_set_roc(struct mt792x_phy *phy,
struct mt792x_bss_conf *mconf,
struct ieee80211_channel *chan,
int duration,
enum mt7925_roc_req type)
{
+ unsigned long throttle;
int err;
+ /* Check rate limiting - if in backoff period, wait or return busy */
+ throttle = mt7925_roc_throttle_check(phy);
+ if (throttle) {
+ /* For short backoffs, wait; for longer ones, return busy */
+ if (throttle < msecs_to_jiffies(200)) {
+ msleep(jiffies_to_msecs(throttle));
+ } else {
+ dev_dbg(phy->dev->mt76.dev,
+ "mt7925: ROC throttled, %u ms remaining\n",
+ jiffies_to_msecs(throttle));
+ return -EBUSY;
+ }
+ }
+
+ /* Clear stale abort flag from previous ROC */
+ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state);
+
if (test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state))
return -EBUSY;
@@ -527,7 +635,11 @@ static int mt7925_set_roc(struct mt792x_phy *phy,
if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) {
mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id);
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ mt7925_roc_record_timeout(phy);
err = -ETIMEDOUT;
+ } else {
+ /* Successful ROC - reset timeout tracking */
+ mt7925_roc_clear_timeout(phy);
}
out:
@@ -538,8 +650,27 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
struct mt792x_bss_conf *mconf,
u16 sel_links)
{
+ unsigned long throttle;
int err;
+ /* Check rate limiting - MLO ROC is especially prone to rapid-fire
+ * during reconnection cycles after MLO authentication failures.
+ */
+ throttle = mt7925_roc_throttle_check(phy);
+ if (throttle) {
+ if (throttle < msecs_to_jiffies(200)) {
+ msleep(jiffies_to_msecs(throttle));
+ } else {
+ dev_dbg(phy->dev->mt76.dev,
+ "mt7925: MLO ROC throttled, %u ms remaining\n",
+ jiffies_to_msecs(throttle));
+ return -EBUSY;
+ }
+ }
+
+ /* Clear stale abort flag from previous ROC */
+ clear_bit(MT76_STATE_ROC_ABORT, &phy->mt76->state);
+
if (WARN_ON_ONCE(test_and_set_bit(MT76_STATE_ROC, &phy->mt76->state)))
return -EBUSY;
@@ -554,7 +685,10 @@ static int mt7925_set_mlo_roc(struct mt792x_phy *phy,
if (!wait_event_timeout(phy->roc_wait, phy->roc_grant, 4 * HZ)) {
mt7925_mcu_abort_roc(phy, mconf, phy->roc_token_id);
clear_bit(MT76_STATE_ROC, &phy->mt76->state);
+ mt7925_roc_record_timeout(phy);
err = -ETIMEDOUT;
+ } else {
+ mt7925_roc_clear_timeout(phy);
}
out:
@@ -571,6 +705,7 @@ static int mt7925_remain_on_channel(struct ieee80211_hw *hw,
struct mt792x_phy *phy = mt792x_hw_phy(hw);
int err;
+ cancel_work_sync(&phy->roc_work);
mt792x_mutex_acquire(phy->dev);
err = mt7925_set_roc(phy, &mvif->bss_conf,
chan, duration, MT7925_ROC_REQ_ROC);
@@ -878,14 +1013,14 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
if (!mlink)
return -EINVAL;
- idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
- if (idx < 0)
- return -ENOSPC;
-
mconf = mt792x_vif_to_link(mvif, link_id);
if (!mconf)
return -EINVAL;
+ idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
+ if (idx < 0)
+ return -ENOSPC;
+
mt76_wcid_init(&mlink->wcid, 0);
mlink->wcid.sta = 1;
mlink->wcid.idx = idx;
@@ -905,14 +1040,16 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt76_connac_pm_wake(&dev->mphy, &dev->pm);
if (ret)
- return ret;
+ goto err_wcid;
mt7925_mac_wtbl_update(dev, idx,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
- if (!link_conf)
- return -EINVAL;
+ if (!link_conf) {
+ ret = -EINVAL;
+ goto err_wcid;
+ }
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
@@ -924,7 +1061,7 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
link_conf, link_sta, false);
if (ret)
- return ret;
+ goto err_wcid;
}
if (ieee80211_vif_is_mld(vif) &&
@@ -932,28 +1069,34 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto err_wcid;
} else if (ieee80211_vif_is_mld(vif) &&
link_sta != mlink->pri_link) {
ret = mt7925_mcu_sta_update(dev, mlink->pri_link, vif,
true, MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto err_wcid;
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_ASSOC);
if (ret)
- return ret;
+ goto err_wcid;
} else {
ret = mt7925_mcu_sta_update(dev, link_sta, vif, true,
MT76_STA_INFO_STATE_NONE);
if (ret)
- return ret;
+ goto err_wcid;
}
mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
return 0;
+
+err_wcid:
+ rcu_assign_pointer(dev->mt76.wcid[idx], NULL);
+ mt76_wcid_mask_clear(dev->mt76.wcid_mask, idx);
+ mt76_connac_power_save_sched(&dev->mphy, &dev->pm);
+ return ret;
}
static int
@@ -1139,6 +1282,9 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
if (!mlink)
return;
+ /* With Sean's fix, roc_abort_sync uses cancel_work() instead of
+ * cancel_work_sync(), so it's safe to call even with mutex held.
+ */
mt7925_roc_abort_sync(dev);
mt76_connac_free_pending_tx_skbs(&dev->pm, &mlink->wcid);
@@ -1534,6 +1680,8 @@ static int mt7925_suspend(struct ieee80211_hw *hw,
cancel_delayed_work_sync(&dev->pm.ps_work);
mt76_connac_free_pending_tx_skbs(&dev->pm, NULL);
+ /* Cancel ROC before quiescing starts */
+ mt7925_roc_abort_sync(dev);
mt792x_mutex_acquire(dev);
clear_bit(MT76_STATE_RUNNING, &phy->mt76->state);
@@ -1880,6 +2028,8 @@ static void mt7925_mgd_prepare_tx(struct ieee80211_hw *hw,
u16 duration = info->duration ? info->duration :
jiffies_to_msecs(HZ);
+ cancel_work_sync(&mvif->phy->roc_work);
+
mt792x_mutex_acquire(dev);
mt7925_set_roc(mvif->phy, &mvif->bss_conf,
mvif->bss_conf.mt76.ctx->def.chan, duration,
@@ -2037,6 +2187,7 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
if (old_links == new_links)
return 0;
+ cancel_work_sync(&phy->roc_work);
mt792x_mutex_acquire(dev);
for_each_set_bit(link_id, &rem, IEEE80211_MLD_MAX_NUM_LINKS) {
diff --git a/drivers/net/wireless/mediatek/mt76/mt792x.h b/drivers/net/wireless/mediatek/mt76/mt792x.h
index 8388638ed550..d9c1ea709390 100644
--- a/drivers/net/wireless/mediatek/mt76/mt792x.h
+++ b/drivers/net/wireless/mediatek/mt76/mt792x.h
@@ -186,6 +186,13 @@ struct mt792x_phy {
wait_queue_head_t roc_wait;
u8 roc_token_id;
bool roc_grant;
+
+ /* ROC rate limiting to prevent MCU overload during rapid reconnection
+ * cycles (e.g., MLO authentication failures causing repeated ROC).
+ */
+ u8 roc_timeout_count; /* consecutive ROC timeouts */
+ unsigned long roc_last_timeout; /* jiffies of last timeout */
+ unsigned long roc_backoff_until;/* don't issue ROC until this time */
};
struct mt792x_irq_map {
--
2.52.0
^ permalink raw reply related
* [PATCH 11/13] wifi: mt76: mt7925: fix BA session teardown during beacon loss
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
The ieee80211_stop_tx_ba_cb_irqsafe() callback was conditionally called
only when the MCU command succeeded. However, during beacon connection
loss, the MCU command may fail because the AP is no longer reachable.
If the callback is not called, mac80211's BA session state machine gets
stuck in an intermediate state. When mac80211 later tries to tear down
all BA sessions during disconnection, it hits a WARN in
__ieee80211_stop_tx_ba_session() due to the inconsistent state.
Fix by making the callback unconditional, matching the behavior of
mt7921 and mt7996 drivers. The MCU command failure is acceptable during
disconnection - what matters is that mac80211 is notified to complete
the session teardown.
Reported-by: Sean Wang <sean.wang@mediatek.com>
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/main.c | 10 +++++++---
1 file changed, 7 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 7d68b08f445a..82c81c22e39c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -1327,9 +1327,13 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
- ret = mt7925_mcu_uni_tx_ba(dev, params, false);
- if (!ret)
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ /* MCU command may fail during beacon loss, but callback must
+ * always be called to complete the BA session teardown in
+ * mac80211. Otherwise the state machine gets stuck and triggers
+ * WARN in __ieee80211_stop_tx_ba_session().
+ */
+ mt7925_mcu_uni_tx_ba(dev, params, false);
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mt792x_mutex_release(dev);
--
2.52.0
^ permalink raw reply related
* [PATCH 10/13] wifi: mt76: mt7925: fix MLO roaming and ROC setup issues
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
Fix two issues related to MLO roaming and remain-on-channel operations:
1. Key removal failure during MLO roaming:
During MLO roaming, key removal can fail because the WCID (wireless client
ID) is already cleaned up before the key removal operation completes.
When roaming between APs in an MLO setup:
- mac80211 triggers sta_state changes
- mt7925_mac_link_sta_remove() is called for the old link
- WCID is cleared via mt76_wcid_cleanup()
- Later, key removal MCU command uses the now-invalid WCID
Fix by checking if the WCID is still valid before sending key removal
commands to firmware. If the WCID has already been cleaned up, skip
the MCU command since the firmware has already removed the keys.
2. Kernel warning in MLO ROC setup:
When starting a remain-on-channel operation in MLO mode, the driver
passes incorrect parameters to mt7925_mcu_set_roc(), causing a kernel
warning about invalid chanctx usage.
Fix by checking for valid chanctx and link configuration before
setting up ROC, and use the correct link_id from the vif when
available.
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 9 ++++++++-
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 20 +++++++++++++------
2 files changed, 22 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 59a5b22a6ed6..7d68b08f445a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -609,8 +609,15 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
mconf = mt792x_vif_to_link(mvif, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
- if (!link_conf || !mconf || !mlink)
+ if (!link_conf || !mconf || !mlink) {
+ /* During MLO roaming, link state may be torn down before
+ * mac80211 requests key removal. If removing a key and
+ * the link is already gone, consider it successfully removed.
+ */
+ if (cmd != SET_KEY)
+ return 0;
return -EINVAL;
+ }
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 1c58b0be2be4..6f7fc1b9a440 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1342,15 +1342,23 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
for (i = 0; i < ARRAY_SIZE(links); i++) {
links[i].id = i ? __ffs(~BIT(mconf->link_id) & sel_links) :
mconf->link_id;
+
link_conf = mt792x_vif_to_bss_conf(vif, links[i].id);
- if (WARN_ON_ONCE(!link_conf))
- return -EPERM;
+ if (!link_conf)
+ return -ENOLINK;
links[i].chan = link_conf->chanreq.oper.chan;
- if (WARN_ON_ONCE(!links[i].chan))
- return -EPERM;
+ if (!links[i].chan)
+ /* Channel not configured yet - this can happen during
+ * MLO AP setup when links are being added sequentially.
+ * Return -ENOLINK to indicate link not ready.
+ */
+ return -ENOLINK;
links[i].mconf = mt792x_vif_to_link(mvif, links[i].id);
+ if (!links[i].mconf)
+ return -ENOLINK;
+
links[i].tag = links[i].id == mconf->link_id ?
UNI_ROC_ACQUIRE : UNI_ROC_SUB_LINK;
@@ -1364,8 +1372,8 @@ int mt7925_mcu_set_mlo_roc(struct mt792x_bss_conf *mconf, u16 sel_links,
type = MT7925_ROC_REQ_JOIN;
for (i = 0; i < ARRAY_SIZE(links) && i < hweight16(vif->active_links); i++) {
- if (WARN_ON_ONCE(!links[i].mconf || !links[i].chan))
- continue;
+ if (!links[i].mconf || !links[i].chan)
+ return -ENOLINK;
chan = links[i].chan;
center_ch = ieee80211_frequency_to_channel(chan->center_freq);
--
2.52.0
^ permalink raw reply related
* [PATCH 09/13] wifi: mt76: mt7925: add lockdep assertions for mutex verification
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
Add lockdep_assert_held() calls to critical MCU functions to help catch
mutex violations during development and debugging. This follows the
pattern used in other mt76 drivers (mt7996, mt7915, mt7615).
Functions with new assertions:
- mt7925_mcu_add_bss_info(): Core BSS configuration MCU command
- mt7925_mcu_sta_update(): Station record update MCU command
- mt7925_mcu_uni_bss_ps(): Power save state MCU command
These functions modify firmware state and must be called with the
device mutex held to prevent race conditions. The lockdep assertions
will trigger warnings at runtime if code paths exist that call these
functions without proper mutex protection.
This aids in detecting the class of bugs fixed by patches in this series.
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
drivers/net/wireless/mediatek/mt76/mt7925/mcu.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 94ec62a4538a..1c58b0be2be4 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1532,6 +1532,8 @@ int mt7925_mcu_uni_bss_ps(struct mt792x_dev *dev,
},
};
+ lockdep_assert_held(&dev->mt76.mutex);
+
if (link_conf->vif->type != NL80211_IFTYPE_STATION)
return -EOPNOTSUPP;
@@ -2047,6 +2049,8 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
struct mt792x_sta *msta;
struct mt792x_link_sta *mlink = NULL;
+ lockdep_assert_held(&dev->mt76.mutex);
+
if (link_sta) {
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
@@ -2853,6 +2857,8 @@ int mt7925_mcu_add_bss_info(struct mt792x_phy *phy,
struct mt792x_link_sta *mlink_bc;
struct sk_buff *skb;
+ lockdep_assert_held(&dev->mt76.mutex);
+
skb = __mt7925_mcu_alloc_bss_req(&dev->mt76, &mconf->mt76,
MT7925_BSS_UPDATE_MAX_SIZE);
if (IS_ERR(skb))
--
2.52.0
^ permalink raw reply related
* [PATCH 08/13] wifi: mt76: mt7925: add MCU command error handling
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
Add proper error handling for MCU command return values that were
previously being ignored. Without proper error handling, failures in
MCU communication can leave the driver in an inconsistent state.
Functions updated:
1. main.c: mt7925_ampdu_action() - BA session setup
- Check mt7925_mcu_uni_tx_ba() return value
- Check mt7925_mcu_uni_rx_ba() return value
- Return error to mac80211 on failure
2. main.c: mt7925_mac_link_sta_add() - Station addition
- Check mt7925_mcu_add_bss_info() return value
- Propagate errors during station setup
3. main.c: mt7925_set_key() - Key installation
- Check mt7925_mcu_add_bss_info() return value when setting
BSS info before key installation
- Prevent key setup on communication failure
These changes ensure that MCU communication failures are properly
detected and reported to mac80211, allowing proper error recovery
instead of leaving the driver in an undefined state.
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/main.c | 30 +++++++++++--------
1 file changed, 18 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index f1884944f77d..59a5b22a6ed6 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -641,8 +641,10 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
struct mt792x_phy *phy = mt792x_hw_phy(hw);
mconf->mt76.cipher = mt7925_mcu_get_cipher(key->cipher);
- mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf,
- link_sta, true);
+ err = mt7925_mcu_add_bss_info(phy, mconf->mt76.ctx, link_conf,
+ link_sta, true);
+ if (err)
+ goto out;
}
if (cmd == SET_KEY)
@@ -908,11 +910,14 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
if (ieee80211_vif_is_mld(vif))
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, link_sta != mlink->pri_link);
+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta,
+ link_sta != mlink->pri_link);
else
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, false);
+ ret = mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta, false);
+ if (ret)
+ return ret;
}
if (ieee80211_vif_is_mld(vif) &&
@@ -1291,22 +1296,22 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_RX_START:
mt76_rx_aggr_start(&dev->mt76, &msta->deflink.wcid, tid, ssn,
params->buf_size);
- mt7925_mcu_uni_rx_ba(dev, params, true);
+ ret = mt7925_mcu_uni_rx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_RX_STOP:
mt76_rx_aggr_stop(&dev->mt76, &msta->deflink.wcid, tid);
- mt7925_mcu_uni_rx_ba(dev, params, false);
+ ret = mt7925_mcu_uni_rx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
mtxq->aggr = true;
mtxq->send_bar = false;
- mt7925_mcu_uni_tx_ba(dev, params, true);
+ ret = mt7925_mcu_uni_tx_ba(dev, params, true);
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
mtxq->aggr = false;
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
- mt7925_mcu_uni_tx_ba(dev, params, false);
+ ret = mt7925_mcu_uni_tx_ba(dev, params, false);
break;
case IEEE80211_AMPDU_TX_START:
set_bit(tid, &msta->deflink.wcid.ampdu_state);
@@ -1315,8 +1320,9 @@ mt7925_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
case IEEE80211_AMPDU_TX_STOP_CONT:
mtxq->aggr = false;
clear_bit(tid, &msta->deflink.wcid.ampdu_state);
- mt7925_mcu_uni_tx_ba(dev, params, false);
- ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
+ ret = mt7925_mcu_uni_tx_ba(dev, params, false);
+ if (!ret)
+ ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
}
mt792x_mutex_release(dev);
--
2.52.0
^ permalink raw reply related
* [PATCH 06/13] wifi: mt76: mt7925: add comprehensive NULL pointer protection for MLO
From: Zac @ 2026-01-20 20:10 UTC (permalink / raw)
To: sean.wang
Cc: deren.wu, kvalo, linux-kernel, linux-mediatek, linux-wireless,
linux, lorenzo, nbd, ryder.lee, sean.wang, zac, zbowling
In-Reply-To: <20260120201043.38225-1-zac@zacbowling.com>
From: Zac Bowling <zac@zacbowling.com>
Add NULL pointer checks for functions that return pointers to link-related
structures throughout the mt7925 driver. During MLO state transitions,
these functions can return NULL when link configuration is not synchronized.
Functions protected:
- mt792x_vif_to_bss_conf(): Returns link BSS configuration
- mt792x_vif_to_link(): Returns driver link state
- mt792x_sta_to_link(): Returns station link state
Files updated:
1. mac.c:
- mt7925_vif_connect_iter(): Check bss_conf before use
- mt7925_mac_sta_assoc(): Check bss_conf before use
2. main.c:
- mt7925_set_key(): Check link_conf and mlink
- mt7925_mac_link_sta_add(): Check link_conf and mlink
- mt7925_mac_link_sta_assoc(): Check bss_conf and mlink
- mt7925_mac_link_sta_remove(): Check bss_conf and mlink
- mt7925_change_vif_links(): Check conf before use
- mt7925_assign_vif_chanctx(): Check mconf and mlink
- mt7925_unassign_vif_chanctx(): Check mconf and mlink
- mt7925_mgd_prepare_tx(): Check link_conf
3. mcu.c:
- mt7925_mcu_sta_phy_tlv(): Check link_sta
- mt7925_mcu_sta_amsdu_tlv(): Check link_sta
- mt7925_mcu_sta_mld_tlv(): Check link_sta
- mt7925_mcu_sta_cmd(): Check mlink
- mt7925_mcu_add_bss_info(): Check link_conf
- mt7925_mcu_set_chctx(): Check link_conf and mlink
Prevents crashes during:
- BSSID roaming transitions
- MLO setup and teardown
- Hardware reset operations
- Runtime power management
Fixes: c948b5da6bbe ("wifi: mt76: mt7925: add Mediatek Wi-Fi7 driver for mt7925 device")
Signed-off-by: Zac Bowling <zac@zacbowling.com>
---
.../net/wireless/mediatek/mt76/mt7925/mac.c | 6 ++
.../net/wireless/mediatek/mt76/mt7925/main.c | 82 ++++++++++++++++---
.../net/wireless/mediatek/mt76/mt7925/mcu.c | 22 ++++-
3 files changed, 97 insertions(+), 13 deletions(-)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
index 871b67101976..184efe8afa10 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mac.c
@@ -1271,6 +1271,12 @@ mt7925_vif_connect_iter(void *priv, u8 *mac,
bss_conf = mt792x_vif_to_bss_conf(vif, i);
mconf = mt792x_vif_to_link(mvif, i);
+ /* Skip links that don't have bss_conf set up yet in mac80211.
+ * This can happen during HW reset when link state is inconsistent.
+ */
+ if (!bss_conf)
+ continue;
+
mt76_connac_mcu_uni_add_dev(&dev->mphy, bss_conf, &mconf->mt76,
&mvif->sta.deflink.wcid, true);
mt7925_mcu_set_tx(dev, bss_conf);
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/main.c b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
index 05990455ee7d..74a48742e234 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/main.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/main.c
@@ -608,6 +608,10 @@ static int mt7925_set_link_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
link_sta = sta ? mt792x_sta_to_link_sta(vif, sta, link_id) : NULL;
mconf = mt792x_vif_to_link(mvif, link_id);
mlink = mt792x_sta_to_link(msta, link_id);
+
+ if (!link_conf || !mconf || !mlink)
+ return -EINVAL;
+
wcid = &mlink->wcid;
wcid_keyidx = &wcid->hw_key_idx;
@@ -860,12 +864,17 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return -EINVAL;
idx = mt76_wcid_alloc(dev->mt76.wcid_mask, MT792x_WTBL_STA - 1);
if (idx < 0)
return -ENOSPC;
mconf = mt792x_vif_to_link(mvif, link_id);
+ if (!mconf)
+ return -EINVAL;
+
mt76_wcid_init(&mlink->wcid, 0);
mlink->wcid.sta = 1;
mlink->wcid.idx = idx;
@@ -891,6 +900,8 @@ static int mt7925_mac_link_sta_add(struct mt76_dev *mdev,
MT_WTBL_UPDATE_ADM_COUNT_CLEAR);
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ if (!link_conf)
+ return -EINVAL;
/* should update bss info before STA add */
if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
@@ -997,18 +1008,29 @@ mt7925_mac_set_links(struct mt76_dev *mdev, struct ieee80211_vif *vif)
{
struct mt792x_dev *dev = container_of(mdev, struct mt792x_dev, mt76);
struct mt792x_vif *mvif = (struct mt792x_vif *)vif->drv_priv;
- struct ieee80211_bss_conf *link_conf =
- mt792x_vif_to_bss_conf(vif, mvif->deflink_id);
- struct cfg80211_chan_def *chandef = &link_conf->chanreq.oper;
- enum nl80211_band band = chandef->chan->band, secondary_band;
+ struct ieee80211_bss_conf *link_conf;
+ struct cfg80211_chan_def *chandef;
+ enum nl80211_band band, secondary_band;
+ u16 sel_links;
+ u8 secondary_link_id;
- u16 sel_links = mt76_select_links(vif, 2);
- u8 secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links);
+ link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id);
+ if (!link_conf)
+ return;
+
+ chandef = &link_conf->chanreq.oper;
+ band = chandef->chan->band;
+
+ sel_links = mt76_select_links(vif, 2);
+ secondary_link_id = __ffs(~BIT(mvif->deflink_id) & sel_links);
if (!ieee80211_vif_is_mld(vif) || hweight16(sel_links) < 2)
return;
link_conf = mt792x_vif_to_bss_conf(vif, secondary_link_id);
+ if (!link_conf)
+ return;
+
secondary_band = link_conf->chanreq.oper.chan->band;
if (band == NL80211_BAND_2GHZ ||
@@ -1036,6 +1058,8 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
mt792x_mutex_acquire(dev);
@@ -1045,12 +1069,13 @@ static void mt7925_mac_link_sta_assoc(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, vif->bss_conf.link_id);
}
- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_bss_conf *mconf;
mconf = mt792x_link_conf_to_mconf(link_conf);
- mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
- link_conf, link_sta, true);
+ if (mconf)
+ mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx,
+ link_conf, link_sta, true);
}
ewma_avg_signal_init(&mlink->avg_ack_signal);
@@ -1097,6 +1122,8 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_id);
+ if (!mlink)
+ return;
mt7925_roc_abort_sync(dev);
@@ -1110,10 +1137,12 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
- if (vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
+ if (link_conf && vif->type == NL80211_IFTYPE_STATION && !link_sta->sta->tdls) {
struct mt792x_bss_conf *mconf;
mconf = mt792x_link_conf_to_mconf(link_conf);
+ if (!mconf)
+ goto out;
if (ieee80211_vif_is_mld(vif))
mt792x_mac_link_bss_remove(dev, mconf, mlink);
@@ -1121,6 +1150,7 @@ static void mt7925_mac_link_sta_remove(struct mt76_dev *mdev,
mt7925_mcu_add_bss_info(&dev->phy, mconf->mt76.ctx, link_conf,
link_sta, false);
}
+out:
spin_lock_bh(&mdev->sta_poll_lock);
if (!list_empty(&mlink->wcid.poll_list))
@@ -1308,6 +1338,8 @@ mt7925_mlo_pm_iter(void *priv, u8 *mac, struct ieee80211_vif *vif)
mt792x_mutex_acquire(dev);
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
bss_conf = mt792x_vif_to_bss_conf(vif, i);
+ if (!bss_conf)
+ continue;
mt7925_mcu_uni_bss_ps(dev, bss_conf);
}
mt792x_mutex_release(dev);
@@ -1634,6 +1666,8 @@ static void mt7925_ipv6_addr_change(struct ieee80211_hw *hw,
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
bss_conf = mt792x_vif_to_bss_conf(vif, i);
+ if (!bss_conf)
+ continue;
__mt7925_ipv6_addr_change(hw, bss_conf, idev);
}
}
@@ -1695,6 +1729,9 @@ mt7925_conf_tx(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
[IEEE80211_AC_BK] = 1,
};
+ if (!mconf)
+ return -EINVAL;
+
/* firmware uses access class index */
mconf->queue_params[mq_to_aci[queue]] = *params;
@@ -1865,6 +1902,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
if (changed & BSS_CHANGED_ARP_FILTER) {
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
bss_conf = mt792x_vif_to_bss_conf(vif, i);
+ if (!bss_conf)
+ continue;
mt7925_mcu_update_arp_filter(&dev->mt76, bss_conf);
}
}
@@ -1880,6 +1919,8 @@ static void mt7925_vif_cfg_changed(struct ieee80211_hw *hw,
} else if (mvif->mlo_pm_state == MT792x_MLO_CHANGED_PS) {
for_each_set_bit(i, &valid, IEEE80211_MLD_MAX_NUM_LINKS) {
bss_conf = mt792x_vif_to_bss_conf(vif, i);
+ if (!bss_conf)
+ continue;
mt7925_mcu_uni_bss_ps(dev, bss_conf);
}
}
@@ -1901,7 +1942,12 @@ static void mt7925_link_info_changed(struct ieee80211_hw *hw,
struct ieee80211_bss_conf *link_conf;
mconf = mt792x_vif_to_link(mvif, info->link_id);
+ if (!mconf)
+ return;
+
link_conf = mt792x_vif_to_bss_conf(vif, mconf->link_id);
+ if (!link_conf)
+ return;
mt792x_mutex_acquire(dev);
@@ -2025,6 +2071,11 @@ mt7925_change_vif_links(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
mlink = mlinks[link_id];
link_conf = mt792x_vif_to_bss_conf(vif, link_id);
+ if (!link_conf) {
+ err = -EINVAL;
+ goto free;
+ }
+
rcu_assign_pointer(mvif->link_conf[link_id], mconf);
rcu_assign_pointer(mvif->sta.link[link_id], mlink);
@@ -2105,9 +2156,14 @@ static int mt7925_assign_vif_chanctx(struct ieee80211_hw *hw,
if (ieee80211_vif_is_mld(vif)) {
mconf = mt792x_vif_to_link(mvif, link_conf->link_id);
+ if (!mconf) {
+ mutex_unlock(&dev->mt76.mutex);
+ return -EINVAL;
+ }
+
pri_link_conf = mt792x_vif_to_bss_conf(vif, mvif->deflink_id);
- if (vif->type == NL80211_IFTYPE_STATION &&
+ if (pri_link_conf && vif->type == NL80211_IFTYPE_STATION &&
mconf == &mvif->bss_conf)
mt7925_mcu_add_bss_info(&dev->phy, NULL, pri_link_conf,
NULL, true);
@@ -2136,6 +2192,10 @@ static void mt7925_unassign_vif_chanctx(struct ieee80211_hw *hw,
if (ieee80211_vif_is_mld(vif)) {
mconf = mt792x_vif_to_link(mvif, link_conf->link_id);
+ if (!mconf) {
+ mutex_unlock(&dev->mt76.mutex);
+ return;
+ }
if (vif->type == NL80211_IFTYPE_STATION &&
mconf == &mvif->bss_conf)
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index cf0fdea45cf7..94ec62a4538a 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1087,6 +1087,8 @@ mt7925_mcu_sta_hdr_trans_tlv(struct sk_buff *skb,
struct mt792x_link_sta *mlink;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
wcid = &mlink->wcid;
} else {
wcid = &mvif->sta.deflink.wcid;
@@ -1120,6 +1122,9 @@ int mt7925_mcu_wtbl_update_hdr_trans(struct mt792x_dev *dev,
link_sta = mt792x_sta_to_link_sta(vif, sta, link_id);
mconf = mt792x_vif_to_link(mvif, link_id);
+ if (!mlink || !mconf)
+ return -EINVAL;
+
skb = __mt76_connac_mcu_alloc_sta_req(&dev->mt76, &mconf->mt76,
&mlink->wcid,
MT7925_STA_UPDATE_MAX_SIZE);
@@ -1741,6 +1746,8 @@ mt7925_mcu_sta_amsdu_tlv(struct sk_buff *skb,
amsdu->amsdu_en = true;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
+ if (!mlink)
+ return;
mlink->wcid.amsdu = true;
switch (link_sta->agg.max_amsdu_len) {
@@ -1773,6 +1780,10 @@ mt7925_mcu_sta_phy_tlv(struct sk_buff *skb,
link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id);
mconf = mt792x_vif_to_link(mvif, link_sta->link_id);
+
+ if (!link_conf || !mconf)
+ return;
+
chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def :
&link_conf->chanreq.oper;
@@ -1851,6 +1862,10 @@ mt7925_mcu_sta_rate_ctrl_tlv(struct sk_buff *skb,
link_conf = mt792x_vif_to_bss_conf(vif, link_sta->link_id);
mconf = mt792x_vif_to_link(mvif, link_sta->link_id);
+
+ if (!link_conf || !mconf)
+ return;
+
chandef = mconf->mt76.ctx ? &mconf->mt76.ctx->def :
&link_conf->chanreq.oper;
band = chandef->chan->band;
@@ -1935,6 +1950,9 @@ mt7925_mcu_sta_mld_tlv(struct sk_buff *skb,
mconf = mt792x_vif_to_link(mvif, i);
mlink = mt792x_sta_to_link(msta, i);
+ if (!mconf || !mlink)
+ continue;
+
mld->link[cnt].wlan_id = cpu_to_le16(mlink->wcid.idx);
mld->link[cnt++].bss_idx = mconf->mt76.idx;
@@ -2027,13 +2045,13 @@ int mt7925_mcu_sta_update(struct mt792x_dev *dev,
.rcpi = to_rcpi(rssi),
};
struct mt792x_sta *msta;
- struct mt792x_link_sta *mlink;
+ struct mt792x_link_sta *mlink = NULL;
if (link_sta) {
msta = (struct mt792x_sta *)link_sta->sta->drv_priv;
mlink = mt792x_sta_to_link(msta, link_sta->link_id);
}
- info.wcid = link_sta ? &mlink->wcid : &mvif->sta.deflink.wcid;
+ info.wcid = (link_sta && mlink) ? &mlink->wcid : &mvif->sta.deflink.wcid;
info.newly = state != MT76_STA_INFO_STATE_ASSOC;
return mt7925_mcu_sta_cmd(&dev->mphy, &info);
--
2.52.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox