Linux wireless drivers development
 help / color / mirror / Atom feed
* [PATCH rtw-next v2 1/1] wifi: rtw89: usb: Support switching to USB 3 mode
From: Devin Wittmayer @ 2026-05-11 16:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel, Devin Wittmayer
In-Reply-To: <20260511160811.17647-1-lucid_duck@justthetip.ca>

From: Bitterblue Smith <rtl8821cerfe2@gmail.com>

The Realtek wifi 6/7 devices which support USB 3 are weird: when first
plugged in, they pretend to be USB 2. The driver needs to send some
commands to the device, which make it disappear and come back as a
USB 3 device.

Implement the required commands in rtw89.

When a USB 3 device is plugged into a USB 2 port, rtw89 will try to
switch it to USB 3 mode only once. The device will disappear and come
back still in USB 2 mode, of course.

Some people experience heavy interference in the 2.4 GHz band in
USB 3 mode, so add a module parameter switch_usb_mode with the
default value 1 to let people disable the switching.

Tested with RTL8832BU and RTL8832CU.

Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>
---
 drivers/net/wireless/realtek/rtw89/reg.h |  4 +++
 drivers/net/wireless/realtek/rtw89/usb.c | 41 ++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
index 42ffe83931a3..7d4c085d9fb2 100644
--- a/drivers/net/wireless/realtek/rtw89/reg.h
+++ b/drivers/net/wireless/realtek/rtw89/reg.h
@@ -164,6 +164,10 @@
 #define R_AX_DBG_PORT_SEL 0x00C0
 #define B_AX_DEBUG_ST_MASK GENMASK(31, 0)
 
+#define R_AX_PAD_CTRL2 0x00C4
+#define U2SWITCHU3 0xB
+#define USB_SWITCH_DELAY 0xF
+
 #define R_AX_PMC_DBG_CTRL2 0x00CC
 #define B_AX_SYSON_DIS_PMCR_AX_WRMSK BIT(2)
 
diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
index 767a95f759b1..4fb25791d118 100644
--- a/drivers/net/wireless/realtek/rtw89/usb.c
+++ b/drivers/net/wireless/realtek/rtw89/usb.c
@@ -9,6 +9,11 @@
 #include "txrx.h"
 #include "usb.h"
 
+static bool rtw89_switch_usb_mode = true;
+module_param_named(switch_usb_mode, rtw89_switch_usb_mode, bool, 0644);
+MODULE_PARM_DESC(switch_usb_mode,
+		 "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");
+
 static void rtw89_usb_read_port_complete(struct urb *urb);
 
 static void rtw89_usb_vendorreq(struct rtw89_dev *rtwdev, u32 addr,
@@ -1027,6 +1032,35 @@ static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev,
 	usb_set_intfdata(intf, NULL);
 }
 
+static int rtw89_usb_switch_mode(struct rtw89_dev *rtwdev)
+{
+	struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
+
+	if (!rtw89_switch_usb_mode)
+		return 0;
+
+	/* No known USB 3 devices with this chip. */
+	if (rtwdev->chip->chip_id == RTL8851B)
+		return 0;
+
+	if (rtwusb->udev->speed == USB_SPEED_SUPER)
+		return 0;
+
+	rtw89_debug(rtwdev, RTW89_DBG_HCI, "%s: pad_ctrl2: %#x %#x\n",
+		    __func__,
+		    rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 1),
+		    rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 2));
+
+	/* Already tried to switch but it's a USB 2 port. */
+	if (rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 1) == USB_SWITCH_DELAY)
+		return 0;
+
+	rtw89_write8(rtwdev, R_AX_PAD_CTRL2 + 1, USB_SWITCH_DELAY);
+	rtw89_write8(rtwdev, R_AX_PAD_CTRL2 + 2, U2SWITCHU3);
+
+	return 1;
+}
+
 int rtw89_usb_probe(struct usb_interface *intf,
 		    const struct usb_device_id *id)
 {
@@ -1059,6 +1093,13 @@ int rtw89_usb_probe(struct usb_interface *intf,
 		goto err_free_hw;
 	}
 
+	ret = rtw89_usb_switch_mode(rtwdev);
+	if (ret) {
+		/* Not a fail, but we do need to skip rtw89_core_register. */
+		ret = 0;
+		goto err_intf_deinit;
+	}
+
 	if (rtwusb->udev->speed == USB_SPEED_SUPER)
 		rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB3;
 	else
-- 
2.53.0


^ permalink raw reply related

* [PATCH rtw-next v2 0/1] wifi: rtw89: usb: Support switching to USB 3 mode
From: Devin Wittmayer @ 2026-05-11 16:08 UTC (permalink / raw)
  To: linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel, Devin Wittmayer
In-Reply-To: <20260508054421.128938-1-lucid_duck@justthetip.ca>

This patch adds USB 2 to USB 3 mode switching for the AX-generation
chips in the rtw89 USB driver (8852AU, 8852BU, 8852CU and helper
variants). Without it, those adapters enumerate at USB 2.0
high-speed on first plug and stay there, capping real-world
throughput around 260 Mbps TCP regardless of radio capability.

It is Bitterblue Smith's morrownr/rtw89 commit cd287ccf544b
(2025-07-16) rebased onto rtw-next without code changes:
author's Signed-off-by preserved, my Signed-off-by added as
relayer, Tested-by per chip based on the matrix below.

Changes since v1
================

- Rebased onto pkshih/rtw rtw-next (HEAD c1ed02655f91) per
  maintainer feedback. The patch diff is unchanged from v1; the
  test matrix below carries forward.
- Cover letter tightened to AX-generation scope only.

The bug
=======

These chips present as USB 2 devices on first plug. The driver is
expected to send a switch-mode register write to make them disappear
and re-enumerate as USB 3 SuperSpeed. Mainline rtw89 does not issue
these commands anywhere. Every user with one of these adapters on
a mainline-derived distribution sits at the USB 2.0 ceiling for
the life of the plug, regardless of negotiated radio rate.

The fix
=======

The patch covers AX-generation chips (8852AU, 8852BU, 8852CU and
helper variants) via R_AX_PAD_CTRL2. It also adds the
switch_usb_mode module parameter (default on) for users who
experience 2.4 GHz interference under USB 3.

Mainline precedent
==================

The same mechanism is in mainline rtw88 across three commits
between July 2024 and April 2025, all authored by Bitterblue Smith:

  commit 315c23a64e99 ("wifi: rtw88: usb: Support USB 3 with RTL8822CU/RTL8822BU")
  commit 82a35723a67c ("wifi: rtw88: usb: Support USB 3 with RTL8812AU")
  commit bf1103654df9 ("wifi: rtw88: usb: Enable switching the RTL8814AU to USB 3")

Test results
============

60 plug-cycles + 30+ gated throughput cells captured 2026-04-11
to 2026-05-07. Both x86_64 (Tiger Lake xHCI) and aarch64
(Broadcom RP1 xHCI) reproductions confirm the bug and the fix.

  Hosts:    Framework 13 (x86_64, Fedora 43 / 6.19.13, Tiger Lake xHCI)
            NucBox K8 Plus (x86_64, Arch Linux / 6.17.9, AMD F19h USB)
            Raspberry Pi 5 (aarch64, Pi OS / 6.12.47, BCM2712 + RP1)
            Banana Pi BPi-R4 Pro (aarch64, OpenWrt / 6.6.93, MT7988A;
                                  also used as a controlled lab AP)
  Adapters: D-Link DWA-X1850 A1 / B1 (RTL8852AU)
            BrosTrend AX1L compact / AX4L high-gain (RTL8852BU)
            BrosTrend AX8L AXE5400 / EDUP AXE5400 (RTL8852CU)
  APs:      consumer multi-band router (WPA3-SAE / WPA2-PSK)
            BPi-R4 Pro single-band lab AP (WPA3-SAE)
  Server:   Linux iperf3 host on 2.5 GbE wired Ethernet

Full per-cell evidence (raw iperf3 stdout, dmesg captures, sysfs
snapshots, iw link snapshots, byte-counter deltas, per-host detail)
at https://github.com/Lucid-Duck/rtw89-usb3-gap.

Plug-cycle. N=10 cycles per (chip, host) cell. Pass = post-plug
/sys/bus/usb/devices/<id>/speed reads 5000 (USB 3 SuperSpeed),
zero WARN/BUG/Oops in cycle-bracketed dmesg, non-empty association
BSSID after settle.

  Adapter (chip)               FW13 6.19      K8 Plus 6.17
  ---------------------------  -------------  --------------
  DWA-X1850 A1 (RTL8852AU)     10/10 PASS     10/10 PASS
  BrosTrend AX1L (RTL8852BU)   10/10 PASS     10/10 PASS

  FW13:    Fedora 43, 6.19.13, wireless-next + this patch
  K8 Plus: Arch Linux, 6.17.9-arch1-1, morrownr/rtw89 (upstream
           fork; identical AX-gen behavior to this patch)

Throughput. TCP iperf3, N=10 30-second iterations per sub-cell,
four sub-cells per cell (P=8 and P=1, each direction), to a Linux
2.5 GbE host. Per-cell /32 host route forces traffic onto the WiFi
adapter; per-iteration byte-counter cross-check on every cited cell
shows wireless tx/rx delta at 103-108% of iperf3 reported bytes
(excess is normal TCP/IP framing), so wired-NIC bleed is ruled out.
Linux tuning applied (rmem 32 MB, RPS=ff on the WiFi RX queue).

FW13 stock (in-kernel rtw89, USB 2 stuck) vs patched (USB 3
SuperSpeed), same adapter / AP / kernel / capture script, P=8 mean
Mbps, AP is the consumer multi-band router:

  Adapter (chip)              Band, width      UL stock  UL patched  DL stock  DL patched
  --------------------------  ---------------  --------  ----------  --------  ----------
  EDUP AXE5400 (RTL8852CU)    6 GHz, 160 MHz       269        1364       327         579
  AX8L AXE5400 (RTL8852CU)    6 GHz, 160 MHz       269        1440       324         510
  AX4L AX1800 (RTL8852BU)     5 GHz,  80 MHz       208         597       293         695
  AX1L AX1800 (RTL8852BU)     5 GHz,  80 MHz       235         608       273         843
  DWA-X1850 A1 (RTL8852AU)    5 GHz,  80 MHz       254         748       264         707
  DWA-X1850 B1 (RTL8852AU)    5 GHz,  80 MHz       248         706       265         679

USB enumeration verified at SuperSpeed (5000 Mbps) on every
patched cell, both pre and post.

K8 Plus second-rig spot check, kernel 6.17.9-arch1-1, consumer
multi-band router, single-link 5 GHz 80 MHz, TCP P=1, N=10:

  DWA-X1850 A1 (RTL8852AU)    788 UL / 693 DL Mbps (sigma 16 / 54)

For comparison, every stock cell above caps at 208-327 Mbps, the
USB 2.0 ceiling.

Submission notes
================

Applies cleanly on pkshih/rtw rtw-next HEAD c1ed02655f91.
checkpatch.pl --strict: zero errors, zero warnings, zero checks.

Bitterblue Smith (1):
  wifi: rtw89: usb: Support switching to USB 3 mode

 drivers/net/wireless/realtek/rtw89/reg.h |  4 +++
 drivers/net/wireless/realtek/rtw89/usb.c | 41 ++++++++++++++++++++++++
 2 files changed, 45 insertions(+)

--
2.53.0


^ permalink raw reply

* Re: [PATCH 2/3] [v5 net-next] p54spi: convert to devicetree
From: Simon Horman @ 2026-05-11 16:12 UTC (permalink / raw)
  To: arnd
  Cc: 'Simon Horman', netdev, arnd, aaro.koskinen, andreas,
	brgl, bcousson, davem, dmitry.torokhov, edumazet, balbi, kuba,
	johannes, khilman, krzk+dt, linusw, pabeni, robh+dt, rogerq, tony,
	linux-wireless, devicetree, linux-kernel, linux-arm-kernel,
	linux-gpio, linux-omap, krzk
In-Reply-To: <20260507212451.3333185-3-arnd@kernel.org>

From: 'Simon Horman' <horms@kernel.org>

This is an AI-generated review of your patch. The human sending this
email has considered the AI review valid, or at least plausible.
Full review at: https://sashiko.dev
---
p54spi: convert to devicetree

This commit converts the Prism54 SPI driver from using hardcoded GPIO
module parameters to using the GPIO descriptor interface and device tree
probing.

> diff --git a/drivers/net/wireless/intersil/p54/p54spi.c b/drivers/net/wireless/intersil/p54/p54spi.c
> index 9d66dcae54e02..d18be25450285 100644
> --- a/drivers/net/wireless/intersil/p54/p54spi.c
> +++ b/drivers/net/wireless/intersil/p54/p54spi.c

[ ... ]

> @@ -30,19 +31,6 @@
>  MODULE_FIRMWARE("3826.arm");
>  MODULE_FIRMWARE("3826.eeprom");
>  
> -/* gpios should be handled in board files and provided via platform data,
> - * but because it's currently impossible for p54spi to have a header file
> - * in include/linux, let's use module parameters for now
> - */
> -
> -static int p54spi_gpio_power = 97;
> -module_param(p54spi_gpio_power, int, 0444);
> -MODULE_PARM_DESC(p54spi_gpio_power, "gpio number for power line");
> -
> -static int p54spi_gpio_irq = 87;
> -module_param(p54spi_gpio_irq, int, 0444);
> -MODULE_PARM_DESC(p54spi_gpio_irq, "gpio number for irq line");
> -
>  static void p54spi_spi_read(struct p54s_priv *priv, u8 address,
>  			      void *buf, size_t len)
>  {

Simon says: As a pre-existing issue I don't think we need to be concerned
            about this in the scope of this patch-set. But it may
	    be a potential for follow-up.

This problem wasn't introduced by this patch, but I noticed a pre-existing
issue in the context here. Does the p54spi_spi_read() function perform an SPI
transfer using a stack-allocated buffer?

Looking at p54spi_spi_read(), the addr variable is allocated on the stack and
passed as a transfer buffer to spi_sync(). The SPI framework maps transfer
buffers for DMA. Passing a stack-allocated buffer is illegal, particularly with
CONFIG_VMAP_STACK enabled, because stack memory resides in vmalloc space and
cannot be safely DMA-mapped.

Could this cause memory corruption or a kernel panic during the transfer?

[ ... ]

> @@ -608,31 +596,20 @@ static int p54spi_probe(struct spi_device *spi)
>  		goto err_free;
>  	}
>  
> -	ret = gpio_request(p54spi_gpio_power, "p54spi power");
> -	if (ret < 0) {
> -		dev_err(&priv->spi->dev, "power GPIO request failed: %d", ret);
> +	priv->gpio_powerdown = gpiod_get_optional(&spi->dev, "powerdown", GPIOD_OUT_HIGH);
> +	if (IS_ERR(priv->gpio_powerdown)) {
> +		ret = dev_err_probe(&priv->spi->dev, PTR_ERR(priv->gpio_powerdown),
> +				    "powerdown GPIO request failed\n");
>  		goto err_free;
>  	}
>  
> -	ret = gpio_request(p54spi_gpio_irq, "p54spi irq");
> -	if (ret < 0) {
> -		dev_err(&priv->spi->dev, "irq GPIO request failed: %d", ret);
> -		goto err_free_gpio_power;
> -	}
> -
> -	gpio_direction_output(p54spi_gpio_power, 0);
> -	gpio_direction_input(p54spi_gpio_irq);
> -
> -	ret = request_irq(gpio_to_irq(p54spi_gpio_irq),
> -			  p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi",
> -			  priv->spi);
> +	ret = request_irq(spi->irq, p54spi_interrupt, IRQF_NO_AUTOEN, "p54spi", priv->spi);

Simon says: This one seems more concerning in the context of this patch-set.

Is there missing validation for spi->irq before calling request_irq()?

If the device tree node lacks an interrupts property, the SPI core may set
spi->irq to 0 or a negative error code.

Passing this directly to request_irq() without validation can successfully
hijack a core system interrupt like the system timer on some architectures,
leading to system instability or deadlocks.

Should there be a check like if (spi->irq <= 0) to fail the probe gracefully?

>  	if (ret < 0) {
>  		dev_err(&priv->spi->dev, "request_irq() failed");
> -		goto err_free_gpio_irq;
> +		goto err_free_gpio_power;
>  	}

^ permalink raw reply

* Re: [PATCH rtw-next v2 1/1] wifi: rtw89: usb: Support switching to USB 3 mode
From: Johannes Berg @ 2026-05-11 17:26 UTC (permalink / raw)
  To: Devin Wittmayer, linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel
In-Reply-To: <20260511160811.17647-2-lucid_duck@justthetip.ca>

On Mon, 2026-05-11 at 09:08 -0700, Devin Wittmayer wrote:
> 
> +static bool rtw89_switch_usb_mode = true;
> +module_param_named(switch_usb_mode, rtw89_switch_usb_mode, bool, 0644);
> +MODULE_PARM_DESC(switch_usb_mode,
> +		 "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");

We shouldn't really add new module parameters.

johannes

^ permalink raw reply

* [PATCH iwlwifi-next 00/15] wifi: iwlwifi: updates - 2026-05-11
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless

Hi,

Features, cleanups and fixes from our internal tree.
A few more NAN commits.

Thanks,
Miri
---

Avinash Bhatt (1):
  wifi: iwlwifi: fix buffer overflow when firmware reports no channels

Emmanuel Grumbach (3):
  wifi: iwlwifi: fix the access to CNVR TOP registers
  wifi: iwlwifi: mld: honor BSS_CHANGED_BEACON_ENABLED
  wifi: iwlwifi: mld: move iwl_mld_link_info_changed_ap_ibss to ap.c

Johannes Berg (7):
  wifi: iwlwifi: mld: clean up station handling in key APIs
  wifi: iwlwifi: mld: add TLC support for NAN stations
  wifi: iwlwifi: mld: track TX/RX IGTKs separately
  wifi: iwlwifi: mld: don't report bad STA ID in EHT TB sniffer
  wifi: iwlwifi: api: RX: define UHR RX PHY flags
  wifi: iwlwifi: fw: api: fix UHR U-SIG whitespace
  wifi: iwlwifi: fw: api: add/fix some UHR sniffer definitions

Miri Korenblit (2):
  wifi: iwlwifi: bump core version for BZ/SC/DR to 103
  wifi: iwlwifi: mld: allow NAN data

Pagadala Yesu Anjaneyulu (2):
  wifi: iwlwifi: add RF name handling for PE chip type for debugfs
  wifi: iwlwifi: add XIAOMI to PPAG approved list

 drivers/net/wireless/intel/iwlwifi/cfg/bz.c   |   2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c   |   2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c   |   2 +-
 .../net/wireless/intel/iwlwifi/fw/api/rx.h    |  38 +++-
 .../wireless/intel/iwlwifi/fw/regulatory.c    |   7 +-
 drivers/net/wireless/intel/iwlwifi/iwl-csr.h  |   3 +-
 drivers/net/wireless/intel/iwlwifi/iwl-io.c   |  18 +-
 drivers/net/wireless/intel/iwlwifi/iwl-io.h   |   4 +-
 .../wireless/intel/iwlwifi/iwl-nvm-parse.c    |  21 +-
 drivers/net/wireless/intel/iwlwifi/iwl-prph.h |   7 +-
 drivers/net/wireless/intel/iwlwifi/mld/ap.c   |  58 +++++-
 drivers/net/wireless/intel/iwlwifi/mld/ap.h   |   8 +-
 drivers/net/wireless/intel/iwlwifi/mld/d3.c   |  20 +-
 .../net/wireless/intel/iwlwifi/mld/iface.h    |  15 ++
 drivers/net/wireless/intel/iwlwifi/mld/key.c  | 110 +++++-----
 drivers/net/wireless/intel/iwlwifi/mld/link.h |   9 +-
 .../net/wireless/intel/iwlwifi/mld/mac80211.c |  51 ++---
 drivers/net/wireless/intel/iwlwifi/mld/nan.c  |  41 +++-
 drivers/net/wireless/intel/iwlwifi/mld/rx.c   |  15 +-
 drivers/net/wireless/intel/iwlwifi/mld/sta.h  |   4 +
 drivers/net/wireless/intel/iwlwifi/mld/tlc.c  | 189 +++++++++++++++---
 .../intel/iwlwifi/pcie/gen1_2/trans-gen2.c    |   9 +-
 .../intel/iwlwifi/pcie/gen1_2/trans.c         |  26 ++-
 23 files changed, 486 insertions(+), 173 deletions(-)

-- 
2.34.1


^ permalink raw reply

* [PATCH iwlwifi-next 01/15] wifi: iwlwifi: add RF name handling for PE chip type for debugfs
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>

Implement RF name handling for PE chip type in debugfs,
including special case handling to show PETC when the
silicon is in Z step.

Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-csr.h             | 3 ++-
 .../net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c  | 9 ++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
index f3fa37fee2e4..d2fa80a3dd04 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-csr.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
@@ -366,6 +366,7 @@ enum {
 #define CSR_HW_RF_ID_TYPE_GF4		(0x0010E000)
 #define CSR_HW_RF_ID_TYPE_FM		(0x00112000)
 #define CSR_HW_RF_ID_TYPE_WP		(0x00113000)
+#define CSR_HW_RF_ID_TYPE_PE		(0x00114000)
 
 /* HW_RF CHIP STEP  */
 #define CSR_HW_RF_STEP(_val) (((_val) >> 8) & 0xF)
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
index a50e845cea42..87e5f79ccb3c 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans-gen2.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
  */
 #include "iwl-trans.h"
 #include "iwl-prph.h"
@@ -327,6 +327,13 @@ static void iwl_pcie_get_rf_name(struct iwl_trans *trans)
 		else
 			pos = scnprintf(buf, buflen, "WH");
 		break;
+	case CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_PE):
+		if (SILICON_Z_STEP ==
+		    CSR_HW_RFID_STEP(trans->info.hw_rf_id))
+			pos = scnprintf(buf, buflen, "PETC");
+		else
+			pos = scnprintf(buf, buflen, "PE");
+		break;
 	default:
 		return;
 	}
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 02/15] wifi: iwlwifi: bump core version for BZ/SC/DR to 103
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

Start supporting Core 103 FW on these devices.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c | 2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c | 2 +-
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index 3653ddbf3ce9..8b3f15899396 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -10,7 +10,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_BZ_UCODE_CORE_MAX	102
+#define IWL_BZ_UCODE_CORE_MAX	103
 
 /* Lowest firmware API version supported */
 #define IWL_BZ_UCODE_API_MIN	100
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index 83d893b10f8e..a8f2ac688d31 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -9,7 +9,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_DR_UCODE_CORE_MAX	102
+#define IWL_DR_UCODE_CORE_MAX	103
 
 /* Lowest firmware API version supported */
 #define IWL_DR_UCODE_API_MIN	100
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index 749d46dc0236..8e6efde3c64b 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -10,7 +10,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_SC_UCODE_CORE_MAX	102
+#define IWL_SC_UCODE_CORE_MAX	103
 
 /* Lowest firmware API version supported */
 #define IWL_SC_UCODE_API_MIN	100
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 03/15] wifi: iwlwifi: fix the access to CNVR TOP registers
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach, Daniel Gabay
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

For Dr and Sc, we need to wait until the TOP is ready to gets its
registers read by the host.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Reviewed-by: Daniel Gabay <daniel.gabay@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/iwl-io.c   | 18 ++++++++++++-
 drivers/net/wireless/intel/iwlwifi/iwl-io.h   |  4 ++-
 drivers/net/wireless/intel/iwlwifi/iwl-prph.h |  7 ++++-
 .../intel/iwlwifi/pcie/gen1_2/trans.c         | 26 ++++++++++++++++++-
 4 files changed, 51 insertions(+), 4 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.c b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
index b1944584c693..c4ccfffdf6af 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2003-2014, 2018-2022, 2024-2025 Intel Corporation
+ * Copyright (C) 2003-2014, 2018-2022, 2024-2026 Intel Corporation
  * Copyright (C) 2015-2016 Intel Deutschland GmbH
  */
 #include <linux/device.h>
@@ -168,6 +168,22 @@ int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
 	return -ETIMEDOUT;
 }
 
+int iwl_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr,
+				    u32 bits, u32 mask, int timeout)
+{
+	int t = 0;
+
+	do {
+		if ((iwl_read_umac_prph_no_grab(trans, addr) & mask) ==
+		    (bits & mask))
+			return 0;
+		udelay(IWL_POLL_INTERVAL);
+		t += IWL_POLL_INTERVAL;
+	} while (t < timeout);
+
+	return -ETIMEDOUT;
+}
+
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask)
 {
 	if (iwl_trans_grab_nic_access(trans)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-io.h b/drivers/net/wireless/intel/iwlwifi/iwl-io.h
index 5bcec239ffc4..d920a32fc173 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-io.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-io.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2018-2021, 2025 Intel Corporation
+ * Copyright (C) 2018-2021, 2025-2026 Intel Corporation
  */
 #ifndef __iwl_io_h__
 #define __iwl_io_h__
@@ -51,6 +51,8 @@ static inline void iwl_write_prph(struct iwl_trans *trans, u32 ofs, u32 val)
 
 int iwl_poll_prph_bit(struct iwl_trans *trans, u32 addr,
 		      u32 bits, u32 mask, int timeout);
+int iwl_poll_umac_prph_bits_no_grab(struct iwl_trans *trans, u32 addr,
+				    u32 bits, u32 mask, int timeout);
 void iwl_set_bits_prph(struct iwl_trans *trans, u32 ofs, u32 mask);
 void iwl_set_bits_mask_prph(struct iwl_trans *trans, u32 ofs,
 			    u32 bits, u32 mask);
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
index a7214ddcfaf5..6ca1f51b69a1 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-prph.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2005-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2005-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
@@ -411,6 +411,11 @@ enum {
 #define HPM_SECONDARY_DEVICE_STATE      0xa03404
 #define WFPM_MAC_OTP_CFG7_ADDR		0xa03338
 #define WFPM_MAC_OTP_CFG7_DATA		0xa0333c
+#define WFPM_RSRCS_4PHS_REQ_STTS	0xa033f8
+#define WFPM_RSRCS_4PHS_ACK_STTS	0xa033fc
+
+#define RSRC_REQ_CNVR_TOP BIT(6)
+#define RSRC_ACK_CNVR_TOP BIT(6)
 
 
 /* For UMAG_GEN_HW_STATUS reg check */
diff --git a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
index a05f60f9224b..377b2e30b540 100644
--- a/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
+++ b/drivers/net/wireless/intel/iwlwifi/pcie/gen1_2/trans.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2007-2015, 2018-2024 Intel Corporation
+ * Copyright (C) 2007-2015, 2018-2024, 2026 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -4000,6 +4000,30 @@ static void get_crf_id(struct iwl_trans *iwl_trans,
 	else
 		sd_reg_ver_addr = SD_REG_VER;
 
+	/* wait until the device is ready to access the prph registers */
+	if (iwl_trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_DR ||
+	    iwl_trans->mac_cfg->device_family == IWL_DEVICE_FAMILY_SC) {
+		u32 req = iwl_read_umac_prph_no_grab(iwl_trans,
+						     WFPM_RSRCS_4PHS_REQ_STTS);
+		int ret;
+
+		if (!(req & RSRC_REQ_CNVR_TOP)) {
+			IWL_ERR(iwl_trans,
+				"WFPM_RSRCS_4PHS_REQ_STTS bit 6 is clear 0x%x\n",
+				req);
+			return;
+		}
+
+		ret = iwl_poll_umac_prph_bits_no_grab(iwl_trans,
+						      WFPM_RSRCS_4PHS_ACK_STTS,
+						      RSRC_ACK_CNVR_TOP,
+						      RSRC_ACK_CNVR_TOP,
+						      50 * 1000);
+		if (ret < 0)
+			IWL_ERR(iwl_trans,
+				"WFPM_RSRCS_4PHS_ACK_STTS bit 6 is clear\n");
+	}
+
 	/* Enable access to peripheral registers */
 	val = iwl_read_umac_prph_no_grab(iwl_trans, WFPM_CTRL_REG);
 	val |= WFPM_AUX_CTL_AUX_IF_MAC_OWNER_MSK;
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: mld: honor BSS_CHANGED_BEACON_ENABLED
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

We should stick to mac80211's flow to start / stop beaconing. This
allows to stop beaconing before we remove the BIGTK.

Note that the start and stop beaconing flows are not exactly symmetric.
When we start beaconing, we just update the beacon template. We assume
that mac80211 won't update the beacons, if we're not supposed to be
sending it.

Also note that we now send the beacon template after the broadcast
station was added to the firmware: the broadcast station is added in
the start_ap() flow, while the beacon template is now added in the
link_changed() flow which happens later. This is not what we did
before this patch, but this sequence is supported by the firmware as
well.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/ap.c   | 25 +++++++++++++++----
 drivers/net/wireless/intel/iwlwifi/mld/ap.h   |  6 ++++-
 .../net/wireless/intel/iwlwifi/mld/mac80211.c |  8 +++++-
 3 files changed, 32 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ap.c b/drivers/net/wireless/intel/iwlwifi/mld/ap.c
index 5c59acc8c4c5..c29e4a77be05 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ap.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ap.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024, 2026 Intel Corporation
  */
 #include <linux/crc32.h>
 
@@ -239,6 +239,25 @@ int iwl_mld_store_ap_early_key(struct iwl_mld *mld,
 	return -ENOSPC;
 }
 
+void iwl_mld_stop_beacon(struct iwl_mld *mld, struct ieee80211_vif *vif,
+			 struct ieee80211_bss_conf *link)
+{
+	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
+	struct iwl_mac_beacon_cmd cmd = {};
+	int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, BEACON_TEMPLATE_CMD, 14);
+
+	if (WARN_ON(!mld_link))
+		return;
+
+	if (cmd_ver < 15)
+		return;
+
+	/* leave byte_cnt 0 */
+	cmd.link_id = cpu_to_le32(mld_link->fw_id);
+
+	iwl_mld_send_cmd_pdu(mld, BEACON_TEMPLATE_CMD, &cmd);
+}
+
 static int iwl_mld_send_ap_early_keys(struct iwl_mld *mld,
 				      struct ieee80211_vif *vif,
 				      struct ieee80211_bss_conf *link)
@@ -276,10 +295,6 @@ int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw,
 	if (vif->type == NL80211_IFTYPE_AP)
 		iwl_mld_send_ap_tx_power_constraint_cmd(mld, vif, link);
 
-	ret = iwl_mld_update_beacon_template(mld, vif, link);
-	if (ret)
-		return ret;
-
 	/* the link should be already activated when assigning chan context,
 	 * and LINK_CONTEXT_MODIFY_EHT_PARAMS is deprecated
 	 */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ap.h b/drivers/net/wireless/intel/iwlwifi/mld/ap.h
index 4a6f52b9552d..a3b6bed814ad 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ap.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ap.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024, 2026 Intel Corporation
  */
 #ifndef __iwl_ap_h__
 #define __iwl_ap_h__
@@ -14,6 +14,10 @@ int iwl_mld_update_beacon_template(struct iwl_mld *mld,
 				   struct ieee80211_vif *vif,
 				   struct ieee80211_bss_conf *link_conf);
 
+void iwl_mld_stop_beacon(struct iwl_mld *mld,
+			 struct ieee80211_vif *vif,
+			 struct ieee80211_bss_conf *link_conf);
+
 int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
 			  struct ieee80211_bss_conf *link);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 1106ad651cfe..403bc38ac2bc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1258,8 +1258,14 @@ iwl_mld_link_info_changed_ap_ibss(struct iwl_mld *mld,
 	if (link_changes)
 		iwl_mld_change_link_in_fw(mld, link, link_changes);
 
-	if (changes & BSS_CHANGED_BEACON)
+	if (changes & BSS_CHANGED_BEACON) {
+		WARN_ON(!link->enable_beacon);
 		iwl_mld_update_beacon_template(mld, vif, link);
+	}
+
+	/* Enabling beacons was already covered above */
+	if ((changes & BSS_CHANGED_BEACON_ENABLED) && !link->enable_beacon)
+		iwl_mld_stop_beacon(mld, vif, link);
 }
 
 static
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mld: move iwl_mld_link_info_changed_ap_ibss to ap.c
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>

This function is ap mode related, move it to ap.c.
Also, don't call iwl_mld_ftm_responder_clear from stop_ap() since
mac80211 does it now before stopping the AP.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/ap.c   | 37 ++++++++++++++++++-
 drivers/net/wireless/intel/iwlwifi/mld/ap.h   |  8 ++--
 .../net/wireless/intel/iwlwifi/mld/mac80211.c | 33 -----------------
 3 files changed, 40 insertions(+), 38 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ap.c b/drivers/net/wireless/intel/iwlwifi/mld/ap.c
index c29e4a77be05..bc426b911ce5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ap.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ap.c
@@ -239,8 +239,8 @@ int iwl_mld_store_ap_early_key(struct iwl_mld *mld,
 	return -ENOSPC;
 }
 
-void iwl_mld_stop_beacon(struct iwl_mld *mld, struct ieee80211_vif *vif,
-			 struct ieee80211_bss_conf *link)
+static void iwl_mld_stop_beacon(struct iwl_mld *mld, struct ieee80211_vif *vif,
+				struct ieee80211_bss_conf *link)
 {
 	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link);
 	struct iwl_mac_beacon_cmd cmd = {};
@@ -258,6 +258,39 @@ void iwl_mld_stop_beacon(struct iwl_mld *mld, struct ieee80211_vif *vif,
 	iwl_mld_send_cmd_pdu(mld, BEACON_TEMPLATE_CMD, &cmd);
 }
 
+void
+iwl_mld_link_info_changed_ap_ibss(struct iwl_mld *mld,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_bss_conf *link,
+				  u64 changes)
+{
+	u32 link_changes = 0;
+
+	if (changes & BSS_CHANGED_ERP_SLOT)
+		link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;
+
+	if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))
+		link_changes |= LINK_CONTEXT_MODIFY_PROTECT_FLAGS;
+
+	if (changes & (BSS_CHANGED_QOS | BSS_CHANGED_BANDWIDTH))
+		link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;
+
+	if (changes & BSS_CHANGED_HE_BSS_COLOR)
+		link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
+
+	if (link_changes)
+		iwl_mld_change_link_in_fw(mld, link, link_changes);
+
+	if (changes & BSS_CHANGED_BEACON) {
+		WARN_ON(!link->enable_beacon);
+		iwl_mld_update_beacon_template(mld, vif, link);
+	}
+
+	/* Enabling beacons was already covered above */
+	if ((changes & BSS_CHANGED_BEACON_ENABLED) && !link->enable_beacon)
+		iwl_mld_stop_beacon(mld, vif, link);
+}
+
 static int iwl_mld_send_ap_early_keys(struct iwl_mld *mld,
 				      struct ieee80211_vif *vif,
 				      struct ieee80211_bss_conf *link)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/ap.h b/drivers/net/wireless/intel/iwlwifi/mld/ap.h
index a3b6bed814ad..f10e9c9a38ff 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/ap.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/ap.h
@@ -14,9 +14,11 @@ int iwl_mld_update_beacon_template(struct iwl_mld *mld,
 				   struct ieee80211_vif *vif,
 				   struct ieee80211_bss_conf *link_conf);
 
-void iwl_mld_stop_beacon(struct iwl_mld *mld,
-			 struct ieee80211_vif *vif,
-			 struct ieee80211_bss_conf *link_conf);
+void
+iwl_mld_link_info_changed_ap_ibss(struct iwl_mld *mld,
+				  struct ieee80211_vif *vif,
+				  struct ieee80211_bss_conf *link,
+				  u64 changes);
 
 int iwl_mld_start_ap_ibss(struct ieee80211_hw *hw,
 			  struct ieee80211_vif *vif,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 403bc38ac2bc..c02994e63b14 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1235,39 +1235,6 @@ int iwl_mld_mac80211_set_rts_threshold(struct ieee80211_hw *hw, int radio_idx,
 	return 0;
 }
 
-static void
-iwl_mld_link_info_changed_ap_ibss(struct iwl_mld *mld,
-				  struct ieee80211_vif *vif,
-				  struct ieee80211_bss_conf *link,
-				  u64 changes)
-{
-	u32 link_changes = 0;
-
-	if (changes & BSS_CHANGED_ERP_SLOT)
-		link_changes |= LINK_CONTEXT_MODIFY_RATES_INFO;
-
-	if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_HT))
-		link_changes |= LINK_CONTEXT_MODIFY_PROTECT_FLAGS;
-
-	if (changes & (BSS_CHANGED_QOS | BSS_CHANGED_BANDWIDTH))
-		link_changes |= LINK_CONTEXT_MODIFY_QOS_PARAMS;
-
-	if (changes & BSS_CHANGED_HE_BSS_COLOR)
-		link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
-
-	if (link_changes)
-		iwl_mld_change_link_in_fw(mld, link, link_changes);
-
-	if (changes & BSS_CHANGED_BEACON) {
-		WARN_ON(!link->enable_beacon);
-		iwl_mld_update_beacon_template(mld, vif, link);
-	}
-
-	/* Enabling beacons was already covered above */
-	if ((changes & BSS_CHANGED_BEACON_ENABLED) && !link->enable_beacon)
-		iwl_mld_stop_beacon(mld, vif, link);
-}
-
 static
 u32 iwl_mld_link_changed_mapping(struct iwl_mld *mld,
 				 struct ieee80211_vif *vif,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 06/15] wifi: iwlwifi: add XIAOMI to PPAG approved list
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>

Add XIAOMI to the list of the OEMs that are allowed to use
the PPAG feature

Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/regulatory.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 55128caac7ed..8d9ff36e30f5 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2023, 2025 Intel Corporation
+ * Copyright (C) 2023, 2025-2026 Intel Corporation
  */
 #include <linux/dmi.h>
 #include "iwl-drv.h"
@@ -112,6 +112,11 @@ static const struct dmi_system_id dmi_ppag_approved_list[] = {
 			DMI_MATCH(DMI_SYS_VENDOR, "WIKO"),
 		},
 	},
+	{ .ident = "XIAOMI",
+	  .matches = {
+			DMI_MATCH(DMI_SYS_VENDOR, "XIAOMI"),
+		},
+	},
 	{}
 };
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: clean up station handling in key APIs
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

The internal key APIs, when called with group keys where mac80211
doesn't pass the (AP) station pointer, are still sometimes called
with the AP station pointer on internal calls. This is confusing.
Clean it up and always call them with the AP STA when it exists,
even when coming in from mac80211, by looking it up immediately.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/key.c      | 12 ++----------
 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 11 +++++++++++
 2 files changed, 13 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c
index 04192c5f07ff..2cb312ebd7a7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024 Intel Corporation
+ * Copyright (C) 2024, 2026 Intel Corporation
  */
 #include "key.h"
 #include "iface.h"
@@ -12,7 +12,6 @@ static u32 iwl_mld_get_key_flags(struct iwl_mld *mld,
 				 struct ieee80211_sta *sta,
 				 struct ieee80211_key_conf *key)
 {
-	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
 	bool pairwise = key->flags & IEEE80211_KEY_FLAG_PAIRWISE;
 	bool igtk = key->keyidx == 4 || key->keyidx == 5;
 	u32 flags = 0;
@@ -38,9 +37,6 @@ static u32 iwl_mld_get_key_flags(struct iwl_mld *mld,
 		break;
 	}
 
-	if (!sta && vif->type == NL80211_IFTYPE_STATION)
-		sta = mld_vif->ap_sta;
-
 	/* If we are installing an iGTK (in AP or STA mode), we need to tell
 	 * the firmware this key will en/decrypt MGMT frames.
 	 * Same goes if we are installing a pairwise key for an MFP station.
@@ -92,11 +88,7 @@ static u32 iwl_mld_get_key_sta_mask(struct iwl_mld *mld,
 		return BIT(link->mcast_sta.sta_id);
 	}
 
-	/* for client mode use the AP STA also for group keys */
-	if (!sta && vif->type == NL80211_IFTYPE_STATION)
-		sta = mld_vif->ap_sta;
-
-	/* STA should be non-NULL now */
+	/* STA should be non-NULL */
 	if (WARN_ON(!sta))
 		return 0;
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index c02994e63b14..4b5f50ff2b05 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -2282,9 +2282,20 @@ static int iwl_mld_mac80211_set_key(struct ieee80211_hw *hw,
 				    struct ieee80211_sta *sta,
 				    struct ieee80211_key_conf *key)
 {
+	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
 	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
 	int ret;
 
+	/*
+	 * FW always needs the AP STA for client mode.
+	 * Note that during removal this could already
+	 * be NULL (mac80211 removes keys after STAs)
+	 * but then we'll already have removed the key
+	 * and set hw_key_idx = STA_KEY_IDX_INVALID.
+	 */
+	if (!sta && vif->type == NL80211_IFTYPE_STATION)
+		sta = mld_vif->ap_sta;
+
 	switch (cmd) {
 	case SET_KEY:
 		ret = iwl_mld_set_key_add(mld, vif, sta, key);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 09/15] wifi: iwlwifi: mld: allow NAN data
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

Allow NAN_DATA interfaces when FW supports it.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/mac80211.c | 13 +++++++++----
 drivers/net/wireless/intel/iwlwifi/mld/nan.c      | 12 ++++++++++--
 2 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 4b5f50ff2b05..8856f96a9760 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -62,13 +62,17 @@ static const struct ieee80211_iface_limit iwl_mld_limits_ap[] = {
 
 static const struct ieee80211_iface_limit iwl_mld_limits_nan[] = {
 	{
-		.max = 2,
+		.max = 1,
 		.types = BIT(NL80211_IFTYPE_STATION),
 	},
 	{
 		.max = 1,
 		.types = BIT(NL80211_IFTYPE_NAN),
 	},
+	{
+		.max = 2,
+		.types = BIT(NL80211_IFTYPE_NAN_DATA),
+	},
 };
 
 static const struct ieee80211_iface_combination
@@ -87,8 +91,8 @@ iwl_mld_iface_combinations[] = {
 	},
 	/* NAN combination follow, this excludes P2P and AP */
 	{
-		.num_different_channels = 2,
-		.max_interfaces = 3,
+		.num_different_channels = 3,
+		.max_interfaces = 4,
 		.limits = iwl_mld_limits_nan,
 		.n_limits = ARRAY_SIZE(iwl_mld_limits_nan),
 	},
@@ -266,6 +270,7 @@ static void iwl_mld_hw_set_nan(struct iwl_mld *mld)
 	struct ieee80211_hw *hw = mld->hw;
 
 	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN);
+	hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_NAN_DATA);
 
 	hw->wiphy->nan_supported_bands = BIT(NL80211_BAND_2GHZ);
 	if (mld->nvm_data->bands[NL80211_BAND_5GHZ].n_channels)
@@ -363,7 +368,7 @@ static void iwl_mac_hw_set_wiphy(struct iwl_mld *mld)
 			ARRAY_SIZE(iwl_mld_iface_combinations);
 		iwl_mld_hw_set_nan(mld);
 	} else {
-		/* Do not include NAN combinations */
+		/* Do not include NAN combination */
 		wiphy->n_iface_combinations =
 			ARRAY_SIZE(iwl_mld_iface_combinations) - 1;
 	}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
index 59e85818b613..cb7a3e01adb4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
@@ -18,8 +18,16 @@
 
 bool iwl_mld_nan_supported(struct iwl_mld *mld)
 {
-	return fw_has_capa(&mld->fw->ucode_capa,
-			   IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT);
+	const struct iwl_fw *fw = mld->fw;
+
+	if (fw_has_capa(&fw->ucode_capa, IWL_UCODE_TLV_CAPA_NAN_SYNC_SUPPORT) &&
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, NAN_SCHEDULE_CMD), 0) >= 1 &&
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, NAN_PEER_CMD), 0) >= 1 &&
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD), 0) >= 3 &&
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(MAC_CONF_GROUP, MAC_CONFIG_CMD), 0) >= 4 &&
+	    iwl_fw_lookup_cmd_ver(fw, WIDE_ID(DATA_PATH_GROUP, TLC_MNG_CONFIG_CMD), 0) >= 6)
+		return true;
+	return false;
 }
 
 static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: add TLC support for NAN stations
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

In order to support NAN, TLC now has a station bitmap. Use this
and update TLC for the NAN stations accordingly whenever links
(and thus PHYs) change, and whenever else mac80211 might update
the rate scale information.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Co-developed-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/nan.c |  29 ++-
 drivers/net/wireless/intel/iwlwifi/mld/tlc.c | 189 +++++++++++++++----
 2 files changed, 182 insertions(+), 36 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
index ceea66c01205..59e85818b613 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
@@ -7,6 +7,7 @@
 #include "iface.h"
 #include "link.h"
 #include "mlo.h"
+#include "tlc.h"
 #include "fw/api/mac-cfg.h"
 #include "fw/api/mac.h"
 #include "fw/api/rs.h"
@@ -437,15 +438,26 @@ iwl_mld_nan_link_add(struct iwl_mld *mld,
 }
 
 static int iwl_mld_nan_link_set_active(struct iwl_mld *mld,
+				       struct ieee80211_vif *vif,
 				       struct iwl_mld_nan_link *nan_link,
 				       bool active)
 {
 	struct iwl_link_config_cmd cmd;
+	struct ieee80211_sta *sta;
 	int ret;
 
 	if (nan_link->active == active)
 		return 0;
 
+	if (active) {
+		for_each_station(sta, mld->hw) {
+			struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+
+			if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI)
+				iwl_mld_config_tlc(mld, mld_sta->vif, sta);
+		}
+	}
+
 	nan_link->active = active;
 
 	iwl_mld_nan_link_prep_cmd(mld, nan_link, &cmd,
@@ -457,8 +469,10 @@ static int iwl_mld_nan_link_set_active(struct iwl_mld *mld,
 		return ret;
 	}
 
-	if (!active)
+	if (!active) {
 		nan_link->chanctx = NULL;
+		/* TODO: when FW is ready, Update phy in TLC to invalid after */
+	}
 
 	return 0;
 }
@@ -590,7 +604,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
 		if (links[i]) {
 			added_links = true;
 			link_used[links[i]->fw_id] = true;
-			iwl_mld_nan_link_set_active(mld, links[i], true);
+			iwl_mld_nan_link_set_active(mld, vif, links[i], true);
 		}
 	}
 
@@ -630,7 +644,7 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
 	/* prepare stations for links we'll remove */
 	for_each_mld_nan_valid_link(mld_vif, nan_link) {
 		if (!link_used[nan_link->fw_id]) {
-			iwl_mld_nan_link_set_active(mld, nan_link, false);
+			iwl_mld_nan_link_set_active(mld, vif, nan_link, false);
 			remove_link_ids |= BIT(nan_link->fw_id);
 			/* mark unused for STA updates */
 			nan_link->fw_id = FW_CTXT_ID_INVALID;
@@ -694,6 +708,15 @@ int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
 		.len[1] = sched->ulw_size,
 		.dataflags[1] = IWL_HCMD_DFL_DUP,
 	};
+	struct ieee80211_sta *iter;
+
+	/* Update TLC in case peer channels were added/removed/updated */
+	for_each_station(iter, mld->hw) {
+		struct iwl_mld_sta *tmp = iwl_mld_sta_from_mac80211(iter);
+
+		if (tmp->sta_type == STATION_TYPE_NAN_PEER_NDI)
+			iwl_mld_config_tlc(mld, tmp->vif, iter);
+	}
 
 	for (int i = 0; i < ARRAY_SIZE(sched->maps); i++) {
 		if (sched->maps[i].map_id == CFG80211_NAN_INVALID_MAP_ID)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c
index b1722982db9c..7db56eefc7df 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tlc.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tlc.c
@@ -529,7 +529,7 @@ static int iwl_mld_convert_tlc_cmd_to_v4(struct iwl_tlc_config_cmd *cmd,
 static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
 				 struct ieee80211_vif *vif,
 				 struct iwl_mld_sta *mld_sta,
-				 int fw_sta_id, int phy_id,
+				 int fw_sta_mask, int phy_id,
 				 struct iwl_mld_tlc_sta_capa *capa)
 {
 	struct iwl_tlc_config_cmd cmd = {
@@ -550,10 +550,7 @@ static void iwl_mld_send_tlc_cmd(struct iwl_mld *mld,
 	u8 cmd_size;
 	int ret;
 
-	if (fw_sta_id < 0)
-		return;
-
-	cmd.sta_mask = cpu_to_le32(BIT(fw_sta_id));
+	cmd.sta_mask = cpu_to_le32(fw_sta_mask);
 	cmd.phy_id = cpu_to_le32(phy_id);
 
 	iwl_mld_fill_supp_rates(mld, vif, capa, &cmd);
@@ -617,25 +614,27 @@ int iwl_mld_send_tlc_dhc(struct iwl_mld *mld, u8 sta_id, u32 type, u32 data)
 	return ret;
 }
 
-void iwl_mld_config_tlc_link(struct iwl_mld *mld,
-			     struct ieee80211_vif *vif,
-			     struct ieee80211_bss_conf *link_conf,
-			     struct ieee80211_link_sta *link_sta)
+static void _iwl_mld_config_tlc_link(struct iwl_mld *mld,
+				     struct ieee80211_vif *vif,
+				     struct ieee80211_chanctx_conf *chan_ctx,
+				     u32 fw_sta_mask,
+				     struct ieee80211_link_sta *link_sta,
+				     struct iwl_mld_tlc_sta_capa *capa)
 {
 	struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(link_sta->sta);
-	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
-	struct ieee80211_chanctx_conf *chan_ctx;
 	struct ieee80211_supported_band *sband;
-	struct iwl_mld_tlc_sta_capa capa = {};
 	unsigned long rates_bitmap;
 	enum nl80211_band band;
-	int fw_sta_id, i;
+	int i;
 
-	if (WARN_ON_ONCE(!mld_link))
-		return;
+	/*
+	 * Note: Due to NAN, the chan_ctx here might not be the same as the
+	 * vif->links[link_sta->link_id] one (which is NULL in NAN), so some
+	 * care is needed in this function (and the 'capa' exists to make it
+	 * less error-prone, the other functions need not worry about it.)
+	 */
 
-	chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx);
-	if (WARN_ON_ONCE(!chan_ctx))
+	if (WARN_ON(!chan_ctx))
 		return;
 
 	band = chan_ctx->def.chan->band;
@@ -653,25 +652,18 @@ void iwl_mld_config_tlc_link(struct iwl_mld *mld,
 	/* non HT rates */
 	rates_bitmap = link_sta->supp_rates[sband->band];
 	for_each_set_bit(i, &rates_bitmap, BITS_PER_LONG)
-		capa.non_ht_rates |= BIT(sband->bitrates[i].hw_value);
+		capa->non_ht_rates |= BIT(sband->bitrates[i].hw_value);
 
-	capa.rx_nss = link_sta->rx_nss;
-	capa.smps_mode = link_sta->smps_mode;
-	capa.bandwidth = link_sta->bandwidth;
-	capa.max_amsdu_len = link_sta->agg.max_amsdu_len;
-	capa.ht_cap = &link_sta->ht_cap;
-	capa.vht_cap = &link_sta->vht_cap;
-	capa.he_cap = &link_sta->he_cap;
-	capa.eht_cap = &link_sta->eht_cap;
-	capa.uhr_cap = &link_sta->uhr_cap;
-	capa.own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
-	capa.own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif);
-	capa.own_uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, vif);
+	capa->max_amsdu_len = link_sta->agg.max_amsdu_len;
+	capa->ht_cap = &link_sta->ht_cap;
+	capa->vht_cap = &link_sta->vht_cap;
+	capa->he_cap = &link_sta->he_cap;
+	capa->eht_cap = &link_sta->eht_cap;
+	capa->uhr_cap = &link_sta->uhr_cap;
 
-	fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
-	iwl_mld_send_tlc_cmd(mld, vif, mld_sta, fw_sta_id,
+	iwl_mld_send_tlc_cmd(mld, vif, mld_sta, fw_sta_mask,
 			     iwl_mld_phy_from_mac80211(chan_ctx)->fw_id,
-			     &capa);
+			     capa);
 }
 
 void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif,
@@ -717,6 +709,136 @@ void iwl_mld_tlc_update_phy(struct iwl_mld *mld, struct ieee80211_vif *vif,
 	}
 }
 
+static void iwl_mld_config_tlc_nan(struct iwl_mld *mld,
+				   struct ieee80211_vif *vif,
+				   struct ieee80211_link_sta *link_sta,
+				   int fw_sta_id)
+{
+	struct ieee80211_nan_peer_sched *sched;
+	struct iwl_mld_nan_link *nan_link;
+	struct ieee80211_sta *nmi, *iter;
+	struct iwl_mld_vif *nan_mld_vif;
+	u32 fw_sta_mask;
+
+	nmi = wiphy_dereference(mld->wiphy, link_sta->sta->nmi);
+	if (WARN_ON(!nmi))
+		return;
+
+	sched = nmi->nan_sched;
+
+	/* This sta might not be in the list yet as it is just getting added */
+	fw_sta_mask = BIT(fw_sta_id);
+	for_each_station(iter, mld->hw) {
+		struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(iter);
+		struct ieee80211_sta *iter_nmi;
+
+		iter_nmi = wiphy_dereference(mld->wiphy, iter->nmi);
+
+		if (iter_nmi == nmi)
+			fw_sta_mask |= BIT(mld_sta->deflink.fw_id);
+	}
+
+	if (WARN_ON(!mld->nan_device_vif))
+		return;
+
+	nan_mld_vif = iwl_mld_vif_from_mac80211(mld->nan_device_vif);
+
+	for_each_mld_nan_valid_link(nan_mld_vif, nan_link) {
+		struct ieee80211_chanctx_conf *chan_ctx;
+		struct iwl_mld_tlc_sta_capa capa = {};
+		struct cfg80211_chan_def *chandef;
+		bool common_channel = false;
+
+		chan_ctx = nan_link->chanctx;
+		if (!chan_ctx)
+			continue;
+
+		chandef = iwl_mld_get_chandef_from_chanctx(mld, chan_ctx);
+
+		capa.smps_mode = IEEE80211_SMPS_OFF; /* always off */
+
+		capa.rx_nss = 2; /* maximum we support */
+		capa.bandwidth = ieee80211_chan_width_to_rx_bw(chandef->width);
+
+		for (int j = 0; j < (sched ? sched->n_channels : 0); j++) {
+			enum ieee80211_sta_rx_bandwidth rx_bw;
+			enum nl80211_chan_width width;
+			int chains;
+
+			if (sched->channels[j].chanctx_conf != chan_ctx)
+				continue;
+
+			common_channel = true;
+
+			width = sched->channels[j].chanreq.oper.width;
+			rx_bw = ieee80211_chan_width_to_rx_bw(width);
+			capa.bandwidth = min(capa.bandwidth, rx_bw);
+
+			chains = sched->channels[j].needed_rx_chains;
+			capa.rx_nss = min(capa.rx_nss, chains);
+		}
+
+		/* Apply minimum parameters if there is no common channel */
+		if (!common_channel) {
+			capa.bandwidth = IEEE80211_STA_RX_BW_20;
+			capa.rx_nss = 1;
+		}
+
+		capa.own_he_cap = &mld->wiphy->nan_capa.phy.he;
+		/* no EHT/UHR for NAN */
+
+		_iwl_mld_config_tlc_link(mld, vif, chan_ctx, fw_sta_mask,
+					 link_sta, &capa);
+	}
+}
+
+void iwl_mld_config_tlc_link(struct iwl_mld *mld,
+			     struct ieee80211_vif *vif,
+			     struct ieee80211_bss_conf *link_conf,
+			     struct ieee80211_link_sta *link_sta)
+{
+	struct iwl_mld_link *mld_link = iwl_mld_link_from_mac80211(link_conf);
+	int fw_sta_id = iwl_mld_fw_sta_id_from_link_sta(mld, link_sta);
+	struct ieee80211_chanctx_conf *chan_ctx;
+	struct ieee80211_supported_band *sband;
+	struct iwl_mld_tlc_sta_capa capa = {};
+	struct cfg80211_chan_def *chandef;
+	enum nl80211_band band;
+
+	if (fw_sta_id < 0)
+		return;
+
+	if (vif->type == NL80211_IFTYPE_NAN)
+		return;
+
+	if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+		iwl_mld_config_tlc_nan(mld, vif, link_sta, fw_sta_id);
+		return;
+	}
+
+	if (WARN_ON_ONCE(!mld_link))
+		return;
+
+	chan_ctx = rcu_dereference_wiphy(mld->wiphy, mld_link->chan_ctx);
+	if (WARN_ON_ONCE(!chan_ctx))
+		return;
+
+	chandef = &iwl_mld_phy_from_mac80211(chan_ctx)->chandef;
+	band = chandef->chan->band;
+	sband = mld->hw->wiphy->bands[band];
+
+	capa.smps_mode = link_sta->smps_mode;
+	capa.rx_nss = link_sta->rx_nss;
+	capa.bandwidth = ieee80211_chan_width_to_rx_bw(chandef->width);
+	capa.bandwidth = min(capa.bandwidth, link_sta->bandwidth);
+	capa.own_he_cap = ieee80211_get_he_iftype_cap_vif(sband, vif);
+	capa.own_eht_cap = ieee80211_get_eht_iftype_cap_vif(sband, vif);
+	capa.own_uhr_cap = ieee80211_get_uhr_iftype_cap_vif(sband, vif);
+
+	_iwl_mld_config_tlc_link(mld, vif, chan_ctx, BIT(fw_sta_id),
+				 link_sta, &capa);
+}
+
 void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
 			struct ieee80211_sta *sta)
 {
@@ -725,6 +847,7 @@ void iwl_mld_config_tlc(struct iwl_mld *mld, struct ieee80211_vif *vif,
 
 	lockdep_assert_wiphy(mld->wiphy);
 
+	/* Note: for NAN this is only the mac80211-level deflink */
 	for_each_vif_active_link(vif, link, link_id) {
 		struct ieee80211_link_sta *link_sta =
 			link_sta_dereference_check(sta, link_id);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 10/15] wifi: iwlwifi: mld: track TX/RX IGTKs separately
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Due to FW/HW limitations and the MME being at the end of the
frame, the devices only support a single IGTK for RX. For TX
multiple aren't needed, only the latest will be used, but in
the device there are space restrictions, so we can also only
install one.

For NAN, however, we will have one for RX for each peer, and
one for ourselves to transmit with.

Separate out the tracking of IGTK: instead of being per link
make the TX ones per link and the RX ones per (link) station.

Note that we currently hardcode that the FW can only have two
(IWL_MAX_NUM_IGTKS) IGTKs, which won't be sufficient for NAN
with security, concurrently with BSS.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/d3.c   | 20 ++--
 .../net/wireless/intel/iwlwifi/mld/iface.h    | 15 +++
 drivers/net/wireless/intel/iwlwifi/mld/key.c  | 98 ++++++++++++-------
 drivers/net/wireless/intel/iwlwifi/mld/link.h |  9 +-
 drivers/net/wireless/intel/iwlwifi/mld/sta.h  |  4 +
 5 files changed, 97 insertions(+), 49 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/d3.c b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
index ef98efc8fb1b..c44f02f225ce 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/d3.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/d3.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #include "mld.h"
 
@@ -951,19 +951,25 @@ iwl_mld_add_mcast_rekey(struct ieee80211_vif *vif,
 
 	iwl_mld_update_mcast_rx_seq(key_config, key_data);
 
-	/* The FW holds only one igtk so we keep track of the valid one */
+	/* The FW holds only one IGTK so we keep track of the valid one */
 	if (key_config->keyidx == 4 || key_config->keyidx == 5) {
-		struct iwl_mld_link *mld_link =
-			iwl_mld_link_from_mac80211(link_conf);
+		struct iwl_mld_link_sta *mld_ap_link_sta;
+
+		mld_ap_link_sta = iwl_mld_get_ap_link_sta(vif,
+							  link_conf->link_id);
+		if (WARN_ON(!mld_ap_link_sta))
+			return;
 
 		/* If we had more than one rekey, mac80211 will tell us to
 		 * remove the old and add the new so we will update the IGTK in
 		 * drv_set_key
 		 */
-		if (mld_link->igtk && mld_link->igtk != key_config) {
+		if (mld_ap_link_sta->rx_igtk &&
+		    mld_ap_link_sta->rx_igtk != key_config) {
 			/* mark the old IGTK as not in FW */
-			mld_link->igtk->hw_key_idx = STA_KEY_IDX_INVALID;
-			mld_link->igtk = key_config;
+			mld_ap_link_sta->rx_igtk->hw_key_idx =
+				STA_KEY_IDX_INVALID;
+			mld_ap_link_sta->rx_igtk = key_config;
 		}
 	}
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
index ce4f8ca885cf..147ff6787ed9 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
@@ -289,4 +289,19 @@ static inline bool iwl_mld_vif_low_latency(const struct iwl_mld_vif *mld_vif)
 
 struct ieee80211_vif *iwl_mld_get_bss_vif(struct iwl_mld *mld);
 
+static inline struct iwl_mld_link_sta *
+iwl_mld_get_ap_link_sta(struct ieee80211_vif *vif, int link_id)
+{
+	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+	struct ieee80211_sta *ap_sta = mld_vif->ap_sta;
+	struct iwl_mld_sta *mld_ap_sta;
+
+	if (!ap_sta)
+		return NULL;
+
+	mld_ap_sta = iwl_mld_sta_from_mac80211(ap_sta);
+
+	return iwl_mld_link_sta_dereference_check(mld_ap_sta, link_id);
+}
+
 #endif /* __iwl_mld_iface_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c
index 2cb312ebd7a7..944d5487c110 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c
@@ -170,34 +170,69 @@ static void iwl_mld_remove_key_from_fw(struct iwl_mld *mld, u32 sta_mask,
 	iwl_mld_send_cmd_pdu(mld, WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD), &cmd);
 }
 
+static struct ieee80211_key_conf **
+iwl_mld_get_igtk_ptr(struct ieee80211_vif *vif,
+		     struct ieee80211_sta *sta,
+		     struct ieee80211_key_conf *key)
+{
+	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+	/* key's link ID is set to -1 for non-MLO */
+	int link_id = key->link_id < 0 ? 0 : key->link_id;
+	struct iwl_mld_link_sta *mld_ap_link_sta;
+	struct iwl_mld_link *mld_link;
+	struct iwl_mld_sta *mld_sta;
+
+	if (key->keyidx != 4 && key->keyidx != 5)
+		return NULL;
+
+	switch (vif->type) {
+	case NL80211_IFTYPE_STATION:
+		if (WARN_ON(!sta))
+			return NULL;
+
+		mld_sta = iwl_mld_sta_from_mac80211(sta);
+		mld_ap_link_sta = iwl_mld_link_sta_dereference_check(mld_sta,
+								     link_id);
+		if (WARN_ON(!mld_ap_link_sta))
+			return NULL;
+
+		return &mld_ap_link_sta->rx_igtk;
+	case NL80211_IFTYPE_NAN:
+		if (sta) {
+			mld_sta = iwl_mld_sta_from_mac80211(sta);
+
+			return &mld_sta->deflink.rx_igtk;
+		}
+
+		return &mld_vif->deflink.tx_igtk;
+	case NL80211_IFTYPE_AP:
+		mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
+		if (WARN_ON(!mld_link))
+			return NULL;
+
+		return &mld_link->tx_igtk;
+	default:
+		WARN_ONCE(1, "invalid iftype %d for IGTK\n", vif->type);
+		return NULL;
+	}
+}
+
 void iwl_mld_remove_key(struct iwl_mld *mld, struct ieee80211_vif *vif,
 			struct ieee80211_sta *sta,
 			struct ieee80211_key_conf *key)
 {
 	u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
 	u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
-	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+	struct ieee80211_key_conf **igtk_ptr;
 
 	lockdep_assert_wiphy(mld->wiphy);
 
 	if (!sta_mask)
 		return;
 
-	if (key->keyidx == 4 || key->keyidx == 5) {
-		struct iwl_mld_link *mld_link;
-		unsigned int link_id = 0;
-
-		/* set to -1 for non-MLO right now */
-		if (key->link_id >= 0)
-			link_id = key->link_id;
-
-		mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
-		if (WARN_ON(!mld_link))
-			return;
-
-		if (mld_link->igtk == key)
-			mld_link->igtk = NULL;
-
+	igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key);
+	if (igtk_ptr && *igtk_ptr == key) {
+		*igtk_ptr = NULL;
 		mld->num_igtks--;
 	}
 
@@ -214,9 +249,7 @@ int iwl_mld_add_key(struct iwl_mld *mld,
 {
 	u32 sta_mask = iwl_mld_get_key_sta_mask(mld, vif, sta, key);
 	u32 key_flags = iwl_mld_get_key_flags(mld, vif, sta, key);
-	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
-	struct iwl_mld_link *mld_link = NULL;
-	bool igtk = key->keyidx == 4 || key->keyidx == 5;
+	struct ieee80211_key_conf **igtk_ptr;
 	int ret;
 
 	lockdep_assert_wiphy(mld->wiphy);
@@ -224,36 +257,25 @@ int iwl_mld_add_key(struct iwl_mld *mld,
 	if (!sta_mask)
 		return -EINVAL;
 
-	if (igtk) {
+	igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key);
+	if (igtk_ptr) {
 		if (mld->num_igtks == IWL_MAX_NUM_IGTKS)
 			return -EOPNOTSUPP;
 
-		u8 link_id = 0;
-
-		/* set to -1 for non-MLO right now */
-		if (key->link_id >= 0)
-			link_id = key->link_id;
-
-		mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
-
-		if (WARN_ON(!mld_link))
-			return -EINVAL;
-
-		if (mld_link->igtk) {
+		if (*igtk_ptr) {
 			IWL_DEBUG_MAC80211(mld, "remove old IGTK %d\n",
-					   mld_link->igtk->keyidx);
-			iwl_mld_remove_key(mld, vif, sta, mld_link->igtk);
+					   (*igtk_ptr)->keyidx);
+			iwl_mld_remove_key(mld, vif, sta, *igtk_ptr);
 		}
-
-		WARN_ON(mld_link->igtk);
 	}
 
 	ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key);
 	if (ret)
 		return ret;
 
-	if (mld_link) {
-		mld_link->igtk = key;
+	if (igtk_ptr) {
+		WARN_ON(*igtk_ptr);
+		*igtk_ptr = key;
 		mld->num_igtks++;
 	}
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.h b/drivers/net/wireless/intel/iwlwifi/mld/link.h
index 84d9a24134a8..2b3e6b55367f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #ifndef __iwl_mld_link_h__
 #define __iwl_mld_link_h__
@@ -34,8 +34,9 @@ struct iwl_probe_resp_data {
  * @chan_ctx: pointer to the channel context assigned to the link. If a link
  *	has an assigned channel context it means that it is active.
  * @he_ru_2mhz_block: 26-tone RU OFDMA transmissions should be blocked.
- * @igtk: fw can only have one IGTK at a time, whereas mac80211 can have two.
- *	This tracks the one IGTK that currently exists in FW.
+ * @tx_igtk: FW can only have one IGTK per MAC at a time, whereas mac80211 can
+ *	have two. This tracks the one IGTK that currently exists in FW, for TX
+ *	purposes. The RX IGTKs are tracked per station.
  * @bigtks: BIGTKs of the AP. Only valid for STA mode.
  * @bcast_sta: station used for broadcast packets. Used in AP, GO and IBSS.
  * @mcast_sta: station used for multicast packets. Used in AP, GO and IBSS.
@@ -60,7 +61,7 @@ struct iwl_mld_link {
 		struct ieee80211_tx_queue_params queue_params[IEEE80211_NUM_ACS];
 		struct ieee80211_chanctx_conf __rcu *chan_ctx;
 		bool he_ru_2mhz_block;
-		struct ieee80211_key_conf *igtk;
+		struct ieee80211_key_conf *tx_igtk;
 		struct ieee80211_key_conf __rcu *bigtks[2];
 	);
 	/* And here fields that survive a fw restart */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.h b/drivers/net/wireless/intel/iwlwifi/mld/sta.h
index 13644ffd185d..dff14ff0a5af 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.h
@@ -28,6 +28,9 @@ struct iwl_mld_rxq_dup_data {
  * This represents the link-level sta - the driver level equivalent to the
  * ieee80211_link_sta
  *
+ * @rx_igtk: FW can only have one IGTK for RX at a time, whereas mac80211 will
+ *	have two. This tracks the one IGTK that currently exists in FW, to
+ *	remove it there when a new one is installed.
  * @last_rate_n_flags: rate_n_flags from the last &iwl_tlc_update_notif
  * @signal_avg: the signal average coming from the firmware
  * @in_fw: whether the link STA is uploaded to the FW (false during restart)
@@ -37,6 +40,7 @@ struct iwl_mld_rxq_dup_data {
 struct iwl_mld_link_sta {
 	/* Add here fields that need clean up on restart */
 	struct_group(zeroed_on_hw_restart,
+		struct ieee80211_key_conf *rx_igtk;
 		u32 last_rate_n_flags;
 		bool in_fw;
 		s8 signal_avg;
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: don't report bad STA ID in EHT TB sniffer
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

The field being reported here is part of the EHT union, and not
valid in EHT TB. Don't report it there. We could probably report
the station ID we're following, but for now just don't, since it
appears nobody really cared.

Fixes: 92e87cee465c ("wifi: iwlwifi: mld: update to new sniffer API")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/rx.c | 15 +++++++--------
 1 file changed, 7 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/rx.c b/drivers/net/wireless/intel/iwlwifi/mld/rx.c
index b270cf87824d..a9f08f984633 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/rx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/rx.c
@@ -1206,6 +1206,13 @@ static void iwl_mld_decode_eht_non_tb(struct iwl_mld_rx_phy_data *phy_data,
 	iwl_mld_eht_set_ru_alloc(rx_status,
 				 le32_get_bits(phy_data->ntfy->sigs.eht.b2,
 					       OFDM_RX_FRAME_EHT_STA_RU));
+
+	if (phy_data->with_data)
+		eht->user_info[0] |=
+			cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) |
+			LE32_DEC_ENC(phy_data->ntfy->sigs.eht.user_id,
+				     OFDM_RX_FRAME_EHT_USER_FIELD_ID,
+				     IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID);
 }
 
 static void iwl_mld_decode_eht_phy_data(struct iwl_mld_rx_phy_data *phy_data,
@@ -1314,14 +1321,6 @@ static void iwl_mld_rx_eht(struct iwl_mld *mld, struct sk_buff *skb,
 	if (likely(!phy_data->ntfy))
 		return;
 
-	if (phy_data->with_data) {
-		eht->user_info[0] |=
-			cpu_to_le32(IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID_KNOWN) |
-			LE32_DEC_ENC(phy_data->ntfy->sigs.eht.user_id,
-				     OFDM_RX_FRAME_EHT_USER_FIELD_ID,
-				     IEEE80211_RADIOTAP_EHT_USER_INFO_STA_ID);
-	}
-
 	iwl_mld_decode_eht_usig(phy_data, skb);
 	iwl_mld_decode_eht_phy_data(phy_data, rx_status, eht);
 }
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 12/15] wifi: iwlwifi: api: RX: define UHR RX PHY flags
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Define a couple of UHR PHY flags in the metadata that carry
information about 2x LDPC, UEQM and NPCA.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
index ac6c1ef2cbcd..8ef764787ba4 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
@@ -263,6 +263,9 @@ enum iwl_rx_mpdu_reorder_data {
 
 enum iwl_rx_mpdu_phy_info {
 	IWL_RX_MPDU_PHY_EOF_INDICATION	= BIT(0),
+	IWL_RX_MPDU_PHY_UEQM		= BIT(1) | BIT(2),
+	IWL_RX_MPDU_PHY_2X_LDPC		= BIT(3),
+	IWL_RX_MPDU_PHY_NPCA		= BIT(4),
 	IWL_RX_MPDU_PHY_AMPDU		= BIT(5),
 	IWL_RX_MPDU_PHY_AMPDU_TOGGLE	= BIT(6),
 	IWL_RX_MPDU_PHY_SHORT_PREAMBLE	= BIT(7),
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 13/15] wifi: iwlwifi: fw: api: fix UHR U-SIG whitespace
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Somehow I put tabs there where it should be spaces, fix that.

Fixes: 3b6e7afaf7c3 ("wifi: iwlwifi: fw: api: add UHR data definitions")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
index 8ef764787ba4..e46e2fe46eaa 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
@@ -1278,15 +1278,15 @@ struct iwl_uhr_sigs {
 	__le32 usig_a1;
 #define OFDM_RX_FRAME_UHR_BSS_COLOR2			0x0000003f
 	__le32 usig_a1_uhr;
-#define	OFDM_RX_FRAME_UHR_PPDU_TYPE			0x00000003
-#define	OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE		0x00000004
-#define	OFDM_RX_FRAME_UHR_PUNC_CHANNEL			0x000000f8
-#define	OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8		0x00000100
-#define	OFDM_RX_FRAME_UHR_SIG_MCS			0x00000600
-#define	OFDM_RX_FRAME_UHR_SIG_SYM_NUM			0x0000f800
-#define	OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1		0x000f0000
-#define	OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2		0x00f00000
-#define	OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD		0x1f000000
+#define OFDM_RX_FRAME_UHR_PPDU_TYPE			0x00000003
+#define OFDM_RX_FRAME_UHR_COBF_CSR_DISABLE		0x00000004
+#define OFDM_RX_FRAME_UHR_PUNC_CHANNEL			0x000000f8
+#define OFDM_RX_FRAME_UHR_USIG2_VALIDATE_B8		0x00000100
+#define OFDM_RX_FRAME_UHR_SIG_MCS			0x00000600
+#define OFDM_RX_FRAME_UHR_SIG_SYM_NUM			0x0000f800
+#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1		0x000f0000
+#define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2		0x00f00000
+#define OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD		0x1f000000
 	__le32 usig_a2_uhr;
 #define OFDM_RX_FRAME_UHR_SPATIAL_REUSE			0x0000000f
 #define OFDM_RX_FRAME_UHR_GI_LTF_TYPE			0x00000030
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 14/15] wifi: iwlwifi: fw: api: add/fix some UHR sniffer definitions
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Johannes Berg <johannes.berg@intel.com>

Add some remaining definitions for the UHR sniffer API, and fix
the ELR where instead of usig_a2_uhr we'll get usig_a2_uhr_elr.

Fixes: 3b6e7afaf7c3 ("wifi: iwlwifi: fw: api: add UHR data definitions")
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/api/rx.h | 17 +++++++++++++++--
 1 file changed, 15 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
index e46e2fe46eaa..aa4e5e9d4d4e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/rx.h
@@ -1172,8 +1172,14 @@ struct iwl_he_tb_sigs {
 #define OFDM_UCODE_TRIG_BASE_RX_BANDWIDTH		0x00007000
 #define OFDM_UCODE_TRIG_BASE_PS160			0x00008000
 #define OFDM_UCODE_EHT_TRIG_CONTROL_CHANNEL		0x000f0000
+/* for UHR, since PE RF: */
+#define OFDM_UCODE_TRIG_BASE_RX_MCS_UHR_AND_LATER	0x01f00000
+#define OFDM_UCODE_RX_IS_DRU				0x02000000
+#define OFDM_UCODE_RX_IS_2XLDPC_ENABLED			0x04000000
+#define OFDM_UCODE_RX_DRU_DBW				0x60000000
 	__le32 tb_rx0;
-#define OFDM_UCODE_TRIG_BASE_RX_MCS			0x0000000f
+/* prior to PE RF, cannot have 5 bits needed for UHR: */
+#define OFDM_UCODE_TRIG_BASE_RX_MCS_PRE_UHR		0x0000000f
 #define OFDM_UCODE_TRIG_BASE_RX_DCM			0x00000010
 #define OFDM_UCODE_TRIG_BASE_RX_GI_LTF_TYPE		0x00000060
 #define OFDM_UCODE_TRIG_BASE_RX_NSTS			0x00000380
@@ -1287,6 +1293,7 @@ struct iwl_uhr_sigs {
 #define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_1		0x000f0000
 #define OFDM_RX_FRAME_UHR_TRIG_SPATIAL_REUSE_2		0x00f00000
 #define OFDM_RX_FRAME_UHR_TRIG_USIG2_DISREGARD		0x1f000000
+#define OFDM_RX_FRAME_UHR_USIG_CRC_OK			0x40000000
 	__le32 usig_a2_uhr;
 #define OFDM_RX_FRAME_UHR_SPATIAL_REUSE			0x0000000f
 #define OFDM_RX_FRAME_UHR_GI_LTF_TYPE			0x00000030
@@ -1308,6 +1315,7 @@ struct iwl_uhr_sigs {
 #define OFDM_RX_FRAME_UHR_CODING			0x00000200
 #define OFDM_RX_FRAME_UHR_SPATIAL_CONFIG		0x00003c00
 #define OFDM_RX_FRAME_UHR_STA_RU			0x003fc000
+#define OFDM_RX_FRAME_UHR_STA_RU_P80			0x00004000
 #define OFDM_RX_FRAME_UHR_STA_RU_PS160			0x00400000
 #define OFDM_RX_FRAME_UHR_UEQM				0x00800000
 #define OFDM_RX_FRAME_UHR_2XLDPC			0x01000000
@@ -1333,7 +1341,12 @@ struct iwl_uhr_tb_sigs {
 
 struct iwl_uhr_elr_sigs {
 	/* same as UHR above */
-	__le32 usig_a1, usig_a2_uhr;
+	__le32 usig_a1;
+#define OFDM_RX_VECTOR_UHR_ELR_PPDU_TYPE		0x00000003
+#define OFDM_RX_VECTOR_UHR_ELR_USIG_STA_ID		0x00001ffc
+#define OFDM_RX_VECTOR_UHR_ELR_VALIDATE			0x0000e000
+#define OFDM_RX_VECTOR_UHR_ELR_CRC_OK			0x00010000
+	__le32 usig_a2_uhr_elr;
 #define OFDM_RX_VECTOR_UHR_ELR_VER_ID			0x00000007
 #define OFDM_RX_VECTOR_UHR_ELR_UPLINK_FLAG		0x00000008
 #define OFDM_RX_VECTOR_UHR_ELR_MCS			0x00000010
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 15/15] wifi: iwlwifi: fix buffer overflow when firmware reports no channels
From: Miri Korenblit @ 2026-05-11 17:36 UTC (permalink / raw)
  To: linux-wireless; +Cc: Avinash Bhatt
In-Reply-To: <20260511173631.1067831-1-miriam.rachel.korenblit@intel.com>

From: Avinash Bhatt <avinash.bhatt@intel.com>

On parsing NVM in setting country code, if firmware reports 0 channels,
buffer is allocated for 0 rules but a dummy rule is added for cfg80211
compatibility, causing kmemdup() to read 128 bytes from a 32-byte buffer.

Allocate regd buffer for one rule addition when reported
channels are 0.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../wireless/intel/iwlwifi/iwl-nvm-parse.c    | 21 ++++++++++---------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 0736c8c00d4e..455d6e8c7028 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -1724,8 +1724,16 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
 	IWL_DEBUG_DEV(dev, IWL_DL_LAR, "building regdom for %d channels\n",
 		      num_of_ch);
 
-	/* build a regdomain rule for every valid channel */
-	regd = kzalloc_flex(*regd, reg_rules, num_of_ch);
+	/* build a regdomain rule for every valid channel.
+	 * Certain firmware versions might report no valid channels
+	 * if booted in RF-kill, i.e. not all calibrations etc. are
+	 * running. We'll get out of this situation later when the
+	 * rfkill is removed and we update the regdomain again, but
+	 * since cfg80211 doesn't accept an empty regdomain, we need
+	 * to allocate space for at least one rule to add a dummy
+	 * (unusable) rule in this case so we can init.
+	 */
+	regd = kzalloc_flex(*regd, reg_rules, num_of_ch ?: 1);
 	if (!regd)
 		return ERR_PTR(-ENOMEM);
 
@@ -1799,14 +1807,7 @@ iwl_parse_nvm_mcc_info(struct iwl_trans *trans,
 		reg_query_regdb_wmm(regd->alpha2, center_freq, rule);
 	}
 
-	/*
-	 * Certain firmware versions might report no valid channels
-	 * if booted in RF-kill, i.e. not all calibrations etc. are
-	 * running. We'll get out of this situation later when the
-	 * rfkill is removed and we update the regdomain again, but
-	 * since cfg80211 doesn't accept an empty regdomain, add a
-	 * dummy (unusable) rule here in this case so we can init.
-	 */
+	/* If no valid rules were found, add a dummy rule */
 	if (!valid_rules) {
 		valid_rules = 1;
 		rule = &regd->reg_rules[valid_rules - 1];
-- 
2.34.1


^ permalink raw reply related

* Re: [bug report] wifi: mt76: mt7925: iw set txpower fixed accepted but ignored
From: John Henry @ 2026-05-11 17:58 UTC (permalink / raw)
  To: Sean Wang
  Cc: Javier Tia, Bradley Pizzimenti, linux-wireless, linux-kernel, nbd,
	lorenzo, ryder.lee, shayne.chen, sean.wang,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <CAGp9LzqkJ8QoOnBAiGu=uum3-LmCB3yHr91sw1HoLw+7ewNx6A@mail.gmail.com>

Bradley/Sean,

Thank you all very much for the information.
I tested this on mt7921u based Alfa AWUS unit and also an mt7925 based
Netgear Nighthawk unit.
I can confirm that the RF tick issue is present on both models when in
Monitor Mode. I'm assuming it is in the base mt76?

I attempted sudo iw dev wlxxx set txpower fixed nn where nn is the
minimum value, next few values up, and then a few near the max values,
and see no change in the signal strength of the RF Ticks when scanning
through 5 or more channels.

Please keep this in mind when attempting to resolve the known txpower
3dBm issue if possible, or please generate a new bug report for that
specifically so that I can track when it is patched, or in ??? version
so that I can test here locally.

Incidentally, I'd appreciate it if anyone could please attempt to
repeat using the scripts I had shown in the previous posts and confirm
it is indeed seen by others.

Thank you very much for your time and assistance

John Henry




From: Bradley Pizzimenti <brad.pizzimenti@gmail.com>
To: linux-wireless@vger.kernel.org
Cc: linux-kernel@vger.kernel.org, nbd@nbd.name, lorenzo@kernel.org,
ryder.lee@mediatek.com, shayne.chen@mediatek.com,
sean.wang@mediatek.com
Subject: [bug report] wifi: mt76: mt7925: iw set txpower fixed
accepted but ignored
Date: Mon, 4 May 2026 15:04:35 -0700 [thread overview]
Message-ID: <CACjnFagN9zeSkwEv3-CSPJDUENPcEcOLjKyQoLQ91Yjn=rq5ww@mail.gmail.com>
(raw)

Hi there maintainers,

`iw dev <iface> set txpower fixed N` returns success on mt7925 for any
N tested, but the reported txpower never changes from a stuck value of
3.00 dBm. The kernel accepts and ignores the call silently in both
directions (above and below the displayed value), and well below the
regulatory ceiling.

I'm aware there's prior art on the cosmetic 3.00 dBm display issue
(Razvan Grigore's v2 series, Feb 2025; Ming Yen Hsieh's txpower init
refactor, Sept 2025). What seems potentially distinct here is that the
user-issued `iw set txpower fixed N` itself is silently no-op'd,
separate from the reported-value question. Reporting as breadcrumbs
in case the second observation is a separate bug rather than the same
one.

Hardware
--------
MEDIATEK MT7925 [Filogic 360], 802.11be 2x2, PCI 14c3:7925
ASIC revision 0x79250000
Driver in use: mt7925e (in-tree)

Firmware (from dmesg at probe)
------------------------------
mt7925e 0000:01:00.0: HW/SW Version: 0x8a108a10,
                     Build Time: 20260106153007a
mt7925e 0000:01:00.0: WM Firmware Version: ____000000,
                     Build Time: 20260106153120
Files: mediatek/mt7925/WIFI_MT7925_PATCH_MCU_1_1_hdr.bin
       mediatek/mt7925/WIFI_RAM_CODE_MT7925_1_1.bin

Kernel
------
6.18.18-1-MANJARO (close to vanilla 6.18 stable; not yet tested on
wireless-next or nbd168/wireless HEAD -- happy to retest if needed,
but flagging the data point in case it helps as-is).

Tools: iw version 6.17

Regulatory
----------
$ iw reg get
country US: DFS-FCC
   ...
   (5730 - 5850 @ 80), (N/A, 30), (N/A), AUTO-BW
   ...

Connection context: 5GHz channel 161 (5805 MHz), 80 MHz, VHT-MCS,
NSS 1. So we are on a band with a 30 dBm regulatory cap.

Observed
--------
$ iw dev wlp1s0 info | grep txpower
        txpower 3.00 dBm

$ sudo iw dev wlp1s0 set txpower fixed 100   # 1 dBm
$ iw dev wlp1s0 info | grep txpower
        txpower 3.00 dBm

$ sudo iw dev wlp1s0 set txpower fixed 1500  # 15 dBm
$ iw dev wlp1s0 info | grep txpower
        txpower 3.00 dBm

$ sudo iw dev wlp1s0 set txpower auto
$ iw dev wlp1s0 info | grep txpower
        txpower 3.00 dBm

All four `set` invocations return exit code 0. The reported value
never moves.

Expected
--------
Either:
  - The reported txpower follows the requested value (or, where
    capped, the actual applied value with extack indicating the
    cap reason), or
  - The set call returns an error rather than silently ignoring the
    request.

Caveats
-------
- Not yet tested on wireless-next or nbd168/wireless HEAD. If a
  reproduction on a current dev tree would be useful, I can do that.
- I have not verified whether the actual radiated TX power changes
  in response to `set txpower fixed`; I am reporting only the
  user-visible behavior.

Thanks,
Bradley

On Wed, May 6, 2026 at 8:12 PM Sean Wang <sean.wang@kernel.org> wrote:
>
> Hi,
>
> The TX power reporting issue has already been investigated by Lucid
> from the Linux WiFi USB community, and there is a proposed solution.
> I think we can continue checking whether there are any remaining
> issues on top of that work. Please refer to the patches here:
> https://lists.infradead.org/pipermail/linux-mediatek/2026-April/105726.html
> Thanks everyone for reporting and raising these concerns.
>
> On Wed, May 6, 2026 at 3:09 PM Javier Tia <floss@jetm.me> wrote:
> >
> > On Sun May  4 22:04:48 2026 Bradley Pizzimenti wrote:
> > > `iw dev <iface> set txpower fixed N` returns success on mt7925 for
> > > any N tested, but the reported txpower never changes from a stuck
> > > value of 3.00 dBm.
> >
> > Hi Bradley,
> >
> > The 3 dBm display bug is a known issue we have seen when using mt7927
> > and a tested fix has been working well so far. The root cause is that
> > mt7925_mcu_set_rate_txpower() programs the per-band SKU tables into
> > firmware but never assigns phy->txpower_cur. mt76_get_txpower() then
> > computes:
> >
> >   DIV_ROUND_UP(0 + 6, 2) = 3
> >
> > regardless of the actual power level. The RF output is unaffected;
> > it is a display-only bug.
> >
> > The fix reads the effective TX power back from the rate power limits
> > after programming the SKU tables and writes it to phy->txpower_cur,
> > following the same pattern used by mt7996:
> >
> >   https://github.com/jetm/mediatek-mt7927-dkms/blob/master/mt7927-wifi-14-fix-reported-txpower-always-showing-3-db.patch
> >
> > This is part of a series we are targeting for wireless-next; not
> > yet upstream.
> >
> > > What seems potentially distinct here is that the user-issued
> > > `iw set txpower fixed N` itself is silently no-op'd, separate
> > > from the reported-value question.
> >
> > Agreed those are two separate issues. Our patch addresses the
> > display-only side: after applying it, iw will report the value the
> > firmware is actually using based on the SKU tables, rather than
> > always 3 dBm. Whether `set txpower fixed N` propagates to firmware
> > to change actual output power is orthogonal and not addressed here.
> >
> > If you can test the patch on your MT7925 and confirm the displayed
> > value reflects the correct power after association, a Tested-by
> > would be appreciated.
> >
> > Best,
> > Javier
> >
>

^ permalink raw reply

* Re: [PATCH rtw-next v2 1/1] wifi: rtw89: usb: Support switching to USB 3 mode
From: Devin Wittmayer @ 2026-05-11 18:03 UTC (permalink / raw)
  To: johannes, linux-wireless
  Cc: pkshih, rtl8821cerfe2, linux-kernel, Devin Wittmayer
In-Reply-To: <6d553cffcb0ae84e141006ae1430f6f37909ad2b.camel@sipsolutions.net>

On Mon, 2026-05-11 at 19:26 +0200, Johannes Berg wrote:
> > +static bool rtw89_switch_usb_mode = true;
> > +module_param_named(switch_usb_mode, rtw89_switch_usb_mode, bool, 0644);
> > +MODULE_PARM_DESC(switch_usb_mode,
> > +         "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");
>
> We shouldn't really add new module parameters.

This module parameter follows the pattern Bitterblue established for
rtw88: same user-facing name (switch_usb_mode), same description, same
default. Commit 315c23a64e99 "wifi: rtw88: usb: Support USB 3 with
RTL8822CU/RTL8822BU" (2024-07-10) added it to rtw88/usb.c and it
remains in-tree.

Three v3 paths I see:

1. Drop the param. Users hitting USB3 2.4 GHz harmonic interference
   would need to use a USB 2 port instead.
2. Move the escape hatch behind a sysfs or nl80211 control. New UABI
   surface; open to design suggestions on that.
3. Keep it for rtw89/rtw88 symmetry on the same USB3 / 2.4 GHz
   harmonic interference issue.

Any of the three works on my side. If the rtw88 param is grandfathered
and we should not add new module parameters even in this case, I will
respin without it in v3.

Devin

^ permalink raw reply

* Re: [PATCH rtw-next v2 1/1] wifi: rtw89: usb: Support switching to USB 3 mode
From: Bitterblue Smith @ 2026-05-11 18:14 UTC (permalink / raw)
  To: Devin Wittmayer, linux-wireless; +Cc: pkshih, linux-kernel
In-Reply-To: <20260511160811.17647-2-lucid_duck@justthetip.ca>

On 11/05/2026 19:08, Devin Wittmayer wrote:
> From: Bitterblue Smith <rtl8821cerfe2@gmail.com>
> 
> The Realtek wifi 6/7 devices which support USB 3 are weird: when first
> plugged in, they pretend to be USB 2. The driver needs to send some
> commands to the device, which make it disappear and come back as a
> USB 3 device.
> 
> Implement the required commands in rtw89.
> 
> When a USB 3 device is plugged into a USB 2 port, rtw89 will try to
> switch it to USB 3 mode only once. The device will disappear and come
> back still in USB 2 mode, of course.
> 
> Some people experience heavy interference in the 2.4 GHz band in
> USB 3 mode, so add a module parameter switch_usb_mode with the
> default value 1 to let people disable the switching.
> 
> Tested with RTL8832BU and RTL8832CU.
> 
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
> Signed-off-by: Devin Wittmayer <lucid_duck@justthetip.ca>
> Tested-by: Devin Wittmayer <lucid_duck@justthetip.ca>

Are you quite sure you tested this?

> ---
>  drivers/net/wireless/realtek/rtw89/reg.h |  4 +++
>  drivers/net/wireless/realtek/rtw89/usb.c | 41 ++++++++++++++++++++++++
>  2 files changed, 45 insertions(+)
> 
> diff --git a/drivers/net/wireless/realtek/rtw89/reg.h b/drivers/net/wireless/realtek/rtw89/reg.h
> index 42ffe83931a3..7d4c085d9fb2 100644
> --- a/drivers/net/wireless/realtek/rtw89/reg.h
> +++ b/drivers/net/wireless/realtek/rtw89/reg.h
> @@ -164,6 +164,10 @@
>  #define R_AX_DBG_PORT_SEL 0x00C0
>  #define B_AX_DEBUG_ST_MASK GENMASK(31, 0)
>  
> +#define R_AX_PAD_CTRL2 0x00C4
> +#define U2SWITCHU3 0xB
> +#define USB_SWITCH_DELAY 0xF
> +
>  #define R_AX_PMC_DBG_CTRL2 0x00CC
>  #define B_AX_SYSON_DIS_PMCR_AX_WRMSK BIT(2)
>  
> diff --git a/drivers/net/wireless/realtek/rtw89/usb.c b/drivers/net/wireless/realtek/rtw89/usb.c
> index 767a95f759b1..4fb25791d118 100644
> --- a/drivers/net/wireless/realtek/rtw89/usb.c
> +++ b/drivers/net/wireless/realtek/rtw89/usb.c
> @@ -9,6 +9,11 @@
>  #include "txrx.h"
>  #include "usb.h"
>  
> +static bool rtw89_switch_usb_mode = true;
> +module_param_named(switch_usb_mode, rtw89_switch_usb_mode, bool, 0644);
> +MODULE_PARM_DESC(switch_usb_mode,
> +		 "Set to N to disable switching to USB 3 mode to avoid potential interference in the 2.4 GHz band (default: Y)");
> +
>  static void rtw89_usb_read_port_complete(struct urb *urb);
>  
>  static void rtw89_usb_vendorreq(struct rtw89_dev *rtwdev, u32 addr,
> @@ -1027,6 +1032,35 @@ static void rtw89_usb_intf_deinit(struct rtw89_dev *rtwdev,
>  	usb_set_intfdata(intf, NULL);
>  }
>  
> +static int rtw89_usb_switch_mode(struct rtw89_dev *rtwdev)
> +{
> +	struct rtw89_usb *rtwusb = rtw89_usb_priv(rtwdev);
> +
> +	if (!rtw89_switch_usb_mode)
> +		return 0;
> +
> +	/* No known USB 3 devices with this chip. */
> +	if (rtwdev->chip->chip_id == RTL8851B)
> +		return 0;
> +
> +	if (rtwusb->udev->speed == USB_SPEED_SUPER)
> +		return 0;
> +
> +	rtw89_debug(rtwdev, RTW89_DBG_HCI, "%s: pad_ctrl2: %#x %#x\n",
> +		    __func__,
> +		    rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 1),
> +		    rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 2));
> +
> +	/* Already tried to switch but it's a USB 2 port. */
> +	if (rtw89_read8(rtwdev, R_AX_PAD_CTRL2 + 1) == USB_SWITCH_DELAY)
> +		return 0;
> +
> +	rtw89_write8(rtwdev, R_AX_PAD_CTRL2 + 1, USB_SWITCH_DELAY);
> +	rtw89_write8(rtwdev, R_AX_PAD_CTRL2 + 2, U2SWITCHU3);
> +
> +	return 1;
> +}
> +
>  int rtw89_usb_probe(struct usb_interface *intf,
>  		    const struct usb_device_id *id)
>  {
> @@ -1059,6 +1093,13 @@ int rtw89_usb_probe(struct usb_interface *intf,
>  		goto err_free_hw;
>  	}
>  
> +	ret = rtw89_usb_switch_mode(rtwdev);
> +	if (ret) {
> +		/* Not a fail, but we do need to skip rtw89_core_register. */
> +		ret = 0;
> +		goto err_intf_deinit;
> +	}
> +
>  	if (rtwusb->udev->speed == USB_SPEED_SUPER)
>  		rtwdev->hci.dle_type = RTW89_HCI_DLE_TYPE_USB3;
>  	else


^ permalink raw reply

* [PATCH] wifi: mt76: mt7996: avoid memset overwriting tx_info->control.flags
From: Ryder Lee @ 2026-05-11 18:32 UTC (permalink / raw)
  To: Felix Fietkau
  Cc: linux-mediatek, linux-wireless, Shayne Chen, Roy Luo, Ryder Lee

mt76_tx_status_skb_add uses memset on status.status_driver_data, which
overwrite  info->control.flags in ieee80211_tx_info. Copy tx_info before
calling mt76_tx_status_skb_add to ensure control fields are preserved
and remain valid for later processing.

Reported-By: Roy Luo <roy-ch.luo@mediatek.com>
Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt7996/mac.c | 17 +++++++++--------
 .../net/wireless/mediatek/mt76/mt7996/mt7996.h  |  2 +-
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
index e2a83da3a09c..a59c14c8f2af 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mac.c
@@ -855,11 +855,12 @@ mt7996_mac_write_txwi_80211(struct mt7996_dev *dev, __le32 *txwi,
 
 void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
 			   struct sk_buff *skb, struct mt76_wcid *wcid,
-			   struct ieee80211_key_conf *key, int pid,
+			   struct ieee80211_tx_info *tx_info, int pid,
 			   enum mt76_txq_id qid, u32 changed)
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+	struct ieee80211_key_conf *key = tx_info ? tx_info->control.hw_key : NULL;
+	struct ieee80211_tx_info *info = tx_info ? tx_info : IEEE80211_SKB_CB(skb);
 	struct ieee80211_vif *vif = info->control.vif;
 	u8 band_idx = (info->hw_queue & MT_TX_HW_QUEUE_PHY) >> 2;
 	u8 p_fmt, q_idx, omac_idx = 0, wmm_idx = 0;
@@ -1006,15 +1007,15 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 {
 	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx_info->skb->data;
 	struct mt7996_dev *dev = container_of(mdev, struct mt7996_dev, mt76);
-	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx_info->skb);
-	struct ieee80211_key_conf *key = info->control.hw_key;
-	struct ieee80211_vif *vif = info->control.vif;
+	struct ieee80211_tx_info info = *IEEE80211_SKB_CB(tx_info->skb);
+	struct ieee80211_key_conf *key = info.control.hw_key;
+	struct ieee80211_vif *vif = info.control.vif;
 	struct mt7996_vif *mvif = vif ? (struct mt7996_vif *)vif->drv_priv : NULL;
 	struct mt7996_sta *msta = sta ? (struct mt7996_sta *)sta->drv_priv : NULL;
 	struct mt76_vif_link *mlink = NULL;
 	struct mt76_txwi_cache *t;
 	int id, i, pid, nbuf = tx_info->nbuf - 1;
-	bool is_8023 = info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
+	bool is_8023 = info.flags & IEEE80211_TX_CTL_HW_80211_ENCAP;
 	__le32 *ptr = (__le32 *)txwi_ptr;
 	u8 *txwi = (u8 *)txwi_ptr;
 	u8 link_id;
@@ -1031,7 +1032,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 
 		link_id = (tid % 2) ? msta->seclink_id : msta->deflink_id;
 	} else {
-		link_id = u32_get_bits(info->control.flags,
+		link_id = u32_get_bits(info.control.flags,
 				       IEEE80211_TX_CTRL_MLO_LINK);
 	}
 
@@ -1095,7 +1096,7 @@ int mt7996_tx_prepare_skb(struct mt76_dev *mdev, void *txwi_ptr,
 	memset(txwi_ptr, 0, MT_TXD_SIZE);
 	/* Transmit non qos data by 802.11 header and need to fill txd by host*/
 	if (!is_8023 || pid >= MT_PACKET_ID_FIRST)
-		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, key,
+		mt7996_mac_write_txwi(dev, txwi_ptr, tx_info->skb, wcid, &info,
 				      pid, qid, 0);
 
 	/* MT7996 and MT7992 require driver to provide the MAC TXP for AddBA
diff --git a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
index bdcf72457954..319fcc4fb469 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
+++ b/drivers/net/wireless/mediatek/mt76/mt7996/mt7996.h
@@ -854,7 +854,7 @@ void mt7996_mac_cca_stats_reset(struct mt7996_phy *phy);
 void mt7996_mac_enable_nf(struct mt7996_dev *dev, u8 band);
 void mt7996_mac_write_txwi(struct mt7996_dev *dev, __le32 *txwi,
 			   struct sk_buff *skb, struct mt76_wcid *wcid,
-			   struct ieee80211_key_conf *key, int pid,
+			   struct ieee80211_tx_info *tx_info, int pid,
 			   enum mt76_txq_id qid, u32 changed);
 void mt7996_mac_update_beacons(struct mt7996_phy *phy);
 void mt7996_mac_set_coverage_class(struct mt7996_phy *phy);
-- 
2.45.2


^ permalink raw reply related

* Re: [PATCH 2/2] wifi: ath12k: skip unknown direct buffer ring module IDs
From: Jeff Johnson @ 2026-05-11 19:02 UTC (permalink / raw)
  To: Nazar Mokrynskyi, ath12k; +Cc: linux-wireless
In-Reply-To: <20260505172415.566328-3-nazar@mokrynskyi.com>

On 5/5/2026 10:24 AM, Nazar Mokrynskyi wrote:
> The firmware may advertise direct buffer ring capabilities for module
> IDs beyond what the driver currently knows about (WMI_DIRECT_BUF_MAX).
> This happens with newer firmware versions that support additional ring
> types not yet implemented in the driver.

What "newer firmware version" are you using that has this issue?

Can you share the "Skipping unknown direct buf ring module id" logs from your
modified driver?

> 
> The current code treats an unknown module_id as a fatal error, returning
> -EINVAL and tearing down the entire driver initialization. This is
> incorrect: the driver only needs to set up rings for types it uses
> (SPECTRAL=0, CFR=1) and can safely ignore capability advertisements for
> unknown types.
> 
> Change the unknown module_id handling to skip the entry with a debug
> message rather than failing, allowing initialization to proceed.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Nazar Mokrynskyi <nazar@mokrynskyi.com>
> ---
>  drivers/net/wireless/ath/ath12k/wmi.c | 12 ++++--------
>  1 file changed, 4 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 484fdd3b1..0e776a8d8 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -4814,10 +4814,10 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab,
>  	dir_buff_caps = ab->db_caps;
>  	for (i = 0; i < dma_caps_parse->n_dma_ring_caps; i++) {
>  		if (le32_to_cpu(dma_caps[i].module_id) >= WMI_DIRECT_BUF_MAX) {
> -			ath12k_warn(ab, "Invalid module id %d\n",
> -				    le32_to_cpu(dma_caps[i].module_id));
> -			ret = -EINVAL;
> -			goto free_dir_buff;
> +			ath12k_dbg(ab, ATH12K_DBG_WMI,
> +				   "Skipping unknown direct buf ring module id %d\n",
> +				   le32_to_cpu(dma_caps[i].module_id));
> +			continue;

by continuing you don't populate the dir_buff_caps[i] information below,
leaving that record with zeroed data from the initial allocation. Does other
code correctly handle that?

would it be better to have a separate count of the number of dir_buff_caps
records that are actually filled, and then update
dma_caps_parse->n_dma_ring_caps to match once the parsing has completed?

>  		}
>  
>  		dir_buff_caps[i].id = le32_to_cpu(dma_caps[i].module_id);
> @@ -4829,10 +4829,6 @@ static int ath12k_wmi_dma_ring_caps(struct ath12k_base *ab,
>  	}
>  
>  	return 0;
> -
> -free_dir_buff:
> -	ath12k_wmi_free_dbring_caps(ab);
> -	return ret;
>  }
>  
>  static void


^ permalink raw reply


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