* [PATCH wireless-next 1/2] wifi: nl80211: Add NL80211_ATTR_MAX_CH_SWITCH_TIME attribute
From: Shashikala Prabhu @ 2026-05-18 10:31 UTC (permalink / raw)
To: johannes
Cc: linux-wireless, vikram, kiranv, pshashik, cgopi, ybasamma,
vthiagar, sivad, uvignesh, mohathan, abishekg
In-Reply-To: <20260518103106.1462604-1-shashikala.prabhu@oss.qualcomm.com>
From: Chandru Gopi <cgopi@qti.qualcomm.com>
IEEE Std 802.11-2024 subclause 9.4.2.216 (Max Channel Switch Time element)
defines a Switch Time field in the Channel Switch Announcement (CSA)
element that indicates the time delta between the time the last beacon
is transmitted by the AP in the current channel and the expected time
of the first beacon transmitted by the AP in the new channel.
Add a new u32 nl80211 attribute, NL80211_ATTR_MAX_CH_SWITCH_TIME,
to carry this value in the NL80211_CMD_CH_SWITCH_STARTED_NOTIFY
event. Userspace can use this information to decide whether to
remain connected or disconnect before the AP moves to the new
channel.
Signed-off-by: Chandru Gopi <cgopi@qti.qualcomm.com>
Signed-off-by: Shashikala Prabhu <shashikala.prabhu@oss.qualcomm.com>
---
include/uapi/linux/nl80211.h | 11 +++++++++++
net/wireless/nl80211.c | 1 +
2 files changed, 12 insertions(+)
diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
index 9998f6c0a665..65c04e1e54b6 100644
--- a/include/uapi/linux/nl80211.h
+++ b/include/uapi/linux/nl80211.h
@@ -953,6 +953,10 @@
* after %NL80211_ATTR_CH_SWITCH_COUNT TBTT's. The userspace may
* decide to react to this indication by requesting other
* interfaces to change channel as well.
+ * %NL80211_ATTR_MAX_CH_SWITCH_TIME included in this command indicates the
+ * AP's Max Channel Switch Time. Userspace can use this information to
+ * decide whether to remain connected or disconnect before the AP moves to
+ * the new channel.
*
* @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
* its %NL80211_ATTR_WDEV identifier. It must have been created with
@@ -3165,6 +3169,12 @@ enum nl80211_commands {
* @NL80211_ATTR_NPCA_PRIMARY_FREQ: NPCA primary channel (u32)
* @NL80211_ATTR_NPCA_PUNCT_BITMAP: NPCA puncturing bitmap (u32)
*
+ * @NL80211_ATTR_MAX_CH_SWITCH_TIME: u32 attribute carrying the Switch Time
+ * field from the MCST (Max Channel Switch Time) element, indicating the
+ * time delta between the time the last beacon is transmitted by the AP in
+ * the current channel and the expected time of the first beacon
+ * transmitted by the AP in the new channel, expressed in TUs.
+ *
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
* @NL80211_ATTR_MAX: highest attribute number currently defined
* @__NL80211_ATTR_AFTER_LAST: internal use
@@ -3763,6 +3773,7 @@ enum nl80211_attrs {
NL80211_ATTR_NPCA_PRIMARY_FREQ,
NL80211_ATTR_NPCA_PUNCT_BITMAP,
+ NL80211_ATTR_MAX_CH_SWITCH_TIME,
/* add attributes here, update the policy in nl80211.c */
__NL80211_ATTR_AFTER_LAST,
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index c272a2fbad03..14d41142cf79 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -1093,6 +1093,7 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
[NL80211_ATTR_NPCA_PRIMARY_FREQ] = { .type = NLA_U32 },
[NL80211_ATTR_NPCA_PUNCT_BITMAP] =
NLA_POLICY_FULL_RANGE(NLA_U32, &nl80211_punct_bitmap_range),
+ [NL80211_ATTR_MAX_CH_SWITCH_TIME] = { .type = NLA_U32 },
};
/* policy for the key attributes */
--
2.34.1
^ permalink raw reply related
* [PATCH wireless-next 2/2] wifi: cfg80211/mac80211: Pass MCST element value in ch_switch_started_notify
From: Shashikala Prabhu @ 2026-05-18 10:31 UTC (permalink / raw)
To: johannes
Cc: linux-wireless, vikram, kiranv, pshashik, cgopi, ybasamma,
vthiagar, sivad, uvignesh, mohathan, abishekg
In-Reply-To: <20260518103106.1462604-1-shashikala.prabhu@oss.qualcomm.com>
From: Chandru Gopi <cgopi@qti.qualcomm.com>
IEEE Std 802.11-2024 subclause 9.4.2.216 (Max Channel Switch Time element)
defines a Switch Time field in the Channel Switch Announcement (CSA)
element that indicates the time delta between the time the last beacon
is transmitted by the AP in the current channel and the expected time
of the first beacon transmitted by the AP in the new channel.
Forward the already-parsed MCST (Maximum Channel Switch Time) element
value to userspace via the NL80211_CMD_CH_SWITCH_STARTED_NOTIFY netlink
command. Userspace can use this information to decide whether to remain
connected or disconnect before the AP moves to the new channel.
Pass mcst_tu=0 in the __ieee80211_channel_switch() call to
cfg80211_ch_switch_started_notify() since the AP-initiated channel
switch path does not carry a MCST element, as this element is only
present in Beacon/Probe Response frames processed on the STA side via
ieee80211_sta_process_chanswitch().
Signed-off-by: Chandru Gopi <cgopi@qti.qualcomm.com>
Signed-off-by: Shashikala Prabhu <shashikala.prabhu@oss.qualcomm.com>
---
include/net/cfg80211.h | 4 +++-
net/mac80211/cfg.c | 2 +-
net/mac80211/mlme.c | 2 +-
net/wireless/nl80211.c | 12 ++++++++----
4 files changed, 13 insertions(+), 7 deletions(-)
diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index ddcf559430dd..c55b7f4ea48a 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -9979,6 +9979,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
* @link_id: the link ID for MLO, must be 0 for non-MLO
* @count: the number of TBTTs until the channel switch happens
* @quiet: whether or not immediate quiet was requested by the AP
+ * @mcst_tu: max channel switch time in TUs, 0 if the MCST element was not
+ * present
*
* Inform the userspace about the channel switch that has just
* started, so that it can take appropriate actions (eg. starting
@@ -9987,7 +9989,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
void cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
unsigned int link_id, u8 count,
- bool quiet);
+ bool quiet, u32 mcst_tu);
/**
* ieee80211_operating_class_to_band - convert operating class to band
diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c
index 0b1291ff7a2c..0cb6d949665a 100644
--- a/net/mac80211/cfg.c
+++ b/net/mac80211/cfg.c
@@ -4768,7 +4768,7 @@ __ieee80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
cfg80211_ch_switch_started_notify(sdata->dev,
&link_data->csa.chanreq.oper, link_id,
- params->count, params->block_tx);
+ params->count, params->block_tx, 0);
if (changed) {
ieee80211_link_info_change_notify(sdata, link_data, changed);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 5b02141b0cb2..76f3c3a8feba 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3182,7 +3182,7 @@ ieee80211_sta_process_chanswitch(struct ieee80211_link_data *link,
cfg80211_ch_switch_started_notify(sdata->dev, &csa_ie.chanreq.oper,
link->link_id, csa_ie.count,
- csa_ie.mode);
+ csa_ie.mode, csa_ie.max_switch_time);
/* we may have to handle timeout for deactivated link in software */
now = ktime_get_boottime();
diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
index 14d41142cf79..a17e87e782e4 100644
--- a/net/wireless/nl80211.c
+++ b/net/wireless/nl80211.c
@@ -22271,7 +22271,8 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
struct cfg80211_chan_def *chandef,
gfp_t gfp,
enum nl80211_commands notif,
- u8 count, bool quiet)
+ u8 count, bool quiet,
+ u32 mcst_tu)
{
struct wireless_dev *wdev = netdev->ieee80211_ptr;
struct sk_buff *msg;
@@ -22303,6 +22304,9 @@ static void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
if (quiet &&
nla_put_flag(msg, NL80211_ATTR_CH_SWITCH_BLOCK_TX))
goto nla_put_failure;
+ if (mcst_tu &&
+ nla_put_u32(msg, NL80211_ATTR_MAX_CH_SWITCH_TIME, mcst_tu))
+ goto nla_put_failure;
}
genlmsg_end(msg, hdr);
@@ -22355,7 +22359,7 @@ void cfg80211_ch_switch_notify(struct net_device *dev,
cfg80211_sched_dfs_chan_update(rdev);
nl80211_ch_switch_notify(rdev, dev, link_id, chandef, GFP_KERNEL,
- NL80211_CMD_CH_SWITCH_NOTIFY, 0, false);
+ NL80211_CMD_CH_SWITCH_NOTIFY, 0, false, 0);
}
EXPORT_SYMBOL(cfg80211_ch_switch_notify);
@@ -22402,7 +22406,7 @@ EXPORT_SYMBOL(cfg80211_incumbent_signal_notify);
void cfg80211_ch_switch_started_notify(struct net_device *dev,
struct cfg80211_chan_def *chandef,
unsigned int link_id, u8 count,
- bool quiet)
+ bool quiet, u32 mcst_tu)
{
struct wireless_dev *wdev = dev->ieee80211_ptr;
struct wiphy *wiphy = wdev->wiphy;
@@ -22416,7 +22420,7 @@ void cfg80211_ch_switch_started_notify(struct net_device *dev,
nl80211_ch_switch_notify(rdev, dev, link_id, chandef, GFP_KERNEL,
NL80211_CMD_CH_SWITCH_STARTED_NOTIFY,
- count, quiet);
+ count, quiet, mcst_tu);
}
EXPORT_SYMBOL(cfg80211_ch_switch_started_notify);
--
2.34.1
^ permalink raw reply related
* RE: [RFT rtw/rtw-next] wifi: rtw88: check if center channel is supported before setting
From: Zong-Zhe Yang @ 2026-05-18 10:58 UTC (permalink / raw)
To: Thadeu Lima de Souza Cascardo, Ping-Ke Shih
Cc: linux-wireless@vger.kernel.org
In-Reply-To: <agYJNW7Mxt0dOfTw@quatroqueijos.cascardo.eti.br>
Thadeu Lima de Souza Cascardo <cascardo@igalia.com> wrote:
>
> On Mon, Apr 13, 2026 at 01:36:01PM +0800, Ping-Ke Shih wrote:
> > From: Zong-Zhe Yang <kevin_yang@realtek.com>
> >
> > Some unusual center channels may be assigned to driver. However, RF
> > doesn't really expect them, and then warnings happen due to lack of TX
> > power limit configurations. For example, center channel 114/130 with
> > 80MHz. So, add a check before setting the channel.
> >
> > Signed-off-by: Zong-Zhe Yang <kevin_yang@realtek.com>
> > Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
>
> Hi,
>
> I have tested this patch and it does prevent 80MHz from being used.
> However, RF seems to accept those center channels with 80MHz just fine. I can
> get up to 600Mbps with UDP while I can get past 300Mbps after applying this
> patch.
>
> Should we apply something like [1] instead?
>
> https://lore.kernel.org/linux-wireless/20260306-rtw88_channel130-v1-1-ff25a5
> bc930a@igalia.com
>
> Regards.
> Cascardo.
>
Hi,
The chipsets supported by rtw88 are only verified with the existing center channels
before 160MHz. Although you set 80MHz here, but these center channels actually
appeared after 160MHz. I also have checked with our HW members. They said they
cannot guarantee everything will be right. So, we won't officially allow these center
channels.
Maybe you think your test result is fine to you, but throughput test doesn't tell the
whole story, e.g., is it really fine for regulatory? So, I suggest that you change the AP
configuration to use another center channel with 80MHz.
Thanks.
> > ---
> > drivers/net/wireless/realtek/rtw88/mac80211.c | 7 +++++--
> > drivers/net/wireless/realtek/rtw88/main.c | 13 +++++++++++--
> > drivers/net/wireless/realtek/rtw88/main.h | 2 +-
> > drivers/net/wireless/realtek/rtw88/phy.c | 18 ++++++++++++++++++
> > drivers/net/wireless/realtek/rtw88/phy.h | 2 ++
> > 5 files changed, 37 insertions(+), 5 deletions(-)
> >
> > diff --git a/drivers/net/wireless/realtek/rtw88/mac80211.c
> > b/drivers/net/wireless/realtek/rtw88/mac80211.c
> > index 766f22d31079..9d97e8dd0c1e 100644
> > --- a/drivers/net/wireless/realtek/rtw88/mac80211.c
> > +++ b/drivers/net/wireless/realtek/rtw88/mac80211.c
> > @@ -92,8 +92,11 @@ static int rtw_ops_config(struct ieee80211_hw *hw,
> int radio_idx, u32 changed)
> > }
> > }
> >
> > - if (changed & IEEE80211_CONF_CHANGE_CHANNEL)
> > - rtw_set_channel(rtwdev);
> > + if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
> > + ret = rtw_set_channel(rtwdev);
> > + if (ret)
> > + goto out;
> > + }
> >
> > if ((changed & IEEE80211_CONF_CHANGE_IDLE) &&
> > (hw->conf.flags & IEEE80211_CONF_IDLE) && diff --git
> > a/drivers/net/wireless/realtek/rtw88/main.c
> > b/drivers/net/wireless/realtek/rtw88/main.c
> > index cd9254370fcc..08aebb3c5a78 100644
> > --- a/drivers/net/wireless/realtek/rtw88/main.c
> > +++ b/drivers/net/wireless/realtek/rtw88/main.c
> > @@ -868,23 +868,30 @@ void rtw_get_channel_params(struct
> cfg80211_chan_def *chandef,
> > chan_params->primary_chan = channel->hw_value; }
> >
> > -void rtw_set_channel(struct rtw_dev *rtwdev)
> > +int rtw_set_channel(struct rtw_dev *rtwdev)
> > {
> > const struct rtw_chip_info *chip = rtwdev->chip;
> > struct ieee80211_hw *hw = rtwdev->hw;
> > struct rtw_hal *hal = &rtwdev->hal;
> > struct rtw_channel_params ch_param;
> > u8 center_chan, primary_chan, bandwidth, band;
> > + int ch_idx;
> >
> > rtw_get_channel_params(&hw->conf.chandef, &ch_param);
> > if (WARN(ch_param.center_chan == 0, "Invalid channel\n"))
> > - return;
> > + return -EINVAL;
> >
> > center_chan = ch_param.center_chan;
> > primary_chan = ch_param.primary_chan;
> > bandwidth = ch_param.bandwidth;
> > band = ch_param.center_chan > 14 ? RTW_BAND_5G :
> RTW_BAND_2G;
> >
> > + ch_idx = rtw_band_channel_to_idx(band, center_chan);
> > + if (ch_idx < 0) {
> > + rtw_warn(rtwdev, "not support band %d ch %d\n", band,
> center_chan);
> > + return -EOPNOTSUPP;
> > + }
> > +
> > rtw_update_channel(rtwdev, center_chan, primary_chan, band,
> > bandwidth);
> >
> > if (rtwdev->scan_info.op_chan)
> > @@ -910,6 +917,8 @@ void rtw_set_channel(struct rtw_dev *rtwdev)
> > */
> > if (!test_bit(RTW_FLAG_SCANNING, rtwdev->flags))
> > rtwdev->need_rfk = true;
> > +
> > + return 0;
> > }
> >
> > void rtw_chip_prepare_tx(struct rtw_dev *rtwdev) diff --git
> > a/drivers/net/wireless/realtek/rtw88/main.h
> > b/drivers/net/wireless/realtek/rtw88/main.h
> > index 9c0b746540b0..a368f1a4a003 100644
> > --- a/drivers/net/wireless/realtek/rtw88/main.h
> > +++ b/drivers/net/wireless/realtek/rtw88/main.h
> > @@ -2241,7 +2241,7 @@ bool ltecoex_reg_write(struct rtw_dev *rtwdev,
> > u16 offset, u32 value); void rtw_restore_reg(struct rtw_dev *rtwdev,
> > struct rtw_backup_info *bckp, u32 num); void
> > rtw_desc_to_mcsrate(u16 rate, u8 *mcs, u8 *nss); -void
> > rtw_set_channel(struct rtw_dev *rtwdev);
> > +int rtw_set_channel(struct rtw_dev *rtwdev);
> > void rtw_chip_prepare_tx(struct rtw_dev *rtwdev); void
> > rtw_vif_port_config(struct rtw_dev *rtwdev, struct rtw_vif *rtwvif,
> > u32 config);
> > diff --git a/drivers/net/wireless/realtek/rtw88/phy.c
> > b/drivers/net/wireless/realtek/rtw88/phy.c
> > index e2ac5c6fd500..a543eaa57f2c 100644
> > --- a/drivers/net/wireless/realtek/rtw88/phy.c
> > +++ b/drivers/net/wireless/realtek/rtw88/phy.c
> > @@ -1630,6 +1630,24 @@ static int rtw_channel_to_idx(u8 band, u8
> channel)
> > return ch_idx;
> > }
> >
> > +int rtw_band_channel_to_idx(enum rtw_supported_band band, u8 channel)
> > +{
> > + u8 phy_band;
> > +
> > + switch (band) {
> > + case RTW_BAND_2G:
> > + phy_band = PHY_BAND_2G;
> > + break;
> > + case RTW_BAND_5G:
> > + phy_band = PHY_BAND_5G;
> > + break;
> > + default:
> > + return -1;
> > + }
> > +
> > + return rtw_channel_to_idx(phy_band, channel); }
> > +
> > static void rtw_phy_set_tx_power_limit(struct rtw_dev *rtwdev, u8 regd,
> u8 band,
> > u8 bw, u8 rs, u8 ch, s8
> > pwr_limit) { diff --git a/drivers/net/wireless/realtek/rtw88/phy.h
> > b/drivers/net/wireless/realtek/rtw88/phy.h
> > index 8449936497bb..98aeb576e24d 100644
> > --- a/drivers/net/wireless/realtek/rtw88/phy.h
> > +++ b/drivers/net/wireless/realtek/rtw88/phy.h
> > @@ -201,4 +201,6 @@ enum rtw_phy_cck_pd_lv { #define
> > RRSR_RATE_ORDER_MAX 0xfffff
> > #define RRSR_RATE_ORDER_CCK_LEN 4
> >
> > +int rtw_band_channel_to_idx(enum rtw_supported_band band, u8
> > +channel);
> > +
> > #endif
> > --
> > 2.25.1
> >
> >
^ permalink raw reply
* [PATCH RFC 0/2] bcma: support for SHIM-attached SoC backplane (BCM6362)
From: Alessio Ferri @ 2026-05-18 11:35 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: linux-wireless, linux-mips
This RFC introduces the minimal infrastructure in bcma to support
SoCs that publish a SHIM-style mini-EROM: a backplane on a big-
endian peripheral bus where ChipCommon, the IEEE 802.11 core and
BCMA_CORE_SHIM all report NMW=NSW=0 because clock and reset
gating happens in the SHIM's per-core Control register rather
than in per-core DMP wrappers.
The two patches:
1/2 bcma: host_soc: support big-endian SoC backplane with
wrapper-less core synthesis
2/2 bcma: scan: allow SHIM-style mini-EROM wrapper-less cores
These two are infrastructure-only and don't interfare with
existing SoC: the default brcm,bus-axi compatible
keeps the existing behaviour, and the new code paths gate on
bus->big_endian and bus->shim_attached, both populated only
when DT compatible is one of the new SHIM-quirks ones
(brcm,bcm6362-bus-axi, brcm,bcm63268-bus-axi). I didn't
include the DT bindings YAML for those new compatibles
from this RFC - the binding design depends on the feedback.
Context: this builds on an earlier design question to the list
that did not draw a response:
https://lore.kernel.org/linux-wireless/CAHDv23WJLBEp3ETscVT4Z6E5PQfzTDcofxbZ6jAezZNYde7C0w@mail.gmail.com/
The companion b43 series for the same hardware (BCM6362 single-
die N-PHY rev 8 + radio 2057 rev 8) is in review here:
https://lore.kernel.org/linux-wireless/4581a48e-a6e4-46b1-853f-16db445d6890@mythread.it/
That b43 series stands on its own (b43 dispatcher gaps for a
PHY+radio combination already partially supported in tree).
This bcma series creates the conditions for b43 to
bind to a BCM6362 d11 core, but does not change anything for any
other b43 user.
Open design questions:
1. DT bindings for the new compatible strings. I added
"brcm,bcm6362-bus-axi" and "brcm,bcm63268-bus-axi" as new
compatibles alongside the existing "brcm,bus-axi", each with
its own quirks data block. Is it ok?
2. SHIM peephole base address. The brcm-shim quirks block
hard-codes shim_base = 0x10007000, which is the address
used by both BCM6362 and BCM63268 per the OEM SoC map
headers. I left the hard-coded value in place for the
RFC since i think it is fixed, but i'm ok to move it
to DT if asked.
3. Accessor set duplication. The BE variants in patch 1/2
(read16_be / read32_be / write16_be / write32_be /
aread32_be / awrite32_be) are direct duplicates of the
existing helpers with the underlying ioread/iowrite calls
swapped.
4. The allow-list extension in patch 2/2 (CHIPCOMMON, 80211,
SHIM) is gated on bus->shim_attached at the point of the
check.
If this design is acceptable in principle, the follow-up work
that depends on it is:
- DT bindings YAML for the new compatibles;
- A SoC-side wlan-shim platform driver to take the BCM6362
SHIM out of reset before bcma scans it (currently handled by
an out-of-tree driver during my bring-up; will upstream);
- A SPROM fallback driver that registers via
bcma_arch_register_fallback_sprom(), BCM6362 is spromless
- DT nodes for BCM6362 and BCM63268-class boards under
arch/mips/boot/dts/brcm/.
Tested on a D-Link DSL-3580L (BCM6362 SoC, single-die N-PHY rev
8 + radio 2057 rev 8). With patches 1-2 applied plus the
out-of-tree wlan-shim driver and SPROM fallback, bcma scan
enumerates the three SHIM-attached cores, b43 binds to the
802.11 core, and the d11 reaches firmware load and PSM run-up.
If asked, i can provide the full dmesg to verify working status.
I also own a NetGear D4220 and some other broadcom routers
that i plan to bring up after the BCM6362, they are BCM63168
and BCM63268.
The shim_base in quirks block already covers BCM63268 per the
OEM SoC map headers, and i expect the same SHIM-attached
backplane shape for the BCM63168.
I plan to reuse this infrastructure for their bring up.
Alessio Ferri (2):
bcma: host_soc: support big-endian SoC backplane with wrapper-less
core synthesis
bcma: scan: allow SHIM-style mini-EROM wrapper-less cores
drivers/bcma/host_soc.c | 243 +++++++++++++++++++++++++++++++++++++-
drivers/bcma/scan.c | 19 ++-
include/linux/bcma/bcma.h | 10 ++
3 files changed, 269 insertions(+), 3 deletions(-)
--
2.43.0
^ permalink raw reply
* [PATCH RFC 1/2] bcma: host_soc: support quirked big-endian SoC backplane
From: Alessio Ferri @ 2026-05-18 11:39 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: linux-wireless, linux-mips
In-Reply-To: <3e236bf0-5269-4631-8e56-1bc199c2f643@mythread.it>
bcma_host_soc currently assumes the PCI/MIPS-LE layout: little-
endian MMIO and a populated io_wrap on every core. On a SHIM-
attached backplane both assumptions fail. Add the minimal
infrastructure to host_soc for this class of SoC:
* A big-endian accessor set covering read16/32, write16/32,
aread32 and awrite32. read8/write8 are byte accesses and
endian-agnostic, so the LE helpers are reused.
block_read/block_write are intentionally omitted -
CONFIG_BCMA_BLOCKIO is not set on the targets that need this.
* A wrapper-register synthesizer reached when core->io_wrap is
NULL. It maps BCMA_IOCTL and BCMA_RESET_CTL accesses on the
ChipCommon and 802.11 cores to the SHIM Control register.
SICF_* bits in the SHIM Control register are bit-for-bit
BCMA_IOCTL; SICF_WOC_CORE_RESET (bit 16) is the per-core
wrapper RESET_CTL bit 0 promoted into the same register.
BCMA_IOST for the 802.11 core is hard-coded to a stable value
rather than synthesized from the SHIM Status register because
the latter's SISF_CORE_BITS field is unreliable while the d11
is in reset (observed: MacStatus=0x1008 on a disabled d11,
where the "2G_PHY" indicator bit 0 is clear, which would
steer b43 down a nonexistent 5 GHz path).
* struct bcma_host_soc_quirks selected by DT compatible string
via of_device_get_match_data(). The default quirks block keeps
the existing brcm,bus-axi behaviour (LE, no SHIM, NMW=NSW=0
cores rejected); a second quirks block selects the BE accessor
set, sets bus->shim_attached and supplies the SHIM peephole
physical base for ioremap. The new "brcm,bcm6362-bus-axi" and
"brcm,bcm63268-bus-axi" compatibles map to the SHIM quirks.
* struct bcma_bus gains three fields populated from quirks data:
big_endian (consumed by scan.c on the mini-EROM reads),
shim_attached (consumed by the companion scan.c patch to allow
NMW=NSW=0 cores through), and shim_iomem (the mapped SHIM
peephole used by the synthesizer).
scan.c's bcma_scan_read32 and bcma_erom_get_ent now branch on
bus->big_endian: a BE backplane otherwise reads the mini-EROM with
the wrong endianness and bcma_get_next_core() bails out on
nonsense component IDs before any of the new code paths matter.
Signed-off-by: Alessio Ferri <alessio.ferri@mythread.it>
---
drivers/bcma/host_soc.c | 243 +++++++++++++++++++++++++++++++++++++-
drivers/bcma/scan.c | 4 +-
include/linux/bcma/bcma.h | 10 ++
3 files changed, 254 insertions(+), 3 deletions(-)
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 20b1816c5..964ff84fc 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -165,6 +165,224 @@ static const struct bcma_host_ops bcma_host_soc_ops = {
.awrite32 = bcma_host_soc_awrite32,
};
+/* SHIM peephole layout (subset of WlanShimRegs). SICF_* bits in the
+ * per-core Control register are bit-for-bit BCMA_IOCTL; bit 16
+ * (SICF_WOC_CORE_RESET) is the per-core wrapper RESET_CTL bit 0
+ * promoted into the SHIM Control register. CC is ChipCommon, MAC is
+ * the IEEE 802.11 core.
+ */
+#define BCMA_SHIM_CC_CONTROL 0x08
+#define BCMA_SHIM_MAC_CONTROL 0x10
+#define SICF_WOC_CORE_RESET 0x10000
+
+/* Resolve the SHIM Control register for a given core (CcControl for
+ * ChipCommon, MacControl for the 802.11 core). Returns NULL for any
+ * other core, including the SHIM core itself - the SHIM has been
+ * running since boot and needs no gating from bcma_core_enable().
+ */
+static void __iomem *bcma_host_soc_shim_ctrl_reg(struct bcma_device *core)
+{
+ void __iomem *shim = core->bus->shim_iomem;
+
+ if (!shim)
+ return NULL;
+
+ switch (core->id.id) {
+ case BCMA_CORE_CHIPCOMMON:
+ return shim + BCMA_SHIM_CC_CONTROL;
+ case BCMA_CORE_80211:
+ return shim + BCMA_SHIM_MAC_CONTROL;
+ }
+ return NULL;
+}
+
+/* Synthesize wrapper-register responses for cores whose DMP wrapper
+ * space does not exist in the standard bcma layout. On SoCs that
+ * publish a SHIM-style mini-EROM (BMIPS xDSL family: BCM6362, ...)
+ * ChipCommon and the 802.11 core report NMW=NSW=0; clock and reset
+ * gating happens in the SHIM's per-core Control register, which is
+ * where this synth routes BCMA_IOCTL and BCMA_RESET_CTL accesses.
+ */
+static u32 bcma_host_soc_synth_aread32(struct bcma_device *core, u16 offset)
+{
+ void __iomem *ctrl_reg = bcma_host_soc_shim_ctrl_reg(core);
+ u32 sicf;
+
+ switch (offset) {
+ case BCMA_IOCTL:
+ /* Low 16 bits of the SHIM Control register map bit-for-bit
+ * to BCMA_IOCTL. Returning the live value lets
+ * bcma_core_is_enabled() observe a prior disable that
+ * cleared CLOCK_EN/FGC. For cores not in the SHIM map
+ * (e.g. the SHIM core itself) return BCMA_IOCTL_CLK so the
+ * core is treated as already-up; the SHIM has been running
+ * since boot and has nothing to enable.
+ */
+ if (ctrl_reg)
+ return ioread32be(ctrl_reg) & 0xFFFF;
+ return BCMA_IOCTL_CLK;
+
+ case BCMA_IOST:
+ /* IOST is synthesized rather than read from the SHIM
+ * Status register: while the d11 is in reset, MacStatus's
+ * SISF_CORE_BITS field is unreliable (observed: 0x1008 on
+ * a disabled d11, where the "2G_PHY" indicator bit 0 is
+ * clear, which would steer b43 down a nonexistent 5 GHz
+ * path on a 2.4 GHz-only single-die part).
+ *
+ * Synthesize a stable IOST for the 802.11 core:
+ * bit 0 (2G_PHY) = 1 single-die 2.4 GHz
+ * bit 1 (5G_PHY) = 0 no 5 GHz radio wired
+ * bit 12 (BCMA_IOST_DMA64)= 1 corerev 22 is DMA64
+ *
+ * Other cores have no defined IOST bits of interest here.
+ */
+ if (core->id.id == BCMA_CORE_80211)
+ return 0x01 | BCMA_IOST_DMA64;
+ return 0;
+
+ case BCMA_RESET_CTL:
+ /* SICF_WOC_CORE_RESET is the wrapper RESET_CTL bit 0 in
+ * the SHIM Control register.
+ */
+ if (ctrl_reg) {
+ sicf = ioread32be(ctrl_reg);
+ return (sicf & SICF_WOC_CORE_RESET) ? 1 : 0;
+ }
+ return 0;
+
+ case BCMA_RESET_ST:
+ /* No "reset pending" semantics in the SHIM Control reg. */
+ return 0;
+
+ default:
+ pr_info("bcma: synth aread32 unhandled offset 0x%03x on core idx=%u id=0x%x\n",
+ offset, core->core_index, core->id.id);
+ return 0;
+ }
+}
+
+static void bcma_host_soc_synth_awrite32(struct bcma_device *core,
+ u16 offset, u32 value)
+{
+ void __iomem *ctrl_reg = bcma_host_soc_shim_ctrl_reg(core);
+ u32 cur, new_val;
+
+ if (ctrl_reg) {
+ switch (offset) {
+ case BCMA_IOCTL:
+ /* SICF low 16 bits == BCMA_IOCTL. Preserve
+ * SICF_WOC_CORE_RESET (the RESET_CTL view) so an
+ * IOCTL write does not accidentally release reset.
+ */
+ cur = ioread32be(ctrl_reg);
+ new_val = (value & 0xFFFF) |
+ (cur & SICF_WOC_CORE_RESET);
+ iowrite32be(new_val, ctrl_reg);
+ pr_debug("bcma: synth IOCTL core=0x%x SHIM %08x->%08x (req %08x)\n",
+ core->id.id, cur, new_val, value);
+ return;
+ case BCMA_RESET_CTL:
+ cur = ioread32be(ctrl_reg);
+ if (value & 1)
+ new_val = cur | SICF_WOC_CORE_RESET;
+ else
+ new_val = cur & ~SICF_WOC_CORE_RESET;
+ iowrite32be(new_val, ctrl_reg);
+ pr_debug("bcma: synth RESET_CTL core=0x%x SHIM %08x->%08x (req %08x)\n",
+ core->id.id, cur, new_val, value);
+ return;
+ }
+ }
+
+ /* No routing applies: surface as info so unexpected accesses are
+ * visible without DYNAMIC_DEBUG.
+ */
+ pr_info("bcma: synth awrite32 dropped on core idx=%u id=0x%x offset=0x%03x value=0x%08x\n",
+ core->core_index, core->id.id, offset, value);
+}
+
+/* Big-endian accessor variants for SoCs whose AXI backplane sits on a
+ * big-endian peripheral bus (BMIPS xDSL family). read8/write8 are
+ * endian-agnostic byte accesses and reuse the LE helpers above.
+ * 16/32-bit pairs use ioread/iowrite *be helpers. block_read/write
+ * are intentionally omitted: CONFIG_BCMA_BLOCKIO is not set on this
+ * target. aread32/awrite32 dispatch to the synthesizer when
+ * core->io_wrap is NULL (legitimate on SHIM-attached cores; that
+ * NULL state is allow-listed in scan.c by a companion patch).
+ */
+static u32 bcma_host_soc_read32_be(struct bcma_device *core, u16 offset)
+{
+ return ioread32be(core->io_addr + offset);
+}
+
+static u16 bcma_host_soc_read16_be(struct bcma_device *core, u16 offset)
+{
+ return ioread16be(core->io_addr + offset);
+}
+
+static void bcma_host_soc_write32_be(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ iowrite32be(value, core->io_addr + offset);
+}
+
+static void bcma_host_soc_write16_be(struct bcma_device *core, u16 offset,
+ u16 value)
+{
+ iowrite16be(value, core->io_addr + offset);
+}
+
+static u32 bcma_host_soc_aread32_be(struct bcma_device *core, u16 offset)
+{
+ if (likely(core->io_wrap))
+ return ioread32be(core->io_wrap + offset);
+ return bcma_host_soc_synth_aread32(core, offset);
+}
+
+static void bcma_host_soc_awrite32_be(struct bcma_device *core, u16 offset,
+ u32 value)
+{
+ if (likely(core->io_wrap)) {
+ iowrite32be(value, core->io_wrap + offset);
+ return;
+ }
+ bcma_host_soc_synth_awrite32(core, offset, value);
+}
+
+static const struct bcma_host_ops bcma_host_soc_ops_brcm_shim = {
+ .read8 = bcma_host_soc_read8,
+ .read16 = bcma_host_soc_read16_be,
+ .read32 = bcma_host_soc_read32_be,
+ .write8 = bcma_host_soc_write8,
+ .write16 = bcma_host_soc_write16_be,
+ .write32 = bcma_host_soc_write32_be,
+ .aread32 = bcma_host_soc_aread32_be,
+ .awrite32 = bcma_host_soc_awrite32_be,
+};
+
+/* Per-SoC quirks selected by DT compatible string. */
+struct bcma_host_soc_quirks {
+ const struct bcma_host_ops *ops;
+ bool big_endian;
+ bool shim_attached;
+ phys_addr_t shim_base;
+ size_t shim_size;
+};
+
+static const struct bcma_host_soc_quirks bcma_host_soc_quirks_default = {
+ .ops = &bcma_host_soc_ops,
+};
+
+static const struct bcma_host_soc_quirks bcma_host_soc_quirks_brcm_shim = {
+ .ops = &bcma_host_soc_ops_brcm_shim,
+ .big_endian = true,
+ .shim_attached = true,
+ .shim_base = 0x10007000,
+ .shim_size = 0x100,
+};
+
+
int __init bcma_host_soc_register(struct bcma_soc *soc)
{
struct bcma_bus *bus = &soc->bus;
@@ -176,9 +394,25 @@ int __init bcma_host_soc_register(struct bcma_soc *soc)
if (!bus->mmio)
return -ENOMEM;
+ quirks = of_device_get_match_data(dev);
+ if (!quirks)
+ quirks = &bcma_host_soc_quirks_default;
+
/* Host specific */
bus->hosttype = BCMA_HOSTTYPE_SOC;
- bus->ops = &bcma_host_soc_ops;
+ bus->ops = quirks->ops;
+ bus->big_endian = quirks->big_endian;
+ bus->shim_attached = quirks->shim_attached;
+
+ if (quirks->shim_base) {
+ bus->shim_iomem = ioremap(quirks->shim_base, quirks->shim_size);
+ if (!bus->shim_iomem) {
+ dev_err(dev, "failed to ioremap SHIM peephole @ %pap\n",
+ &quirks->shim_base);
+ err = -ENOMEM;
+ goto err_unmap_mmio;
+ }
+ }
/* Initialize struct, detect chip */
bcma_init_bus(bus);
@@ -202,6 +436,7 @@ int __init bcma_host_soc_init(struct bcma_soc *soc)
#ifdef CONFIG_OF
static int bcma_host_soc_probe(struct platform_device *pdev)
{
+ const struct bcma_host_soc_quirks *quirks;
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct bcma_bus *bus;
@@ -245,12 +480,16 @@ static void bcma_host_soc_remove(struct platform_device *pdev)
struct bcma_bus *bus = platform_get_drvdata(pdev);
bcma_bus_unregister(bus);
+ if (bus->shim_iomem)
+ iounmap(bus->shim_iomem);
iounmap(bus->mmio);
platform_set_drvdata(pdev, NULL);
}
static const struct of_device_id bcma_host_soc_of_match[] = {
- { .compatible = "brcm,bus-axi", },
+ { .compatible = "brcm,bcm6362-bus-axi", .data = &bcma_host_soc_quirks_brcm_shim },
+ { .compatible = "brcm,bcm63268-bus-axi", .data = &bcma_host_soc_quirks_brcm_shim },
+ { .compatible = "brcm,bus-axi", .data = &bcma_host_soc_quirks_default },
{},
};
MODULE_DEVICE_TABLE(of, bcma_host_soc_of_match);
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 84742408a..983a62dde 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -143,6 +143,8 @@ static const char *bcma_device_name(const struct bcma_device_id *id)
static u32 bcma_scan_read32(struct bcma_bus *bus, u16 offset)
{
+ if (bus->big_endian)
+ return ioread32be(bus->mmio + offset);
return readl(bus->mmio + offset);
}
@@ -155,7 +157,7 @@ static void bcma_scan_switch_core(struct bcma_bus *bus, u32 addr)
static u32 bcma_erom_get_ent(struct bcma_bus *bus, u32 __iomem **eromptr)
{
- u32 ent = readl(*eromptr);
+ u32 ent = bus->big_endian ? ioread32be(*eromptr) : readl(*eromptr);
(*eromptr)++;
return ent;
}
diff --git a/include/linux/bcma/bcma.h b/include/linux/bcma/bcma.h
index 60b94b944..f41616ba2 100644
--- a/include/linux/bcma/bcma.h
+++ b/include/linux/bcma/bcma.h
@@ -362,6 +362,16 @@ struct bcma_bus {
/* We decided to share SPROM struct with SSB as long as we do not need
* any hacks for BCMA. This simplifies drivers code. */
struct ssb_sprom sprom;
+
+ /* SoC quirks populated from host_soc per-compatible match data.
+ * big_endian selects ioread*be/iowrite*be on the scan and accessor
+ * paths; shim_attached tells scan.c that wrapper-less cores (NMW=
+ * NSW=0) are legitimate on this backplane and routes IOCTL/
+ * RESET_CTL through the SHIM Control register via shim_iomem.
+ */
+ bool big_endian;
+ bool shim_attached;
+ void __iomem *shim_iomem;
};
static inline u32 bcma_read8(struct bcma_device *core, u16 offset)
--
2.43.0
^ permalink raw reply related
* [PATCH RFC 2/2] bcma: scan: allow SHIM-style mini-EROM wrapper-less
From: Alessio Ferri @ 2026-05-18 11:41 UTC (permalink / raw)
To: Rafał Miłecki; +Cc: linux-wireless, linux-mips
In-Reply-To: <82d2ae7c-3913-4d1c-8e2f-f586c4196ce1@mythread.it>
bcma_get_next_core() rejects with -ENXIO any component whose
component_B descriptor reports NMW=NSW=0 unless its core id is in
a short allowlist (4706 MAC GBIT, NS_CHIPCOMMON_B, PMU, GCI).
On SoCs that publish a SHIM-style mini-EROM (BMIPS xDSL family:
BCM6362, BCM63268), the WLAN backplane lists three components:
ChipCommon, IEEE 802.11 and BCMA_CORE_SHIM. None of the three is
in the existing allowlist, so all three are skipped silently,
bus->cores stays empty, bcma_find_core(BCMA_CORE_CHIPCOMMON)
returns NULL, and a later bcma_chipco_watchdog_register()
dereferences cc->core->bus on its first line and oopses mid-probe.
BCMA_CORE_SHIM (0x837) is already defined in
include/linux/bcma/bcma.h with the in-tree comment "SHIM
component in ubus/6362"; this patch is what makes the SHIM core
actually probe and bind.
Signed-off-by: Alessio Ferri <alessio.ferri@mythread.it>
---
drivers/bcma/scan.c | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 983a62dde..871baa221 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -318,6 +318,21 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
case BCMA_CORE_GCI:
/* Not used yet: case BCMA_CORE_OOB_ROUTER: */
break;
+ case BCMA_CORE_CHIPCOMMON:
+ case BCMA_CORE_80211:
+ case BCMA_CORE_SHIM:
+ /* SHIM-style mini-EROM SoCs publish CHIPCOMMON, the IEEE
+ * 802.11 core and the SHIM core itself with NMW=NSW=0
+ * because clock and reset gating happens at the SoC level
+ * via the SHIM, not via per-core DMP wrappers. The
+ * companion host_soc patch sets bus->shim_attached on
+ * those SoCs from per-compatible quirks data; the strict
+ * NMW=NSW=0 rejection still applies to PCI-attached cards
+ * and to SoCs without that quirk.
+ */
+ if (bus->shim_attached)
+ break;
+ fallthrough;
default:
bcma_erom_skip_component(bus, eromptr);
return -ENXIO;
--
2.43.0
^ permalink raw reply related
* Re: [PATCH] wifi: mt76: mt7996: avoid memset overwriting tx_info->control.flags
From: Lorenzo Bianconi @ 2026-05-18 12:31 UTC (permalink / raw)
To: Cheng Hao Luo
Cc: Ryder Lee, Felix Fietkau, linux-mediatek, linux-wireless,
Shayne Chen, Roy Luo
In-Reply-To: <CAHoxojJX2BRRTLMuM_QcJqMMmshxS4EAwrB1VjU3rsZ+0k2PAg@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 5379 bytes --]
On May 15, Cheng Hao Luo wrote:
> > struct ieee80211_tx_info {
> > u32 flags; /* 0 4 */
> > u32 band:3; /* 4: 0 4 */
> > u32 status_data_idr:1; /* 4: 3 4 */
> > u32 status_data:13; /* 4: 4 4 */
> > u32 hw_queue:4; /* 4:17 4 */
> > u32 tx_time_est:10; /* 4:21 4 */
> >
> > /* XXX 1 bit hole, try to pack */
> >
> > union {
> > struct {
> > union {
> > struct {
> > struct ieee80211_tx_rate rates[4]; /* 8 12 */
> > s8 rts_cts_rate_idx; /* 20 1 */
> > u8 use_rts:1; /* 21: 0 1 */
> > u8 use_cts_prot:1; /* 21: 1 1 */
> > u8 short_preamble:1; /* 21: 2 1 */
> > u8 skip_table:1; /* 21: 3 1 */
> > u8 antennas:2; /* 21: 4 1 */
> > }; /* 8 14 */
> > long unsigned int jiffies; /* 8 8 */
> > }; /* 8 16 */
> > struct ieee80211_vif * vif; /* 24 8 */
> > struct ieee80211_key_conf * hw_key; /* 32 8 */
> > u32 flags; /* 40 4 */
> > codel_time_t enqueue_time; /* 44 4 */
> > } control; /* 8 40 */
> > struct {
> > u64 cookie; /* 8 8 */
> > } ack; /* 8 8 */
> > struct {
> > struct ieee80211_tx_rate rates[4]; /* 8 12 */
> > s32 ack_signal; /* 20 4 */
> > u8 ampdu_ack_len; /* 24 1 */
> > u8 ampdu_len; /* 25 1 */
> > u8 antenna; /* 26 1 */
> > u8 pad; /* 27 1 */
> > u16 tx_time; /* 28 2 */
> > u8 flags; /* 30 1 */
> > u8 pad2; /* 31 1 */
> > void * status_driver_data[2]; /* 32 16 */
> > } status; /* 8 40 */
> > struct {
> > struct ieee80211_tx_rate driver_rates[4]; /* 8 12 */
> > u8 pad[4]; /* 20 4 */
> > void * rate_driver_data[3]; /* 24 24 */
> > }; /* 8 40 */
> > void * driver_data[5]; /* 8 40 */
> > }; /* 8 40 */
> >
> > /* size: 48, cachelines: 1, members: 7 */
> > /* sum members: 44 */
> > /* sum bitfield members: 31 bits, bit holes: 1, sum bit holes: 1 bits */
> > /* last cacheline: 48 bytes */
> > };
> >
> > According to pahole, the size of the control inner union is actually 16 bytes
> > since the compiler adds 2 bytes of padding. Since mt76_tx_status_skb_add()
> > meset to 0 just mt76_tx_cb size (that is 16 bytes) I can't see how
> > control.flags is overwritten. Am I missing something?
> >
> > struct mt76_tx_cb {
> > long unsigned int jiffies; /* 0 8 */
> > u16 wcid; /* 8 2 */
> > u8 pktid; /* 10 1 */
> > u8 flags; /* 11 1 */
> >
> > /* size: 16, cachelines: 1, members: 4 */
> > /* padding: 4 */
> > /* last cacheline: 16 bytes */
> > };
>
> Hi Lorenzo,
>
> The mt76_tx_cb is placed at status.status_driver_data (offset 32).
> It overlaps with hw_key, flags and enqueue_time in the control union.
>
> static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
> {
> BUILD_BUG_ON(sizeof(struct mt76_tx_cb) >
> sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data));
> return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data);
> }
Hi Roy,
I still do not understand since mt76_tx_status_skb_add() sets to 0 just sizeof
of mt76_tx_cb, that according to pahole is 16 bytes, so it can't overwrite
hw_key pointer (whose offset respect to the beginning of the control struct is
24, 32 - 8).
Regards,
Lorenzo
>
> Regards,
> Roy Luo
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply
* Re: [PATCH v4] wifi: ath11k: fix peer resolution on rx path when peer_id=0
From: Jeff Johnson @ 2026-05-18 13:54 UTC (permalink / raw)
To: Jeff Johnson, Matthew Leach
Cc: Baochen Qiang, Rameshkumar Sundaram, linux-wireless, ath11k,
linux-kernel, kernel
In-Reply-To: <20260424-ath11k-null-peerid-workaround-v4-1-252b224d3cf6@collabora.com>
On Fri, 24 Apr 2026 10:50:35 +0100, Matthew Leach wrote:
> It has been observed that on certain chipsets a peer can be assigned
> peer_id=0. For reception of non-aggregated MPDUs this is fine as
> ath11k_dp_rx_h_find_peer() has a fallback case where it locates the peer
> based upon the source MAC address. On an aggregated link, the mpdu_start
> header is only populated by hardware on the first sub-MSDU. This causes
> the peer resolution to be skipped for the subsequent MSDUs and the
> encryption type of these frames to be set to an incorrect value,
> resulting in these MSDUs being dropped by ieee80211.
>
> [...]
Applied, thanks!
[1/1] wifi: ath11k: fix peer resolution on rx path when peer_id=0
commit: 2a2451a34afdf563b3102d36a4b6cf335cf813e2
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH v2] wifi: ath11k: fix use after free in ath11k_dp_rx_msdu_coalesce.
From: Jeff Johnson @ 2026-05-18 13:54 UTC (permalink / raw)
To: jjohnson, Willmar Knikker; +Cc: linux-wireless, ath11k
In-Reply-To: <20260505171709.547274-1-willmar@met-dubbel-l.nl>
On Tue, 05 May 2026 17:17:43 +0000, Willmar Knikker wrote:
> In ath11k_dp_rx_msdu_coalesce the loop uses ->is_continuation after
> the dev_kfree_skb_any. This can cause a use after free kfence.
>
> Use flag for caching is_continuation for use after the
> dev_kfree_skb_any.
>
> Changes in v2:
> - add bool _is_continuation for use after the free.
> - Add Fixes, label to commit.
>
> [...]
Applied, thanks!
[1/1] wifi: ath11k: fix use after free in ath11k_dp_rx_msdu_coalesce.
commit: 72b8654e3b83548f64524add2e9145e9b6c8a852
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] wifi: ath11k: clear shared SRNG pointer state on restart
From: Jeff Johnson @ 2026-05-18 13:54 UTC (permalink / raw)
To: Jeff Johnson, Muhammad Usama Anjum, Baochen Qiang, Kyle Farnung
Cc: linux-wireless, ath11k, linux-kernel, santiagorr, stable
In-Reply-To: <20260513-kfarnung-ath11k-srng-clear-pointer-state-v1-1-bc700dd8b333@gmail.com>
On Wed, 13 May 2026 21:52:12 -0700, Kyle Farnung wrote:
> LMAC rings reuse the shared rdp/wrp pointer buffers without going
> through the normal SRNG hw-init path that zeros non-LMAC ring
> pointers. After restart, ath11k_hal_srng_clear() can therefore hand
> stale hp/tp state from the previous firmware instance back to the new
> one.
>
> Clear the shared pointer buffers while keeping the allocations in
> place so restart still avoids reallocating SRNG DMA memory, but starts
> with fresh ring-pointer state.
>
> [...]
Applied, thanks!
[1/1] wifi: ath11k: clear shared SRNG pointer state on restart
commit: f51e4b3b5574ad8cb5b16b11f8a1452147ece87a
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH ath-current] wifi: ath12k: fix EHT TX MCS limitation due to wrong 20 MHz-only parsing
From: Jeff Johnson @ 2026-05-18 13:54 UTC (permalink / raw)
To: Jeff Johnson, Baochen Qiang; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260514-ath12k-fix-20mhz-only-mcs-map-v1-1-a38d4a9b21a2@oss.qualcomm.com>
On Thu, 14 May 2026 11:32:51 +0800, Baochen Qiang wrote:
> When connecting to an AP configured for EHT 20 MHz with a full EHT
> MCS/NSS map (supporting MCS 0-13)
>
> Supported EHT-MCS and NSS Set
> EHT-MCS Map (BW <= 80MHz): 0x444444
> .... .... .... .... .... 0100 = Rx Max Nss That Supports EHT-MCS 0-9: 4
> .... .... .... .... 0100 .... = Tx Max Nss That Supports EHT-MCS 0-9: 4
> .... .... .... 0100 .... .... = Rx Max Nss That Supports EHT-MCS 10-11: 4
> .... .... 0100 .... .... .... = Tx Max Nss That Supports EHT-MCS 10-11: 4
> .... 0100 .... .... .... .... = Rx Max Nss That Supports EHT-MCS 12-13: 4
> 0100 .... .... .... .... .... = Tx Max Nss That Supports EHT-MCS 12-13: 4
>
> [...]
Applied, thanks!
[1/1] wifi: ath12k: fix EHT TX MCS limitation due to wrong 20 MHz-only parsing
commit: 60fb2cf51e77bb1c0261160b4be44209d68956b1
Best regards,
--
Jeff Johnson <jeff.johnson@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v4] wifi: rtw88: usb: fix memory leaks on USB write failures
From: luka.gejak @ 2026-05-18 14:23 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: Kalle Valo, Luka Gejak, linux-wireless, linux-kernel, stable
In-Reply-To: <20260518142311.10328-1-luka.gejak@linux.dev>
From: Luka Gejak <luka.gejak@linux.dev>
When rtw_usb_write_port() fails to submit a USB Request Block (URB)
(e.g., due to device disconnect or ENOMEM), the completion callback is
never executed.
Currently, the driver ignores the return value of rtw_usb_write_port()
in rtw_usb_write_data() and rtw_usb_tx_agg_skb(). Because these
functions rely on the completion callback to free the socket buffers
(skbs) and the transaction control block (txcb), a submission failure
results in:
1. A memory leak of the allocated skb in rtw_usb_write_data().
2. A memory leak of the txcb structure and all aggregated skbs in
rtw_usb_tx_agg_skb().
Fix this by checking the return value of rtw_usb_write_port(). If it
fails, explicitly free the skb in rtw_usb_write_data(), and properly
purge the tx_ack_queue and free the txcb in rtw_usb_tx_agg_skb().
The issue was discovered in practice during device disconnect/reconnect
scenarios and memory pressure conditions. Tested by verifying normal TX
operation continues after the fix without regressions.
Fixes: a82dfd33d123 ("wifi: rtw88: Add common USB chip support")
Cc: stable@vger.kernel.org
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
Tested-by: Luka Gejak <luka.gejak@linux.dev>
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
Changes in v4:
- Fixed checkpatch issues and picked up Acked-by tag.
Changes in v3:
- Updated the Fixes tag to the commit that introduced USB support.
Changes in v2:
- Use ret = rtw_usb_write_port(...); style, and check by next line (in
rtw_usb_tx_agg_skb)
- Remove unnecessary comment
- Use ieee80211_purge_tx_queue() instead of skb_queue_purge()
- Add testing details to commit message
drivers/net/wireless/realtek/rtw88/usb.c | 13 +++++++++++--
1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/realtek/rtw88/usb.c b/drivers/net/wireless/realtek/rtw88/usb.c
index 718940ebba31..1a0bdbf52cb0 100644
--- a/drivers/net/wireless/realtek/rtw88/usb.c
+++ b/drivers/net/wireless/realtek/rtw88/usb.c
@@ -399,6 +399,7 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list
int agg_num = 0;
unsigned int align_next = 0;
u8 qsel;
+ int ret;
if (skb_queue_empty(list))
return false;
@@ -456,7 +457,13 @@ static bool rtw_usb_tx_agg_skb(struct rtw_usb *rtwusb, struct sk_buff_head *list
tx_desc = (struct rtw_tx_desc *)skb_head->data;
qsel = le32_get_bits(tx_desc->w1, RTW_TX_DESC_W1_QSEL);
- rtw_usb_write_port(rtwdev, qsel, skb_head, rtw_usb_write_port_tx_complete, txcb);
+ ret = rtw_usb_write_port(rtwdev, qsel, skb_head,
+ rtw_usb_write_port_tx_complete, txcb);
+ if (ret) {
+ ieee80211_purge_tx_queue(rtwdev->hw, &txcb->tx_ack_queue);
+ kfree(txcb);
+ return false;
+ }
return true;
}
@@ -518,8 +525,10 @@ static int rtw_usb_write_data(struct rtw_dev *rtwdev,
ret = rtw_usb_write_port(rtwdev, qsel, skb,
rtw_usb_write_port_complete, skb);
- if (unlikely(ret))
+ if (unlikely(ret)) {
rtw_err(rtwdev, "failed to do USB write, ret=%d\n", ret);
+ dev_kfree_skb_any(skb);
+ }
return ret;
}
--
2.54.0
^ permalink raw reply related
* [PATCH v4] wifi: rtw88: increase TX report timeout to fix race condition
From: luka.gejak @ 2026-05-18 14:23 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: Kalle Valo, Luka Gejak, linux-wireless, linux-kernel, stable
From: Luka Gejak <luka.gejak@linux.dev>
The driver expects the firmware to report TX status within 500ms.
However, a timeout can be triggered when the hardware performs
background scans while under TX load. During these scans, the firmware
stays off-channel for periods exceeding 500ms, delaying the delivery of
TX reports back to the driver.
When this occurs, the purge timer fires prematurely and drops the
tracking skbs from the queue. This results in the host stack
interpreting the missing status as packet loss, leading to TCP window
collapse. In testing with iperf3, this causes throughput to drop from
~90 Mbps to near-zero for approximately 2 seconds until the connection
recovers.
Increase RTW_TX_PROBE_TIMEOUT to 2500ms for RTL8723DU. This duration is
sufficient to accommodate off-channel dwell time during full background
scans, ensuring the purge timer only trips during genuine firmware
lockups and preventing unnecessary TCP retransmission cycles.
Fixes: a82dfd33d123 ("wifi: rtw88: Add common USB chip support")
Cc: stable@vger.kernel.org
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
Tested-by: Luka Gejak <luka.gejak@linux.dev>
Signed-off-by: Luka Gejak <luka.gejak@linux.dev>
---
Changes in v4:
- Picked up Acked-by tag.
Changes in v3:
-Declared timeout with RTW_TX_PROBE_TIMEOUT as the default value and
removed the else branch.
-Updated the Fixes tag to the commit that introduced USB support.
Changes in v2:
-Isolated the change to RTL8723DU as requested by Ping-Ke
drivers/net/wireless/realtek/rtw88/tx.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/realtek/rtw88/tx.c b/drivers/net/wireless/realtek/rtw88/tx.c
index 3106edb84fb4..a6e43314a4e9 100644
--- a/drivers/net/wireless/realtek/rtw88/tx.c
+++ b/drivers/net/wireless/realtek/rtw88/tx.c
@@ -196,6 +196,7 @@ void rtw_tx_report_purge_timer(struct timer_list *t)
void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
{
struct rtw_tx_report *tx_report = &rtwdev->tx_report;
+ unsigned long timeout = RTW_TX_PROBE_TIMEOUT;
unsigned long flags;
u8 *drv_data;
@@ -207,7 +208,11 @@ void rtw_tx_report_enqueue(struct rtw_dev *rtwdev, struct sk_buff *skb, u8 sn)
__skb_queue_tail(&tx_report->queue, skb);
spin_unlock_irqrestore(&tx_report->q_lock, flags);
- mod_timer(&tx_report->purge_timer, jiffies + RTW_TX_PROBE_TIMEOUT);
+ if (rtwdev->chip->id == RTW_CHIP_TYPE_8723D &&
+ rtwdev->hci.type == RTW_HCI_TYPE_USB)
+ timeout = msecs_to_jiffies(2500);
+
+ mod_timer(&tx_report->purge_timer, jiffies + timeout);
}
EXPORT_SYMBOL(rtw_tx_report_enqueue);
--
2.54.0
^ permalink raw reply related
* [PATCH v3 0/1] wifi: mac80211: fix monitor mode frame capture for real chanctx drivers
From: Devin Wittmayer @ 2026-05-18 17:01 UTC (permalink / raw)
To: linux-wireless
Cc: Johannes Berg, Felix Fietkau, Lorenzo Bianconi, linux-kernel,
stable, Oscar Alfonso Diaz, fjhhz1997, Devin Wittmayer
In-Reply-To: <20260308164510.5927-1-fjhhz1997@gmail.com>
v2 [1] used list_is_singular() + list_first_entry() to find the
fallback chanctx. Johannes pointed out [2] that the pair is the
rculist.h anti-pattern: the two reads of head->next race
list_del_rcu() of the sole entry between the singularity check
and the entry fetch. v3 uses list_first_or_null_rcu() with an
rcu_access_pointer() check that the entry is the only one in
the list, as rculist.h suggests.
The v2 user-visible TX path is unchanged in v3, so my Tested-by
from v2 carries forward: the airgeddon evil-twin flow on mt7921e
PCIe + mt7921u USB + Kali VM with MT7921U passthrough still
applies.
[1] https://lore.kernel.org/linux-wireless/20260518064025.96792-1-lucid_duck@justthetip.ca/
[2] https://lore.kernel.org/linux-wireless/70c49e598ffba2864c8168c7185c0abec76b59dd.camel@sipsolutions.net/
傅继晗 (1):
wifi: mac80211: fix monitor mode frame capture for real chanctx drivers
net/mac80211/tx.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
^ permalink raw reply
* [PATCH v3] wifi: mac80211: fix monitor mode frame capture for real chanctx drivers
From: Devin Wittmayer @ 2026-05-18 17:01 UTC (permalink / raw)
To: linux-wireless
Cc: Johannes Berg, Felix Fietkau, Lorenzo Bianconi, linux-kernel,
stable, Oscar Alfonso Diaz, fjhhz1997, Devin Wittmayer
In-Reply-To: <20260518170147.13885-1-lucid_duck@justthetip.ca>
From: 傅继晗 <fjhhz1997@gmail.com>
Commit d594cc6f2c58 ("wifi: mac80211: restore non-chanctx injection
behaviour") restored the monitor injection fallback for drivers using
chanctx emulation but explicitly deferred the harder case of drivers
that transitioned to real chanctx ops. mt76 falls in that category
and still drops every injected frame when monitor coexists with
another interface.
When the monitor has no chanctx of its own, fall back to the only
chanctx in flight if there is exactly one. Refuse if multiple are
present: picking arbitrarily would inject onto an unrelated channel.
Reran the airgeddon evil-twin flow (hostapd AP + coexisting monitor
VIF on the same phy + aireplay-ng deauth from the monitor) on
mt7921e PCIe and mt7921u USB across 2.4 GHz and 5 GHz, and on a
Kali VM with MT7921U passthrough as the closest match to the
original reporter's setup. None reproduced the hang seen against
the earlier attempt at this fix
(<20251216111909.25076-2-johannes@sipsolutions.net>) or against v1
on lore in March.
Cc: stable@vger.kernel.org # 6.9+
Reported-by: Oscar Alfonso Diaz <oscar.alfonso.diaz@gmail.com>
Closes: https://github.com/morrownr/USB-WiFi/issues/682
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Fixes: 0a44dfc07074 ("wifi: mac80211: simplify non-chanctx drivers")
Signed-off-by: 傅继晗 <fjhhz1997@gmail.com>
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
---
v3:
- Replace list_is_singular() + list_first_entry() with
list_first_or_null_rcu() and an rcu_access_pointer() check
that the entry is the only one in the list. The v2 pair
re-read ->next without RCU between the singularity check
and the entry fetch, racing list_del_rcu() of the sole entry
(rculist.h).
- Tested-by carries from v2: v3 changes the lookup primitive
only, not the TX path, so the v2 airgeddon evil-twin flow on
mt7921e/mt7921u/Kali-VM still applies.
v2:
- First respin under my submitter signoff; preserves fjh1997
authorship.
- Verification matrix; airgeddon evil-twin flow on mt7921e/
mt7921u/Kali-VM does not reproduce the hang reported against
the v1 attempt at this fix.
net/mac80211/tx.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c
index 933c86ca21c3..6d2c71a13f26 100644
--- a/net/mac80211/tx.c
+++ b/net/mac80211/tx.c
@@ -2407,12 +2407,20 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
rcu_dereference(tmp_sdata->vif.bss_conf.chanctx_conf);
}
- if (chanctx_conf)
+ if (chanctx_conf) {
chandef = &chanctx_conf->def;
- else if (local->emulate_chanctx)
+ } else if (local->emulate_chanctx) {
chandef = &local->hw.conf.chandef;
- else
- goto fail_rcu;
+ } else {
+ struct ieee80211_chanctx *ctx;
+
+ ctx = list_first_or_null_rcu(&local->chanctx_list,
+ struct ieee80211_chanctx, list);
+ if (!ctx ||
+ rcu_access_pointer(ctx->list.next) != &local->chanctx_list)
+ goto fail_rcu;
+ chandef = &ctx->conf.def;
+ }
/*
* If driver/HW supports IEEE80211_CHAN_CAN_MONITOR we still
^ permalink raw reply related
* Re: [PATCH] wifi: mt76: mt7996: avoid memset overwriting tx_info->control.flags
From: Roy Luo @ 2026-05-18 18:23 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: Ryder Lee, Felix Fietkau, linux-mediatek, linux-wireless,
Shayne Chen, Roy Luo
In-Reply-To: <agsGiHKH6ly1afaf@lore-desk>
On Mon, May 18, 2026 at 5:31 AM Lorenzo Bianconi <lorenzo@kernel.org> wrote:
>
> On May 15, Cheng Hao Luo wrote:
> > > struct ieee80211_tx_info {
> > > u32 flags; /* 0 4 */
> > > u32 band:3; /* 4: 0 4 */
> > > u32 status_data_idr:1; /* 4: 3 4 */
> > > u32 status_data:13; /* 4: 4 4 */
> > > u32 hw_queue:4; /* 4:17 4 */
> > > u32 tx_time_est:10; /* 4:21 4 */
> > >
> > > /* XXX 1 bit hole, try to pack */
> > >
> > > union {
> > > struct {
> > > union {
> > > struct {
> > > struct ieee80211_tx_rate rates[4]; /* 8 12 */
> > > s8 rts_cts_rate_idx; /* 20 1 */
> > > u8 use_rts:1; /* 21: 0 1 */
> > > u8 use_cts_prot:1; /* 21: 1 1 */
> > > u8 short_preamble:1; /* 21: 2 1 */
> > > u8 skip_table:1; /* 21: 3 1 */
> > > u8 antennas:2; /* 21: 4 1 */
> > > }; /* 8 14 */
> > > long unsigned int jiffies; /* 8 8 */
> > > }; /* 8 16 */
> > > struct ieee80211_vif * vif; /* 24 8 */
> > > struct ieee80211_key_conf * hw_key; /* 32 8 */
> > > u32 flags; /* 40 4 */
> > > codel_time_t enqueue_time; /* 44 4 */
> > > } control; /* 8 40 */
> > > struct {
> > > u64 cookie; /* 8 8 */
> > > } ack; /* 8 8 */
> > > struct {
> > > struct ieee80211_tx_rate rates[4]; /* 8 12 */
> > > s32 ack_signal; /* 20 4 */
> > > u8 ampdu_ack_len; /* 24 1 */
> > > u8 ampdu_len; /* 25 1 */
> > > u8 antenna; /* 26 1 */
> > > u8 pad; /* 27 1 */
> > > u16 tx_time; /* 28 2 */
> > > u8 flags; /* 30 1 */
> > > u8 pad2; /* 31 1 */
> > > void * status_driver_data[2]; /* 32 16 */
> > > } status; /* 8 40 */
> > > struct {
> > > struct ieee80211_tx_rate driver_rates[4]; /* 8 12 */
> > > u8 pad[4]; /* 20 4 */
> > > void * rate_driver_data[3]; /* 24 24 */
> > > }; /* 8 40 */
> > > void * driver_data[5]; /* 8 40 */
> > > }; /* 8 40 */
> > >
> > > /* size: 48, cachelines: 1, members: 7 */
> > > /* sum members: 44 */
> > > /* sum bitfield members: 31 bits, bit holes: 1, sum bit holes: 1 bits */
> > > /* last cacheline: 48 bytes */
> > > };
> > >
> > > According to pahole, the size of the control inner union is actually 16 bytes
> > > since the compiler adds 2 bytes of padding. Since mt76_tx_status_skb_add()
> > > meset to 0 just mt76_tx_cb size (that is 16 bytes) I can't see how
> > > control.flags is overwritten. Am I missing something?
> > >
> > > struct mt76_tx_cb {
> > > long unsigned int jiffies; /* 0 8 */
> > > u16 wcid; /* 8 2 */
> > > u8 pktid; /* 10 1 */
> > > u8 flags; /* 11 1 */
> > >
> > > /* size: 16, cachelines: 1, members: 4 */
> > > /* padding: 4 */
> > > /* last cacheline: 16 bytes */
> > > };
> >
> > Hi Lorenzo,
> >
> > The mt76_tx_cb is placed at status.status_driver_data (offset 32).
> > It overlaps with hw_key, flags and enqueue_time in the control union.
> >
> > static inline struct mt76_tx_cb *mt76_tx_skb_cb(struct sk_buff *skb)
> > {
> > BUILD_BUG_ON(sizeof(struct mt76_tx_cb) >
> > sizeof(IEEE80211_SKB_CB(skb)->status.status_driver_data));
> > return ((void *)IEEE80211_SKB_CB(skb)->status.status_driver_data);
> > }
>
> Hi Roy,
>
> I still do not understand since mt76_tx_status_skb_add() sets to 0 just sizeof
> of mt76_tx_cb, that according to pahole is 16 bytes, so it can't overwrite
> hw_key pointer (whose offset respect to the beginning of the control struct is
> 24, 32 - 8).
>
> Regards,
> Lorenzo
>
> >
> > Regards,
> > Roy Luo
Hi Lorenzo,
The mt76_tx_status_skb_add() memset zero the 16 bytes starting from
status.status_driver_data (please see the above inline function shared
in my last response) whose offset with respect to the beginning of
the control/status union is exactly 24 (32 - 8) instead of 0.
Regards,
Roy Luo
^ permalink raw reply
* [PATCH wireless-next] wifi: mwifiex: Use flexible array for RX reorder table
From: Rosen Penev @ 2026-05-18 21:18 UTC (permalink / raw)
To: linux-wireless
Cc: Brian Norris, Francesco Dolcini, Kees Cook, Gustavo A. R. Silva,
open list,
open list:KERNEL HARDENING (not covered by other areas):Keyword:b__counted_by(_le|_be|_ptr)?b
Embed the RX reorder pointer array in struct mwifiex_rx_reorder_tbl
instead of allocating it separately.
This ties the array to the reorder table lifetime and removes a separate
allocation and cleanup path.
Use kzalloc_flex() for this and move the counting variable assignment to
after it as it does for GCC >= 15 already.
Assisted-by: Codex:GPT-5.5
Signed-off-by: Rosen Penev <rosenp@gmail.com>
---
.../wireless/marvell/mwifiex/11n_rxreorder.c | 20 +++----------------
drivers/net/wireless/marvell/mwifiex/main.h | 2 +-
2 files changed, 4 insertions(+), 18 deletions(-)
diff --git a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
index 610ec8302adf..a266f09cb763 100644
--- a/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/marvell/mwifiex/11n_rxreorder.c
@@ -213,7 +213,6 @@ mwifiex_del_rx_reorder_entry(struct mwifiex_private *priv,
list_del(&tbl->list);
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
- kfree(tbl->rx_reorder_ptr);
kfree(tbl);
spin_lock_bh(&priv->adapter->rx_proc_lock);
@@ -329,7 +328,6 @@ static void
mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
int tid, int win_size, int seq_num)
{
- int i;
struct mwifiex_rx_reorder_tbl *tbl, *new_node;
u16 last_seq = 0;
struct mwifiex_sta_node *node;
@@ -344,10 +342,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
return;
}
/* if !tbl then create one */
- new_node = kzalloc_obj(struct mwifiex_rx_reorder_tbl);
+ new_node = kzalloc_flex(*new_node, rx_reorder_ptr, win_size);
if (!new_node)
return;
+ new_node->win_size = win_size;
+
INIT_LIST_HEAD(&new_node->list);
new_node->tid = tid;
memcpy(new_node->ta, ta, ETH_ALEN);
@@ -381,26 +381,12 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->flags |= RXREOR_INIT_WINDOW_SHIFT;
}
- new_node->win_size = win_size;
-
- new_node->rx_reorder_ptr = kcalloc(win_size, sizeof(void *),
- GFP_KERNEL);
- if (!new_node->rx_reorder_ptr) {
- kfree(new_node);
- mwifiex_dbg(priv->adapter, ERROR,
- "%s: failed to alloc reorder_ptr\n", __func__);
- return;
- }
-
new_node->timer_context.ptr = new_node;
new_node->timer_context.priv = priv;
new_node->timer_context.timer_is_set = false;
timer_setup(&new_node->timer_context.timer, mwifiex_flush_data, 0);
- for (i = 0; i < win_size; ++i)
- new_node->rx_reorder_ptr[i] = NULL;
-
spin_lock_bh(&priv->rx_reorder_tbl_lock);
list_add_tail(&new_node->list, &priv->rx_reorder_tbl_ptr);
spin_unlock_bh(&priv->rx_reorder_tbl_lock);
diff --git a/drivers/net/wireless/marvell/mwifiex/main.h b/drivers/net/wireless/marvell/mwifiex/main.h
index 27559e2ddc31..67da5daa48b4 100644
--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++ b/drivers/net/wireless/marvell/mwifiex/main.h
@@ -708,10 +708,10 @@ struct mwifiex_rx_reorder_tbl {
int init_win;
int start_win;
int win_size;
- void **rx_reorder_ptr;
struct reorder_tmr_cnxt timer_context;
u8 amsdu;
u8 flags;
+ void *rx_reorder_ptr[] __counted_by(win_size);
};
struct mwifiex_bss_prio_node {
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2] wireless-regdb: Update regulatory info for Brunei Darussalam (BN) for 2022
From: hfzz7 @ 2026-05-18 21:22 UTC (permalink / raw)
To: linux-wireless; +Cc: wireless-regdb
In-Reply-To: <CAGb2v67NMBPs5bbNfoPNjK1mum-y5FsqAa_HVTq_P3e48Dnh3A@mail.gmail.com>
Yes, that's fine!
Thanks!
^ permalink raw reply
* ath12k: QCN9274 hw2.0 single-band cards on IPQ9574 — firmware RDDM after WMI_INIT_CMD (WLAN.WBE.1.6-01243)
From: insalata.fresca @ 2026-05-18 23:18 UTC (permalink / raw)
To: jjohnson, quic_rajkbhag; +Cc: ath12k, linux-wireless, quic_bqiang
[-- Attachment #1: Type: text/plain, Size: 4649 bytes --]
Hi Jeff, Raj Kumar, all,
I'm bringing up mainline OpenWrt on a Wallys DR9574 (IPQ9574 SoC + three
QCN9274 hw2.0 M.2 cards: one 2.4 GHz, one 5 GHz, one 6 GHz, all single-band,
all single-mac firmware). After working through two host-side bugs I've hit
what looks like a firmware crash and would appreciate guidance.
Hardware
--------
Platform : Wallys DR9574 (Qualcomm AP-AL02-C4 reference design)
SoC : IPQ9574, soc_id 0x401a2200
Cards : 3x QCN9274 hw2.0 M.2 (DR9274-2GK / DR9274-5GK / DR9274-6GK)
Firmware : WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1 (linux-firmware 20260410)
fw_version 0x160484db, built 2025-12-09 19:48
Kernel : 6.12.89 + ath12k from current ath-next + backports-6.18.26
OTP : slot 0001 board_id=0x1 (2.4 GHz card, programmed)
slots 0002 0003 board_id=0xff (5/6 GHz cards, unprogrammed)
Two host-side fixes required (separate patches)
-----------------------------------------------
Fix A -- single-mac cards must not request WMI MAC1:
Without: HTC service WMI MAC1 connect response: status: 0x1 (NOT_FOUND)
Cause : hw_params.max_radios=2 for qcn9274 hw2.0 unconditionally drives
ath12k_htc_init() to open two WMI endpoints. Single-mac firmware
(dualmac OTP bit clear) does not advertise the MAC1 WMI service.
Fix : read dualmac OTP at MHI register time; scope wmi_ep_count to 1
when ab->dualmac is false for qcn9274 hw2.0.
Fix B -- DMA ring capability parser must tolerate unknown module IDs:
Without: "Invalid module id 3" -> "failed to parse tlv -22" -> WMI ready timeout
Cause : WBE.1.6 sends capability entries for module_id 3 (and possibly
others) the host enum does not know. ath12k_dp_get_ring_num()
returns -EINVAL for unknown IDs, breaking TLV parsing entirely.
Fix : warn-and-skip on unknown module_id instead of returning -EINVAL.
Both confirmed working on this hardware. Happy to format as [PATCH ath-next] if
useful -- they get all three cards from "won't init" to "init proceeds cleanly
through WMI SVC_READY_EXT".
The blocker: firmware RDDM ~316 ms after host sends WMI_INIT_CMD
-----------------------------------------------------------------
With both fixes applied and CONFIG_ATH12K_DEBUG=y + debug_mask=0xffffff, boot
is clean through service negotiation:
[19.482] Control service: ul pipe 0 dl pipe 1 eid 0 ready
[19.485] HTT Data connect response: status: 0, assigned ep: 1
[19.485] WMI connect response: status: 0, assigned ep: 2
[19.486] wmi_ext_service_bitmap 0x5e45be01 0x2d94d02 0x1c7010c6 0xee7d5c14
[19.486] num hw modes 1 preferred_hw_mode 0
slot 0002 (5/6 GHz): supported_bands 2 freq 5 GHz [4890-7125 MHz]
slot 0001 (2.4 GHz): supported_bands 1 freq 2 GHz [2401-2495 MHz]
[19.486] unsupported dma ring cap module id 3, skipping (Fix B)
[20.408] htc ep 2 consumed 1 credits (total 1) <-- WMI_INIT_CMD sent
[20.724] ath12k_pci 0003:01:00.0: mhi notify status reason MHI_CB_EE_RDDM
[20.883] ath12k_pci 0001:01:00.0: mhi notify status reason MHI_CB_EE_RDDM
[24.517] ath12k_pci 0002:01:00.0: failed to receive wmi unified ready event: -110
MHI_CB_EE_RDDM (RAM Dump Debug Mode) fires 316-476 ms after the host sends
WMI_INIT_CMD. The crash hits all three cards on every boot. Card 0002 does not
crash but times out waiting for WMI_UNIFIED_READY, presumably because the
firmware group is stuck.
I also attempted two host-side patches targeting the post-INIT path: a
NULL-ptr guard in ath12k_core_start and a DMA ring config timing fix in
ath12k_core_hw_group_start. Both were confirmed to have no effect -- RDDM fires
before either code path is reached, ruling out those theories.
A 21013-line verbose ath12k log (multiple consecutive boots) is available on
request.
Questions
---------
1. Is WLAN.WBE.1.6-01243 known to work with current ath-next on QCN9274 hw2.0
single-band cards? Is there a known-good firmware version to try
(WBE.1.4.x or WBE.1.3.x)?
2. Is the WMI_INIT_CMD payload format expected to differ between single-band
and dual-band QCN9274 variants in a way current ath-next doesn't handle?
3. Is there a way to extract an RDDM dump after this crash (debugfs, PCIe BAR,
MHI API) to identify the specific firmware fault?
4. Wallys vendor documentation says "only single band modules can work with
current ath12k without extra development". My cards ARE single-band yet all
three crash. Is there known additional host-side work beyond Fixes A and B?
Full verbose dmesg on request. Patches A and B are ready to post in proper
format if useful upstream.
Thanks,
Stefano
^ permalink raw reply
* [PATCH v5 0/2] genirq/ath12k: fallback to threaded NAPI when IRQ affinity is unavailable
From: Hangtian Zhu @ 2026-05-19 1:07 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
From: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
This series improves ath12k datapath behavior on platforms where the
effective IRQ path for WLAN MSI interrupts does not support affinity
setting.
In such setups, DP processing cannot be distributed as intended and can
become CPU-constrained. The ath12k change switches to threaded NAPI when
runtime IRQ capability indicates affinity is unavailable.
Patch 1 exports irq_can_set_affinity() for module drivers so they can
reuse the IRQ core helper instead of open-coding equivalent checks.
Patch 2 uses irq_can_set_affinity() in ath12k PCI to enable threaded NAPI
for DP interrupt groups only when affinity cannot be set.
On RB3Gen2 with QCC2072, EHT160 UDP downlink throughput improved from
802 Mbps to 2.58 Gbps after enabling threaded NAPI.
Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0.c2-00074-QCACOLSWPL_V1_TO_SILICONZ-1
Thanks,
Hangtian Zhu
---
v2: sanity check irq >=0 before irq_can_set_affinity in patch 2
v1: initial post
Hangtian Zhu (2):
genirq: export irq_can_set_affinity() for module drivers
wifi: ath12k: enable threaded NAPI when DP IRQ affinity is unavailable
drivers/net/wireless/ath/ath12k/pci.c | 11 ++++++++++-
kernel/irq/manage.c | 1 +
2 files changed, 11 insertions(+), 1 deletion(-)
base-commit: e12d2d3983acb150fd987d19ec6a2a530da110df
--
2.25.1
^ permalink raw reply
* [PATCH v5 1/2] genirq: export irq_can_set_affinity() for module drivers
From: Hangtian Zhu @ 2026-05-19 1:07 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260519010758.712297-1-hangtian@qti.qualcomm.com>
From: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
Export irq_can_set_affinity() for loadable drivers that need a runtime
check for IRQ affinity capability.
In hierarchical IRQ setups where the effective irqchip path lacks
.irq_set_affinity(), drivers may need to switch to a fallback policy.
Without this export, module drivers cannot use the core helper and have
to open-code equivalent checks.
Signed-off-by: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
---
kernel/irq/manage.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2e8072437826..c3aa33ef4be9 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -171,6 +171,7 @@ int irq_can_set_affinity(unsigned int irq)
{
return __irq_can_set_affinity(irq_to_desc(irq));
}
+EXPORT_SYMBOL_GPL(irq_can_set_affinity);
/**
* irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space
--
2.25.1
^ permalink raw reply related
* [PATCH v5 2/2] wifi: ath12k: enable threaded NAPI when DP IRQ affinity is unavailable
From: Hangtian Zhu @ 2026-05-19 1:07 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260519010758.712297-1-hangtian@qti.qualcomm.com>
From: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
Determine threaded NAPI policy from runtime IRQ capability of the DP MSI
IRQ.
If irq_can_set_affinity() reports that affinity cannot be set, enable
threaded NAPI for DP interrupt groups so datapath processing is not
constrained by a single-CPU softirq context.
On RB3Gen2, where IRQ affinity is unavailable in the effective IRQ path,
EHT160 UDP downlink throughput improved from 802 Mbps to 2.58 Gbps after
enabling threaded NAPI.
Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0.c2-00074-QCACOLSWPL_V1_TO_SILICONZ-1
Signed-off-by: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/pci.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 375277ca2b89..065449806ea9 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/time.h>
@@ -537,6 +538,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
int i, j, n, ret, num_vectors = 0;
u32 user_base_data = 0, base_vector = 0, base_idx;
struct ath12k_ext_irq_grp *irq_grp;
+ bool threaded_napi = false;
+ int irq;
base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
ret = ath12k_pci_get_user_msi_assignment(ab, "DP",
@@ -546,6 +549,10 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
if (ret < 0)
return ret;
+ irq = ath12k_pci_get_msi_irq(ab->dev, base_vector);
+ if (irq >= 0)
+ threaded_napi = !irq_can_set_affinity(irq);
+
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
irq_grp = &ab->ext_irq_grp[i];
u32 num_irq = 0;
@@ -560,6 +567,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
ath12k_pci_ext_grp_napi_poll);
+ if (threaded_napi)
+ netif_threaded_enable(irq_grp->napi_ndev);
if (ab->hw_params->ring_mask->tx[i] ||
ab->hw_params->ring_mask->rx[i] ||
@@ -578,7 +587,7 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
for (j = 0; j < irq_grp->num_irq; j++) {
int irq_idx = irq_grp->irqs[j];
int vector = (i % num_vectors) + base_vector;
- int irq = ath12k_pci_get_msi_irq(ab->dev, vector);
+ irq = ath12k_pci_get_msi_irq(ab->dev, vector);
ab->irq_num[irq_idx] = irq;
--
2.25.1
^ permalink raw reply related
* [RESEND PATCH 0/2] genirq/ath12k: fallback to threaded NAPI when IRQ affinity is unavailable
From: Hangtian Zhu @ 2026-05-19 1:16 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
This series improves ath12k datapath behavior on platforms where the
effective IRQ path for WLAN MSI interrupts does not support affinity
setting.
In such setups, DP processing cannot be distributed as intended and can
become CPU-constrained. The ath12k change switches to threaded NAPI when
runtime IRQ capability indicates affinity is unavailable.
Patch 1 exports irq_can_set_affinity() for module drivers so they can
reuse the IRQ core helper instead of open-coding equivalent checks.
Patch 2 uses irq_can_set_affinity() in ath12k PCI to enable threaded NAPI
for DP interrupt groups only when affinity cannot be set.
On RB3Gen2 with QCC2072, EHT160 UDP downlink throughput improved from
802 Mbps to 2.58 Gbps after enabling threaded NAPI.
Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0.c2-00074-QCACOLSWPL_V1_TO_SILICONZ-1
Thanks,
Hangtian Zhu
Hangtian Zhu (2):
genirq: export irq_can_set_affinity() for module drivers
wifi: ath12k: enable threaded NAPI when DP IRQ affinity is unavailable
drivers/net/wireless/ath/ath12k/pci.c | 11 ++++++++++-
kernel/irq/manage.c | 1 +
2 files changed, 11 insertions(+), 1 deletion(-)
base-commit: db17e958184be9fe2b6242b7c5b7b261c0ce7110
--
2.25.1
^ permalink raw reply
* [RESEND PATCH 1/2] genirq: export irq_can_set_affinity() for module drivers
From: Hangtian Zhu @ 2026-05-19 1:16 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260519011627.713068-1-hangtian.zhu@oss.qualcomm.com>
Export irq_can_set_affinity() for loadable drivers that need a runtime
check for IRQ affinity capability.
In hierarchical IRQ setups where the effective irqchip path lacks
.irq_set_affinity(), drivers may need to switch to a fallback policy.
Without this export, module drivers cannot use the core helper and have
to open-code equivalent checks.
Signed-off-by: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
---
kernel/irq/manage.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 2e8072437826..c3aa33ef4be9 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -171,6 +171,7 @@ int irq_can_set_affinity(unsigned int irq)
{
return __irq_can_set_affinity(irq_to_desc(irq));
}
+EXPORT_SYMBOL_GPL(irq_can_set_affinity);
/**
* irq_can_set_affinity_usr - Check if affinity of a irq can be set from user space
--
2.25.1
^ permalink raw reply related
* [RESEND PATCH 2/2] wifi: ath12k: enable threaded NAPI when DP IRQ affinity is unavailable
From: Hangtian Zhu @ 2026-05-19 1:16 UTC (permalink / raw)
To: tglx, jjohnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260519011627.713068-1-hangtian.zhu@oss.qualcomm.com>
Determine threaded NAPI policy from runtime IRQ capability of the DP MSI
IRQ.
If irq_can_set_affinity() reports that affinity cannot be set, enable
threaded NAPI for DP interrupt groups so datapath processing is not
constrained by a single-CPU softirq context.
On RB3Gen2, where IRQ affinity is unavailable in the effective IRQ path,
EHT160 UDP downlink throughput improved from 802 Mbps to 2.58 Gbps after
enabling threaded NAPI.
Tested-on: QCC2072 hw1.0 PCI WLAN.COL.1.0.c2-00074-QCACOLSWPL_V1_TO_SILICONZ-1
Signed-off-by: Hangtian Zhu <hangtian.zhu@oss.qualcomm.com>
---
drivers/net/wireless/ath/ath12k/pci.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/ath/ath12k/pci.c b/drivers/net/wireless/ath/ath12k/pci.c
index 375277ca2b89..065449806ea9 100644
--- a/drivers/net/wireless/ath/ath12k/pci.c
+++ b/drivers/net/wireless/ath/ath12k/pci.c
@@ -5,6 +5,7 @@
*/
#include <linux/module.h>
+#include <linux/interrupt.h>
#include <linux/msi.h>
#include <linux/pci.h>
#include <linux/time.h>
@@ -537,6 +538,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
int i, j, n, ret, num_vectors = 0;
u32 user_base_data = 0, base_vector = 0, base_idx;
struct ath12k_ext_irq_grp *irq_grp;
+ bool threaded_napi = false;
+ int irq;
base_idx = ATH12K_PCI_IRQ_CE0_OFFSET + CE_COUNT_MAX;
ret = ath12k_pci_get_user_msi_assignment(ab, "DP",
@@ -546,6 +549,10 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
if (ret < 0)
return ret;
+ irq = ath12k_pci_get_msi_irq(ab->dev, base_vector);
+ if (irq >= 0)
+ threaded_napi = !irq_can_set_affinity(irq);
+
for (i = 0; i < ATH12K_EXT_IRQ_GRP_NUM_MAX; i++) {
irq_grp = &ab->ext_irq_grp[i];
u32 num_irq = 0;
@@ -560,6 +567,8 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
netif_napi_add(irq_grp->napi_ndev, &irq_grp->napi,
ath12k_pci_ext_grp_napi_poll);
+ if (threaded_napi)
+ netif_threaded_enable(irq_grp->napi_ndev);
if (ab->hw_params->ring_mask->tx[i] ||
ab->hw_params->ring_mask->rx[i] ||
@@ -578,7 +587,7 @@ static int ath12k_pci_ext_irq_config(struct ath12k_base *ab)
for (j = 0; j < irq_grp->num_irq; j++) {
int irq_idx = irq_grp->irqs[j];
int vector = (i % num_vectors) + base_vector;
- int irq = ath12k_pci_get_msi_irq(ab->dev, vector);
+ irq = ath12k_pci_get_msi_irq(ab->dev, vector);
ab->irq_num[irq_idx] = irq;
--
2.25.1
^ 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