* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
From: Sean Wang @ 2026-03-12 5:24 UTC (permalink / raw)
To: bryam vargas, lucid_duck
Cc: linux-wireless, nbd, lorenzo,
moderated list:ARM/Mediatek SoC support
In-Reply-To: <CANAPQzgD312EPSbvaQTE6U+wn85L65+xZHms7DP509ApxWvSZA@mail.gmail.com>
Hi,
I just realized that Lucid already implemented another approach to
obtain the TX power here:
https://lore.kernel.org/linux-wireless/20260130215839.53270-1-lucid_duck@justthetip.ca/
We should respect his work. Could you also take a look at it and reply
to his patch to avoid potential rework?
On Wed, Mar 11, 2026 at 3:57 PM bryam vargas
<bryamestebanvargas@gmail.com> wrote:
>
> From 6c75ad481f0c3667d6ae2a2c8f7c2df08b1d52b5 Mon Sep 17 00:00:00 2001
> From: bryam <bryamestebanvargas@gmail.com>
> Date: Mon, 9 Mar 2026 11:52:53 -0500
> Subject: [PATCH v2 1/2] mt76: mt7921: add mt7921-specific get_txpower callback
>
> Instead of updating txpower_cur in the write path
> (mt76_connac_mcu_set_rate_txpower), implement a mt7921-specific
> .get_txpower callback that derives the reported TX power directly
> from the SKU limits at query time.
>
> This avoids mixing write-side configuration with reporting logic.
> The callback uses mt76_get_power_bound() for SAR constraints and
> chain delta, then mt76_get_rate_power_limits() for per-rate EEPROM
> limits, yielding the actual TX power value.
>
> Fixes: 3b4a3bdba808 ("mt76: mt7921: add support for reporting tx power")
> Signed-off-by: Bryam Vargas <bryamestebanvargas@gmail.com>
> ---
> .../net/wireless/mediatek/mt76/mt7921/main.c | 27 ++++++++++++++++++-
> 1 file changed, 26 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> index 67383c4..35454e5 100644
> --- a/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> +++ b/drivers/net/wireless/mediatek/mt76/mt7921/main.c
> @@ -1517,6 +1517,31 @@ static void mt7921_rfkill_poll(struct ieee80211_hw *hw)
> wiphy_rfkill_set_hw_state(hw->wiphy, ret ? false : true);
> }
>
> +
> +static int mt7921_get_txpower(struct ieee80211_hw *hw,
> + struct ieee80211_vif *vif,
> + unsigned int link_id, int *dbm)
> +{
> + struct mt76_phy *phy = mt76_vif_phy(hw, vif);
> + struct mt76_power_limits limits;
> + int n_chains, delta;
> + s8 tx_power;
> +
> + if (!phy)
> + return -EINVAL;
> +
> + if (!phy->chandef.chan)
> + return mt76_get_txpower(hw, vif, link_id, dbm);
> +
> + n_chains = hweight16(phy->chainmask);
> + delta = mt76_tx_power_path_delta(n_chains);
> + tx_power = mt76_get_power_bound(phy, phy->chandef.chan->max_power);
> + tx_power = mt76_get_rate_power_limits(phy, phy->chandef.chan,
> + &limits, tx_power);
> + *dbm = DIV_ROUND_UP(tx_power + delta, 2);
how can you make sure it is the result of the maximum rate power used
in the loop within mt76_connac_mcu_rate_txpower_band (updated with
each call) ?
> + return 0;
> +}
> +
> const struct ieee80211_ops mt7921_ops = {
> .tx = mt792x_tx,
> .start = mt7921_start,
> @@ -1541,7 +1566,7 @@ const struct ieee80211_ops mt7921_ops = {
> .wake_tx_queue = mt76_wake_tx_queue,
> .release_buffered_frames = mt76_release_buffered_frames,
> .channel_switch_beacon = mt7921_channel_switch_beacon,
> - .get_txpower = mt76_get_txpower,
> + .get_txpower = mt7921_get_txpower,
> .get_stats = mt792x_get_stats,
> .get_et_sset_count = mt792x_get_et_sset_count,
> .get_et_strings = mt792x_get_et_strings,
> --
> 2.43.0
^ permalink raw reply
* Re: [PATCH wireless-next v3 0/3] misc chandef cleanups
From: Lachlan Hodges @ 2026-03-12 5:06 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge
In-Reply-To: <20260312045804.362974-1-lachlan.hodges@morsemicro.com>
> Lachlan Hodges (3):
> wifi: mac80211: don't use cfg80211_chandef_create() for default
> chandef
> wifi: cfg80211: restrict cfg80211_chandef_create() to only HT-based
> bands
> wifi: cfg80211: check non-S1G width with S1G chandef
Ah something I forgot to mention is I put the mac80211 patch first,
otherwise maybe during some bisect or something it would break if
we changed the cfg80211_create_chandef() without modifying the
creation of the default one first.
lachlan
^ permalink raw reply
* Re: [PATCH wireless-next v3 3/3] wifi: cfg80211: check non-S1G width with S1G chandef
From: Lachlan Hodges @ 2026-03-12 5:02 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge
In-Reply-To: <20260312045804.362974-4-lachlan.hodges@morsemicro.com>
> + if (cfg80211_chandef_is_s1g(chandef) &&
> + chandef->width != NL80211_CHAN_WIDTH_1 &&
> + chandef->width != NL80211_CHAN_WIDTH_2 &&
> + chandef->width != NL80211_CHAN_WIDTH_4 &&
> + chandef->width != NL80211_CHAN_WIDTH_8 &&
> + chandef->width != NL80211_CHAN_WIDTH_16)
> + return false;
> +
Admittedly this makes this already noisy functiona fair bit noiser. An
option was to do the following:
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
case NL80211_CHAN_WIDTH_20:
case NL80211_CHAN_WIDTH_20_NOHT:
if (ieee80211_chandef_to_khz(chandef) !=
ieee80211_channel_to_khz(chandef->chan))
return false;
if (chandef->center_freq2)
return false;
+ if (cfg80211_chandef_is_s1g(chandef))
+ return false;
break;
Since that would cover all the cases where a chandef is initialised,
but not some weird edge case where maybe an S1G chandef somehow got a
80MHz width or something but I guess better to cover all cases.
lachlan
^ permalink raw reply
* [PATCH wireless-next v3 3/3] wifi: cfg80211: check non-S1G width with S1G chandef
From: Lachlan Hodges @ 2026-03-12 4:58 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge, Lachlan Hodges
In-Reply-To: <20260312045804.362974-1-lachlan.hodges@morsemicro.com>
It is not valid to have an S1G chandef with a non-S1G width. Enforce
this during chandef validation.
Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
---
net/wireless/chan.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 4d2c2b9f1eed..f80bc5144037 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -353,6 +353,14 @@ bool cfg80211_chandef_valid(const struct cfg80211_chan_def *chandef)
control_freq = chandef->chan->center_freq;
+ if (cfg80211_chandef_is_s1g(chandef) &&
+ chandef->width != NL80211_CHAN_WIDTH_1 &&
+ chandef->width != NL80211_CHAN_WIDTH_2 &&
+ chandef->width != NL80211_CHAN_WIDTH_4 &&
+ chandef->width != NL80211_CHAN_WIDTH_8 &&
+ chandef->width != NL80211_CHAN_WIDTH_16)
+ return false;
+
switch (chandef->width) {
case NL80211_CHAN_WIDTH_5:
case NL80211_CHAN_WIDTH_10:
--
2.43.0
^ permalink raw reply related
* [PATCH wireless-next v3 2/3] wifi: cfg80211: restrict cfg80211_chandef_create() to only HT-based bands
From: Lachlan Hodges @ 2026-03-12 4:58 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge, Lachlan Hodges
In-Reply-To: <20260312045804.362974-1-lachlan.hodges@morsemicro.com>
cfg80211_chandef_create() should only be used by bands that are
HT-based and the chantype argument makes sense. Insert a WARN such
that it isn't used on 60GHz and S1GHz bands and to catch any
potential existing uses by those bands.
Suggested-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
---
net/wireless/chan.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/net/wireless/chan.c b/net/wireless/chan.c
index 68221b1ab45e..4d2c2b9f1eed 100644
--- a/net/wireless/chan.c
+++ b/net/wireless/chan.c
@@ -29,9 +29,11 @@ void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
*chandef = (struct cfg80211_chan_def) {
.chan = chan,
- .freq1_offset = chan->freq_offset,
};
+ WARN_ON(chan->band == NL80211_BAND_60GHZ ||
+ chan->band == NL80211_BAND_S1GHZ);
+
switch (chan_type) {
case NL80211_CHAN_NO_HT:
chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
--
2.43.0
^ permalink raw reply related
* [PATCH wireless-next v3 1/3] wifi: mac80211: don't use cfg80211_chandef_create() for default chandef
From: Lachlan Hodges @ 2026-03-12 4:58 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge, Lachlan Hodges
In-Reply-To: <20260312045804.362974-1-lachlan.hodges@morsemicro.com>
cfg80211_chandef_create() is called universally to create the
default chandef during hw registration, however it only really
makes sense to be used for 2GHz, 5GHz, and 6GHz (and by extension
the 'LC' band) as it relies on the channel type which is only
relevant to those specific bands.
To reduce some confusion, create a generic helper for creating the
default chandef that makes sense for all supported bands.
Suggested-by: Johannes Berg <johannes@sipsolutions.net>
Signed-off-by: Lachlan Hodges <lachlan.hodges@morsemicro.com>
---
net/mac80211/main.c | 18 +++++++++++++++---
1 file changed, 15 insertions(+), 3 deletions(-)
diff --git a/net/mac80211/main.c b/net/mac80211/main.c
index 616f86b1a7e4..ed5d60328041 100644
--- a/net/mac80211/main.c
+++ b/net/mac80211/main.c
@@ -1117,6 +1117,19 @@ ieee80211_ifcomb_check(const struct ieee80211_iface_combination *c, int n_comb)
return true;
}
+static void ieee80211_create_default_chandef(struct cfg80211_chan_def *chandef,
+ struct ieee80211_channel *chan)
+{
+ *chandef = (struct cfg80211_chan_def) {
+ .chan = chan,
+ .width = chan->band == NL80211_BAND_S1GHZ ?
+ NL80211_CHAN_WIDTH_1 :
+ NL80211_CHAN_WIDTH_20_NOHT,
+ .center_freq1 = chan->center_freq,
+ .freq1_offset = chan->freq_offset,
+ };
+}
+
int ieee80211_register_hw(struct ieee80211_hw *hw)
{
struct ieee80211_local *local = hw_to_local(hw);
@@ -1260,9 +1273,8 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
/* if none found then use the first anyway */
if (i == sband->n_channels)
i = 0;
- cfg80211_chandef_create(&dflt_chandef,
- &sband->channels[i],
- NL80211_CHAN_NO_HT);
+ ieee80211_create_default_chandef(&dflt_chandef,
+ &sband->channels[i]);
/* init channel we're on */
local->monitor_chanreq.oper = dflt_chandef;
if (local->emulate_chanctx) {
--
2.43.0
^ permalink raw reply related
* [PATCH wireless-next v3 0/3] misc chandef cleanups
From: Lachlan Hodges @ 2026-03-12 4:58 UTC (permalink / raw)
To: johannes; +Cc: linux-wireless, arien.judge, Lachlan Hodges
It was discussed in [1] that calling cfg80211_create_chandef() probably
doesn't make the most sense for non-HT based bands (that being S1G and
60GHz currently). Even though it's called fairly frequently, most of
those paths are unrelated or not supported yet. However creating
the default chandef is one. So creating a helper specifically for
creating the default chandef which is band-agnostic makes more
sense. Additionally, insert a WARN into cfg80211_chandef_create() to
catch any misuses by S1G and 60GHz bands.
hwsim tests were run just to double check nothing broke on hostap
tip 11620497a ("EPPKE: Do not start Authenticator state machine on
reassociation") and wireless-next 97492c019da4 ("wifi: mwifiex: drop
redundant device reference").
The 3rd patch adds some simple validation for when we have an S1G
chandef but a non-S1G width to catch any weird corner cases like one
discussed in [2].
[1] https://lore.kernel.org/linux-wireless/6832f8f0b516157452bd9c23b7c7af087d63d425.camel@sipsolutions.net/T/#mdd8f8115f3c8195638568cface3e20ab777f9f33
[2] https://lore.kernel.org/linux-wireless/20260311061800.517849-1-lachlan.hodges@morsemicro.com/
lachlan
Lachlan Hodges (3):
wifi: mac80211: don't use cfg80211_chandef_create() for default
chandef
wifi: cfg80211: restrict cfg80211_chandef_create() to only HT-based
bands
wifi: cfg80211: check non-S1G width with S1G chandef
net/mac80211/main.c | 18 +++++++++++++++---
net/wireless/chan.c | 12 +++++++++++-
2 files changed, 26 insertions(+), 4 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH 6.1.y] wifi: brcmfmac: fix use-after-free when rescheduling brcmf_btcoex_info work
From: Robert Garcia @ 2026-03-12 3:14 UTC (permalink / raw)
To: stable, Duoming Zhou
Cc: Johannes Berg, Robert Garcia, Arend van Spriel, Kalle Valo,
Franky Lin, Hante Meuleman, David S . Miller, Eric Dumazet,
Jakub Kicinski, Paolo Abeni, Pieter-Paul Giesberts, Piotr Haber,
John W . Linville, linux-wireless, brcm80211-dev-list.pdl,
SHA-cyfmac-dev-list, netdev, linux-kernel
From: Duoming Zhou <duoming@zju.edu.cn>
[ Upstream commit 9cb83d4be0b9b697eae93d321e0da999f9cdfcfc ]
The brcmf_btcoex_detach() only shuts down the btcoex timer, if the
flag timer_on is false. However, the brcmf_btcoex_timerfunc(), which
runs as timer handler, sets timer_on to false. This creates critical
race conditions:
1.If brcmf_btcoex_detach() is called while brcmf_btcoex_timerfunc()
is executing, it may observe timer_on as false and skip the call to
timer_shutdown_sync().
2.The brcmf_btcoex_timerfunc() may then reschedule the brcmf_btcoex_info
worker after the cancel_work_sync() has been executed, resulting in
use-after-free bugs.
The use-after-free bugs occur in two distinct scenarios, depending on
the timing of when the brcmf_btcoex_info struct is freed relative to
the execution of its worker thread.
Scenario 1: Freed before the worker is scheduled
The brcmf_btcoex_info is deallocated before the worker is scheduled.
A race condition can occur when schedule_work(&bt_local->work) is
called after the target memory has been freed. The sequence of events
is detailed below:
CPU0 | CPU1
brcmf_btcoex_detach | brcmf_btcoex_timerfunc
| bt_local->timer_on = false;
if (cfg->btcoex->timer_on) |
... |
cancel_work_sync(); |
... |
kfree(cfg->btcoex); // FREE |
| schedule_work(&bt_local->work); // USE
Scenario 2: Freed after the worker is scheduled
The brcmf_btcoex_info is freed after the worker has been scheduled
but before or during its execution. In this case, statements within
the brcmf_btcoex_handler() — such as the container_of macro and
subsequent dereferences of the brcmf_btcoex_info object will cause
a use-after-free access. The following timeline illustrates this
scenario:
CPU0 | CPU1
brcmf_btcoex_detach | brcmf_btcoex_timerfunc
| bt_local->timer_on = false;
if (cfg->btcoex->timer_on) |
... |
cancel_work_sync(); |
... | schedule_work(); // Reschedule
|
kfree(cfg->btcoex); // FREE | brcmf_btcoex_handler() // Worker
/* | btci = container_of(....); // USE
The kfree() above could | ...
also occur at any point | btci-> // USE
during the worker's execution|
*/ |
To resolve the race conditions, drop the conditional check and call
timer_shutdown_sync() directly. It can deactivate the timer reliably,
regardless of its current state. Once stopped, the timer_on state is
then set to false.
Fixes: 61730d4dfffc ("brcmfmac: support critical protocol API for DHCP")
Acked-by: Arend van Spriel <arend.vanspriel@broadcom.com>
Signed-off-by: Duoming Zhou <duoming@zju.edu.cn>
Link: https://patch.msgid.link/20250822050839.4413-1-duoming@zju.edu.cn
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[ Keep del_timer_sync() instead of timer_shutdown_sync() here. ]
Signed-off-by: Robert Garcia <rob_garcia@163.com>
---
drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
index f9f18ff451ea..f46e40900217 100644
--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/btcoex.c
@@ -392,10 +392,8 @@ void brcmf_btcoex_detach(struct brcmf_cfg80211_info *cfg)
if (!cfg->btcoex)
return;
- if (cfg->btcoex->timer_on) {
- cfg->btcoex->timer_on = false;
- del_timer_sync(&cfg->btcoex->timer);
- }
+ del_timer_sync(&cfg->btcoex->timer);
+ cfg->btcoex->timer_on = false;
cancel_work_sync(&cfg->btcoex->work);
--
2.34.1
^ permalink raw reply related
* Re: [PATCH rtw-next 01/13] wifi: rtw89: mac: finish active TX immediately without waiting for DMAC
From: Ping-Ke Shih @ 2026-03-12 3:00 UTC (permalink / raw)
To: Ping-Ke Shih, linux-wireless; +Cc: timlee, phhuang, kevin_yang
In-Reply-To: <20260310080146.31113-2-pkshih@realtek.com>
Ping-Ke Shih <pkshih@realtek.com> wrote:
> Currently active TX only finishes after ensuring PCIE and DMAC become idle.
> However, the waiting time might be long. Since the packet is already
> transmitted over the air, update the registers to finish active TX
> immediately, regardless of the PCIE/DMAC status.
>
> Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
As internal test, this will affect performance, so drop this. Still keep
remaining patches.
Set patchset state to Not Applicable
[rtw-next,01/13] wifi: rtw89: mac: finish active TX immediately without waiting for DMAC
---
https://github.com/pkshih/rtw.git
^ permalink raw reply
* RE: [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU
From: Isaiah @ 2026-03-12 2:30 UTC (permalink / raw)
To: Bitterblue Smith, Ping-Ke Shih, linux-wireless@vger.kernel.org; +Cc: Mh_chen
In-Reply-To: <197660d0061246518129933398072dd5@realtek.com>
________________________________________
寄件者: Bitterblue Smith <mailto:rtl8821cerfe2@gmail.com>
寄件日期: 2026年3月11日 上午 06:16
收件者: Ping-Ke Shih; mailto:linux-wireless@vger.kernel.org
副本: Mh_chen; Isaiah
主旨: Re: [PATCH rtw-next] wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU
External mail : This email originated from outside the organization. Do not reply, click links, or open attachments unless you recognize the sender and know the content is safe.
On 09/03/2026 10:58, Ping-Ke Shih wrote:
> From: Shin-Yi Lin <mailto:isaiah@realtek.com>
>
> USB RX Aggregation is a performance optimization technique used
> in USB network devices to increase throughput.
>
> Instead of sending every received network packet to the host computer
> individually, the device hardware groups multiple smaller packets
> into a single, large USB Bulk Transfer.
>
> * toAP/toNB use iperf3 respectively.
>
> With BE6000 - iperf3 tcp 10 pair (to another NB)
>
> RTL8832CU-USB3.0
> before after
> TX 941 941
> RX 847 919
>
> RTL8832CU-USB2.0
> before after
> TX 864 877
> RX 864 902
> I wonder if these numbers are actually from a different scenario?
> USB 2.0 can't go that fast.
Sorry, I made a mistake in the data.
Details as below. The corrected data will be included in next patch.
[6G 160Mhz]:
RTL8832CU-USB3.0
before after
TX 941 941
RX 847 919
RTL8832CU-USB2.0
before after
TX 293 286
RX 342 356
-------------------------------
[5G 80Mhz]:
RTL8832CU-USB3.0
before after
TX 864 877
RX 864 902
RTL8832CU-USB2.0
before after
TX 279 271
RX 327 349
RTL8851BU
before after
TX 115 114
RX 295 306
>
> RTL8851BU
> before after
> TX 115 114
> RX 295 306
>
> Signed-off-by: Shin-Yi Lin <mailto:isaiah@realtek.com>
> Signed-off-by: Ping-Ke Shih <mailto:pkshih@realtek.com>
> ---
> This one is to add USB RX aggregation to improve performance. The other
> one is TX aggregation, which we are working on.
> That is wonderful news.
> ---
> .../net/wireless/realtek/rtw89/rtw8851bu.c | 1 +
> .../net/wireless/realtek/rtw89/rtw8852au.c | 1 +
> .../net/wireless/realtek/rtw89/rtw8852bu.c | 1 +
> .../net/wireless/realtek/rtw89/rtw8852cu.c | 1 +
> drivers/net/wireless/realtek/rtw89/usb.c | 84 ++++++++++++++++---
> drivers/net/wireless/realtek/rtw89/usb.h | 12 +++
> 6 files changed, 87 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> index 959d62aefdd8..6a8d31544314 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8851bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8851b_usb_info = {
> .usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
> .usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
> .usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
> + .rx_agg_alignment = 8,
> .bulkout_id = {
> [RTW89_DMA_ACH0] = 3,
> [RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852au.c b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> index ccdbcc178c2a..4cced4619b7d 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852au.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852a_usb_info = {
> .usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
> .usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
> .usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
> + .rx_agg_alignment = 8,
> .bulkout_id = {
> [RTW89_DMA_ACH0] = 3,
> [RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> index 84cd3ec971f9..37111fed276f 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852bu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852b_usb_info = {
> .usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0,
> .usb_endpoint_0 = R_AX_USB_ENDPOINT_0,
> .usb_endpoint_2 = R_AX_USB_ENDPOINT_2,
> + .rx_agg_alignment = 8,
> .bulkout_id = {
> [RTW89_DMA_ACH0] = 3,
> [RTW89_DMA_ACH1] = 4,
> diff --git a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> index 3b9825c92a0d..0c5aebaed873 100644
> --- a/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> +++ b/drivers/net/wireless/realtek/rtw89/rtw8852cu.c
> @@ -15,6 +15,7 @@ static const struct rtw89_usb_info rtw8852c_usb_info = {
> .usb3_mac_npi_config_intf_0 = R_AX_USB3_MAC_NPI_CONFIG_INTF_0_V1,
> .usb_endpoint_0 = R_AX_USB_ENDPOINT_0_V1,
> .usb_endpoint_2 = R_AX_USB_ENDPOINT_2_V1,
> + .rx_agg_alignment = 8,
> .bulkout_id = {
> [RTW89_DMA_ACH0] = 3,
> [RTW89_DMA_ACH2] = 5,
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
> index da1b7ce8089e..4482ce61592b 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.c
> +++ b/drivers/net/wireless/realtek/rtw89/usb.c
> @@ -408,11 +408,14 @@ static int rtw89_usb_ops_tx_write(struct rtw89_dev *rtwdev,
> static void rtw89_usb_rx_handler(struct work_struct *work)
> {
> struct rtw89_usb *rtwusb = container_of(work, struct rtw89_usb, rx_work);
> + const struct rtw89_usb_info *info = rtwusb->info;
> struct rtw89_dev *rtwdev = rtwusb->rtwdev;
> struct rtw89_rx_desc_info desc_info;
> + s32 aligned_offset, remaining;
> struct sk_buff *rx_skb;
> struct sk_buff *skb;
> u32 pkt_offset;
> + u8 *pkt_ptr;
> int limit;
>
> for (limit = 0; limit < 200; limit++) {
> @@ -425,23 +428,38 @@ static void rtw89_usb_rx_handler(struct work_struct *work)
> goto free_or_reuse;
> }
>
> - memset(&desc_info, 0, sizeof(desc_info));
> - rtw89_chip_query_rxdesc(rtwdev, &desc_info, rx_skb->data, 0);
> + pkt_ptr = rx_skb->data;
> + remaining = rx_skb->len;
>
> - skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> - if (!skb) {
> - rtw89_debug(rtwdev, RTW89_DBG_HCI,
> - "failed to allocate RX skb of size %u\n",
> - desc_info.pkt_size);
> - goto free_or_reuse;
> - }
> + do {
> + memset(&desc_info, 0, sizeof(desc_info));
> + rtw89_chip_query_rxdesc(rtwdev, &desc_info, pkt_ptr, 0);
>
> - pkt_offset = desc_info.offset + desc_info.rxd_len;
> + pkt_offset = desc_info.offset + desc_info.rxd_len;
> + if (remaining < (pkt_offset + desc_info.pkt_size)) {
> + rtw89_debug(rtwdev, RTW89_DBG_HCI,
> + "Failed to get remaining RX pkt %u > %u\n",
> + pkt_offset + desc_info.pkt_size, remaining);
> + goto free_or_reuse;
> + }
>
> - skb_put_data(skb, rx_skb->data + pkt_offset,
> - desc_info.pkt_size);
> + skb = rtw89_alloc_skb_for_rx(rtwdev, desc_info.pkt_size);
> + if (!skb) {
> + rtw89_debug(rtwdev, RTW89_DBG_HCI,
> + "failed to allocate RX skb of size %u\n",
> + desc_info.pkt_size);
> + goto free_or_reuse;
> + }
> +
> + skb_put_data(skb, pkt_ptr + pkt_offset, desc_info.pkt_size);
> + rtw89_core_rx(rtwdev, &desc_info, skb);
>
> - rtw89_core_rx(rtwdev, &desc_info, skb);
> + /* next frame */
> + pkt_offset += desc_info.pkt_size;
> + aligned_offset = ALIGN(pkt_offset, info->rx_agg_alignment);
> + pkt_ptr += aligned_offset;
> + remaining -= aligned_offset;
> + } while (remaining > 0);
>
> free_or_reuse:
> if (skb_queue_len(&rtwusb->rx_free_queue) >= RTW89_USB_RX_SKB_NUM)
> @@ -745,6 +763,44 @@ static int rtw89_usb_ops_mac_pre_deinit(struct rtw89_dev *rtwdev)
> return 0; /* Nothing to do. */
> }
>
> +static void usb_rx_agg_cfg_v1(struct rtw89_dev *rtwdev)
> Maybe give the new functions the usual "rtw89_" prefix?
OK, I will refine in next patch
> +{
> + const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 0) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_4K, 5);
> +
> + rtw89_write32(rtwdev, R_AX_RXAGG_0, rxagg_0);
> +}
> +
> +static void usb_rx_agg_cfg_v2(struct rtw89_dev *rtwdev)
> +{
> + const u32 rxagg_0 = FIELD_PREP_CONST(B_AX_RXAGG_0_EN, 1) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_NUM_TH, 255) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_TIME_32US_TH, 32) |
> + FIELD_PREP_CONST(B_AX_RXAGG_0_BUF_SZ_K, 20);
> +
> + rtw89_write32(rtwdev, R_AX_RXAGG_0_V1, rxagg_0);
> + rtw89_write32(rtwdev, R_AX_RXAGG_1_V1, 0x1F);
> +}
> +
> +static void usb_rx_agg_cfg(struct rtw89_dev *rtwdev)
> +{
> + switch (rtwdev->chip->chip_id) {
> + case RTL8851B:
> + case RTL8852A:
> + case RTL8852B:
> + usb_rx_agg_cfg_v1(rtwdev);
> + break;
> + case RTL8852C:
> + usb_rx_agg_cfg_v2(rtwdev);
> + break;
> + default:
> + rtw89_warn(rtwdev, "%s: USB RX agg not support\n", __func__);
> + return;
> + }
> The subject only mentions RTL8832CU and RTL8851BU, but looks like you
> implemented it for every chip currently supported.
Basically all are supported, but I have only verified RTL8832CU and RTL8851BU.
> +}
> +
> static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
> {
> struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> @@ -773,6 +829,8 @@ static int rtw89_usb_ops_mac_post_init(struct rtw89_dev *rtwdev)
> rtw89_write8(rtwdev, info->usb_endpoint_2 + 1, NUMP);
> }
>
> + usb_rx_agg_cfg(rtwdev);
> +
> return 0;
> }
>
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.h b/drivers/net/wireless/realtek/rtw89/usb.h
> index 203ec8e993e9..afc62c1f687f 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.h
> +++ b/drivers/net/wireless/realtek/rtw89/usb.h
> @@ -20,6 +20,17 @@
> #define RTW89_MAX_ENDPOINT_NUM 9
> #define RTW89_MAX_BULKOUT_NUM 7
>
> +#define R_AX_RXAGG_0_V1 0x6000
> +#define B_AX_RXAGG_0_EN BIT(31)
> +#define B_AX_RXAGG_0_NUM_TH GENMASK(23, 16)
> +#define B_AX_RXAGG_0_TIME_32US_TH GENMASK(15, 8)
> +#define B_AX_RXAGG_0_BUF_SZ_K GENMASK(7, 0)
> Is it missing a number before the letter K ?
OK, I will refine in next patch
> +
> +#define R_AX_RXAGG_1_V1 0x6004
> +
> +#define R_AX_RXAGG_0 0x8900
> +#define B_AX_RXAGG_0_BUF_SZ_4K GENMASK(7, 0)
> +
> struct rtw89_usb_info {
> u32 usb_host_request_2;
> u32 usb_wlan0_1;
> @@ -27,6 +38,7 @@ struct rtw89_usb_info {
> u32 usb3_mac_npi_config_intf_0;
> u32 usb_endpoint_0;
> u32 usb_endpoint_2;
> + u8 rx_agg_alignment;
> u8 bulkout_id[RTW89_DMA_CH_NUM];
> };
>
>
> base-commit: 039cd522dc70151da13329a5e3ae19b1736f468a
^ permalink raw reply
* RE: [PATCH] wifi: rtw89: retry efuse physical map dump on transient failure
From: Ping-Ke Shih @ 2026-03-12 2:22 UTC (permalink / raw)
To: Christian Hewitt
Cc: Bitterblue Smith, linux-wireless@vger.kernel.org,
linux-kernel@vger.kernel.org
In-Reply-To: <B9D5D4CC-0729-4867-AD1B-18D80D78841B@gmail.com>
Christian Hewitt <christianshewitt@gmail.com> wrote:
> > On 11 Mar 2026, at 7:05 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >
> > Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>
> >>> On 9 Mar 2026, at 6:35 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>
> >>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>
> >>>>> On 2 Mar 2026, at 10:04 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>
> >>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>> On 2 Mar 2026, at 9:47 am, Ping-Ke Shih <pkshih@realtek.com> wrote:
> >>>>>>>
> >>>>>>> Christian Hewitt <christianshewitt@gmail.com> wrote:
> >>>>>>>> On Radxa Rock 5B with a RTL8852BE combo WiFi/BT card, the efuse
> >>>>>>>> physical map dump intermittently fails with -EBUSY during probe.
> >>>>>>>> The failure occurs in rtw89_dump_physical_efuse_map_ddv() where
> >>>>>>>> read_poll_timeout_atomic() times out waiting for the B_AX_EF_RDY
> >>>>>>>> bit after 1 second.
> >>>>>>>
> >>>>>>> I'm checking internally how we handle this case.
> >>>
> >>> Sorry for the late.
> >>>
> >>> We encountered WiFi/BT reading efuse at the same time causing similar
> >>> problem as yours. The workaround is like yours, which adds timeout
> >>> time.
> >>>
> >>>>>>>
> >>>>>>> [...]
> >>>>>>>
> >>>>>>>>
> >>>>>>>> For context, firmware also fails (and recovers) sometimes:
> >>>>>>>
> >>>>>>> Did you mean this doesn't always happen? sometimes?
> >>>>>>
> >>>>>> It’s another intermittent behaviour observed on this board (and not
> >>>>>> related to the issue this patch targets). It occurs less frequently
> >>>>>> than the efuse issue and the existing retry mechanism in the driver
> >>>>>> ensures firmware load always succeeds.
> >>>
> >>> This might be the same cause due to reading efuse in firmware.
> >>>
> >>> Though we can add more timeout and retry times as workaround, I wonder
> >>> if you can control loading time of WiFi and BT kernel modules?
> >>>
> >>> More, can you do experiment that you load BT module first, and then load
> >>> WiFi module after 10 seconds (choose a large number intentionally, or
> >>> even larger)?
> >>
> >> https://paste.libreelec.tv/charmed-turkey.sh
> >>
> >> I’ve run the above script ^ which removes the wifi and bt modules in
> >> sequence then reloads them in the reverse order with a delay between
> >> bt and wifi modules loading, then checks for error messages. Over 200
> >> test cycles with a 10s delay all were clean (no errors). I also ran
> >> cycles with a 2 second delay and 0 second delay before starting wifi
> >> module load and those were clear too. I guess that proves sequencing
> >> avoids the efuse contention issue? - although it’s not possible in
> >> the real-world so not sure there’s huge value in knowing that :)
> >
> > Thanks for the experiments.
> >
> > Still want to know is it possible to change sequence/time of loading
> > kernel modules at boot time from system level? I mean can you adjust
> > the sequence in the Rock 5B board?
>
> I’m not a kernel expert, but I’ve always understood module probe and
> load ordering to not be guaranteed; as many things run in parallel and
> are highly subjective to the specific hardware capabilities and kernel
> config being used.
I have heard people about changing sequence/time of kernel modules, so
I'd like you can try this method.
I did ask AI, it said it is possible to create a .conf file under
/etc/modprobe.d/ and use `softdep` syntax to ensure loading sequence.
Could you try this?
>
> > In addition, did below messages not appear in these experiments?
> >
> > [ 7.864148] rtw89_8852be 0002:21:00.0: fw security fail
> > [ 7.864154] rtw89_8852be 0002:21:00.0: download firmware fail
>
> No, because even if we have a 0s delay between each group of modules
> being loaded, they are loaded in series, so we workaround the issue.
> Tweaking the script to background the module load loops so both run
> in parallel would be closer to normal conditions, and I would expect
> to start seeing failures and the retry mechanisms within the modules
> (as added in this patch) being triggered.
Additional question for downloading firmware. As you reported this
issue initially (load modules at boot time in parallel), it seems
appear this message by chance. Since this driver will retry to download
firmware, will it successfully downloads firmware finally? Or it still
fails to download after 5 times retry?
Ping-Ke
^ permalink raw reply
* RE: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: Ping-Ke Shih @ 2026-03-12 1:56 UTC (permalink / raw)
To: LB F; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqQee1sjgdBAPJSyb1gL6ksK4z8Uw_v3ANTnyXE+LXFAiA@mail.gmail.com>
LB F <goainwo@gmail.com> wrote:
> Hi Ping-Ke,
>
> I successfully applied your patch out-of-tree and performed rigorous
> testing on the host machine.
>
> I can officially confirm that the patch works flawlessly. The DMI
> quirk triggered correctly and successfully prevented the
> hardware-level PCIe bus lockups on my HP P3S95EA#ACB.
Thanks for your quickly test with my patch. :)
>
> Testing Environment & Methodology:
> - Kernel: CachyOS Linux 6.19.6-2-cachyos x86_64
> - Toolchain: Clang/LLVM 21.1.8 (`make CC=clang LLVM=1 modules`)
> - Extraction: We fetched the strict
> `drivers/net/wireless/realtek/rtw88` sub-tree out of the
> torvalds/linux `v6.19` tree utilizing `git sparse-checkout` to cleanly
> apply the patch without having to compile the entire 2.5GB+ kernel.
> - The resulting `.ko` object files were compressed to `.zst` and
> installed successfully over the generic CachyOS system driver objects.
>
> Verification Conditions:
> - Removed ALL local workarounds. `disable_aspm=Y` is no longer forced
> via `/etc/modprobe.d/` overrides.
> - Power saving remains natively ON `wifi.powersave = 3` (managed by
> NetworkManager).
> - Left the laptop in multiple 5-10 minute complete idle states to
> enforce sleep modes.
>
> Post-Boot Log Analysis & Potential Improvement Proposition:
> The system remained 100% stable without any kernel panics or UI freezes.
> However, I continuously monitored the `dmesg` ring buffer and noticed
> an intriguing behavior. While the laptop sits completely idle
> (NetworkManager connected, but no active traffic), the `rtw88` driver
> starts flooded the logs with thousands of firmware errors:
>
> [ 1084.746485] rtw88_8821ce 0000:13:00.0: firmware failed to leave lps state
> [ 1084.749662] rtw88_8821ce 0000:13:00.0: failed to send h2c command
> [ 1084.752895] rtw88_8821ce 0000:13:00.0: failed to send h2c command
>
> If my understanding of this architecture is correct, previously, when
> ASPM wasn't disabled, this exact failure of the adapter firmare inside
> `LPS_DEEP_MODE_LCLK` would violently lock up the PCIe bus and crash
> the host. Now, thanks to your DMI ASPM quirk at the `rtw88_pci` level,
> the host PCIe controller doesn't enter `L1` and is perfectly shielded
> from the adapter locking itself up! The OS handles the timeouts
> gracefully and driver recovery prevents a hard freeze.
I'm really not sure how/why kernel becomes frozen. As I mentioned before
it might because of received malformed data and no complete validation
before reporting RX packet to mac80211.
Not sure if you can try to dig and add some validation?
(Current DMI patch is fine to me.)
>
> A question for your consideration: Given the immense volume of these
> `h2c` timeout errors (and the underlying firmware's fundamental
> inability to cleanly enter/exit its own sleep states without L1
> participation on this HP model), do you think it would be beneficial
> to *also* dynamically disable LPS Deep sleep when this specific ASPM
> quirk is triggered?
>
> For example, dynamically forcing `rtwdev->lps_conf.deep_mode =
> LPS_DEEP_MODE_NONE` when the DMI ASPM flag is active, strictly to
> prevent the firmware from attempting a sleep cycle that is doomed to
> fail and polluting the queues and logs? Perhaps this might also save
> microscopic CPU interrupts from continuous H2C polling timeouts?
Are the 'h2c' timeout messages flooding? or appears periodically?
Does it really affect connection stable?
If you change another AP or connection on 5GHz band, does the messages
still present?
I think it isn't easy to find out the cause without measuring hardware
signals, since I saw the message very very rare. So, I'd adopt your
suggestion (dynamic LPS_DEEP_MODE_NONE) if the test is positive.
>
> If you believe that simply letting the driver recover and tolerating
> the error spam in `dmesg` is the preferred/safer upstream approach, I
> am perfectly happy. The patch functions as advertised and system
> stability is unequivocally restored!
>
> Thank you immensely for your rapid debugging and definitive patch for
> this long-standing issue and for bringing stability to this model.
>
> Tested-by: Oleksandr Havrylov <goainwo@gmail.com>
I will add this to my patch then.
>
> *(Note: I was a bit unsure which of the two active mailing list
> threads was the most appropriate place for this final report — the
> original bug discussion or the new RFT patch submission thread — so I
> replied to both just to ensure it is correctly attached to the patch.
> Apologies for the duplicate email!)*
>
Let's discuss in this thread. For RFT patch, I suppose you only reply
me about the test result and give me Tested-by tag if it works.
By the way, your this reply is top posting that mailing list isn't
preferred, so I delete old discussion. Please avoid this in the future.
Ping-Ke
^ permalink raw reply
* [PATCH] wifi: iwlwifi: use unique thermal zone type
From: Jiajia Liu @ 2026-03-12 1:40 UTC (permalink / raw)
To: Miri Korenblit, Benjamin Berg, Johannes Berg, linux-wireless,
linux-kernel
Cc: Jiajia Liu
Unloading iwlmld or iwlmvm can trigger hung task when two devices
using iwlmvm and iwlmld respectively on one setup. Their thermal
zones have the same type and share the same hwmon device created
by the first zone. The second zone indirectly holds the first zone
through hwmon and prevents the first zone from unregistering.
Tested with AX211 (8086:7af0) and BE200 (8086:272b).
INFO: task modprobe:5295 blocked for more than 120 seconds.
Not tainted 7.0.0-rc2-up1 #2
Call Trace:
__schedule+0x4df/0xfd0
schedule+0x27/0xd0
schedule_timeout+0xbd/0x100
__wait_for_common+0x97/0x1b0
? __pfx_schedule_timeout+0x10/0x10
thermal_zone_device_unregister+0x173/0x1c0
iwl_mld_thermal_exit+0xbb/0xd0 [iwlmld]
iwl_op_mode_mld_stop+0x37/0x120 [iwlmld]
iwl_opmode_deregister+0xc0/0x160 [iwlwifi]
__do_sys_delete_module+0x1b5/0x320
Signed-off-by: Jiajia Liu <liujiajia@kylinos.cn>
---
drivers/net/wireless/intel/iwlwifi/iwl-utils.c | 10 ++++++++++
drivers/net/wireless/intel/iwlwifi/iwl-utils.h | 4 ++++
drivers/net/wireless/intel/iwlwifi/mld/thermal.c | 4 ++--
drivers/net/wireless/intel/iwlwifi/mvm/tt.c | 6 ++++--
4 files changed, 20 insertions(+), 4 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
index d503544fda40..fe5fa5e59664 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.c
@@ -193,3 +193,13 @@ s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len)
return clamp(average_magnitude - i, -128, 0);
}
IWL_EXPORT_SYMBOL(iwl_average_neg_dbm);
+
+#ifdef CONFIG_THERMAL
+u8 iwl_thermal_zone_get_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(0);
+
+ return atomic_inc_return(&counter) & 0xFF;
+}
+IWL_EXPORT_SYMBOL(iwl_thermal_zone_get_id);
+#endif
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
index 5172035e4d26..84a4543fd290 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-utils.h
@@ -55,4 +55,8 @@ u32 iwl_find_ie_offset(u8 *beacon, u8 eid, u32 frame_size)
s8 iwl_average_neg_dbm(const u8 *neg_dbm_values, u8 len);
+#ifdef CONFIG_THERMAL
+u8 iwl_thermal_zone_get_id(void);
+#endif
+
#endif /* __iwl_utils_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
index f8a8c35066be..500028a4dbd3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/thermal.c
@@ -5,6 +5,7 @@
#ifdef CONFIG_THERMAL
#include <linux/sort.h>
#include <linux/thermal.h>
+#include "iwl-utils.h"
#endif
#include "fw/api/phy.h"
@@ -243,7 +244,6 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)
{
int ret;
char name[16];
- static atomic_t counter = ATOMIC_INIT(0);
struct thermal_trip trips[IWL_MAX_DTS_TRIPS] = {
[0 ... IWL_MAX_DTS_TRIPS - 1] = {
.temperature = THERMAL_TEMP_INVALID,
@@ -254,7 +254,7 @@ static void iwl_mld_thermal_zone_register(struct iwl_mld *mld)
BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
+ sprintf(name, "iwlwifi_%u", iwl_thermal_zone_get_id());
mld->tzone =
thermal_zone_device_register_with_trips(name, trips,
IWL_MAX_DTS_TRIPS,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
index 53bab21ebae2..ea8e616174db 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/tt.c
@@ -7,6 +7,9 @@
#include <linux/sort.h>
#include "mvm.h"
+#ifdef CONFIG_THERMAL
+#include "iwl-utils.h"
+#endif
#define IWL_MVM_NUM_CTDP_STEPS 20
#define IWL_MVM_MIN_CTDP_BUDGET_MW 150
@@ -652,7 +655,6 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
{
int i, ret;
char name[16];
- static atomic_t counter = ATOMIC_INIT(0);
if (!iwl_mvm_is_tt_in_fw(mvm)) {
mvm->tz_device.tzone = NULL;
@@ -662,7 +664,7 @@ static void iwl_mvm_thermal_zone_register(struct iwl_mvm *mvm)
BUILD_BUG_ON(ARRAY_SIZE(name) >= THERMAL_NAME_LENGTH);
- sprintf(name, "iwlwifi_%u", atomic_inc_return(&counter) & 0xFF);
+ sprintf(name, "iwlwifi_%u", iwl_thermal_zone_get_id());
/*
* 0 is a valid temperature,
* so initialize the array with S16_MIN which invalid temperature
--
2.53.0
^ permalink raw reply related
* Re: [PATCH 1/2] mt76: connac: fix txpower_cur not updated in mt76_connac_mcu_set_rate_txpower()
From: bryam vargas @ 2026-03-12 0:49 UTC (permalink / raw)
To: Sean Wang; +Cc: linux-wireless, nbd, lorenzo
In-Reply-To: <CANAPQzgXN2UOjuwV1fRofN2syxG933kSaB9S7DyFAykHHMRzew@mail.gmail.com>
Subject: mt76: mt7921u: WF_MIB registers inaccessible over USB — right
approach for survey fix?
Hi Sean,
Thank you for the v1 review. I've just sent v2 addressing both points.
While investigating why iw reports zero channel time on mt7921u, I
traced the issue to mt792x_phy_update_channel(): it reads
MT_MIB_SDR9/36/37 via mt76_rr(), which works fine on PCIe (direct
MMIO), but on USB these are hardware MAC counters in the WF_MIB block
that the firmware does not map in its USB vendor request table — so
they always return 0.
Evidence:
- iw dev wlan0 survey dump reports 0ms for active/busy/rx/tx time
after transmitting 638 MiB
- Disabling power save has no effect (rules out pm_wake early return)
- mt7925 USB has the same issue (same mt792x_update_channel path)
- WTBL registers (MT_WTBL_AC0_CTT_OFFSET) work fine over USB — used in
mac.c for per-station airtime
Before writing a patch, I wanted to ask:
1. Is there an existing MCU command that can retrieve MIB counters
(busy/tx/rx time) from the firmware in the mt7921 USB case? I didn't
find one in mt7921/mcu.c or mt76_connac_mcu.c.
2. Alternatively, would it be acceptable to accumulate survey data
from the per-station airtime counters (airtime_ac[], already read via
WTBL in mt7921_mac_sta_poll()) into chan_state->cc_tx/cc_rx? This
would give approximate but functional channel utilization reporting.
3. Is there a reason the WF_MIB block is intentionally not exposed
over USB in the firmware?
Any guidance on the preferred approach would be appreciated before I
write a patch.
Best regards,
Bryam Vargas
^ permalink raw reply
* [PATCH wireless-next 15/28] wifi: iwlwifi: mld: Fix use-after-free of bss_conf
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
In certain failure paths, the driver is not fully configured, and
it fails to find the link object. We still need to remove pointers
to the bss_conf to keep from crashing shortly afterwards.
Search all indices for stale pointer if we cannot do the fast
lookup by ID.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/link.c | 42 +++++++++++++++----
1 file changed, 34 insertions(+), 8 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index b5430e8a73d6..1e4959ceb3db 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -504,23 +504,49 @@ void iwl_mld_remove_link(struct iwl_mld *mld,
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(bss_conf->vif);
struct iwl_mld_link *link = iwl_mld_link_from_mac80211(bss_conf);
bool is_deflink = link == &mld_vif->deflink;
- u8 fw_id = link->fw_id;
+ u16 fw_id;
- if (WARN_ON(!link || link->active))
- return;
+ if (WARN_ON_ONCE(!link)) {
+ IWL_ERR(mld, "Remove nonexistent link, bss_conf: 0x%px link-id: %d\n",
+ bss_conf, bss_conf->link_id);
+ fw_id = 0xffff;
+ } else {
+ fw_id = link->fw_id;
+ }
+
+ /* Not cleaning it up seems worse than cleaning up an active link,
+ * so continue on even in warning case.
+ */
+ if (link && WARN_ON_ONCE(link->active))
+ IWL_ERR(mld, "Removing active link, id: %d\n",
+ bss_conf->link_id);
iwl_mld_rm_link_from_fw(mld, bss_conf);
/* Continue cleanup on failure */
- if (!is_deflink)
+ if (link && !is_deflink)
kfree_rcu(link, rcu_head);
+ rcu_read_lock();
RCU_INIT_POINTER(mld_vif->link[bss_conf->link_id], NULL);
- if (WARN_ON(fw_id >= mld->fw->ucode_capa.num_links))
- return;
-
- RCU_INIT_POINTER(mld->fw_id_to_bss_conf[fw_id], NULL);
+ if (fw_id >= mld->fw->ucode_capa.num_links) {
+ struct ieee80211_bss_conf *tmp_bss_conf;
+ int i;
+
+ /* Search for any existing back-pointer */
+ for (i = 0; i < ARRAY_SIZE(mld->fw_id_to_bss_conf); i++) {
+ tmp_bss_conf = rcu_dereference(mld->fw_id_to_bss_conf[i]);
+ if (tmp_bss_conf == bss_conf) {
+ IWL_ERR(mld, "WARNING: Found bss_conf in fw_id_to_bss_conf[%i], Nulling pointer.\n",
+ i);
+ RCU_INIT_POINTER(mld->fw_id_to_bss_conf[i], NULL);
+ }
+ }
+ } else {
+ RCU_INIT_POINTER(mld->fw_id_to_bss_conf[fw_id], NULL);
+ }
+ rcu_read_unlock();
}
void iwl_mld_handle_missed_beacon_notif(struct iwl_mld *mld,
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 22/28] wifi: mac80211: Add force-cleanup call to driver.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
When hardware is determined by mac80211 to be in non-recoverable
state, then SDATA_IN_DRIVER flag is removed, and mac80211 will no
longer do any 'graceful' teardown of the objects in the driver.
This was causing use-after-free crashes in the iwlwifi driver
since it's logic to do internal cleanup is not quite right for
some reason.
Add an explicit callback to the driver to tell it to clean up
whatever it needs to clean up in case mac80211 considers it
dead.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
include/net/mac80211.h | 7 +++++++
net/mac80211/driver-ops.h | 8 ++++++++
net/mac80211/util.c | 5 +++++
3 files changed, 20 insertions(+)
diff --git a/include/net/mac80211.h b/include/net/mac80211.h
index 9cc482191ab9..d963f213863b 100644
--- a/include/net/mac80211.h
+++ b/include/net/mac80211.h
@@ -3934,6 +3934,12 @@ struct ieee80211_prep_tx_info {
* you should ensure to cancel it on this callback.
* Must be implemented and can sleep.
*
+ * @force_cleanup: Called after mac80211 determines the
+ * driver/firmware/hardware has failed and cannot
+ * be restarted. SDATA_IN_DRIVER is false at this point,
+ * so normal cleanup will not happen. This force_cleanup
+ * operation lets the driver do any needed houskeeping.
+ *
* @suspend: Suspend the device; mac80211 itself will quiesce before and
* stop transmitting and doing any other configuration, and then
* ask the device to suspend. This is only invoked when WoWLAN is
@@ -4569,6 +4575,7 @@ struct ieee80211_ops {
struct sk_buff *skb);
int (*start)(struct ieee80211_hw *hw);
void (*stop)(struct ieee80211_hw *hw, bool suspend);
+ void (*force_cleanup)(struct ieee80211_hw *hw);
#ifdef CONFIG_PM
int (*suspend)(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan);
int (*resume)(struct ieee80211_hw *hw);
diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h
index e2283d7dcd1e..3bd3d078ce9b 100644
--- a/net/mac80211/driver-ops.h
+++ b/net/mac80211/driver-ops.h
@@ -300,6 +300,14 @@ static inline void drv_cancel_hw_scan(struct ieee80211_local *local,
trace_drv_return_void(local);
}
+static inline void
+drv_force_cleanup(struct ieee80211_local *local)
+{
+ lockdep_assert_wiphy(local->hw.wiphy);
+ if (local->ops->force_cleanup)
+ local->ops->force_cleanup(&local->hw);
+}
+
static inline int
drv_sched_scan_start(struct ieee80211_local *local,
struct ieee80211_sub_if_data *sdata,
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 55054de62508..ec11ee6b8752 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1692,6 +1692,11 @@ static void ieee80211_handle_reconfig_failure(struct ieee80211_local *local)
*/
list_for_each_entry(ctx, &local->chanctx_list, list)
ctx->driver_present = false;
+
+ /* Tell driver to purge any remaining configuration it may have
+ * lingering around.
+ */
+ drv_force_cleanup(local);
}
static void ieee80211_assign_chanctx(struct ieee80211_local *local,
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 26/28] wifi: mac80211: Ensure link work-items are only initialized once.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Re-initialization could cause corruption in work queues in case
links were not properly stopped for some reason.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
net/mac80211/ieee80211_i.h | 1 +
net/mac80211/link.c | 28 ++++++++++++++++++++--------
2 files changed, 21 insertions(+), 8 deletions(-)
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index d71e0c6d2165..ac4e10f16cd9 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1079,6 +1079,7 @@ struct ieee80211_link_data {
bool operating_11g_mode;
+ bool already_initialized; /* has ieee80211_link_init been called? */
struct {
struct wiphy_work finalize_work;
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 03bfca27d205..6125e79f67c9 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -110,14 +110,25 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
link->user_power_level = sdata->local->user_power_level;
link_conf->txpower = INT_MIN;
- wiphy_work_init(&link->csa.finalize_work,
- ieee80211_csa_finalize_work);
- wiphy_work_init(&link->color_change_finalize_work,
- ieee80211_color_change_finalize_work);
- wiphy_delayed_work_init(&link->color_collision_detect_work,
- ieee80211_color_collision_detection_work);
- wiphy_hrtimer_work_init(&link->dfs_cac_timer_work,
- ieee80211_dfs_cac_timer_work);
+ if (link->already_initialized) {
+ wiphy_delayed_work_cancel(link->sdata->local->hw.wiphy,
+ &link->color_collision_detect_work);
+ wiphy_work_cancel(link->sdata->local->hw.wiphy,
+ &link->color_change_finalize_work);
+ wiphy_work_cancel(link->sdata->local->hw.wiphy,
+ &link->csa.finalize_work);
+ wiphy_hrtimer_work_cancel(link->sdata->local->hw.wiphy,
+ &link->dfs_cac_timer_work);
+ } else {
+ wiphy_work_init(&link->csa.finalize_work,
+ ieee80211_csa_finalize_work);
+ wiphy_work_init(&link->color_change_finalize_work,
+ ieee80211_color_change_finalize_work);
+ wiphy_delayed_work_init(&link->color_collision_detect_work,
+ ieee80211_color_collision_detection_work);
+ wiphy_hrtimer_work_init(&link->dfs_cac_timer_work,
+ ieee80211_dfs_cac_timer_work);
+ }
if (!deflink) {
switch (sdata->vif.type) {
@@ -138,6 +149,7 @@ void ieee80211_link_init(struct ieee80211_sub_if_data *sdata,
ieee80211_link_debugfs_add(link);
}
+ link->already_initialized = true;
rcu_assign_pointer(sdata->vif.link_conf[link_id], link_conf);
rcu_assign_pointer(sdata->link[link_id], link);
}
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 24/28] wifi: iwlwifi: mld: Fix NPE in flush logic.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
It appears that sometimes the sta can be NULL, so check for
that and return early.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 288fc4b7604e..06e064466e3b 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -779,6 +779,9 @@ void iwl_mld_flush_sta_txqs(struct iwl_mld *mld, struct ieee80211_sta *sta)
void iwl_mld_wait_sta_txqs_empty(struct iwl_mld *mld, struct ieee80211_sta *sta)
{
+ if (!sta)
+ return;
+
/* Avoid a warning in iwl_trans_wait_txq_empty if are anyway on the way
* to a restart.
*/
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 13/28] wifi: iwlwifi: mld: Remove warning about BAID.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
It seems to be expected behaviour, and is seen fairly often
in testing in adverse conditions, so make it a one-line log
message instead of WARN splat.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/agg.c | 12 +++++++++---
1 file changed, 9 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/agg.c b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
index a757077b0a7a..23d55374ef8a 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/agg.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/agg.c
@@ -216,10 +216,16 @@ iwl_mld_reorder(struct iwl_mld *mld, struct napi_struct *napi,
if (baid == IWL_RX_REORDER_DATA_INVALID_BAID)
return IWL_MLD_PASS_SKB;
- /* no sta yet */
- if (WARN_ONCE(!sta,
- "Got valid BAID without a valid station assigned\n"))
+ /* no sta yet. This happens fairly often, don't WARN_ON about it. */
+ if (!sta) {
+ static bool done_once;
+
+ if (!done_once) {
+ IWL_ERR(mld, "Got valid BAID without a valid station assigned, will not log again.\n");
+ done_once = true;
+ }
return IWL_MLD_PASS_SKB;
+ }
mld_sta = iwl_mld_sta_from_mac80211(sta);
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 20/28] wifi: iwlwifi: mld: Improve logging message.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Indicate that the problem is being fixed.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index d44ec81d2ce4..aa4d391ffc00 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -647,7 +647,7 @@ void iwl_mld_mac80211_stop(struct ieee80211_hw *hw, bool suspend)
*/
for (int i = 0; i < ARRAY_SIZE(mld->scan.uid_status); i++)
if (WARN_ONCE(mld->scan.uid_status[i],
- "UMAC scan UID %d status was not cleaned (0x%x 0x%x)\n",
+ "mac80211-stop: UMAC scan UID %d status was not cleaned (0x%x 0x%x), forcing to 0\n",
i, mld->scan.uid_status[i], mld->scan.status))
mld->scan.uid_status[i] = 0;
}
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 28/28] wifi: mac80211: Decrease WARN spam.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Comment one of them out, and make another WARN_ONCE.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
net/mac80211/link.c | 1 -
net/mac80211/util.c | 3 ++-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/net/mac80211/link.c b/net/mac80211/link.c
index 6125e79f67c9..e3a825ea3a04 100644
--- a/net/mac80211/link.c
+++ b/net/mac80211/link.c
@@ -544,7 +544,6 @@ static int _ieee80211_set_active_links(struct ieee80211_sub_if_data *sdata,
ret = drv_change_sta_links(local, sdata, &sta->sta,
old_active | active_links,
active_links);
- WARN_ON_ONCE(ret);
/*
* Do it again, just in case - the driver might very
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index ec11ee6b8752..df156f8b5211 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -1879,7 +1879,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
if (suspended)
WARN(1, "Hardware became unavailable upon resume. This could be a software issue prior to suspend or a hardware issue.\n");
else
- WARN(1, "Hardware became unavailable during restart.\n");
+ WARN_ONCE(1, "Hardware became unavailable during restart: %d\n", res);
+
ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
IEEE80211_QUEUE_STOP_REASON_SUSPEND,
false);
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 18/28] wifi: iwlwifi: mld: Use warn-on-once in emlsr exit logic.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Only splat warning once, and improve logging to indicate more
about why it is in the problem state.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
index f842f5183223..7a37ca64a612 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
@@ -164,7 +164,10 @@ static void iwl_mld_check_emlsr_prevention(struct iwl_mld *mld,
* The timeouts are chosen so that this will not happen, i.e.
* IWL_MLD_EMLSR_PREVENT_LONG > IWL_MLD_PREVENT_EMLSR_TIMEOUT
*/
- WARN_ON(mld_vif->emlsr.exit_repeat_count > 3);
+ if (WARN_ON_ONCE(mld_vif->emlsr.exit_repeat_count > 3)) {
+ IWL_ERR(mld, "check-emlsr-prevention exit repeats: %d > 3, blocked-reasons: 0x%x\n",
+ mld_vif->emlsr.exit_repeat_count, mld_vif->emlsr.blocked_reasons);
+ }
}
IWL_DEBUG_EHT(mld,
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 16/28] wifi: iwlwifi: mld: Check for null in iwl_mld_wait_sta_txqs_empty
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
I saw some crashes here in eMLSR torture test, looks like mld_txq
was NULL, so add check.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 6338ca46f68e..288fc4b7604e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -789,7 +789,7 @@ void iwl_mld_wait_sta_txqs_empty(struct iwl_mld *mld, struct ieee80211_sta *sta)
struct iwl_mld_txq *mld_txq =
iwl_mld_txq_from_mac80211(sta->txq[i]);
- if (!mld_txq->status.allocated)
+ if (!mld_txq || !mld_txq->status.allocated)
continue;
iwl_trans_wait_txq_empty(mld->trans, mld_txq->fw_id);
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 25/28] wifi: iwlwifi: mld: Fix bad return address in tx code.
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
iwl_mld_txq_from_mac80211 was returning the offset into
txq without checking if txq was NULL. In case txq is
NULL, this would return a small, but non NULL pointer.
The safety check in calling code would then treat it
as non-null and attempt to dereference.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/tx.h | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.h b/drivers/net/wireless/intel/iwlwifi/mld/tx.h
index 520f15f9d33c..8b0da098c25f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tx.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.h
@@ -45,6 +45,8 @@ static inline void iwl_mld_init_txq(struct iwl_mld_txq *mld_txq)
static inline struct iwl_mld_txq *
iwl_mld_txq_from_mac80211(struct ieee80211_txq *txq)
{
+ if (!txq)
+ return NULL;
return (void *)txq->drv_priv;
}
--
2.42.0
^ permalink raw reply related
* [PATCH wireless-next 21/28] wifi: iwlwifi: mld: Protect from null mld_sta
From: greearb @ 2026-03-11 23:07 UTC (permalink / raw)
To: linux-wireless; +Cc: Ben Greear
In-Reply-To: <20260311230730.163348-1-greearb@candelatech.com>
From: Ben Greear <greearb@candelatech.com>
Torture tests were crashing here, protect against a null
mld_sta.
Signed-off-by: Ben Greear <greearb@candelatech.com>
---
drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index aa4d391ffc00..badaceb120b3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1911,6 +1911,7 @@ static void iwl_mld_mac80211_flush(struct ieee80211_hw *hw,
iwl_mld_add_txq_list(mld);
for (int i = 0; i < mld->fw->ucode_capa.num_stations; i++) {
+ struct iwl_mld_sta *mld_sta;
struct ieee80211_link_sta *link_sta =
wiphy_dereference(mld->wiphy,
mld->fw_id_to_link_sta[i]);
@@ -1919,7 +1920,8 @@ static void iwl_mld_mac80211_flush(struct ieee80211_hw *hw,
continue;
/* Check that the sta belongs to the given vif */
- if (vif && vif != iwl_mld_sta_from_mac80211(link_sta->sta)->vif)
+ mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
+ if (vif && (!mld_sta || vif != mld_sta->vif))
continue;
if (drop)
--
2.42.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