Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [REGRESSION] iwlwifi 8265 firmware ADVANCED_SYSASSERT in PHY_CONTEXT_CMD on roam (v7.0.3..v7.0.5)
From: Johannes Berg @ 2026-05-13 10:41 UTC (permalink / raw)
  To: Branislav Klocok, regressions; +Cc: linux-wireless
In-Reply-To: <d2ffd82d-01cb-470e-bb02-70c163c61216@ofz.sk>

On Wed, 2026-05-13 at 12:35 +0200, Branislav Klocok wrote:
>  #regzbot introduced: v7.0.3..v7.0.5

That cannot be right, there are no patches for wifi between those except
a handful in drivers you're not running.

johannes

^ permalink raw reply

* [REGRESSION] iwlwifi 8265 firmware ADVANCED_SYSASSERT in PHY_CONTEXT_CMD on roam (v7.0.3..v7.0.5)
From: Branislav Klocok @ 2026-05-13 10:35 UTC (permalink / raw)
  To: regressions; +Cc: linux-wireless


[-- Attachment #1.1: Type: text/plain, Size: 2860 bytes --]

Hi,

I would like to report a regression in stable kernel 7.0.x affecting
iwlwifi on Intel Wireless-AC 8265. Bug filed at
https://bugzilla.kernel.org/show_bug.cgi?id=221512 (network-wireless-intel)
and openSUSE Bugzilla https://bugzilla.suse.com/show_bug.cgi?id=1264804.

#regzbot introduced: v7.0.3..v7.0.5
#regzbot link: https://bugzilla.kernel.org/show_bug.cgi?id=221512
#regzbot link: https://bugzilla.suse.com/show_bug.cgi?id=1264804

Summary: every controller-initiated roam between BSSIDs of the same
enterprise ESSID triggers a firmware microcode assertion
(`ADVANCED_SYSASSERT` / `NMI_INTERRUPT_LMAC_FATAL` / `FW error in SYNC
CMD PHY_CONTEXT_CMD`). Driver SW-resets and re-associates in about
4 s, but some triggers send the driver into a cascading restart loop
(observed 6 firmware errors in 23 s, twice in a single session).
Identical hardware, firmware blob (`8265-36.ucode` v36.c8e8e144.0),
network and userspace worked correctly on 7.0.3.

I personally booted only 7.0.3 (good) and 7.0.5 (bad); 7.0.4 was
installed but not run. The 7.0.5 stable changelog contains no
iwlwifi/mac80211/cfg80211 commits, so the regression most likely sits
in the 7.0.4 batch.

Crash backtrace fragment:

iwlwifi 0000:02:00.0: 0x000014FD | ADVANCED_SYSASSERT
iwlwifi 0000:02:00.0: 0x00000070 | NMI_INTERRUPT_LMAC_FATAL
iwlwifi 0000:02:00.0: FW error in SYNC CMD PHY_CONTEXT_CMD
CPU: 2 UID: 0 PID: 1527 Comm: wpa_supplicant
iwl_trans_pcie_send_hcmd+0x402/0x410 [iwlwifi]
iwl_trans_send_cmd+0x3e/0xa0 [iwlwifi]
? nl80211_authenticate+0x373/0x400 [cfg80211]
nl80211_authenticate+0x38d/0x400 [cfg80211]
iwlwifi 0000:02:00.0: PHY ctxt cmd error. ret=-5

Workarounds tested and rejected:
- `802-11-wireless.powersave=2` (CAM) — does not prevent the crash;
client still receives steering and firmware still asserts on
`PHY_CONTEXT_CMD`.
- `modprobe -r iwlmvm iwlwifi && modprobe iwlwifi` — temporary
recovery only; next roam reproduces the crash.

The only known mitigation is staying on 7.0.3 or avoiding networks
with controller-driven band/load steering.

I am happy to test patches against the affected hardware and network.
Full filtered kernel log (3329 lines, both cascading restart loops)
is attached to the bugzilla.kernel.org bug.

Hardware:
- Intel Wireless-AC 8265 [8086:24fd] rev 78, subsys [8086:0010]
- ThinkPad, openSUSE Tumbleweed (rolling) snapshot 20260509
- kernel-firmware-iwlwifi 20260331-1.1
- NetworkManager 1.54.3-3.4, wpa_supplicant 2.11-6.3

Thanks,
Branislav Klocok
*-- *
S pozdravom / Best regards
*Branislav Klocok *
*generálny riaditeľ / general director *


* OFZ, a.s.*
Mobil: 	*+421 908 703 366*
Tel: 	*+421 43 5804 488 *
e-mail: 	**branislav.klocok@ofz.sk* <mailto:branislav.klocok@ofz.sk> *
web: 	**www.ofz.company* <http://www.ofz.company> *


ofz logo


[-- Attachment #1.2.1: Type: text/html, Size: 6169 bytes --]

[-- Attachment #1.2.2: WdtYKUGW07EU0N07.png --]
[-- Type: image/png, Size: 4675 bytes --]

[-- Attachment #2: Kryptografický podpis S/MIME --]
[-- Type: application/pkcs7-signature, Size: 4669 bytes --]

^ permalink raw reply

* Re: [PATCH v2 0/4] treewide: fixup gfp_t printks
From: Brendan Jackman @ 2026-05-13  9:11 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
	Simona Vetter, Stanislaw Gruszka, Alexander Potapenko,
	Marco Elver, Dmitry Vyukov, Allison Henderson, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	dri-devel, linux-kernel, linux-wireless, kasan-dev, linux-mm,
	netdev, linux-rdma, rds-devel
In-Reply-To: <20260512140532.f16379be75ab006f2cca4747@linux-foundation.org>

On Tue, 12 May 2026 at 23:05, Andrew Morton <akpm@linux-foundation.org> wrote:
>
> On Tue, 12 May 2026 12:58:20 +0000 Brendan Jackman <jackmanb@google.com> wrote:
>
> > On Thu Mar 26, 2026 at 12:31 PM UTC, Brendan Jackman wrote:
> > > This patchset used to be about switching gfp_t to unsigned long. That is
> > > probably not gonna happen any more but while writing it I found these
> > > cleanups that seem worthwhile regardless.
> > >
> >
> > ...
> >
> > Any chance someone can take these?
>
> [2/4] is merged into the wireless tree (I assume) and the other three
> are in mm.git's mm-unstable branch.

Oh sorry, I just checked and I did actually receive the notification
when you queued it, I guess I just didn't parse it mentally.

^ permalink raw reply

* [PATCH v2] wifi: mt76: mt7925: Add coredump callback in pci_driver
From: JB Tsai @ 2026-05-13  7:23 UTC (permalink / raw)
  To: nbd, lorenzo
  Cc: linux-wireless, linux-mediatek, Deren.Wu, Sean.Wang, Quan.Zhou,
	Ryder.Lee, Leon.Yen, litien.chang, jeff.hsu, jb.tsai, Jeff Hsu

From: Jeff Hsu <Jeff.Hsu@mediatek.com>

Register coredump callback(mt7925_coredump) in pci_driver,
it can let platform can trigger core dump to collect the
log and recover back after coredump complete without debugfs

Some platform not have debugfs

Signed-off-by: Jeff Hsu <Jeff.Hsu@mediatek.com>
---
 drivers/net/wireless/mediatek/mt76/mt7925/mcu.c |  1 +
 drivers/net/wireless/mediatek/mt76/mt7925/pci.c | 12 ++++++++++++
 2 files changed, 13 insertions(+)

diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
index 37cdf3e8a067..cd502166a7f9 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/mcu.c
@@ -1014,6 +1014,7 @@ int mt7925_mcu_chip_config(struct mt792x_dev *dev, const char *cmd)
 	return mt76_mcu_send_msg(&dev->mt76, MCU_UNI_CMD(CHIP_CONFIG),
 				 &req, sizeof(req), false);
 }
+EXPORT_SYMBOL_GPL(mt7925_mcu_chip_config);
 
 int mt7925_mcu_set_deep_sleep(struct mt792x_dev *dev, bool enable)
 {
diff --git a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
index c4161754c01d..57006cd75b1c 100644
--- a/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
+++ b/drivers/net/wireless/mediatek/mt76/mt7925/pci.c
@@ -610,6 +610,17 @@ static int mt7925_pci_restore(struct device *device)
 	return _mt7925_pci_resume(device, true);
 }
 
+static void mt7925_coredump(struct device *dev)
+{
+	struct pci_dev *pdev = to_pci_dev(dev);
+	struct mt76_dev *mdev = pci_get_drvdata(pdev);
+	struct mt792x_dev *dev_792x = container_of(mdev, struct mt792x_dev, mt76);
+
+	mt792x_mutex_acquire(dev_792x);
+	mt7925_mcu_chip_config(dev_792x, "assert");
+	mt792x_mutex_release(dev_792x);
+}
+
 static const struct dev_pm_ops mt7925_pm_ops = {
 	.suspend = pm_sleep_ptr(mt7925_pci_suspend),
 	.resume  = pm_sleep_ptr(mt7925_pci_resume),
@@ -626,6 +637,7 @@ static struct pci_driver mt7925_pci_driver = {
 	.remove		= mt7925_pci_remove,
 	.shutdown       = mt7925_pci_shutdown,
 	.driver.pm	= pm_sleep_ptr(&mt7925_pm_ops),
+	.driver.coredump = mt7925_coredump,
 };
 
 module_pci_driver(mt7925_pci_driver);
-- 
2.45.2


^ permalink raw reply related

* [PATCH v3 3/3] wifi: iwlwifi: dt: use Device Tree as fallback BIOS configuration source
From: Avinash Bhatt @ 2026-05-13  6:05 UTC (permalink / raw)
  To: devicetree, linux-wireless
  Cc: robh, krzk+dt, conor+dt, johannes, miriam.rachel.korenblit,
	linux-kernel, kobi.guetta, emmanuel.grumbach
In-Reply-To: <20260513060531.8130-1-avinash.bhatt@intel.com>

When neither UEFI variables nor ACPI methods provide a BIOS
configuration table, fall back to Device Tree. This preserves the
existing UEFI -> ACPI priority order and extends it with DT as the
lowest-priority source.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/fw/regulatory.c  | 3 +++
 drivers/net/wireless/intel/iwlwifi/mld/mld.c        | 3 +++
 drivers/net/wireless/intel/iwlwifi/mld/regulatory.c | 5 ++++-
 3 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 640e729091..d7ead787c2 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -8,6 +8,7 @@
 #include "regulatory.h"
 #include "fw/runtime.h"
 #include "fw/uefi.h"
+#include "fw/dt.h"
 
 #define GET_BIOS_TABLE(__name, ...)					\
 do {									\
@@ -16,6 +17,8 @@ do {									\
 		ret = iwl_uefi_get_ ## __name(__VA_ARGS__);		\
 	if (ret < 0)							\
 		ret = iwl_acpi_get_ ## __name(__VA_ARGS__);		\
+	if (ret < 0 && iwl_dt_is_compatible(fwrt))			\
+		ret = iwl_dt_get_ ## __name(__VA_ARGS__);		\
 	return ret;							\
 } while (0)
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 130eba60b4..1a95b19d33 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
@@ -12,6 +12,7 @@
 #include "fw/api/coex.h"
 #include "fw/dbg.h"
 #include "fw/uefi.h"
+#include "fw/dt.h"
 
 #include "mld.h"
 #include "mlo.h"
@@ -466,6 +467,8 @@ iwl_op_mode_mld_start(struct iwl_trans *trans, const struct iwl_rf_cfg *cfg,
 	iwl_mld_get_bios_tables(mld);
 	iwl_uefi_get_sgom_table(trans, &mld->fwrt);
 	mld->bios_enable_puncturing = iwl_uefi_get_puncturing(&mld->fwrt);
+	if (!mld->bios_enable_puncturing && iwl_dt_is_compatible(&mld->fwrt))
+		mld->bios_enable_puncturing = iwl_dt_get_puncturing(&mld->fwrt);
 	mld->rfi.bios_enabled = iwl_rfi_is_enabled_in_bios(&mld->fwrt);
 
 	iwl_mld_hw_set_regulatory(mld);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index 97b2283f51..ce539a0be7 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.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 <linux/dmi.h>
@@ -8,6 +8,7 @@
 #include "fw/regulatory.h"
 #include "fw/acpi.h"
 #include "fw/uefi.h"
+#include "fw/dt.h"
 
 #include "regulatory.h"
 #include "mld.h"
@@ -64,6 +65,8 @@ void iwl_mld_get_bios_tables(struct iwl_mld *mld)
 	}
 
 	iwl_uefi_get_uats_table(mld->trans, &mld->fwrt);
+	if (!mld->fwrt.ap_type_cmd_valid && iwl_dt_is_compatible(&mld->fwrt))
+		iwl_dt_get_uats_table(&mld->fwrt);
 	iwl_uefi_get_uneb_table(mld->trans, &mld->fwrt);
 
 	iwl_bios_get_phy_filters(&mld->fwrt);
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 2/3] wifi: iwlwifi: dt: add Device Tree BIOS configuration infrastructure
From: Avinash Bhatt @ 2026-05-13  6:05 UTC (permalink / raw)
  To: devicetree, linux-wireless
  Cc: robh, krzk+dt, conor+dt, johannes, miriam.rachel.korenblit,
	linux-kernel, kobi.guetta, emmanuel.grumbach
In-Reply-To: <20260513060531.8130-1-avinash.bhatt@intel.com>

On platforms that use Device Tree and do not provide UEFI variables or
ACPI methods, discrete Intel Wi-Fi adapters have no way to receive BIOS
configuration. Add Device Tree as a supported configuration source for
SAR limits and 6 GHz AP type support, with stub hooks for TAS and
per-platform antenna gain tables.

DT support is gated on CONFIG_OF and is a no-op on x86. BIOS_SOURCE_DT
is added to enum bios_source to track the configuration origin.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/Makefile   |   1 +
 drivers/net/wireless/intel/iwlwifi/fw/acpi.h  |   5 +-
 .../wireless/intel/iwlwifi/fw/api/nvm-reg.h   |   4 +-
 drivers/net/wireless/intel/iwlwifi/fw/dt.c    | 332 ++++++++++++++++++
 drivers/net/wireless/intel/iwlwifi/fw/dt.h    | 161 +++++++++
 drivers/net/wireless/intel/iwlwifi/fw/init.c  |   4 +-
 .../wireless/intel/iwlwifi/fw/regulatory.h    |   3 +-
 .../net/wireless/intel/iwlwifi/fw/runtime.h   |   6 +-
 intc-scripts/publishable-files                |   2 +
 9 files changed, 510 insertions(+), 8 deletions(-)
 create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/dt.c
 create mode 100644 drivers/net/wireless/intel/iwlwifi/fw/dt.h

diff --git a/drivers/net/wireless/intel/iwlwifi/Makefile b/drivers/net/wireless/intel/iwlwifi/Makefile
index 060604fa6c..c7a2d5ee66 100644
--- a/drivers/net/wireless/intel/iwlwifi/Makefile
+++ b/drivers/net/wireless/intel/iwlwifi/Makefile
@@ -18,6 +18,7 @@ iwlwifi-$(CPTCFG_IWLMVM) += fw/paging.o fw/smem.o fw/init.o
 iwlwifi-$(CPTCFG_IWLMLD) += fw/smem.o fw/init.o
 iwlwifi-$(CONFIG_ACPI) += fw/acpi.o
 iwlwifi-$(CONFIG_EFI)	+= fw/uefi.o
+iwlwifi-$(CONFIG_OF)	+= fw/dt.o
 
 iwlwifi-$(CPTCFG_IWLXVT)	+= fw/paging.o fw/smem.o
 iwlwifi-$(CPTCFG_IWLPROD)	+= fw/init.o
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index a1f89ced15..2356365db2 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2023, 2025 Intel Corporation
+ * Copyright (C) 2018-2023, 2025-2026 Intel Corporation
  */
 #ifndef __iwl_fw_acpi__
 #define __iwl_fw_acpi__
@@ -115,9 +115,6 @@
 #define ACPI_PPAG_WIFI_DATA_SIZE_V3	((ACPI_PPAG_NUM_CHAINS * \
 					  ACPI_PPAG_NUM_BANDS_V3) + 2)
 
-#define IWL_SAR_ENABLE_MSK		BIT(0)
-#define IWL_REDUCE_POWER_FLAGS_POS	1
-
 /* The Inidcator whether UEFI WIFI GUID tables are locked is read from ACPI */
 #define UEFI_WIFI_GUID_UNLOCKED		0
 
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
index 2bec56937c..4b3b97f137 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/nvm-reg.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2012-2014, 2018-2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2026 Intel Corporation
  * Copyright (C) 2013-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016-2017 Intel Deutschland GmbH
  */
@@ -527,11 +527,13 @@ struct iwl_tas_config_cmd_v2_v4 {
  * @BIOS_SOURCE_NONE: BIOS source is not defined
  * @BIOS_SOURCE_ACPI: BIOS source is ACPI
  * @BIOS_SOURCE_UEFI: BIOS source is UEFI
+ * @BIOS_SOURCE_DT: BIOS source is Device Tree
  */
 enum bios_source {
 	BIOS_SOURCE_NONE,
 	BIOS_SOURCE_ACPI,
 	BIOS_SOURCE_UEFI,
+	BIOS_SOURCE_DT,
 };
 
 /**
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dt.c b/drivers/net/wireless/intel/iwlwifi/fw/dt.c
new file mode 100644
index 0000000000..5fd7628ec1
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dt.c
@@ -0,0 +1,332 @@
+// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+#include <linux/of.h>
+#include "iwl-drv.h"
+#include "iwl-debug.h"
+#include "fw/runtime.h"
+#include "fw/regulatory.h"
+#include "dt.h"
+
+/* PCI compatible strings for supported hardware */
+static const char * const iwl_dt_compatible[] = {
+	"pci8086,272b",	/* Intel Wi-Fi 7 BE200 */
+	NULL
+};
+
+void iwl_dt_init(struct iwl_fw_runtime *fwrt)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	const char * const *compat;
+
+	if (!node)
+		return;
+
+	for (compat = iwl_dt_compatible; *compat; compat++) {
+		if (of_device_is_compatible(node, *compat)) {
+			fwrt->dt_compatible = true;
+			return;
+		}
+	}
+
+	IWL_ERR(fwrt,
+		"DT node compatible does not match any supported hardware - ignoring DT\n");
+}
+IWL_EXPORT_SYMBOL(iwl_dt_init);
+
+/* intel,wcpe - channel puncturing enable bits */
+#define IWL_DT_WCPE_USA_EN		BIT(0)	/* USA */
+#define IWL_DT_WCPE_CANADA_EN		BIT(1)	/* Canada */
+#define IWL_DT_WCPE_MASK \
+	(IWL_DT_WCPE_USA_EN | IWL_DT_WCPE_CANADA_EN)
+
+/* SAR layout for "intel,wrds": 4 chains x 12 subbands */
+#define IWL_DT_WRDS_NUM_CHAINS		4
+#define IWL_DT_WRDS_NUM_SUBBANDS	12
+/* Total cell count: 1-cell mode header + SAR data */
+#define IWL_DT_WRDS_MAX_CELLS \
+	(1 + IWL_DT_WRDS_NUM_CHAINS * IWL_DT_WRDS_NUM_SUBBANDS)
+
+int iwl_dt_get_wrds_table(struct iwl_fw_runtime *fwrt)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	u32 buf[IWL_DT_WRDS_MAX_CELLS];
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32_array(node, "intel,wrds", buf,
+					 IWL_DT_WRDS_MAX_CELLS);
+	if (ret) {
+		IWL_DEBUG_RADIO(fwrt, "DT: intel,wrds read failed (%d)\n", ret);
+		return ret;
+	}
+
+	IWL_DEBUG_RADIO(fwrt,
+			"DT: reading intel,wrds (%u chains, %u subbands)\n",
+			IWL_DT_WRDS_NUM_CHAINS, IWL_DT_WRDS_NUM_SUBBANDS);
+
+	/* buf[0]: mode; bit 0 (IWL_SAR_ENABLE_MSK) enables SAR */
+
+	BUILD_BUG_ON(IWL_DT_WRDS_NUM_CHAINS > BIOS_SAR_MAX_CHAINS_PER_PROFILE);
+	BUILD_BUG_ON(IWL_DT_WRDS_NUM_SUBBANDS > BIOS_SAR_MAX_SUB_BANDS_NUM);
+
+	/* buf[1..]: chains[0..N-1] x subbands[0..M-1] in row-major order */
+	for (int i = 0; i < IWL_DT_WRDS_NUM_CHAINS; i++) {
+		for (int j = 0; j < IWL_DT_WRDS_NUM_SUBBANDS; j++) {
+			u32 val = buf[1 + i * IWL_DT_WRDS_NUM_SUBBANDS + j];
+
+			if (val > U8_MAX) {
+				IWL_DEBUG_RADIO(fwrt,
+						"DT: intel,wrds OOB [%u][%u]=%u\n",
+						i, j, val);
+				return -EINVAL;
+			}
+			fwrt->sar_profiles[0].chains[i].subbands[j] = (u8)val;
+		}
+	}
+
+	if (buf[0] & IWL_SAR_ENABLE_MSK)
+		fwrt->sar_profiles[0].enabled = true;
+
+	return 0;
+}
+
+void iwl_dt_get_uats_table(struct iwl_fw_runtime *fwrt)
+{
+	size_t map_size = sizeof(fwrt->ap_type_cmd.mcc_to_ap_type_map);
+	struct device_node *node = dev_of_node(fwrt->dev);
+	const u8 *prop_data;
+	int len;
+
+	if (!node)
+		return;
+
+	prop_data = of_get_property(node, "intel,uats", &len);
+	if (!prop_data)
+		return;
+
+	if (len != (int)map_size) {
+		IWL_DEBUG_FW(fwrt,
+			     "DT: intel,uats bad length %d (expected %zu)\n",
+			     len, map_size);
+		return;
+	}
+
+	IWL_DEBUG_FW(fwrt, "DT: reading intel,uats\n");
+	memcpy(fwrt->ap_type_cmd.mcc_to_ap_type_map, prop_data, map_size);
+	fwrt->ap_type_cmd_valid = true;
+}
+IWL_EXPORT_SYMBOL(iwl_dt_get_uats_table);
+
+int iwl_dt_get_srd(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	const char *str;
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_string(node, "intel,srd", &str);
+	if (ret)
+		return ret;
+
+	if (!strcmp(str, "active-scan"))
+		*value = 0;
+	else if (!strcmp(str, "passive-scan"))
+		*value = 1;
+	else if (!strcmp(str, "disabled"))
+		*value = 2;
+	else
+		return -EINVAL;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,srd = %s (%u)\n", str, *value);
+	return 0;
+}
+
+int iwl_dt_get_6e_uhb(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,6e-uhb", value);
+	if (ret)
+		return ret;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,6e-uhb = 0x%x\n", *value);
+	return 0;
+}
+
+int iwl_dt_get_regulatory_special(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,regulatory-special", value);
+	if (ret)
+		return ret;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,regulatory-special = 0x%x\n", *value);
+	return 0;
+}
+
+int iwl_dt_get_activate_channel(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,activate-channel", value);
+	if (ret)
+		return ret;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,activate-channel = 0x%x\n", *value);
+	return 0;
+}
+
+int iwl_dt_get_force_disable_channels(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,force-disable-channels", value);
+	if (ret)
+		return ret;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,force-disable-channels = 0x%x\n",
+			*value);
+	return 0;
+}
+
+int iwl_dt_get_11be(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,11be", value);
+	if (ret)
+		return ret;
+
+	if (fwrt->dsm_source == BIOS_SOURCE_NONE) {
+		fwrt->dsm_source = BIOS_SOURCE_DT;
+		fwrt->dsm_revision = 0;
+	}
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,11be = 0x%x\n", *value);
+	return 0;
+}
+
+int iwl_dt_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
+		   u32 *value)
+{
+	switch (func) {
+	case DSM_FUNC_DISABLE_SRD:
+		return iwl_dt_get_srd(fwrt, value);
+	case DSM_FUNC_ENABLE_6E:
+		return iwl_dt_get_6e_uhb(fwrt, value);
+	case DSM_FUNC_REGULATORY_CONFIG:
+		return iwl_dt_get_regulatory_special(fwrt, value);
+	case DSM_FUNC_ACTIVATE_CHANNEL:
+		return iwl_dt_get_activate_channel(fwrt, value);
+	case DSM_FUNC_FORCE_DISABLE_CHANNELS:
+		return iwl_dt_get_force_disable_channels(fwrt, value);
+	case DSM_FUNC_ENABLE_11BE:
+		return iwl_dt_get_11be(fwrt, value);
+	default:
+		return -EOPNOTSUPP;
+	}
+}
+
+int iwl_dt_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *data)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	u32 val;
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,splc", &val);
+	if (ret)
+		return ret;
+
+	*data = val;
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,splc = %u mW\n", val);
+	return 0;
+}
+
+int iwl_dt_get_wbem(struct iwl_fw_runtime *fwrt, u32 *data)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	int ret;
+
+	if (!node)
+		return -ENOENT;
+
+	ret = of_property_read_u32(node, "intel,wbem", data);
+	if (ret)
+		return ret;
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,wbem = 0x%x\n", *data);
+	return 0;
+}
+
+int iwl_dt_get_puncturing(struct iwl_fw_runtime *fwrt)
+{
+	struct device_node *node = dev_of_node(fwrt->dev);
+	u32 val;
+	int ret;
+
+	if (!node)
+		return 0;
+
+	ret = of_property_read_u32(node, "intel,wcpe", &val);
+	if (ret)
+		return 0;
+
+	IWL_DEBUG_RADIO(fwrt, "DT: intel,wcpe = 0x%x\n", val);
+	return val & IWL_DT_WCPE_MASK;
+}
+IWL_EXPORT_SYMBOL(iwl_dt_get_puncturing);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/dt.h b/drivers/net/wireless/intel/iwlwifi/fw/dt.h
new file mode 100644
index 0000000000..70ab6f309b
--- /dev/null
+++ b/drivers/net/wireless/intel/iwlwifi/fw/dt.h
@@ -0,0 +1,161 @@
+/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
+/*
+ * Copyright (C) 2026 Intel Corporation
+ */
+#ifndef __iwl_fw_dt_h__
+#define __iwl_fw_dt_h__
+
+#include "fw/runtime.h"
+
+/*
+ * Device Tree property parsing for Intel Wi-Fi 7 BE200 PCIe adapters.
+ *
+ * On platforms without UEFI variables or ACPI methods, regulatory and
+ * power configuration can be supplied via Device Tree properties in the
+ * Wi-Fi PCIe device node.
+ *
+ * DT is the lowest-priority source: UEFI variables take precedence, then
+ * ACPI methods, and finally these DT properties.
+ */
+
+#if IS_ENABLED(CONFIG_OF)
+
+/* Functions implemented in fw/dt.c */
+void iwl_dt_init(struct iwl_fw_runtime *fwrt);
+
+static inline bool iwl_dt_is_compatible(struct iwl_fw_runtime *fwrt)
+{
+	return fwrt->dt_compatible;
+}
+
+int iwl_dt_get_wrds_table(struct iwl_fw_runtime *fwrt);
+void iwl_dt_get_uats_table(struct iwl_fw_runtime *fwrt);
+int iwl_dt_get_srd(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_6e_uhb(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_regulatory_special(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_activate_channel(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_force_disable_channels(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_11be(struct iwl_fw_runtime *fwrt, u32 *value);
+int iwl_dt_get_dsm(struct iwl_fw_runtime *fwrt, enum iwl_dsm_funcs func,
+		   u32 *value);
+int iwl_dt_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *data);
+int iwl_dt_get_wbem(struct iwl_fw_runtime *fwrt, u32 *data);
+int iwl_dt_get_puncturing(struct iwl_fw_runtime *fwrt);
+#else /* !CONFIG_OF */
+
+static inline void iwl_dt_init(struct iwl_fw_runtime *fwrt) {}
+
+static inline bool iwl_dt_is_compatible(struct iwl_fw_runtime *fwrt)
+{
+	return false;
+}
+
+static inline int iwl_dt_get_wrds_table(struct iwl_fw_runtime *fwrt)
+{
+	return -ENOENT;
+}
+
+static inline void iwl_dt_get_uats_table(struct iwl_fw_runtime *fwrt) {}
+
+static inline int iwl_dt_get_srd(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_6e_uhb(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_regulatory_special(struct iwl_fw_runtime *fwrt,
+						u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_activate_channel(struct iwl_fw_runtime *fwrt,
+					      u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_force_disable_channels(struct iwl_fw_runtime *fwrt,
+						    u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_11be(struct iwl_fw_runtime *fwrt, u32 *value)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_pwr_limit(struct iwl_fw_runtime *fwrt, u64 *data)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_wbem(struct iwl_fw_runtime *fwrt, u32 *data)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_puncturing(struct iwl_fw_runtime *fwrt)
+{
+	return 0;
+}
+
+static inline int iwl_dt_get_dsm(struct iwl_fw_runtime *fwrt,
+				 enum iwl_dsm_funcs func, u32 *value)
+{
+	return -ENOENT;
+}
+
+#endif /* CONFIG_OF */
+
+/*
+ * The following tables have no Device Tree implementation regardless of
+ * CONFIG_OF. Callers fall back gracefully when these return -ENOENT.
+ */
+static inline int iwl_dt_get_ppag_table(struct iwl_fw_runtime *fwrt)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_tas_table(struct iwl_fw_runtime *fwrt,
+				       struct iwl_tas_data *data)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_ewrd_table(struct iwl_fw_runtime *fwrt)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_wgds_table(struct iwl_fw_runtime *fwrt)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_phy_filters(struct iwl_fw_runtime *fwrt)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_mcc(struct iwl_fw_runtime *fwrt, char *data)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_eckv(struct iwl_fw_runtime *fwrt, u32 *data)
+{
+	return -ENOENT;
+}
+
+static inline int iwl_dt_get_dsbr(struct iwl_fw_runtime *fwrt, u32 *data)
+{
+	return -ENOENT;
+}
+
+#endif /* __iwl_fw_dt_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/init.c b/drivers/net/wireless/intel/iwlwifi/fw/init.c
index d1d8058ad2..7d365947b3 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/init.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/init.c
@@ -1,12 +1,13 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2017 Intel Deutschland GmbH
- * Copyright (C) 2019-2021, 2024-2025 Intel Corporation
+ * Copyright (C) 2019-2021, 2024-2026 Intel Corporation
  */
 #include "iwl-drv.h"
 #include "runtime.h"
 #include "dbg.h"
 #include "debugfs.h"
+#include "dt.h"
 
 #include "fw/api/system.h"
 #include "fw/api/commands.h"
@@ -36,6 +37,7 @@ void iwl_fw_runtime_init(struct iwl_fw_runtime *fwrt, struct iwl_trans *trans,
 		INIT_DELAYED_WORK(&fwrt->dump.wks[i].wk, iwl_fw_error_dump_wk);
 	}
 	iwl_fwrt_dbgfs_register(fwrt, dbgfs_dir);
+	iwl_dt_init(fwrt);
 }
 IWL_EXPORT_SYMBOL(iwl_fw_runtime_init);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 0f6bc61142..a6add973ba 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
 /*
- * Copyright (C) 2023-2025 Intel Corporation
+ * Copyright (C) 2023-2026 Intel Corporation
  */
 
 #ifndef __fw_regulatory_h__
@@ -30,6 +30,7 @@
 #define BIOS_GEO_MIN_PROFILE_NUM	3
 
 #define IWL_SAR_ENABLE_MSK		BIT(0)
+#define IWL_REDUCE_POWER_FLAGS_POS	1
 
 /* PPAG gain value bounds in 1/8 dBm */
 #define IWL_PPAG_MIN_LB	-16
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
index cc976195b1..28161da63c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/runtime.h
@@ -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
  */
 #ifndef __iwl_fw_runtime_h__
 #define __iwl_fw_runtime_h__
@@ -108,6 +108,7 @@ struct iwl_txf_iter_data {
  * @dump: debug dump data
  * @ap_type_cmd: AP type tables (for enablement on 6 GHz)
  * @ap_type_cmd_valid: if &ap_type_cmd is valid
+ * @dt_compatible: true if the DT node compatible matches a supported device
  * @uefi_tables_lock_status: The status of the WIFI GUID UEFI variables lock:
  *	0: Unlocked, 1 and 2: Locked.
  *	Only read the UEFI variables if locked.
@@ -217,6 +218,9 @@ struct iwl_fw_runtime {
 	bool sgom_enabled;
 	struct iwl_mcc_allowed_ap_type_cmd ap_type_cmd;
 	bool ap_type_cmd_valid;
+#if IS_ENABLED(CONFIG_OF)
+	bool dt_compatible;
+#endif
 	u8 uefi_tables_lock_status;
 	struct iwl_phy_specific_cfg phy_filters;
 	enum bios_source dsm_source;
diff --git a/intc-scripts/publishable-files b/intc-scripts/publishable-files
index 81871178ba..91fc3f4d15 100644
--- a/intc-scripts/publishable-files
+++ b/intc-scripts/publishable-files
@@ -76,6 +76,8 @@ drivers/net/wireless/intel/iwlwifi/fw/dbg.h
 drivers/net/wireless/intel/iwlwifi/fw/debugfs.c
 drivers/net/wireless/intel/iwlwifi/fw/debugfs.h
 drivers/net/wireless/intel/iwlwifi/fw/dhc-utils.h
+drivers/net/wireless/intel/iwlwifi/fw/dt.c
+drivers/net/wireless/intel/iwlwifi/fw/dt.h
 drivers/net/wireless/intel/iwlwifi/fw/dump.c
 drivers/net/wireless/intel/iwlwifi/fw/error-dump.h
 drivers/net/wireless/intel/iwlwifi/fw/file.h
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 1/3] dt-bindings: net: wireless: Add Intel Wi-Fi 7 BE200 PCIe adapter
From: Avinash Bhatt @ 2026-05-13  6:05 UTC (permalink / raw)
  To: devicetree, linux-wireless
  Cc: robh, krzk+dt, conor+dt, johannes, miriam.rachel.korenblit,
	linux-kernel, kobi.guetta, emmanuel.grumbach
In-Reply-To: <20260513060531.8130-1-avinash.bhatt@intel.com>

The Intel Wi-Fi 7 BE200 is a discrete PCIe Wi-Fi adapter supporting
802.11be with tri-band operation including the 6 GHz band.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
---
 .../bindings/net/wireless/intel,iwlwifi.yaml  | 248 ++++++++++++++++++
 MAINTAINERS                                   |   1 +
 2 files changed, 249 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/net/wireless/intel,iwlwifi.yaml

diff --git a/Documentation/devicetree/bindings/net/wireless/intel,iwlwifi.yaml b/Documentation/devicetree/bindings/net/wireless/intel,iwlwifi.yaml
new file mode 100644
index 000000000000..e5ba5e7608e2
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/wireless/intel,iwlwifi.yaml
@@ -0,0 +1,248 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2026 Intel Corporation
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/net/wireless/intel,iwlwifi.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Intel Wi-Fi 7 BE200 PCIe adapter
+
+maintainers:
+  - Avinash Bhatt <avinash.bhatt@intel.com>
+  - Miri Korenblit <miriam.rachel.korenblit@intel.com>
+
+description:
+  Intel Wi-Fi 7 BE200 (BE200NGW) IEEE 802.11be discrete PCIe adapter.
+
+allOf:
+  - $ref: /schemas/net/wireless/ieee80211.yaml#
+
+properties:
+  compatible:
+    enum:
+      - pci8086,272b
+
+  reg:
+    maxItems: 1
+
+  intel,wrds:
+    description: |
+      SAR (Specific Absorption Rate) transmit power limits per antenna chain
+      and frequency subband, in units of 0.125 dBm.
+
+      First cell is the mode word: bit 0 set enables SAR limiting, bit 0
+      clear disables it (device uses its certified maximum).
+
+      Followed by 48 limit values for four antenna chains in order:
+      chain A, chain B, CDB chain A, CDB chain B. Each chain has 12
+      subband values covering the following frequency ranges:
+
+        [0]  2.4 GHz  ch  1-13   (2412-2472 MHz)
+        [1]  5 GHz    ch 36-64   (5180-5320 MHz)
+        [2]  5 GHz    ch 68-96   (5340-5480 MHz)
+        [3]  5 GHz    ch 100-144 (5500-5720 MHz)
+        [4]  5 GHz    ch 149-177 (5745-5885 MHz)
+        [5]  6 GHz    ch  1-45   (5955-6175 MHz)
+        [6]  6 GHz    ch 49-93   (6195-6415 MHz)
+        [7]  6 GHz    ch 97-115  (6435-6525 MHz)
+        [8]  6 GHz    ch 117-151 (6535-6705 MHz)
+        [9]  6 GHz    ch 153-183 (6715-6865 MHz)
+        [10] 6 GHz    ch 185-233 (6875-7115 MHz)
+        [11] 6 GHz    ch 237-253 (7135-7215 MHz)
+    $ref: /schemas/types.yaml#/definitions/uint32-array
+    minItems: 49
+    maxItems: 49
+
+  intel,uats:
+    description: |
+      Per-country enablement matrix for 6 GHz AP types. 338-byte array
+      encoding which AP types (AFC, VLP, LPI) are permitted per country.
+
+      Countries are identified by ISO 3166-1 alpha-2 code. The matrix
+      covers all 26x26 = 676 two-letter combinations (AA..ZZ), stored
+      column-major (all second-letter variants for first letter A first,
+      then B, and so on). 26 columns x 13 bytes = 338 bytes total.
+
+      Each country occupies 4 bits (a nibble); two countries are packed
+      per byte, low nibble first:
+        bit 0: AFC (Standard Power AP) permitted
+        bit 1: VLP (Very Low Power AP) permitted
+        bit 2: LPI (Low Power Indoor AP) permitted
+
+      A bit is only effective when the corresponding control bit in
+      intel,6e-uhb is also set (bit 30 for AFC, bit 29 for VLP,
+      bit 31 for LPI per-country mode).
+    $ref: /schemas/types.yaml#/definitions/uint8-array
+    minItems: 338
+    maxItems: 338
+
+  intel,srd:
+    description: |
+      ETSI 5.8 GHz SRD (Short Range Device) channel behaviour in the
+      5725-5875 MHz band for ETSI regulatory domains.
+
+        active-scan  - active scanning permitted (default)
+        passive-scan - device may associate and transfer data but must
+                       not transmit probe requests on SRD channels
+        disabled     - device must not scan, associate, or operate on
+                       any SRD channel
+    enum:
+      - active-scan
+      - passive-scan
+      - disabled
+
+  intel,6e-uhb:
+    description: |
+      6-7 GHz Ultra-High Band (UHB) per-country enable bitmask.
+
+        bit 0:     override control; 0 = use device defaults,
+                   1 = force-disable all countries not explicitly
+                   enabled in bits 1-25
+        bit  1:    USA
+        bit  2:    Rest of World (ROW)
+        bit  3:    EU
+        bit  4:    South Korea
+        bit  5:    Brazil
+        bit  6:    Chile
+        bit  7:    Japan
+        bit  8:    Canada
+        bit  9:    Morocco
+        bit 10:    Mongolia
+        bit 11:    Malaysia
+        bit 12:    Saudi Arabia
+        bit 13:    Mexico
+        bit 14:    Nigeria
+        bit 15:    Thailand
+        bit 16:    Singapore
+        bit 17:    Taiwan
+        bit 18:    South Africa
+        bit 19:    Philippines
+        bit 20:    Serbia
+        bit 21:    Indonesia
+        bit 22:    Azerbaijan
+        bit 23:    Paraguay
+        bit 24:    Vietnam
+        bit 25:    India
+        bit 27:    enable VLP active scan, SoftAP, and P2P-GO in Japan
+        bit 29:    enable VLP mode per intel,uats country table
+        bit 30:    enable AFC mode per intel,uats country table
+        bit 31:    use intel,uats country table for LPI (0 = group mode)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,regulatory-special:
+    description: |
+      Special regulatory configuration flags.
+
+        bit 4:    enable Australia UHB band extension
+        bit 5:    Bangladesh 6 GHz UHB enablement
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,activate-channel:
+    description: |
+      Indoor channel activation bitmask. Enables specific frequency bands
+      for active use when the platform is operating indoors.
+
+        bit 0:    EU U-NII-1 (5150-5250 MHz)
+        bit 1:    Japan U-NII-1 (5150-5250 MHz)
+        bit 2:    China Mainland U-NII-1 (5150-5250 MHz)
+        bit 3:    USA U-NII-4 (5850-5925 MHz)
+        bit 4:    Worldwide U-NII-1 (5150-5250 MHz) for any country
+                  where the band is permitted indoors
+        bit 5:    Canada U-NII-4 (5850-5925 MHz)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,force-disable-channels:
+    description: |
+      Per-band force-disable bitmask. Permanently disables specific
+      frequency bands regardless of regulatory domain.
+
+        bit  0:    2.4 GHz  (ch   1-13,  2412-2472 MHz)
+        bit  1:    5.2 GHz  (ch  36-48,  5180-5240 MHz)
+        bit  2:    5.3 GHz  (ch  52-64,  5260-5320 MHz)
+        bit  3:    5.5 GHz  (ch 100-144, 5500-5720 MHz)
+        bit  4:    5.8 GHz  (ch 149-165, 5745-5825 MHz)
+        bit  5:    5.9 GHz  (ch 169-177, 5845-5885 MHz)
+        bit  6:    6.2 GHz  (ch   1-93,  5955-6415 MHz)
+        bit  7:    6.5 GHz  (ch  97-113, 6435-6525 MHz)
+        bit  8:    6.6 GHz  (ch 117-153, 6535-6705 MHz)
+        bit  9:    6.8 GHz  (ch 157-185, 6715-6885 MHz)
+        bit 10:    7.0 GHz  (ch 185-233, 6875-7115 MHz)
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,11be:
+    description: |
+      802.11be (Wi-Fi 7) per-country enable bitmask.
+
+        bit 0:    China (CN)
+        bit 1:    South Korea
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,splc:
+    description:
+      Platform thermal power limit for the Wi-Fi core in mW. The device
+      will not exceed this limit regardless of regulatory maximums.
+    $ref: /schemas/types.yaml#/definitions/uint32
+    minimum: 1
+
+  intel,wcpe:
+    description: |
+      802.11be channel puncturing enable bitmask. When set, allows the
+      device to puncture (skip) sub-channels within a wide channel for
+      coexistence with incumbents, subject to country certification.
+
+        bit 0:    USA
+        bit 1:    Canada
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+  intel,wbem:
+    description: |
+      320 MHz channel bandwidth enable bitmask per country. Each bit
+      takes effect only if the installed module is certified for 320 MHz
+      in that country.
+
+        bit 0:    Japan
+        bit 1:    South Korea
+    $ref: /schemas/types.yaml#/definitions/uint32
+
+required:
+  - compatible
+  - reg
+
+additionalProperties: false
+
+examples:
+  - |
+    pcie {
+        #address-cells = <3>;
+        #size-cells = <2>;
+
+        pcie@0 {
+            device_type = "pci";
+            reg = <0x0 0x0 0x0 0x0 0x0>;
+            #address-cells = <3>;
+            #size-cells = <2>;
+            ranges;
+            bus-range = <0x01 0xff>;
+
+            wifi@0 {
+                compatible = "pci8086,272b";
+                reg = <0x10000 0x0 0x0 0x0 0x0>;
+
+                /* SAR power limits: mode + 4 chains x 12 subbands */
+                intel,wrds = <
+                    0x01
+                    0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38
+                    0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38 0x38
+                    0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c
+                    0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c 0x3c
+                >;
+
+                intel,splc = <4500>;
+                intel,wcpe = <0x03>;
+                intel,wbem = <0x03>;
+                intel,srd = "passive-scan";
+                intel,activate-channel = <0x01>;
+                intel,6e-uhb = <0x06>;
+            };
+        };
+    };
diff --git a/MAINTAINERS b/MAINTAINERS
index 77fdfcb55f06..674320ef137e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -13256,6 +13256,7 @@ L:	linux-wireless@vger.kernel.org
 S:	Supported
 W:	https://wireless.wiki.kernel.org/en/users/drivers/iwlwifi
 T:	git https://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi-next.git/
+F:	Documentation/devicetree/bindings/net/wireless/intel,iwlwifi.yaml
 F:	drivers/net/wireless/intel/iwlwifi/
 
 INTEL VISION SENSING CONTROLLER DRIVER
-- 
2.34.1


^ permalink raw reply related

* [PATCH v3 0/3] wifi: iwlwifi: add Device Tree hardware integration information
From: Avinash Bhatt @ 2026-05-13  6:05 UTC (permalink / raw)
  To: devicetree, linux-wireless
  Cc: robh, krzk+dt, conor+dt, johannes, miriam.rachel.korenblit,
	linux-kernel, kobi.guetta, emmanuel.grumbach

Add Device Tree support for Intel Wi-Fi hardware integration information
on platforms that do not provide UEFI variables or ACPI methods.

Patch 1/3 adds the DT binding schema for the Intel iwlwifi compatible
node. Patches 2/3 and 3/3 add the driver infrastructure and integrate
DT as the lowest-priority fallback after UEFI and ACPI; they are
included for reference to show how the binding is consumed by the
driver and will be merged through the regular iwlwifi upstreaming
process, not through the DT tree.

Changes since v2:

Binding (patch 1/3):
  - Subject and title updated to describe the BE200 hardware
  - Revision header cell removed from all properties; each property is
    now a scalar uint32 or plain fixed-size array
  - intel,wrds: reduced to 49 cells (mode word + 4x12 SAR values)
  - intel,uats: reduced to 338 bytes (26x13 country nibble matrix)
  - Removed allOf/items const: 0 constraints from all properties
  - intel,srd: changed from integer enum to string enum
    (active-scan/passive-scan/disabled)
  - Removed "reserved, must be 0" annotations; bits with no assigned
    meaning are not documented
  - Added allOf: $ref: /schemas/net/wireless/ieee80211.yaml#

Driver (patch 2/3):
  - Removed dsm_func_to_prop_name() and all IWL_DT_PROP_* defines;
    each property function now calls of_property_read_*() directly with
    the literal property string
  - Driver updated to match binding changes (no revision cells,
    string-based intel,srd, scalar uint32 DSM properties, 338-byte
    intel,uats)
  - Added iwl_dt_init() to validate DT node compatible at probe time;
    all DT reads gated on fwrt->dt_compatible
  - fw/dt.h now includes fw/runtime.h directly, making it self-contained

Fallback integration (patch 3/3):
  - No changes from v2

Link to v2: https://patchwork.kernel.org/project/linux-wireless/patch/20260504095327.30892-1-avinash.bhatt@intel.com/
Link to v1: https://patchwork.kernel.org/project/linux-wireless/patch/20260429081403.46087-2-avinash.bhatt@intel.com/
Link to RFC: https://patchwork.kernel.org/project/devicetree/patch/20260408055709.11579-2-avinash.bhatt@intel.com/

Avinash Bhatt (3):
  dt-bindings: net: wireless: Add Intel Wi-Fi 7 BE200 PCIe adapter
  wifi: iwlwifi: dt: add Device Tree BIOS configuration infrastructure
  wifi: iwlwifi: dt: use Device Tree as fallback BIOS configuration source

 .../bindings/net/wireless/intel,iwlwifi.yaml  | 248 +++++++++++++++++
 MAINTAINERS                                   |   1 +
 drivers/net/wireless/intel/iwlwifi/Makefile   |   1 +
 drivers/net/wireless/intel/iwlwifi/fw/acpi.h  |   5 +-
 .../wireless/intel/iwlwifi/fw/api/nvm-reg.h   |   4 +-
 drivers/net/wireless/intel/iwlwifi/fw/dt.c    | 332 +++++++++++++++++++
 drivers/net/wireless/intel/iwlwifi/fw/dt.h    | 161 +++++++++
 drivers/net/wireless/intel/iwlwifi/fw/init.c  |   4 +-
 .../wireless/intel/iwlwifi/fw/regulatory.c    |   3 +++
 .../wireless/intel/iwlwifi/fw/regulatory.h    |   3 +-
 drivers/net/wireless/intel/iwlwifi/fw/runtime.h |  6 +-
 drivers/net/wireless/intel/iwlwifi/mld/mld.c |   3 +++
 .../intel/iwlwifi/mld/regulatory.c            |   5 ++-
 13 files changed, 772 insertions(+), 11 deletions(-)

-- 
2.34.1

^ permalink raw reply

* Re: [PATCH] wireless-regdb: Update regulatory rules for Sri Lanka (LK)
From: Ping-Ke Shih @ 2026-05-13  5:58 UTC (permalink / raw)
  To: Mohamed Aashif; +Cc: linux-wireless, wireless-regdb
In-Reply-To: <20260506154129.64112-1-maashif011@gmail.com>

Mohamed Aashif <maashif011@gmail.com> wrote:
>
> Update Sri Lanka regulatory domain based on the RTTE Type Approval
> Rules 2020 from the Telecommunications Regulatory Commission of
> Sri Lanka (TRC).
>
> Source: https://www.trc.gov.lk/content/files/licensing/RTTE_GAZETTE-English.pdf
>
> Key changes:
> - Change DFS region from FCC to ETSI (document references ETSI
>   standards EN 300 328 and EN 301 893 as the applicable radio
>   interface standards)
> - 2.4 GHz: expand to 2400-2483.5 MHz at 200 mW (was 2402-2482 at 20 dBm)
> - 5150-5350 MHz: 200 mW with DFS

TPC is not supported, so 5250-5350 should be 20dBm (100mW) as description of
ESTI EN 301 893. Since we can extend adjacent channels, add AUTO-BW attribute
to them.

> - 5470-5725 MHz: 1000 mW with DFS

By source, 1000mW is only for outdoor application. Should be 500mW.
Then, it also satisfies the limit 27 dBm defined by ESTI EN 301 893 without TPC.

> - 5725-5875 MHz: 1000 mW with DFS

I think the range should be reference to ETSI EN 302 502, which EIRP level to a
level not exceeding 24 dBm for ChS = 20 MHz and 21 dBm for ChS = 10 MHz.
Then, this rule should be 24 dBm.

However the source points to standard EN 301 893 (wrongly?).

>
> Signed-off-by: Mohamed Aashif <maashif011@gmail.com>
> ---
>  db.txt | 14 ++++++++------
>  1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/db.txt b/db.txt
> index fdc2c13..d265176 100644
> --- a/db.txt
> +++ b/db.txt
> @@ -1058,12 +1058,14 @@ country LI: DFS-ETSI
>         # 60 GHz band channels 1-4 (ETSI EN 302 567)
>         (57000 - 66000 @ 2160), (40)
>
> -country LK: DFS-FCC
> -       (2402 - 2482 @ 40), (20)
> -       (5170 - 5250 @ 20), (17)
> -       (5250 - 5330 @ 20), (24), DFS
> -       (5490 - 5730 @ 20), (24), DFS
> -       (5735 - 5835 @ 20), (30)
> +# Source:
> +# https://www.trc.gov.lk/content/files/licensing/RTTE_GAZETTE-English.pdf
> +# Sri Lanka RTTE Type Approval Rules 2020, Table 6 - Wideband Data Transmission
> +country LK: DFS-ETSI
> +       (2400 - 2483.5 @ 40), (200 mW)
> +       (5150 - 5350 @ 160), (200 mW), DFS
> +       (5470 - 5725 @ 160), (1000 mW), DFS
> +       (5725 - 5875 @ 80), (1000 mW), DFS
>
>  # Source:
>  # http://lca.org.ls/images/documents/lesotho_national_frequency_allocation_plan.pdf
> --
> 2.54.0
>
>

^ permalink raw reply

* [PATCH iwlwifi-next 15/15] wifi: iwlwifi: mld: set correct key mask for NAN
From: Miri Korenblit @ 2026-05-13  5:44 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg, Ilan Peer
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

For NAN data, the supplicant may derive and install GTKs to
transmit with. As multicast data encryption is supported only
with firmware versions that support adding NAN multicast
data station, allow GTK installation only with such FW
versions. Otherwise, do not install the GTK to the device.

For NAN management, there are no GTKs, but there are IGTKs
and BIGTKs, which need to be installed for the NAN broadcast
and NAN management stations. This is supported only with
firmware versions that allow adding NAN broadcast station
and NAN management station.

Handle both of these cases by adjusting the station mask
appropriately, returning a zero station mask for the GTK
and allowing that to not be an error/warning message.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Co-developed-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/mld/iface.c    |  2 +
 .../net/wireless/intel/iwlwifi/mld/iface.h    |  3 ++
 drivers/net/wireless/intel/iwlwifi/mld/key.c  | 50 +++++++++++++++++--
 .../net/wireless/intel/iwlwifi/mld/mac80211.c |  1 -
 drivers/net/wireless/intel/iwlwifi/mld/sta.c  |  8 ++-
 5 files changed, 59 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index 399efeb469f6..2b837c6fa5fe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -66,6 +66,8 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
 			iwl_mld_free_internal_sta(mld, &mld_vif->nan.bcast_sta);
 		if (mld_vif->nan.mgmt_sta.sta_id != IWL_INVALID_STA)
 			iwl_mld_free_internal_sta(mld, &mld_vif->nan.mgmt_sta);
+
+		mld_vif->nan.tx_igtk = NULL;
 	}
 
 	if (vif->type == NL80211_IFTYPE_NAN_DATA &&
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
index c6a7588df1fa..bc6f45ff76f8 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
@@ -160,6 +160,8 @@ struct iwl_mld_emlsr {
  * @nan.mgmt_sta: internal station used for NAN management frames, e.g., SDFs
  *	and NAFs.
  * @nan.mcast_data_sta: internal station used for multicast NAN Data frames.
+ * @nan.tx_igtk: TX IGTK key for NAN, tracked separately since NAN does not
+ *	use the vif links.
  */
 struct iwl_mld_vif {
 	/* Add here fields that need clean up on restart */
@@ -189,6 +191,7 @@ struct iwl_mld_vif {
 		struct iwl_mld_int_sta bcast_sta;
 		struct iwl_mld_int_sta mgmt_sta;
 		struct iwl_mld_int_sta mcast_data_sta;
+		struct ieee80211_key_conf *tx_igtk;
 	} nan;
 
 	struct iwl_mld_emlsr emlsr;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/key.c b/drivers/net/wireless/intel/iwlwifi/mld/key.c
index 151e35b851f7..a6454d90d0e3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/key.c
@@ -63,6 +63,40 @@ static u32 iwl_mld_get_key_sta_mask(struct iwl_mld *mld,
 
 	lockdep_assert_wiphy(mld->wiphy);
 
+	if (vif->type == NL80211_IFTYPE_NAN_DATA && !sta) {
+		/* Older firmware versions do not support transmission of
+		 * multicast data frames.
+		 */
+		if (!iwl_mld_nan_use_nan_stations(mld))
+			return 0;
+
+		if (WARN_ON(mld_vif->nan.mcast_data_sta.sta_id ==
+			    IWL_INVALID_STA))
+			return 0;
+
+		return BIT(mld_vif->nan.mcast_data_sta.sta_id);
+	}
+
+	if (vif->type == NL80211_IFTYPE_NAN && !sta) {
+		/* Older firmware versions do not support installation of
+		 * IGTK/BIGTK keys.
+		 */
+		if (!iwl_mld_nan_use_nan_stations(mld))
+			return 0;
+
+		if (WARN_ON(mld_vif->nan.bcast_sta.sta_id == IWL_INVALID_STA ||
+			    mld_vif->nan.mgmt_sta.sta_id == IWL_INVALID_STA))
+			return 0;
+
+		if (key->keyidx >= 4 && key->keyidx <= 5)
+			return BIT(mld_vif->nan.mgmt_sta.sta_id);
+
+		if (key->keyidx >= 6 && key->keyidx <= 7)
+			return BIT(mld_vif->nan.bcast_sta.sta_id);
+
+		return 0;
+	}
+
 	/* AP group keys are per link and should be on the mcast/bcast STA */
 	if (vif->type == NL80211_IFTYPE_AP &&
 	    !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) {
@@ -204,7 +238,7 @@ iwl_mld_get_igtk_ptr(struct ieee80211_vif *vif,
 			return &mld_sta->deflink.rx_igtk;
 		}
 
-		return &mld_vif->deflink.tx_igtk;
+		return &mld_vif->nan.tx_igtk;
 	case NL80211_IFTYPE_AP:
 		mld_link = iwl_mld_link_dereference_check(mld_vif, link_id);
 		if (WARN_ON(!mld_link))
@@ -254,8 +288,16 @@ int iwl_mld_add_key(struct iwl_mld *mld,
 
 	lockdep_assert_wiphy(mld->wiphy);
 
-	if (!sta_mask)
+	if (!sta_mask) {
+		/* for NAN (GTK) indicate SW-only, it's not used at all */
+		if (vif->type == NL80211_IFTYPE_NAN_DATA && !sta &&
+		    !iwl_mld_nan_use_nan_stations(mld))
+			return 1;
+
+		/* otherwise that's not valid */
+		IWL_WARN(mld, "empty STA mask for key %d\n", key->keyidx);
 		return -EINVAL;
+	}
 
 	igtk_ptr = iwl_mld_get_igtk_ptr(vif, sta, key);
 	if (igtk_ptr) {
@@ -270,8 +312,10 @@ int iwl_mld_add_key(struct iwl_mld *mld,
 	}
 
 	ret = iwl_mld_add_key_to_fw(mld, sta_mask, key_flags, key);
-	if (ret)
+	if (ret) {
+		IWL_WARN(mld, "failed to add key to FW (%d)\n", ret);
 		return ret;
+	}
 
 	if (igtk_ptr) {
 		WARN_ON(*igtk_ptr);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index b6df09812dae..9736b43155d6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -2248,7 +2248,6 @@ static int iwl_mld_set_key_add(struct iwl_mld *mld,
 
 	ret = iwl_mld_add_key(mld, vif, sta, key);
 	if (ret) {
-		IWL_WARN(mld, "set key failed (%d)\n", ret);
 		if (ptk_pn) {
 			RCU_INIT_POINTER(mld_sta->ptk_pn[keyidx], NULL);
 			kfree(ptk_pn);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index cd13238ed613..77eeeed66116 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -1089,8 +1089,14 @@ iwl_mld_set_internal_sta_to_fw(struct iwl_mld *mld,
 	 * On the other hand, FW will never check this flag during RX since
 	 * an AP/GO doesn't receive protected broadcast management frames.
 	 * So, we can set it unconditionally.
+	 *
+	 * For NAN stations associated with a NAN Device, the MFP bit must be
+	 * set to 1, as otherwise the FW will assert when a key associated with
+	 * these stations would be added.
 	 */
-	if (internal_sta->sta_type == STATION_TYPE_BCAST_MGMT)
+	if (internal_sta->sta_type == STATION_TYPE_BCAST_MGMT ||
+	    internal_sta->sta_type == STATION_TYPE_NAN_BCAST ||
+	    internal_sta->sta_type == STATION_TYPE_NAN_MGMT)
 		cmd.mfp = cpu_to_le32(1);
 
 	if (addr) {
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 14/15] wifi: iwlwifi: mld: Add support for NAN multicast data
From: Miri Korenblit @ 2026-05-13  5:44 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ilan Peer
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

From: Ilan Peer <ilan.peer@intel.com>

The FW added a new station type to allow NAN multicast
data to be transmitted. The queue of the station is
opened by the firmware when all the NAN Peer NDI stations
associated with the NDI are scheduled at the same time.

Add the corresponding support in iwlmld:

- When a NAN data interface is added, add a NAN multicast
  data station and allocate a queue to it.
- When a NAN data interface is removed, remove the NAN
  multicast station.
- On the Tx path, when a multicast data frame is received
  on a NAN data interface, direct it to the NAN multicast
  data queue.

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../wireless/intel/iwlwifi/fw/api/mac-cfg.h   |  6 +-
 .../net/wireless/intel/iwlwifi/mld/iface.c    |  6 ++
 .../net/wireless/intel/iwlwifi/mld/iface.h    |  2 +
 .../net/wireless/intel/iwlwifi/mld/mac80211.c | 32 ++++++-
 drivers/net/wireless/intel/iwlwifi/mld/nan.c  | 29 +++++-
 drivers/net/wireless/intel/iwlwifi/mld/nan.h  |  2 +
 drivers/net/wireless/intel/iwlwifi/mld/sta.c  | 94 ++++++++++++++++---
 drivers/net/wireless/intel/iwlwifi/mld/sta.h  | 11 +++
 drivers/net/wireless/intel/iwlwifi/mld/tx.c   | 11 ++-
 9 files changed, 172 insertions(+), 21 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index 604281eb29c7..d03a2bda4e68 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -747,6 +747,8 @@ struct iwl_link_config_cmd {
  *	discovery. No queue is associated with this station.
  * @STATION_TYPE_NAN_MGMT: NAN station used for NAN management frames, e.g.,
  *	SDFs and NAFs.
+ * @STATION_TYPE_NAN_MCAST_DATA: NAN station used for multicast NAN data
+ *	frames.
  * @STATION_TYPE_MAX: maximum number of FW station types
  * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
  *	for the aux sta, so this type is only for driver - internal use.
@@ -759,6 +761,7 @@ enum iwl_fw_sta_type {
 	STATION_TYPE_NAN_PEER_NDI,
 	STATION_TYPE_NAN_BCAST,
 	STATION_TYPE_NAN_MGMT,
+	STATION_TYPE_NAN_MCAST_DATA,
 	STATION_TYPE_MAX,
 	STATION_TYPE_AUX = STATION_TYPE_MAX /* this doesn't exist in FW */
 }; /* STATION_TYPE_E_VER_1, _VER_2 */
@@ -933,7 +936,8 @@ struct iwl_sta_cfg_cmd_v2 {
  * @mic_prep_pad_delay: MIC prep time padding
  * @mic_compute_pad_delay: MIC compute time padding
  * @nmi_sta_id: for an NDI peer STA, the NMI peer STA ID it relates to
- * @ndi_local_addr: for an NDI peer STA, the local NDI interface MAC address
+ * @ndi_local_addr: for an NDI peer STA or NAN multicast data station,
+ *	the local NDI interface MAC address
  * @reserved: Reserved for alignment
  */
 struct iwl_sta_cfg_cmd {
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index f7a0a8efe374..399efeb469f6 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -68,6 +68,10 @@ void iwl_mld_cleanup_vif(void *data, u8 *mac, struct ieee80211_vif *vif)
 			iwl_mld_free_internal_sta(mld, &mld_vif->nan.mgmt_sta);
 	}
 
+	if (vif->type == NL80211_IFTYPE_NAN_DATA &&
+	    mld_vif->nan.mcast_data_sta.sta_id != IWL_INVALID_STA)
+		iwl_mld_free_internal_sta(mld, &mld_vif->nan.mcast_data_sta);
+
 	CLEANUP_STRUCT(mld_vif);
 }
 
@@ -534,6 +538,8 @@ iwl_mld_init_vif(struct iwl_mld *mld, struct ieee80211_vif *vif)
 
 		iwl_mld_init_internal_sta(&mld_vif->nan.bcast_sta);
 		iwl_mld_init_internal_sta(&mld_vif->nan.mgmt_sta);
+	} else if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+		iwl_mld_init_internal_sta(&mld_vif->nan.mcast_data_sta);
 	}
 
 	iwl_mld_init_internal_sta(&mld_vif->aux_sta);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.h b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
index 75b6727503d3..c6a7588df1fa 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.h
@@ -159,6 +159,7 @@ struct iwl_mld_emlsr {
  *	activities. No queue is associated with it.
  * @nan.mgmt_sta: internal station used for NAN management frames, e.g., SDFs
  *	and NAFs.
+ * @nan.mcast_data_sta: internal station used for multicast NAN Data frames.
  */
 struct iwl_mld_vif {
 	/* Add here fields that need clean up on restart */
@@ -187,6 +188,7 @@ struct iwl_mld_vif {
 		bool mac_added;
 		struct iwl_mld_int_sta bcast_sta;
 		struct iwl_mld_int_sta mgmt_sta;
+		struct iwl_mld_int_sta mcast_data_sta;
 	} nan;
 
 	struct iwl_mld_emlsr emlsr;
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 1f2843af39c1..b6df09812dae 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -663,8 +663,27 @@ int iwl_mld_mac80211_add_interface(struct ieee80211_hw *hw,
 	if (ret)
 		return ret;
 
-	if (vif->type == NL80211_IFTYPE_NAN_DATA)
+	if (vif->type == NL80211_IFTYPE_NAN_DATA) {
+		if (WARN_ON(!mld->nan_device_vif)) {
+			ret = -EINVAL;
+			goto err;
+		}
+
+		if (iwl_mld_nan_use_nan_stations(mld)) {
+			struct iwl_mld_vif *mld_vif =
+				iwl_mld_vif_from_mac80211(vif);
+			struct iwl_mld_int_sta *sta =
+				&mld_vif->nan.mcast_data_sta;
+
+			ret = iwl_mld_add_nan_mcast_data_sta(mld,
+							     vif->addr,
+							     sta);
+			if (ret)
+				goto err;
+		}
+
 		return 0;
+	}
 
 	/*
 	 * Add the default link, but not if this is an MLD vif as that implies
@@ -732,10 +751,17 @@ void iwl_mld_mac80211_remove_interface(struct ieee80211_hw *hw,
 	if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
 		mld->p2p_device_vif = NULL;
 
-	if (vif->type == NL80211_IFTYPE_NAN)
+	if (vif->type == NL80211_IFTYPE_NAN) {
 		mld->nan_device_vif = NULL;
-	else if (vif->type != NL80211_IFTYPE_NAN_DATA)
+	} else if (vif->type != NL80211_IFTYPE_NAN_DATA) {
 		iwl_mld_remove_link(mld, &vif->bss_conf);
+	} else if (iwl_mld_nan_use_nan_stations(mld)) {
+		struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+		struct iwl_mld_int_sta *sta = &mld_vif->nan.mcast_data_sta;
+
+		if (sta->sta_id != IWL_INVALID_STA)
+			iwl_mld_remove_nan_mcast_data_sta(mld, sta);
+	}
 
 #ifdef CONFIG_IWLWIFI_DEBUGFS
 	debugfs_remove(iwl_mld_vif_from_mac80211(vif)->dbgfs_slink);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
index 8f35687c58b1..530ba263c5f0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
@@ -50,7 +50,7 @@ static int iwl_mld_nan_send_config_cmd(struct iwl_mld *mld,
 	return iwl_mld_send_cmd(mld, &hcmd);
 }
 
-static bool iwl_mld_nan_use_nan_stations(struct iwl_mld *mld)
+bool iwl_mld_nan_use_nan_stations(struct iwl_mld *mld)
 {
 	/*
 	 * If the FW supports version 1 of the NAN config command, it means that
@@ -650,6 +650,20 @@ iwl_mld_nan_find_link(struct iwl_mld_vif *mld_vif,
 	return NULL;
 }
 
+static void iwl_mld_nan_set_mcast_data_links(struct ieee80211_vif *vif)
+{
+	struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
+
+	if (vif->type != NL80211_IFTYPE_NAN_DATA)
+		return;
+
+	/* Note that all errors are handled internally so nothing to do
+	 * with the return value (used only to silence compilation warnings)
+	 */
+	iwl_mld_update_nan_mcast_data_sta(mld_vif->mld, vif->addr,
+					  &mld_vif->nan.mcast_data_sta);
+}
+
 void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
 				 struct ieee80211_vif *vif,
 				 u64 changes)
@@ -807,6 +821,19 @@ void iwl_mld_nan_vif_cfg_changed(struct iwl_mld *mld,
 			    mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI)
 				iwl_mld_add_modify_sta_cmd(mld, &sta->deflink);
 		}
+
+		/*
+		 * Iterate over all the NAN Data interfaces and update the links
+		 * for the internal multicast data station.
+		 * In recovery - the station will be added later in
+		 * drv_add_interface
+		 */
+		if (iwl_mld_nan_use_nan_stations(mld) && !mld->fw_status.in_hw_restart) {
+			struct ieee80211_vif *iter;
+
+			for_each_active_interface(iter, mld->hw)
+				iwl_mld_nan_set_mcast_data_links(iter);
+		}
 	}
 
 	/* delete unused links */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h
index 40152dc7d906..f4e4cd4b4e8d 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h
@@ -60,4 +60,6 @@ int iwl_mld_mac802111_nan_peer_sched_changed(struct ieee80211_hw *hw,
 
 int iwl_mld_nan_get_mgmt_queue(struct iwl_mld *mld, struct ieee80211_vif *vif);
 
+bool iwl_mld_nan_use_nan_stations(struct iwl_mld *mld);
+
 #endif /* __iwl_mld_nan_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 4c168ad53b0f..cd13238ed613 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -428,6 +428,10 @@ static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
 
 		len = sizeof(struct iwl_sta_cfg_cmd_v2);
 		cmd_v2->link_id = cpu_to_le32(__ffs(le32_to_cpu(cmd->link_mask)));
+	} else if (cmd->station_type ==
+		   cpu_to_le32(STATION_TYPE_NAN_MCAST_DATA)) {
+		if (WARN_ON(!hweight32(le32_to_cpu(cmd->link_mask))))
+			return -EINVAL;
 	} else if (WARN_ON(cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NMI) &&
 			   cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_PEER_NDI) &&
 			   cmd->station_type != cpu_to_le32(STATION_TYPE_NAN_BCAST) &&
@@ -442,6 +446,19 @@ static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
 	return ret;
 }
 
+static u32 iwl_mld_get_nan_link_mask(struct iwl_mld *mld)
+{
+	struct iwl_mld_vif *nan_dev =
+		iwl_mld_vif_from_mac80211(mld->nan_device_vif);
+	struct iwl_mld_nan_link *nan_link;
+	u32 link_mask = 0;
+
+	for_each_mld_nan_valid_link(nan_dev, nan_link)
+		link_mask |= BIT(nan_link->fw_id);
+
+	return link_mask;
+}
+
 int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
 			      struct ieee80211_link_sta *link_sta)
 {
@@ -459,21 +476,13 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
 
 	if (mld_sta->sta_type == STATION_TYPE_NAN_PEER_NMI ||
 	    mld_sta->sta_type == STATION_TYPE_NAN_PEER_NDI) {
-		struct iwl_mld_nan_link *nan_link;
-		struct iwl_mld_vif *nan_dev;
-
-		is_6ghz = false;
-		uora_exists = false;
-
 		if (WARN_ON(!mld->nan_device_vif))
 			return -EINVAL;
 
-		nan_dev = iwl_mld_vif_from_mac80211(mld->nan_device_vif);
-
-		link_mask = 0;
+		is_6ghz = false;
+		uora_exists = false;
 
-		for_each_mld_nan_valid_link(nan_dev, nan_link)
-			link_mask |= BIT(nan_link->fw_id);
+		link_mask = iwl_mld_get_nan_link_mask(mld);
 	} else {
 		struct ieee80211_bss_conf *link;
 		struct iwl_mld_link *mld_link;
@@ -1063,7 +1072,7 @@ static int iwl_mld_send_aux_sta_cmd(struct iwl_mld *mld,
 }
 
 static int
-iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld,
+iwl_mld_set_internal_sta_to_fw(struct iwl_mld *mld,
 			       const struct iwl_mld_int_sta *internal_sta,
 			       u32 link_mask, const u8 *addr)
 {
@@ -1085,8 +1094,12 @@ iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld,
 		cmd.mfp = cpu_to_le32(1);
 
 	if (addr) {
-		memcpy(cmd.peer_mld_address, addr, ETH_ALEN);
-		memcpy(cmd.peer_link_address, addr, ETH_ALEN);
+		if (internal_sta->sta_type == STATION_TYPE_NAN_MCAST_DATA) {
+			ether_addr_copy(cmd.ndi_local_addr, addr);
+		} else {
+			memcpy(cmd.peer_mld_address, addr, ETH_ALEN);
+			memcpy(cmd.peer_link_address, addr, ETH_ALEN);
+		}
 	}
 
 	return iwl_mld_send_sta_cmd(mld, &cmd);
@@ -1108,7 +1121,7 @@ static int iwl_mld_add_internal_sta(struct iwl_mld *mld,
 
 	internal_sta->sta_type = sta_type;
 
-	ret = iwl_mld_add_internal_sta_to_fw(mld, internal_sta, link_mask,
+	ret = iwl_mld_set_internal_sta_to_fw(mld, internal_sta, link_mask,
 					     addr);
 	if (ret)
 		goto err;
@@ -1432,6 +1445,51 @@ int iwl_mld_add_nan_mgmt_sta(struct iwl_mld *mld,
 					0, NULL, IWL_MAX_TID_COUNT, true);
 }
 
+int iwl_mld_add_nan_mcast_data_sta(struct iwl_mld *mld,
+				   const u8 *ndi_addr,
+				   struct iwl_mld_int_sta *sta)
+{
+	u32 link_mask = iwl_mld_get_nan_link_mask(mld);
+
+	/* In case that there are no NAN links, nothing to do */
+	if (!link_mask)
+		return 0;
+
+	return iwl_mld_add_internal_sta(mld, sta,
+					STATION_TYPE_NAN_MCAST_DATA,
+					link_mask, ndi_addr,
+					0, true);
+}
+
+int iwl_mld_update_nan_mcast_data_sta(struct iwl_mld *mld,
+				      const u8 *ndi_addr,
+				      struct iwl_mld_int_sta *sta)
+{
+	u32 link_mask;
+
+	if (WARN_ON(!mld->nan_device_vif))
+		return -EINVAL;
+
+	/* If the sta doesn't exist, add it */
+	if (sta->sta_id == IWL_INVALID_STA)
+		return iwl_mld_add_nan_mcast_data_sta(mld, ndi_addr, sta);
+
+	/* The station was already added */
+	if (WARN_ON(sta->sta_type != STATION_TYPE_NAN_MCAST_DATA))
+		return -EINVAL;
+
+	link_mask = iwl_mld_get_nan_link_mask(mld);
+	if (link_mask)
+		return iwl_mld_set_internal_sta_to_fw(mld,
+						      sta, link_mask,
+						      ndi_addr);
+
+	/* If no links are associated with NAN, remove the station */
+	iwl_mld_remove_nan_mcast_data_sta(mld, sta);
+
+	return 0;
+}
+
 void iwl_mld_remove_nan_bcast_sta(struct iwl_mld *mld,
 				  struct iwl_mld_int_sta *sta)
 {
@@ -1443,3 +1501,9 @@ void iwl_mld_remove_nan_mgmt_sta(struct iwl_mld *mld,
 {
 	iwl_mld_remove_internal_sta(mld, sta, true, IWL_MAX_TID_COUNT);
 }
+
+void iwl_mld_remove_nan_mcast_data_sta(struct iwl_mld *mld,
+				       struct iwl_mld_int_sta *sta)
+{
+	iwl_mld_remove_internal_sta(mld, sta, true, 0);
+}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.h b/drivers/net/wireless/intel/iwlwifi/mld/sta.h
index df859a9e5230..98d693235c66 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.h
@@ -283,10 +283,21 @@ int iwl_mld_add_nan_bcast_sta(struct iwl_mld *mld,
 int iwl_mld_add_nan_mgmt_sta(struct iwl_mld *mld,
 			     struct iwl_mld_int_sta *sta);
 
+int iwl_mld_add_nan_mcast_data_sta(struct iwl_mld *mld,
+				   const u8 *ndi_addr,
+				   struct iwl_mld_int_sta *sta);
+
+int iwl_mld_update_nan_mcast_data_sta(struct iwl_mld *mld,
+				      const u8 *ndi_addr,
+				      struct iwl_mld_int_sta *sta);
+
 void iwl_mld_remove_nan_bcast_sta(struct iwl_mld *mld,
 				  struct iwl_mld_int_sta *sta);
 
 void iwl_mld_remove_nan_mgmt_sta(struct iwl_mld *mld,
 				 struct iwl_mld_int_sta *sta);
 
+void iwl_mld_remove_nan_mcast_data_sta(struct iwl_mld *mld,
+				       struct iwl_mld_int_sta *sta);
+
 #endif /* __iwl_mld_sta_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tx.c b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
index 39e1d959e42c..1100f7f1e76f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tx.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tx.c
@@ -351,7 +351,8 @@ u8 iwl_mld_get_lowest_rate(struct iwl_mld *mld,
 	iwl_mld_get_basic_rates_and_band(mld, vif, info, &basic_rates, &band);
 
 	if (band >= NUM_NL80211_BANDS) {
-		WARN_ON(vif->type != NL80211_IFTYPE_NAN);
+		WARN_ON(vif->type != NL80211_IFTYPE_NAN &&
+			vif->type != NL80211_IFTYPE_NAN_DATA);
 		return IWL_FIRST_OFDM_RATE;
 	}
 
@@ -682,6 +683,14 @@ iwl_mld_get_tx_queue_id(struct iwl_mld *mld, struct ieee80211_txq *txq,
 	case NL80211_IFTYPE_NAN:
 		WARN_ON(!ieee80211_is_mgmt(fc));
 		return iwl_mld_nan_get_mgmt_queue(mld, info->control.vif);
+	case NL80211_IFTYPE_NAN_DATA:
+		WARN_ON(!ieee80211_is_data(fc));
+
+		if (!iwl_mld_nan_use_nan_stations(mld))
+			break;
+
+		mld_vif = iwl_mld_vif_from_mac80211(info->control.vif);
+		return mld_vif->nan.mcast_data_sta.queue_id;
 	default:
 		WARN_ONCE(1, "Unsupported vif type\n");
 		break;
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 13/15] wifi: iwlwifi: mld: Replace static declarations of IWL_MLD_ALLOC_FN
From: Miri Korenblit @ 2026-05-13  5:44 UTC (permalink / raw)
  To: linux-wireless; +Cc: Ilan Peer
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

From: Ilan Peer <ilan.peer@intel.com>

Replace static declarations of IWL_MLD_ALLOC_FN with a new macro
IWL_MLD_ALLOC_FN_STATIC that declares the static.

This is needed to resolve issues with spatch, which fails to handle
functions after "static IWL_MLD_ALLOC_FN".

Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/iface.c       | 2 +-
 drivers/net/wireless/intel/iwlwifi/mld/mld.h         | 3 +++
 drivers/net/wireless/intel/iwlwifi/mld/sta.c         | 2 +-
 drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c | 6 +++---
 4 files changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index 2a270d689de8..f7a0a8efe374 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -499,7 +499,7 @@ static void iwl_mld_mlo_scan_start_wk(struct wiphy *wiphy,
 	iwl_mld_int_mlo_scan(mld, iwl_mld_vif_to_mac80211(mld_vif));
 }
 
-static IWL_MLD_ALLOC_FN(vif, vif)
+IWL_MLD_ALLOC_FN_STATIC(vif, vif)
 
 /* Constructor function for struct iwl_mld_vif */
 static void
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.h b/drivers/net/wireless/intel/iwlwifi/mld/mld.h
index 1a59b3e4014d..922aa3dbff54 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.h
@@ -552,6 +552,9 @@ iwl_mld_allocate_##_type##_fw_id(struct iwl_mld *mld,					\
 	return -ENOSPC;									\
 }
 
+#define IWL_MLD_ALLOC_FN_STATIC(_type, _mac80211_type) \
+static IWL_MLD_ALLOC_FN(_type, _mac80211_type)
+
 static inline struct ieee80211_bss_conf *
 iwl_mld_fw_id_to_link_conf(struct iwl_mld *mld, u8 fw_link_id)
 {
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 1fae5a6ba8d4..4c168ad53b0f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -577,7 +577,7 @@ int iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
 	return iwl_mld_send_sta_cmd(mld, &cmd);
 }
 
-static IWL_MLD_ALLOC_FN(link_sta, link_sta)
+IWL_MLD_ALLOC_FN_STATIC(link_sta, link_sta)
 
 static int
 iwl_mld_add_link_sta(struct iwl_mld *mld, struct ieee80211_link_sta *link_sta)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
index 0cdbbb86dbd9..cb1968b07452 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/utils.c
@@ -2,7 +2,7 @@
 /*
  * KUnit tests for channel helper functions
  *
- * Copyright (C) 2024-2025 Intel Corporation
+ * Copyright (C) 2024-2026 Intel Corporation
  */
 #include <kunit/test.h>
 #include <kunit/test-bug.h>
@@ -92,7 +92,7 @@ static void iwlmld_kunit_init_link(struct ieee80211_vif *vif,
 	rcu_assign_pointer(vif->link_conf[link_id], link);
 }
 
-static IWL_MLD_ALLOC_FN(vif, vif)
+IWL_MLD_ALLOC_FN_STATIC(vif, vif)
 
 /* Helper function to add and initialize a VIF for KUnit tests */
 struct ieee80211_vif *iwlmld_kunit_add_vif(bool mlo, enum nl80211_iftype type)
@@ -197,7 +197,7 @@ void iwlmld_kunit_assign_chanctx_to_link(struct ieee80211_vif *vif,
 		vif->active_links |= BIT(link->link_id);
 }
 
-static IWL_MLD_ALLOC_FN(link_sta, link_sta)
+IWL_MLD_ALLOC_FN_STATIC(link_sta, link_sta)
 
 static void iwlmld_kunit_add_link_sta(struct ieee80211_sta *sta,
 				      struct ieee80211_link_sta *link_sta,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 12/15] wifi: iwlwifi: define MODULE_FIRMWARE with the correct API
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

A firmware API of a mix and match (MAC + RF) is the lower one of the
two. But the MODULE_FIRMWARE of QU/QUZ/SO/MA/TY with GF/HR, was defined
using the max API of GF/HR, which is 100, instead of the max API of
QU/QUZ/SO/MA/TY, which are API 77/89.
Therefore, the wrong firmware files were published in the modinfo,
leading to missing firmware files.

Fix this by using the right API when declaring MODULE_FIRMWARE.

While at it, add a IWL_FW_AND_PNVM entry for SO and GF4, that was
missing.

Fixes: db35444d557f ("wifi: iwlwifi: assign a FW API range for HR")
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/cfg/22000.c    | 12 ++++++++
 .../net/wireless/intel/iwlwifi/cfg/ax210.c    | 29 +++++++++++++++++++
 .../net/wireless/intel/iwlwifi/cfg/rf-gf.c    | 13 ---------
 .../net/wireless/intel/iwlwifi/cfg/rf-hr.c    | 24 ---------------
 4 files changed, 41 insertions(+), 37 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index e929a08e7585..01ca65eb5acd 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -16,9 +16,18 @@
 #define IWL_22000_UCODE_API_MIN	77
 
 #define IWL_CC_A_FW_PRE			"iwlwifi-cc-a0"
+#define IWL_QU_B_HR_B_FW_PRE		"iwlwifi-Qu-b0-hr-b0"
+#define IWL_QU_C_HR_B_FW_PRE		"iwlwifi-Qu-c0-hr-b0"
+#define IWL_QUZ_A_HR_B_FW_PRE		"iwlwifi-QuZ-a0-hr-b0"
 
 #define IWL_CC_A_MODULE_FIRMWARE(api)			\
 	IWL_CC_A_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_QU_B_HR_B_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_QUZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode"
 
 static const struct iwl_family_base_params iwl_22000_base = {
 	.num_of_queues = 512,
@@ -104,4 +113,7 @@ const char iwl_ax201_killer_1650s_name[] =
 const char iwl_ax201_killer_1650i_name[] =
 	"Killer(R) Wi-Fi 6 AX1650i 160MHz Wireless Network Adapter (201NGW)";
 
+MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_CC_A_MODULE_FIRMWARE(IWL_22000_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
index ec1951a94e23..2519f577669e 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
@@ -15,6 +15,24 @@
 /* Lowest firmware API version supported */
 #define IWL_AX210_UCODE_API_MIN	89
 
+#define IWL_SO_A_GF_A_FW_PRE		"iwlwifi-so-a0-gf-a0"
+#define IWL_TY_A_GF_A_FW_PRE		"iwlwifi-ty-a0-gf-a0"
+#define IWL_MA_A_GF_A_FW_PRE		"iwlwifi-ma-a0-gf-a0"
+#define IWL_MA_B_GF_A_FW_PRE		"iwlwifi-ma-b0-gf-a0"
+#define IWL_SO_A_GF4_A_FW_PRE		"iwlwifi-so-a0-gf4-a0"
+#define IWL_MA_A_GF4_A_FW_PRE		"iwlwifi-ma-a0-gf4-a0"
+#define IWL_MA_B_GF4_A_FW_PRE		"iwlwifi-ma-b0-gf4-a0"
+#define IWL_SO_A_HR_B_FW_PRE		"iwlwifi-so-a0-hr-b0"
+#define IWL_MA_A_HR_B_FW_PRE		"iwlwifi-ma-a0-hr-b0"
+#define IWL_MA_B_HR_B_FW_PRE		"iwlwifi-ma-b0-hr-b0"
+
+#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_SO_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL_MA_A_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_MA_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
+#define IWL_MA_B_HR_B_MODULE_FIRMWARE(api)	\
+	IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode"
+
 static const struct iwl_family_base_params iwl_ax210_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
@@ -112,3 +130,14 @@ const struct iwl_mac_cfg iwl_ma_mac_cfg = {
 	.integrated = true,
 	.umac_prph_offset = 0x300000
 };
+
+IWL_FW_AND_PNVM(IWL_SO_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_TY_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_MA_A_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_MA_B_GF_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_SO_A_GF4_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_MA_A_GF4_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+IWL_FW_AND_PNVM(IWL_MA_B_GF4_A_FW_PRE, IWL_AX210_UCODE_API_MAX);
+MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_MA_A_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX));
+MODULE_FIRMWARE(IWL_MA_B_HR_B_MODULE_FIRMWARE(IWL_AX210_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c
index e6f7066f5c7c..8b63cdb3d66c 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-gf.c
@@ -11,13 +11,6 @@
 /* Lowest firmware API version supported */
 #define IWL_GF_UCODE_API_MIN	100
 
-#define IWL_SO_A_GF_A_FW_PRE		"iwlwifi-so-a0-gf-a0"
-#define IWL_TY_A_GF_A_FW_PRE		"iwlwifi-ty-a0-gf-a0"
-#define IWL_MA_A_GF_A_FW_PRE		"iwlwifi-ma-a0-gf-a0"
-#define IWL_MA_B_GF_A_FW_PRE		"iwlwifi-ma-b0-gf-a0"
-#define IWL_SO_A_GF4_A_FW_PRE		"iwlwifi-so-a0-gf4-a0"
-#define IWL_MA_A_GF4_A_FW_PRE		"iwlwifi-ma-a0-gf4-a0"
-#define IWL_MA_B_GF4_A_FW_PRE		"iwlwifi-ma-b0-gf4-a0"
 #define IWL_BZ_A_GF_A_FW_PRE		"iwlwifi-bz-a0-gf-a0"
 #define IWL_BZ_A_GF4_A_FW_PRE		"iwlwifi-bz-a0-gf4-a0"
 #define IWL_SC_A_GF_A_FW_PRE		"iwlwifi-sc-a0-gf-a0"
@@ -70,12 +63,6 @@ const char iwl_ax211_name[] = "Intel(R) Wi-Fi 6E AX211 160MHz";
 const char iwl_ax231_name[] = "Intel(R) Wi-Fi 6 AX231";
 const char iwl_ax411_name[] = "Intel(R) Wi-Fi 6E AX411 160MHz";
 
-IWL_FW_AND_PNVM(IWL_SO_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX);
-IWL_FW_AND_PNVM(IWL_TY_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX);
-IWL_FW_AND_PNVM(IWL_MA_A_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX);
-IWL_FW_AND_PNVM(IWL_MA_B_GF_A_FW_PRE, IWL_GF_UCODE_API_MAX);
-IWL_FW_AND_PNVM(IWL_MA_A_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX);
-IWL_FW_AND_PNVM(IWL_MA_B_GF4_A_FW_PRE, IWL_GF_UCODE_API_MAX);
 MODULE_FIRMWARE(IWL_BZ_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_BZ_A_GF4_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_SC_A_GF_A_MODULE_FIRMWARE(IWL_GF_UCODE_API_MAX));
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c
index 3c3a8d5702d8..16b9075acdd8 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/rf-hr.c
@@ -11,28 +11,10 @@
 /* Lowest firmware API version supported */
 #define IWL_HR_UCODE_API_MIN	100
 
-#define IWL_QU_B_HR_B_FW_PRE		"iwlwifi-Qu-b0-hr-b0"
-#define IWL_QU_C_HR_B_FW_PRE		"iwlwifi-Qu-c0-hr-b0"
-#define IWL_QUZ_A_HR_B_FW_PRE		"iwlwifi-QuZ-a0-hr-b0"
-#define IWL_SO_A_HR_B_FW_PRE		"iwlwifi-so-a0-hr-b0"
-#define IWL_MA_A_HR_B_FW_PRE		"iwlwifi-ma-a0-hr-b0"
-#define IWL_MA_B_HR_B_FW_PRE		"iwlwifi-ma-b0-hr-b0"
 #define IWL_BZ_A_HR_B_FW_PRE		"iwlwifi-bz-a0-hr-b0"
 #define IWL_SC_A_HR_A_FW_PRE		"iwlwifi-sc-a0-hr-b0"
 #define IWL_SC_A_HR_B_FW_PRE		"iwlwifi-sc-a0-hr-b0"
 
-#define IWL_QU_B_HR_B_MODULE_FIRMWARE(api)	\
-	IWL_QU_B_HR_B_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL_QUZ_A_HR_B_MODULE_FIRMWARE(api)	\
-	IWL_QUZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL_QU_C_HR_B_MODULE_FIRMWARE(api)	\
-	IWL_QU_C_HR_B_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL_SO_A_HR_B_MODULE_FIRMWARE(api)	\
-	IWL_SO_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(api)	\
-	IWL_MA_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
-#define IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(api)	\
-	IWL_MA_B_HR_B_FW_PRE "-" __stringify(api) ".ucode"
 #define IWL_BZ_A_HR_B_MODULE_FIRMWARE(api)	\
 	IWL_BZ_A_HR_B_FW_PRE "-" __stringify(api) ".ucode"
 #define IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(api)	\
@@ -74,12 +56,6 @@ const char iwl_ax200_name[] = "Intel(R) Wi-Fi 6 AX200 160MHz";
 const char iwl_ax201_name[] = "Intel(R) Wi-Fi 6 AX201 160MHz";
 const char iwl_ax203_name[] = "Intel(R) Wi-Fi 6 AX203";
 
-MODULE_FIRMWARE(IWL_QU_B_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL_QU_C_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL_QUZ_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL_SO_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL_MA_A_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-MODULE_FIRMWARE(IWL_MA_B_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_BZ_A_HR_B_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_SC_A_HR_A_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
 MODULE_FIRMWARE(IWL_SC_A_HR_B_FW_MODULE_FIRMWARE(IWL_HR_UCODE_API_MAX));
-- 
2.34.1


^ permalink raw reply related

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

Start supporting Core 104 FW on these devices.

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

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index a70b356d9576..51d7c599e998 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
  */
 #include <linux/module.h>
 #include <linux/stringify.h>
@@ -10,7 +10,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_BZ_UCODE_CORE_MAX	103
+#define IWL_BZ_UCODE_CORE_MAX	104
 
 /* Lowest firmware core release supported */
 #define IWL_BZ_UCODE_CORE_MIN	101
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index e95112fdc664..76fbc120a092 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.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 <linux/module.h>
 #include <linux/stringify.h>
@@ -9,7 +9,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_DR_UCODE_CORE_MAX	103
+#define IWL_DR_UCODE_CORE_MAX	104
 
 /* Lowest firmware core release supported */
 #define IWL_DR_UCODE_CORE_MIN	101
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index d1e5cef42fff..db7858b2cb74 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
  */
 #include <linux/module.h>
 #include <linux/stringify.h>
@@ -10,7 +10,7 @@
 #include "fw/api/txq.h"
 
 /* Highest firmware core release supported */
-#define IWL_SC_UCODE_CORE_MAX	103
+#define IWL_SC_UCODE_CORE_MAX	104
 
 /* Lowest firmware core release supported */
 #define IWL_SC_UCODE_CORE_MIN	101
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 10/15] wifi: iwlwifi: mld: update link grading tables per bandwidth
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Avinash Bhatt, Miriam Rachel Korenblit
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

Replace single RSSI-to-grade table with separate tables for each
operational bandwidth. Grade selection now depends on both RSSI and
the link's operational bandwidth.

Improve puncturing penalty calculation to apply proportional reduction
based on unusable spectrum percentage rather than absolute channel count.

Update existing KUnit tests with RSSI values for new grading tables.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
Tested-by: Miriam Rachel Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 228 ++++++++++++++----
 .../intel/iwlwifi/mld/tests/link-selection.c  |   6 +-
 2 files changed, 183 insertions(+), 51 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index 70965627e2dd..3c1825ba2b86 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -696,35 +696,131 @@ struct iwl_mld_rssi_to_grade {
 	u16 grade;
 };
 
-#define RSSI_TO_GRADE_LINE(_lb, _hb_uhb, _grade) \
+#define RSSI_TO_GRADE_LINE_WITH_LB(_lb, _hb_uhb, _grade) \
 	{ \
 		.rssi = {_lb, _hb_uhb}, \
 		.grade = _grade \
 	}
 
-/*
- * This array must be sorted by increasing RSSI for proper functionality.
- * The grades are actually estimated throughput, represented as fixed-point
- * with a scale factor of 1/10.
- */
-static const struct iwl_mld_rssi_to_grade rssi_to_grade_map[] = {
-	RSSI_TO_GRADE_LINE(-85, -89, 172),
-	RSSI_TO_GRADE_LINE(-83, -86, 344),
-	RSSI_TO_GRADE_LINE(-82, -85, 516),
-	RSSI_TO_GRADE_LINE(-80, -83, 688),
-	RSSI_TO_GRADE_LINE(-77, -79, 1032),
-	RSSI_TO_GRADE_LINE(-73, -76, 1376),
-	RSSI_TO_GRADE_LINE(-70, -74, 1548),
-	RSSI_TO_GRADE_LINE(-69, -72, 1720),
-	RSSI_TO_GRADE_LINE(-65, -68, 2064),
-	RSSI_TO_GRADE_LINE(-61, -66, 2294),
-	RSSI_TO_GRADE_LINE(-58, -61, 2580),
-	RSSI_TO_GRADE_LINE(-55, -58, 2868),
-	RSSI_TO_GRADE_LINE(-46, -55, 3098),
-	RSSI_TO_GRADE_LINE(-43, -54, 3442)
+#define RSSI_TO_GRADE_LINE(_rssi, _grade) \
+	RSSI_TO_GRADE_LINE_WITH_LB(_rssi, _rssi, _grade)
+
+/* Tables must be sorted by increasing RSSI */
+
+/* 20 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_20mhz[] = {
+	RSSI_TO_GRADE_LINE_WITH_LB(-94, -95, 9),
+	RSSI_TO_GRADE_LINE_WITH_LB(-92, -93, 17),
+	RSSI_TO_GRADE_LINE_WITH_LB(-90, -90, 34),
+	RSSI_TO_GRADE_LINE_WITH_LB(-87, -87, 52),
+	RSSI_TO_GRADE_LINE_WITH_LB(-83, -84, 69),
+	RSSI_TO_GRADE_LINE_WITH_LB(-79, -80, 103),
+	RSSI_TO_GRADE_LINE_WITH_LB(-75, -75, 137),
+	RSSI_TO_GRADE_LINE_WITH_LB(-72, -73, 155),
+	RSSI_TO_GRADE_LINE_WITH_LB(-70, -71, 172),
+	RSSI_TO_GRADE_LINE_WITH_LB(-67, -68, 206),
+	RSSI_TO_GRADE_LINE_WITH_LB(-64, -65, 230),
+	RSSI_TO_GRADE_LINE_WITH_LB(-59, -60, 258),
+	RSSI_TO_GRADE_LINE_WITH_LB(-57, -58, 287),
+	RSSI_TO_GRADE_LINE_WITH_LB(-52, -53, 310),
+	RSSI_TO_GRADE_LINE_WITH_LB(-50, -50, 345),
 };
 
-#define MAX_GRADE (rssi_to_grade_map[ARRAY_SIZE(rssi_to_grade_map) - 1].grade)
+/* 40 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_40mhz[] = {
+	RSSI_TO_GRADE_LINE_WITH_LB(-95, -95, 9),
+	RSSI_TO_GRADE_LINE_WITH_LB(-93, -93, 17),
+	RSSI_TO_GRADE_LINE_WITH_LB(-91, -92, 18),
+	RSSI_TO_GRADE_LINE_WITH_LB(-89, -90, 34),
+	RSSI_TO_GRADE_LINE_WITH_LB(-87, -87, 68),
+	RSSI_TO_GRADE_LINE_WITH_LB(-84, -84, 104),
+	RSSI_TO_GRADE_LINE_WITH_LB(-80, -81, 138),
+	RSSI_TO_GRADE_LINE_WITH_LB(-77, -77, 206),
+	RSSI_TO_GRADE_LINE_WITH_LB(-72, -72, 274),
+	RSSI_TO_GRADE_LINE_WITH_LB(-69, -70, 310),
+	RSSI_TO_GRADE_LINE_WITH_LB(-67, -68, 344),
+	RSSI_TO_GRADE_LINE_WITH_LB(-64, -65, 412),
+	RSSI_TO_GRADE_LINE_WITH_LB(-61, -62, 460),
+	RSSI_TO_GRADE_LINE_WITH_LB(-56, -57, 516),
+	RSSI_TO_GRADE_LINE_WITH_LB(-54, -55, 574),
+	RSSI_TO_GRADE_LINE_WITH_LB(-49, -50, 620),
+	RSSI_TO_GRADE_LINE_WITH_LB(-46, -47, 690),
+};
+
+/* 80 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_80mhz[] = {
+	RSSI_TO_GRADE_LINE(-95, 9),
+	RSSI_TO_GRADE_LINE(-93, 17),
+	RSSI_TO_GRADE_LINE(-92, 18),
+	RSSI_TO_GRADE_LINE(-90, 34),
+	RSSI_TO_GRADE_LINE(-89, 36),
+	RSSI_TO_GRADE_LINE(-87, 68),
+	RSSI_TO_GRADE_LINE(-83, 136),
+	RSSI_TO_GRADE_LINE(-80, 208),
+	RSSI_TO_GRADE_LINE(-77, 276),
+	RSSI_TO_GRADE_LINE(-74, 412),
+	RSSI_TO_GRADE_LINE(-69, 548),
+	RSSI_TO_GRADE_LINE(-67, 620),
+	RSSI_TO_GRADE_LINE(-66, 688),
+	RSSI_TO_GRADE_LINE(-61, 824),
+	RSSI_TO_GRADE_LINE(-59, 920),
+	RSSI_TO_GRADE_LINE(-54, 1032),
+	RSSI_TO_GRADE_LINE(-52, 1148),
+	RSSI_TO_GRADE_LINE(-47, 1240),
+	RSSI_TO_GRADE_LINE(-44, 1380),
+};
+
+/* 160 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_160mhz[] = {
+	RSSI_TO_GRADE_LINE(-95, 9),
+	RSSI_TO_GRADE_LINE(-93, 17),
+	RSSI_TO_GRADE_LINE(-92, 18),
+	RSSI_TO_GRADE_LINE(-90, 34),
+	RSSI_TO_GRADE_LINE(-89, 36),
+	RSSI_TO_GRADE_LINE(-87, 68),
+	RSSI_TO_GRADE_LINE(-86, 72),
+	RSSI_TO_GRADE_LINE(-84, 136),
+	RSSI_TO_GRADE_LINE(-81, 272),
+	RSSI_TO_GRADE_LINE(-78, 416),
+	RSSI_TO_GRADE_LINE(-75, 552),
+	RSSI_TO_GRADE_LINE(-71, 824),
+	RSSI_TO_GRADE_LINE(-67, 1096),
+	RSSI_TO_GRADE_LINE(-65, 1240),
+	RSSI_TO_GRADE_LINE(-63, 1376),
+	RSSI_TO_GRADE_LINE(-59, 1648),
+	RSSI_TO_GRADE_LINE(-57, 1840),
+	RSSI_TO_GRADE_LINE(-52, 2064),
+	RSSI_TO_GRADE_LINE(-50, 2296),
+	RSSI_TO_GRADE_LINE(-46, 2480),
+	RSSI_TO_GRADE_LINE(-42, 2760),
+};
+
+/* 320 MHz Operational BW Grading Table */
+static const struct iwl_mld_rssi_to_grade rssi_to_grade_320mhz[] = {
+	RSSI_TO_GRADE_LINE(-95, 9),
+	RSSI_TO_GRADE_LINE(-93, 17),
+	RSSI_TO_GRADE_LINE(-92, 18),
+	RSSI_TO_GRADE_LINE(-90, 34),
+	RSSI_TO_GRADE_LINE(-89, 36),
+	RSSI_TO_GRADE_LINE(-87, 68),
+	RSSI_TO_GRADE_LINE(-86, 72),
+	RSSI_TO_GRADE_LINE(-84, 136),
+	RSSI_TO_GRADE_LINE(-83, 144),
+	RSSI_TO_GRADE_LINE(-81, 272),
+	RSSI_TO_GRADE_LINE(-78, 544),
+	RSSI_TO_GRADE_LINE(-75, 832),
+	RSSI_TO_GRADE_LINE(-72, 1104),
+	RSSI_TO_GRADE_LINE(-69, 1648),
+	RSSI_TO_GRADE_LINE(-64, 2192),
+	RSSI_TO_GRADE_LINE(-62, 2480),
+	RSSI_TO_GRADE_LINE(-61, 2752),
+	RSSI_TO_GRADE_LINE(-57, 3296),
+	RSSI_TO_GRADE_LINE(-55, 3680),
+	RSSI_TO_GRADE_LINE(-50, 4128),
+	RSSI_TO_GRADE_LINE(-47, 4592),
+	RSSI_TO_GRADE_LINE(-43, 4960),
+	RSSI_TO_GRADE_LINE(-40, 5520),
+};
 
 #define DEFAULT_CHAN_LOAD_2GHZ	30
 #define DEFAULT_CHAN_LOAD_5GHZ	15
@@ -734,26 +830,23 @@ static const struct iwl_mld_rssi_to_grade rssi_to_grade_map[] = {
 #define SCALE_FACTOR 256
 #define MAX_CHAN_LOAD 256
 
-static unsigned int
-iwl_mld_get_n_subchannels(const struct ieee80211_bss_conf *link_conf)
+static void
+iwl_mld_apply_puncturing_penalty(const struct ieee80211_bss_conf *link_conf,
+				 unsigned int *grade, int bw_mhz)
 {
-	enum nl80211_chan_width chan_width =
-		link_conf->chanreq.oper.width;
-	int mhz = nl80211_chan_width_to_mhz(chan_width);
-	unsigned int n_subchannels;
+	unsigned int n_punctured, n_subchannels;
 
-	if (WARN_ONCE(mhz < 20 || mhz > 320,
-		      "Invalid channel width : (%d)\n", mhz))
-		return 1;
+	/* Puncturing only applicable for BW >= 80 MHz */
+	if (bw_mhz < 80)
+		return;
 
-	/* total number of subchannels */
-	n_subchannels = mhz / 20;
+	n_punctured = hweight16(link_conf->chanreq.oper.punctured);
+	if (n_punctured == 0)
+		return;
 
-	/* No puncturing if less than 80 MHz */
-	if (mhz >= 80)
-		n_subchannels -= hweight16(link_conf->chanreq.oper.punctured);
+	n_subchannels = bw_mhz / 20;
 
-	return n_subchannels;
+	*grade = *grade * (n_subchannels - n_punctured) / n_subchannels;
 }
 
 static int
@@ -1115,14 +1208,19 @@ static s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
 unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 				    struct ieee80211_bss_conf *link_conf)
 {
+	const struct iwl_mld_rssi_to_grade *grade_table;
 	enum nl80211_band band;
-	int rssi_idx;
+	int rssi_idx, table_size, bw_mhz;
 	s32 link_rssi;
-	unsigned int grade = MAX_GRADE;
+	unsigned int grade;
 
 	if (WARN_ON_ONCE(!link_conf || !link_conf->bss))
 		return 0;
 
+	bw_mhz = nl80211_chan_width_to_mhz(link_conf->chanreq.oper.width);
+	if (bw_mhz < 0)
+		return 0;
+
 	band = link_conf->chanreq.oper.chan->band;
 	if (WARN_ONCE(band != NL80211_BAND_2GHZ &&
 		      band != NL80211_BAND_5GHZ &&
@@ -1149,22 +1247,50 @@ unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 		link_rssi += rssi_adj_6g;
 	}
 
+	/* Select grading table based on operational bandwidth */
+	switch (bw_mhz) {
+	case 20:
+		grade_table = rssi_to_grade_20mhz;
+		table_size = ARRAY_SIZE(rssi_to_grade_20mhz);
+		break;
+	case 40:
+		grade_table = rssi_to_grade_40mhz;
+		table_size = ARRAY_SIZE(rssi_to_grade_40mhz);
+		break;
+	case 80:
+		grade_table = rssi_to_grade_80mhz;
+		table_size = ARRAY_SIZE(rssi_to_grade_80mhz);
+		break;
+	case 160:
+		grade_table = rssi_to_grade_160mhz;
+		table_size = ARRAY_SIZE(rssi_to_grade_160mhz);
+		break;
+	case 320:
+		grade_table = rssi_to_grade_320mhz;
+		table_size = ARRAY_SIZE(rssi_to_grade_320mhz);
+		break;
+	default:
+		WARN_ONCE(1, "Invalid bandwidth: %d MHz\n", bw_mhz);
+		return 0;
+	}
+
+	/* Initialize grade to maximum value from selected table */
+	grade = grade_table[table_size - 1].grade;
+
 	rssi_idx = band == NL80211_BAND_2GHZ ? 0 : 1;
 
-	/* No valid RSSI - take the lowest grade */
+	/* No valid RSSI - take the lowest grade from selected table */
 	if (!link_rssi)
-		link_rssi = rssi_to_grade_map[0].rssi[rssi_idx];
+		link_rssi = grade_table[0].rssi[rssi_idx];
 
 	IWL_DEBUG_EHT(mld,
-		      "Calculating grade of link %d: band = %d, bandwidth = %d, punctured subchannels =0x%x RSSI = %d\n",
-		      link_conf->link_id, band,
-		      link_conf->chanreq.oper.width,
+		      "Calculating grade of link %d: band = %d, BW = %d, punct subchannels = 0x%x RSSI = %d\n",
+		      link_conf->link_id, band, bw_mhz,
 		      link_conf->chanreq.oper.punctured, link_rssi);
 
-	/* Get grade based on RSSI */
-	for (int i = 0; i < ARRAY_SIZE(rssi_to_grade_map); i++) {
-		const struct iwl_mld_rssi_to_grade *line =
-			&rssi_to_grade_map[i];
+	/* Get grade based on RSSI from the bandwidth-specific table */
+	for (int i = 0; i < table_size; i++) {
+		const struct iwl_mld_rssi_to_grade *line = &grade_table[i];
 
 		if (link_rssi > line->rssi[rssi_idx])
 			continue;
@@ -1173,8 +1299,10 @@ unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 	}
 
 	/* Apply the channel load and puncturing factors */
-	grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) / SCALE_FACTOR;
-	grade = grade * iwl_mld_get_n_subchannels(link_conf);
+	grade = grade * iwl_mld_get_avail_chan_load(mld, link_conf) /
+		SCALE_FACTOR;
+
+	iwl_mld_apply_puncturing_penalty(link_conf, &grade, bw_mhz);
 
 	IWL_DEBUG_EHT(mld, "Link %d's grade: %d\n", link_conf->link_id, grade);
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c
index 766c24db3613..69d222a8194c 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/tests/link-selection.c
@@ -2,7 +2,7 @@
 /*
  * KUnit tests for link selection functions
  *
- * Copyright (C) 2025 Intel Corporation
+ * Copyright (C) 2025-2026 Intel Corporation
  */
 #include <kunit/static_stub.h>
 
@@ -34,6 +34,7 @@ static const struct link_grading_test_case {
 			.link_id = 0,
 			.chandef = &chandef_2ghz_20mhz,
 			.active = false,
+			.signal = -70,
 			.has_chan_util_elem = true,
 			.chan_util = 128,
 		},
@@ -45,6 +46,7 @@ static const struct link_grading_test_case {
 			.link_id = 0,
 			.chandef = &chandef_2ghz_20mhz,
 			.active = false,
+			.signal = -70,
 			.has_chan_util_elem = true,
 			.chan_util = 180,
 		},
@@ -55,6 +57,7 @@ static const struct link_grading_test_case {
 		.input.link = {
 			.link_id = 0,
 			.chandef = &chandef_2ghz_20mhz,
+			.signal = -70,
 			.has_chan_util_elem = true,
 			.chan_util = 180,
 			.active = true,
@@ -67,6 +70,7 @@ static const struct link_grading_test_case {
 		.input.link = {
 			.link_id = 0,
 			.chandef = &chandef_2ghz_20mhz,
+			.signal = -70,
 			.active = true,
 		},
 		.expected_grade = 120,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 09/15] wifi: iwlwifi: mld: implement PSD/EIRP RSSI adjustment
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Avinash Bhatt
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

APs operating in PSD mode increase transmit power with bandwidth,
requiring RSSI compensation for accurate link grading.

Parse TPE elements to determine power mode and apply RSSI adjustment
based on operational bandwidth and power constraints.

Signed-off-by: Avinash Bhatt <avinash.bhatt@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 143 ++++++++++++++++++
 1 file changed, 143 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index 785459937fbe..70965627e2dd 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -972,6 +972,145 @@ iwl_mld_get_dup_beacon_rssi_adjust(struct iwl_mld *mld,
 	}
 }
 
+static s8 iwl_mld_get_primary_psd(const struct ieee80211_parsed_tpe_psd *psd,
+				  const struct cfg80211_chan_def *chandef,
+				  int bw_mhz)
+{
+	int start_freq, primary_idx;
+
+	if (!psd->valid)
+		return S8_MAX;
+
+	start_freq = chandef->center_freq1 - (bw_mhz / 2);
+	primary_idx = (chandef->chan->center_freq - start_freq - 10) / 20;
+
+	if (primary_idx < 0 || primary_idx >= psd->count)
+		return S8_MAX;
+
+	/* TPE element stores PSD limit as value * 2 */
+	return psd->power[primary_idx] / 2;
+}
+
+static s8 iwl_mld_get_psd_eirp_rssi_adjust(struct ieee80211_bss_conf *link_conf)
+{
+	const struct ieee80211_parsed_tpe *tpe = &link_conf->tpe;
+	s8 psd_20mhz, psd_oper, psd_local, psd_reg, psd_boost;
+	s8 min_20mhz, min_oper, adjustment, ap_power_limit;
+	s8 psd_avg_local = S8_MAX, psd_avg_reg = S8_MAX;
+	s8 eirp_20mhz, eirp_oper, eirp_local, eirp_reg;
+	int bw_mhz, num_subchans;
+	u8 bw_index;
+
+	/* PSD/EIRP adjustment is only specific to 6 GHz */
+	if (WARN_ONCE(link_conf->chanreq.oper.chan->band != NL80211_BAND_6GHZ,
+		      "PSD/EIRP adjustment called for non-6 GHz band %d\n",
+		      link_conf->chanreq.oper.chan->band))
+		return 0;
+
+	bw_mhz = nl80211_chan_width_to_mhz(link_conf->chanreq.oper.width);
+
+	switch (bw_mhz) {
+	case 20:
+		bw_index = 0;
+		break;
+	case 40:
+		bw_index = 1;
+		break;
+	case 80:
+		bw_index = 2;
+		break;
+	case 160:
+		bw_index = 3;
+		break;
+	case 320:
+		bw_index = 4;
+		break;
+	default:
+		WARN_ONCE(1, "Unexpected bandwidth: %d MHz\n", bw_mhz);
+		return 0;
+	}
+
+	if (link_conf->power_type == IEEE80211_REG_VLP_AP)
+		ap_power_limit = 14;
+	else
+		ap_power_limit = 23;
+
+	/* Primary 20 MHz PSD */
+	psd_local = iwl_mld_get_primary_psd(&tpe->psd_local[0],
+					    &link_conf->chanreq.oper,
+					    bw_mhz);
+	psd_reg = iwl_mld_get_primary_psd(&tpe->psd_reg_client[0],
+					  &link_conf->chanreq.oper,
+					  bw_mhz);
+	psd_20mhz = min(psd_local, psd_reg);
+
+	/* TPE element stores EIRP limit as value * 2 */
+	eirp_local = (tpe->max_local[0].valid && tpe->max_local[0].count > 0) ?
+			tpe->max_local[0].power[0] / 2 : S8_MAX;
+	eirp_reg = (tpe->max_reg_client[0].valid &&
+		    tpe->max_reg_client[0].count > 0) ?
+		      tpe->max_reg_client[0].power[0] / 2 : S8_MAX;
+	eirp_20mhz = min(eirp_local, eirp_reg);
+
+	num_subchans = bw_mhz / 20;
+
+	if (tpe->psd_local[0].valid) {
+		int sum_local = 0, valid_local = 0;
+		int count_local = min(num_subchans, tpe->psd_local[0].count);
+
+		for (int i = 0; i < count_local; i++) {
+			if (tpe->psd_local[0].power[i] != S8_MIN) {
+				sum_local += tpe->psd_local[0].power[i];
+				valid_local++;
+			}
+		}
+		/* TPE element stores PSD limit as value * 2 */
+		if (valid_local > 0)
+			psd_avg_local = sum_local / valid_local / 2;
+	}
+
+	if (tpe->psd_reg_client[0].valid) {
+		int sum_reg = 0, valid_reg = 0;
+		int count_reg = min(num_subchans, tpe->psd_reg_client[0].count);
+
+		for (int i = 0; i < count_reg; i++) {
+			if (tpe->psd_reg_client[0].power[i] != S8_MIN) {
+				sum_reg +=
+					tpe->psd_reg_client[0].power[i];
+				valid_reg++;
+			}
+		}
+		/* TPE element stores PSD limit as value * 2 */
+		if (valid_reg > 0)
+			psd_avg_reg = sum_reg / valid_reg / 2;
+	}
+
+	psd_oper = min(psd_avg_local, psd_avg_reg);
+
+	/* TPE element stores EIRP limit as value * 2 */
+	eirp_local = (tpe->max_local[0].valid &&
+		      tpe->max_local[0].count > bw_index) ?
+			tpe->max_local[0].power[bw_index] / 2 : S8_MAX;
+	eirp_reg = (tpe->max_reg_client[0].valid &&
+		    tpe->max_reg_client[0].count > bw_index) ?
+		      tpe->max_reg_client[0].power[bw_index] / 2 : S8_MAX;
+	eirp_oper = min(eirp_local, eirp_reg);
+
+	min_20mhz = min(ap_power_limit, min(eirp_20mhz, psd_20mhz));
+
+	/* PSD boost: 10*log10(BW/20) approximated as 3*ilog2(BW/20) */
+	psd_boost = 3 * ilog2(bw_mhz / 20);
+
+	/* Use int for psd_oper + psd_boost to prevent s8 overflow */
+	min_oper = min(ap_power_limit,
+		       min(eirp_oper,
+			   (s8)min_t(int, psd_oper + psd_boost, S8_MAX)));
+
+	adjustment = max(min_oper - min_20mhz, 0);
+
+	return adjustment;
+}
+
 /* This function calculates the grade of a link. Returns 0 in error case */
 unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 				    struct ieee80211_bss_conf *link_conf)
@@ -1000,6 +1139,10 @@ unsigned int iwl_mld_get_link_grade(struct iwl_mld *mld,
 		s8 rssi_adj_6g =
 			iwl_mld_get_dup_beacon_rssi_adjust(mld, link_conf);
 
+		if (!rssi_adj_6g)
+			rssi_adj_6g =
+				iwl_mld_get_psd_eirp_rssi_adjust(link_conf);
+
 		if (!rssi_adj_6g)
 			rssi_adj_6g = 4;
 
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: give link STA debugfs files a namespace
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

The generated data structures and function names used are
just the debugfs filename, which is a shared namespace and
could lead to confusion. Prefix these with "link_sta_" to
disambiguate.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../net/wireless/intel/iwlwifi/mld/debugfs.c   | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c
index 9ec8ddce0c38..ba5a47519aa1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/debugfs.c
@@ -1049,20 +1049,22 @@ static ssize_t _iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
 	return ret ? : count;
 }
 
-static ssize_t iwl_dbgfs_fixed_rate_write(struct iwl_mld *mld, char *buf,
-					  size_t count, void *data)
+static ssize_t
+iwl_dbgfs_link_sta_fixed_rate_write(struct iwl_mld *mld, char *buf,
+				    size_t count, void *data)
 {
 	return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, false);
 }
 
-static ssize_t iwl_dbgfs_fixed_rate_v3_write(struct iwl_mld *mld, char *buf,
-					     size_t count, void *data)
+static ssize_t
+iwl_dbgfs_link_sta_fixed_rate_v3_write(struct iwl_mld *mld, char *buf,
+				       size_t count, void *data)
 {
 	return _iwl_dbgfs_fixed_rate_write(mld, buf, count, data, true);
 }
 
-static ssize_t iwl_dbgfs_tlc_dhc_write(struct iwl_mld *mld, char *buf,
-				       size_t count, void *data)
+static ssize_t iwl_dbgfs_link_sta_tlc_dhc_write(struct iwl_mld *mld, char *buf,
+						size_t count, void *data)
 {
 	struct ieee80211_link_sta *link_sta = data;
 	struct iwl_mld_link_sta *mld_link_sta;
@@ -1091,12 +1093,12 @@ static ssize_t iwl_dbgfs_tlc_dhc_write(struct iwl_mld *mld, char *buf,
 
 #define LINK_STA_DEBUGFS_ADD_FILE_ALIAS(alias, name, parent, mode)	\
 	debugfs_create_file(alias, mode, parent, link_sta,		\
-			    &iwl_dbgfs_##name##_ops)
+			    &iwl_dbgfs_link_sta_##name##_ops)
 #define LINK_STA_DEBUGFS_ADD_FILE(name, parent, mode)			\
 	LINK_STA_DEBUGFS_ADD_FILE_ALIAS(#name, name, parent, mode)
 
 #define LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(name, bufsz)			\
-	WIPHY_DEBUGFS_WRITE_FILE_OPS(name, bufsz, link_sta)
+	WIPHY_DEBUGFS_WRITE_FILE_OPS(link_sta_##name, bufsz, link_sta)
 
 LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(tlc_dhc, 64);
 LINK_STA_WIPHY_DEBUGFS_WRITE_OPS(fixed_rate, 64);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: implement UHR DPS
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

For UHR, implement dynamic power save (DPS). Since the firmware
handles most of it, simply advertise DPS capability and set the
corresponding link flag when the AP has advertised that it is a
DPS assisting AP.

DPS assisting is currently not supported.

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/mac-cfg.h |  2 ++
 drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c  |  3 ++-
 drivers/net/wireless/intel/iwlwifi/mld/link.c       | 10 +++++++++-
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index fa2fc6a92e60..604281eb29c7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -550,6 +550,7 @@ enum iwl_link_ctx_protection_flags {
  * @LINK_FLG_NDP_FEEDBACK_ENABLED: mark support for NDP feedback and change
  *	of threshold
  * @LINK_FLG_NPCA: NPCA enabled
+ * @LINK_FLG_DPS: AP is a DPS assisting AP
  */
 enum iwl_link_ctx_flags {
 	LINK_FLG_BSS_COLOR_DIS		= BIT(0),
@@ -557,6 +558,7 @@ enum iwl_link_ctx_flags {
 	LINK_FLG_RU_2MHZ_BLOCK		= BIT(2),
 	LINK_FLG_NDP_FEEDBACK_ENABLED	= BIT(3),
 	LINK_FLG_NPCA			= BIT(4),
+	LINK_FLG_DPS			= BIT(6),
 }; /* LINK_CONTEXT_FLAG_E_VER_1 */
 
 /**
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 4e8222ffe732..f29de029c709 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -696,7 +696,8 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
 			.phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
 				   IEEE80211_UHR_PHY_CAP_ELR_TX,
 			.mac.mac_cap = {
-				[0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP,
+				[0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP |
+				      IEEE80211_UHR_MAC_CAP0_DPS_SUPP,
 			},
 		},
 	},
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index 9ef39b03e67f..785459937fbe 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -335,10 +335,18 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
 			link_sta_dereference_check(mld_vif->ap_sta,
 						   link->link_id);
 
-		if (!WARN_ON(!link_sta) && link_sta->he_cap.has_he &&
+		if (WARN_ON(!link_sta))
+			return -EINVAL;
+
+		if (link_sta->he_cap.has_he &&
 		    link_sta->he_cap.he_cap_elem.mac_cap_info[5] &
 		    IEEE80211_HE_MAC_CAP5_OM_CTRL_UL_MU_DATA_DIS_RX)
 			cmd.ul_mu_data_disable = 1;
+
+		if (link_sta->uhr_cap.has_uhr &&
+		    link_sta->uhr_cap.mac.mac_cap[0] &
+				IEEE80211_UHR_MAC_CAP0_DPS_ASSIST_SUPP)
+			flags |= LINK_FLG_DPS;
 	}
 
 	cmd.htc_trig_based_pkt_ext = link->htc_trig_based_pkt_ext;
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: support NPCA capability for UHR devices
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

UHR devices have NPCA capability, so implement the necessary
configuration and set the capability bit.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../wireless/intel/iwlwifi/fw/api/mac-cfg.h   |  4 +-
 .../wireless/intel/iwlwifi/iwl-nvm-parse.c    |  3 ++
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 15 +++++++
 .../net/wireless/intel/iwlwifi/mld/mac80211.c | 39 ++++++++++++++++++-
 drivers/net/wireless/intel/iwlwifi/mld/phy.c  | 24 ++++++++++--
 5 files changed, 80 insertions(+), 5 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index dde6cfd9d286..fa2fc6a92e60 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -549,12 +549,14 @@ enum iwl_link_ctx_protection_flags {
  *      radar pulses).
  * @LINK_FLG_NDP_FEEDBACK_ENABLED: mark support for NDP feedback and change
  *	of threshold
+ * @LINK_FLG_NPCA: NPCA enabled
  */
 enum iwl_link_ctx_flags {
 	LINK_FLG_BSS_COLOR_DIS		= BIT(0),
 	LINK_FLG_MU_EDCA_CW		= BIT(1),
 	LINK_FLG_RU_2MHZ_BLOCK		= BIT(2),
 	LINK_FLG_NDP_FEEDBACK_ENABLED	= BIT(3),
+	LINK_FLG_NPCA			= BIT(4),
 }; /* LINK_CONTEXT_FLAG_E_VER_1 */
 
 /**
@@ -591,7 +593,7 @@ enum iwl_npca_flags {
  * @initial_qsrc: Indicates the value that is used to initialize the
  *	EDCAF QSRC[AC] variables
  * @min_dur_threshold: minimum PPDU time to switch to the non-primary
- *	NPCA channel (usec)
+ *	NPCA channel (spec representation)
  * @flags: NPCA flags, see &enum iwl_npca_flags
  * @reserved: reserved for alignment purposes
  */
diff --git a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
index 38ff6f944add..4e8222ffe732 100644
--- a/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/intel/iwlwifi/iwl-nvm-parse.c
@@ -695,6 +695,9 @@ static const struct ieee80211_sband_iftype_data iwl_iftype_cap[] = {
 			.has_uhr = true,
 			.phy.cap = IEEE80211_UHR_PHY_CAP_ELR_RX |
 				   IEEE80211_UHR_PHY_CAP_ELR_TX,
+			.mac.mac_cap = {
+				[0] = IEEE80211_UHR_MAC_CAP0_NPCA_SUPP,
+			},
 		},
 	},
 	{
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/link.c b/drivers/net/wireless/intel/iwlwifi/mld/link.c
index 805f2e2eac38..9ef39b03e67f 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/link.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/link.c
@@ -374,6 +374,21 @@ iwl_mld_change_link_in_fw(struct iwl_mld *mld, struct ieee80211_bss_conf *link,
 	if (WARN_ON(changes & LINK_CONTEXT_MODIFY_EHT_PARAMS))
 		changes &= ~LINK_CONTEXT_MODIFY_EHT_PARAMS;
 
+	if (link->uhr_support && link->npca.enabled) {
+		flags |= LINK_FLG_NPCA;
+		if (link->npca.moplen)
+			cmd.npca_params.flags |= IWL_NPCA_FLAG_MAC_HDR_BASED;
+		cmd.npca_params.dis_subch_bmap =
+			cpu_to_le16(link->chanreq.oper.npca_punctured);
+		cmd.npca_params.initial_qsrc = link->npca.init_qsrc;
+		cmd.npca_params.min_dur_threshold = link->npca.min_dur_thresh;
+		/* spec/mac80211 have these in units of 4 usec */
+		cmd.npca_params.switch_delay =
+			4 * link->npca.switch_delay;
+		cmd.npca_params.switch_back_delay =
+			4 * link->npca.switch_back_delay;
+	}
+
 send_cmd:
 	cmd.modify_mask = cpu_to_le32(changes);
 	cmd.flags = cpu_to_le32(flags);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 41bc47e4e00c..1f2843af39c1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -981,6 +981,30 @@ void iwl_mld_remove_chanctx(struct ieee80211_hw *hw,
 	mld->used_phy_ids &= ~BIT(phy->fw_id);
 }
 
+static void
+iwl_mld_update_link_npca_puncturing(struct ieee80211_hw *hw,
+				    struct ieee80211_chanctx_conf *ctx)
+{
+	struct iwl_mld *mld = IWL_MAC80211_GET_MLD(hw);
+	struct ieee80211_vif *vif;
+
+	for_each_active_interface(vif, hw) {
+		struct ieee80211_bss_conf *link;
+		int link_id;
+
+		for_each_vif_active_link(vif, link, link_id) {
+			if (rcu_access_pointer(link->chanctx_conf) != ctx)
+				continue;
+
+			if (!link->npca.enabled)
+				continue;
+
+			iwl_mld_change_link_in_fw(mld, link,
+						  LINK_CONTEXT_MODIFY_UHR_PARAMS);
+		}
+	}
+}
+
 static
 void iwl_mld_change_chanctx(struct ieee80211_hw *hw,
 			    struct ieee80211_chanctx_conf *ctx, u32 changed)
@@ -996,9 +1020,19 @@ void iwl_mld_change_chanctx(struct ieee80211_hw *hw,
 			  IEEE80211_CHANCTX_CHANGE_CHANNEL)))
 		return;
 
+	/* NPCA puncturing is in link API for FW */
+	if (changed & IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT) {
+		iwl_mld_update_link_npca_puncturing(hw, ctx);
+		changed &= ~IEEE80211_CHANCTX_CHANGE_NPCA_PUNCT;
+	}
+
 	/* Check if a FW update is required */
 
-	if (changed & IEEE80211_CHANCTX_CHANGE_AP)
+	if (!changed)
+		return;
+
+	if (changed & IEEE80211_CHANCTX_CHANGE_AP ||
+	    changed & IEEE80211_CHANCTX_CHANGE_NPCA)
 		goto update;
 
 	if (chandef->chan == phy->chandef.chan &&
@@ -1255,6 +1289,9 @@ u32 iwl_mld_link_changed_mapping(struct iwl_mld *mld,
 		link_changes |= LINK_CONTEXT_MODIFY_HE_PARAMS;
 	}
 
+	if (changes & BSS_CHANGED_NPCA)
+		link_changes |= LINK_CONTEXT_MODIFY_UHR_PARAMS;
+
 	return link_changes;
 }
 
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/phy.c b/drivers/net/wireless/intel/iwlwifi/mld/phy.c
index 1d93fb9e4dbf..59bf088ead84 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/phy.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/phy.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 <net/mac80211.h>
 
@@ -99,9 +99,9 @@ iwl_mld_nl80211_width_to_fw(enum nl80211_chan_width width)
 /* Maps the driver specific control channel position (relative to the center
  * freq) definitions to the fw values
  */
-u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
+static u8 _iwl_mld_get_fw_ctrl_pos(u32 control, u32 cf1)
 {
-	int offs = chandef->chan->center_freq - chandef->center_freq1;
+	int offs = control - cf1;
 	int abs_offs = abs(offs);
 	u8 ret;
 
@@ -127,6 +127,12 @@ u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
 	return ret;
 }
 
+u8 iwl_mld_get_fw_ctrl_pos(const struct cfg80211_chan_def *chandef)
+{
+	return _iwl_mld_get_fw_ctrl_pos(chandef->chan->center_freq,
+					chandef->center_freq1);
+}
+
 int iwl_mld_phy_fw_action(struct iwl_mld *mld,
 			  struct ieee80211_chanctx_conf *ctx, u32 action)
 {
@@ -150,6 +156,18 @@ int iwl_mld_phy_fw_action(struct iwl_mld *mld,
 		cmd.sbb_ctrl_channel_loc = iwl_mld_get_fw_ctrl_pos(&ctx->ap);
 	}
 
+	/*
+	 * Set NPCA channel if NPCA is used; if not used, just set it to an
+	 * arbitrary channel on the other side to help firmware.
+	 */
+	if (chandef->npca_chan)
+		cmd.secondary_ctrl_chnl_loc =
+			_iwl_mld_get_fw_ctrl_pos(chandef->npca_chan->center_freq,
+						 chandef->center_freq1);
+	else
+		cmd.secondary_ctrl_chnl_loc =
+			cmd.ci.ctrl_pos ^ IWL_PHY_CTRL_POS_ABOVE;
+
 	ret = iwl_mld_send_cmd_pdu(mld, PHY_CONTEXT_CMD, &cmd);
 	if (ret)
 		IWL_ERR(mld, "Failed to send PHY_CONTEXT_CMD ret = %d\n", ret);
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mld: add handler for NAN ULW attribute notification
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Avraham Stern
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

From: Avraham Stern <avraham.stern@intel.com>

When a notification about a new ULW attribute arrives, send it to
user space so the ULW attribute can be added to the relevant frames
(e.g. SDF).

Signed-off-by: Avraham Stern <avraham.stern@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 .../wireless/intel/iwlwifi/fw/api/mac-cfg.h   | 20 +++++++++++
 drivers/net/wireless/intel/iwlwifi/mld/mld.c  |  1 +
 drivers/net/wireless/intel/iwlwifi/mld/nan.c  | 33 +++++++++++++++++++
 drivers/net/wireless/intel/iwlwifi/mld/nan.h  |  5 +++
 .../net/wireless/intel/iwlwifi/mld/notif.c    |  3 ++
 5 files changed, 62 insertions(+)

diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
index 1df81df5830e..dde6cfd9d286 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -80,6 +80,10 @@ enum iwl_mac_conf_subcmd_ids {
 	 * @NAN_PEER_CMD: &struct iwl_nan_peer_cmd
 	 */
 	NAN_PEER_CMD = 0x14,
+	/**
+	 * @NAN_ULW_ATTR_NOTIF: &struct iwl_nan_ulw_attr_notif
+	 */
+	NAN_ULW_ATTR_NOTIF = 0xf2,
 	/**
 	 * @NAN_DW_END_NOTIF: &struct iwl_nan_dw_end_notif
 	 */
@@ -1393,4 +1397,20 @@ struct iwl_nan_dw_end_notif {
 	u8 reserved[3];
 } __packed; /* NAN_DW_END_NTF_API_S_VER_1 */
 
+#define IWL_NAN_MAX_ENDLESS_ULW_ATTR_LEN	48
+
+/**
+ * struct iwl_nan_ulw_attr_notif - sent to notify the host of a change in the
+ *	ULW attribute
+ *
+ * @attr_len: length of the ULW attribute in bytes
+ * @reserved: reserved
+ * @attr: the ULW attribute including the attribute header
+ */
+struct iwl_nan_ulw_attr_notif {
+	u8 attr_len;
+	u8 reserved[3];
+	u8 attr[IWL_NAN_MAX_ENDLESS_ULW_ATTR_LEN];
+} __packed; /* NAN_ULW_ATTR_NOTIF_API_S_VER_1 */
+
 #endif /* __iwl_fw_api_mac_cfg_h__ */
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mld.c b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
index 3caa76b9b2cb..054bb1134425 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mld.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mld.c
@@ -237,6 +237,7 @@ static const struct iwl_hcmd_names iwl_mld_mac_conf_names[] = {
 	HCMD_NAME(NAN_CFG_CMD),
 	HCMD_NAME(NAN_SCHEDULE_CMD),
 	HCMD_NAME(NAN_PEER_CMD),
+	HCMD_NAME(NAN_ULW_ATTR_NOTIF),
 	HCMD_NAME(NAN_DW_END_NOTIF),
 	HCMD_NAME(NAN_JOINED_CLUSTER_NOTIF),
 	HCMD_NAME(MISSED_BEACONS_NOTIF),
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.c b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
index 351c726be51f..8f35687c58b1 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.c
@@ -353,6 +353,39 @@ bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,
 	return true;
 }
 
+bool iwl_mld_cancel_nan_ulw_attr_notif(struct iwl_mld *mld,
+				       struct iwl_rx_packet *pkt,
+				       u32 obj_id)
+{
+	return true;
+}
+
+void iwl_mld_handle_nan_ulw_attr_notif(struct iwl_mld *mld,
+				       struct iwl_rx_packet *pkt)
+{
+	struct iwl_nan_ulw_attr_notif *notif = (void *)pkt->data;
+	struct wireless_dev *wdev;
+
+	IWL_DEBUG_INFO(mld, "NAN: ULW attr update: len=%u\n", notif->attr_len);
+
+	if (IWL_FW_CHECK(mld, !mld->nan_device_vif,
+			 "NAN: ULW attr update without NAN vif\n"))
+		return;
+
+	if (IWL_FW_CHECK(mld, !ieee80211_vif_nan_started(mld->nan_device_vif),
+			 "NAN: ULW attr update without NAN started\n"))
+		return;
+
+	if (IWL_FW_CHECK(mld,
+			 notif->attr_len > IWL_NAN_MAX_ENDLESS_ULW_ATTR_LEN,
+			 "NAN: ULW attr update invalid len %u\n",
+			 notif->attr_len))
+		return;
+
+	wdev = ieee80211_vif_to_wdev(mld->nan_device_vif);
+	cfg80211_nan_ulw_update(wdev, notif->attr, notif->attr_len, GFP_KERNEL);
+}
+
 void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,
 				     struct iwl_rx_packet *pkt)
 {
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/nan.h b/drivers/net/wireless/intel/iwlwifi/mld/nan.h
index caa98dbb4a75..40152dc7d906 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/nan.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/nan.h
@@ -38,11 +38,16 @@ int iwl_mld_stop_nan(struct ieee80211_hw *hw,
 		     struct ieee80211_vif *vif);
 void iwl_mld_handle_nan_cluster_notif(struct iwl_mld *mld,
 				      struct iwl_rx_packet *pkt);
+void iwl_mld_handle_nan_ulw_attr_notif(struct iwl_mld *mld,
+				       struct iwl_rx_packet *pkt);
 void iwl_mld_handle_nan_dw_end_notif(struct iwl_mld *mld,
 				     struct iwl_rx_packet *pkt);
 bool iwl_mld_cancel_nan_cluster_notif(struct iwl_mld *mld,
 				      struct iwl_rx_packet *pkt,
 				      u32 obj_id);
+bool iwl_mld_cancel_nan_ulw_attr_notif(struct iwl_mld *mld,
+				       struct iwl_rx_packet *pkt,
+				       u32 obj_id);
 bool iwl_mld_cancel_nan_dw_end_notif(struct iwl_mld *mld,
 				     struct iwl_rx_packet *pkt,
 				     u32 obj_id);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/notif.c b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
index 14834395de3a..75adc9651736 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/notif.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/notif.c
@@ -346,6 +346,7 @@ CMD_VERSIONS(time_sync_confirm_notif,
 CMD_VERSIONS(ftm_resp_notif, CMD_VER_ENTRY(10, iwl_tof_range_rsp_ntfy))
 CMD_VERSIONS(beacon_filter_notif, CMD_VER_ENTRY(2, iwl_beacon_filter_notif))
 CMD_VERSIONS(nan_cluster_notif, CMD_VER_ENTRY(1, iwl_nan_cluster_notif))
+CMD_VERSIONS(nan_ulw_attr_notif, CMD_VER_ENTRY(1, iwl_nan_ulw_attr_notif))
 CMD_VERSIONS(nan_dw_end_notif, CMD_VER_ENTRY(1, iwl_nan_dw_end_notif))
 
 DEFINE_SIMPLE_CANCELLATION(session_prot, iwl_session_prot_notif, mac_link_id)
@@ -463,6 +464,8 @@ const struct iwl_rx_handler iwl_mld_rx_handlers[] = {
 			      ftm_resp_notif)
 	RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_JOINED_CLUSTER_NOTIF,
 			  nan_cluster_notif)
+	RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_ULW_ATTR_NOTIF,
+			  nan_ulw_attr_notif)
 	RX_HANDLER_OF_NAN(MAC_CONF_GROUP, NAN_DW_END_NOTIF,
 			  nan_dw_end_notif)
 };
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: smem_offset smem_len are not needed from 22000 and up
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

This was used for the old (pre-ini) debug mechanism which is now
obsolete.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 6 ------
 drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 6 ------
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c    | 6 ------
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c    | 6 ------
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c    | 6 ------
 5 files changed, 30 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 563c596240b2..e929a08e7585 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -15,10 +15,6 @@
 /* Lowest firmware API version supported */
 #define IWL_22000_UCODE_API_MIN	77
 
-/* Memory offsets and lengths */
-#define IWL_22000_SMEM_OFFSET		0x400000
-#define IWL_22000_SMEM_LEN		0xD0000
-
 #define IWL_CC_A_FW_PRE			"iwlwifi-cc-a0"
 
 #define IWL_CC_A_MODULE_FIRMWARE(api)			\
@@ -30,8 +26,6 @@ static const struct iwl_family_base_params iwl_22000_base = {
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
-	.smem_offset = IWL_22000_SMEM_OFFSET,
-	.smem_len = IWL_22000_SMEM_LEN,
 	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
 	.apmg_not_supported = true,
 	.mac_addr_from_csr = 0x380,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
index ee24ded67069..ec1951a94e23 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
@@ -15,18 +15,12 @@
 /* Lowest firmware API version supported */
 #define IWL_AX210_UCODE_API_MIN	89
 
-/* Memory offsets and lengths */
-#define IWL_AX210_SMEM_OFFSET		0x400000
-#define IWL_AX210_SMEM_LEN		0xD0000
-
 static const struct iwl_family_base_params iwl_ax210_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
-	.smem_offset = IWL_AX210_SMEM_OFFSET,
-	.smem_len = IWL_AX210_SMEM_LEN,
 	.features = IWL_TX_CSUM_NETIF_FLAGS | NETIF_F_RXCSUM,
 	.apmg_not_supported = true,
 	.mac_addr_from_csr = 0x380,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index 1b14ba5a09f9..a70b356d9576 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -15,18 +15,12 @@
 /* Lowest firmware core release supported */
 #define IWL_BZ_UCODE_CORE_MIN	101
 
-/* Memory offsets and lengths */
-#define IWL_BZ_SMEM_OFFSET		0x400000
-#define IWL_BZ_SMEM_LEN			0xD0000
-
 static const struct iwl_family_base_params iwl_bz_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
-	.smem_offset = IWL_BZ_SMEM_OFFSET,
-	.smem_len = IWL_BZ_SMEM_LEN,
 	.apmg_not_supported = true,
 	.mac_addr_from_csr = 0x30,
 	.d3_debug_data_base_addr = 0x401000,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index afde84ad0493..e95112fdc664 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -14,10 +14,6 @@
 /* Lowest firmware core release supported */
 #define IWL_DR_UCODE_CORE_MIN	101
 
-/* Memory offsets and lengths */
-#define IWL_DR_SMEM_OFFSET		0x400000
-#define IWL_DR_SMEM_LEN			0xD0000
-
 #define IWL_DR_A_PE_A_FW_PRE		"iwlwifi-dr-a0-pe-a0"
 
 static const struct iwl_family_base_params iwl_dr_base = {
@@ -26,8 +22,6 @@ static const struct iwl_family_base_params iwl_dr_base = {
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
-	.smem_offset = IWL_DR_SMEM_OFFSET,
-	.smem_len = IWL_DR_SMEM_LEN,
 	.apmg_not_supported = true,
 	.mac_addr_from_csr = 0x30,
 	.d3_debug_data_base_addr = 0x401000,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index 52a08105d0c4..d1e5cef42fff 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -15,10 +15,6 @@
 /* Lowest firmware core release supported */
 #define IWL_SC_UCODE_CORE_MIN	101
 
-/* Memory offsets and lengths */
-#define IWL_SC_SMEM_OFFSET		0x400000
-#define IWL_SC_SMEM_LEN			0xD0000
-
 #define IWL_SC_A_FM_B_FW_PRE		"iwlwifi-sc-a0-fm-b0"
 #define IWL_SC_A_FM_C_FW_PRE		"iwlwifi-sc-a0-fm-c0"
 #define IWL_SC_A_WH_A_FW_PRE		"iwlwifi-sc-a0-wh-a0"
@@ -31,8 +27,6 @@ static const struct iwl_family_base_params iwl_sc_base = {
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
-	.smem_offset = IWL_SC_SMEM_OFFSET,
-	.smem_len = IWL_SC_SMEM_LEN,
 	.apmg_not_supported = true,
 	.mac_addr_from_csr = 0x30,
 	.d3_debug_data_base_addr = 0x401000,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 03/15] wifi: iwlwifi: max_event_log_size is needed for iwldvm only
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

This is used to set init_evtlog_size and inst_evtlog_size in case those
are not advertised by the firmware's TLVs.
Those two fields are used only in iwldvm.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/7000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/8000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/9000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c    | 1 -
 8 files changed, 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 0ce8d6229bab..563c596240b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -28,7 +28,6 @@ static const struct iwl_family_base_params iwl_22000_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 256,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL_22000_SMEM_OFFSET,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
index c55995fdf1c7..1be72d71fccf 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
@@ -54,7 +54,6 @@ static const struct iwl_family_base_params iwl7000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.apmg_wake_up_wa = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
index 182a8bf5bcf0..834aa520ab0c 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
@@ -40,7 +40,6 @@ static const struct iwl_family_base_params iwl8000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.nvm_hw_section_num = 10,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index 55db225a02fc..2954434ce851 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -31,7 +31,6 @@ static const struct iwl_family_base_params iwl9000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL9000_SMEM_OFFSET,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
index b355384ee210..ee24ded67069 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
@@ -23,7 +23,6 @@ static const struct iwl_family_base_params iwl_ax210_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL_AX210_SMEM_OFFSET,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index 589bc88727a5..1b14ba5a09f9 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -23,7 +23,6 @@ static const struct iwl_family_base_params iwl_bz_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL_BZ_SMEM_OFFSET,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index ecd48aac4e2a..afde84ad0493 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -24,7 +24,6 @@ static const struct iwl_family_base_params iwl_dr_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL_DR_SMEM_OFFSET,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index 75a9a1c56dd3..52a08105d0c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -29,7 +29,6 @@ static const struct iwl_family_base_params iwl_sc_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
-	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
 	.pcie_l1_allowed = true,
 	.smem_offset = IWL_SC_SMEM_OFFSET,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 02/15] wifi: iwlwifi: shadow_ram_support is needed for iwldvm only.
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

Keep that setting only for devices that use iwldvm.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/7000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/8000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/9000.c  | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c    | 1 -
 8 files changed, 8 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index 5b2a5e254d6e..0ce8d6229bab 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -27,7 +27,6 @@
 static const struct iwl_family_base_params iwl_22000_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 256,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
index 2936ccf1dbb2..c55995fdf1c7 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
@@ -53,7 +53,6 @@ static const struct iwl_family_base_params iwl7000_base = {
 	.eeprom_size = OTP_LOW_IMAGE_SIZE_16K,
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
index 3e936ba7f871..182a8bf5bcf0 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
@@ -39,7 +39,6 @@ static const struct iwl_family_base_params iwl8000_base = {
 	.eeprom_size = OTP_LOW_IMAGE_SIZE_32K,
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index 7194f681cec2..55db225a02fc 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -30,7 +30,6 @@ static const struct iwl_family_base_params iwl9000_base = {
 	.eeprom_size = OTP_LOW_IMAGE_SIZE_32K,
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
index 1f862748e33d..b355384ee210 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
@@ -22,7 +22,6 @@
 static const struct iwl_family_base_params iwl_ax210_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index 7b3837b2a8e5..589bc88727a5 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -22,7 +22,6 @@
 static const struct iwl_family_base_params iwl_bz_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index 12feac3bc0a2..ecd48aac4e2a 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -23,7 +23,6 @@
 static const struct iwl_family_base_params iwl_dr_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index f82ba1d64b63..75a9a1c56dd3 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -28,7 +28,6 @@
 static const struct iwl_family_base_params iwl_sc_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
-	.shadow_ram_support = true,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
-- 
2.34.1


^ permalink raw reply related

* [PATCH iwlwifi-next 01/15] wifi: iwlwifi: led_compensation is needed for iwldvm only
From: Miri Korenblit @ 2026-05-13  5:43 UTC (permalink / raw)
  To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260513054402.2897702-1-miriam.rachel.korenblit@intel.com>

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

Keep that setting only for devices that use iwldvm.

Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
 drivers/net/wireless/intel/iwlwifi/cfg/22000.c | 3 +--
 drivers/net/wireless/intel/iwlwifi/cfg/7000.c  | 3 +--
 drivers/net/wireless/intel/iwlwifi/cfg/8000.c  | 3 +--
 drivers/net/wireless/intel/iwlwifi/cfg/9000.c  | 3 +--
 drivers/net/wireless/intel/iwlwifi/cfg/ax210.c | 3 +--
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c    | 1 -
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c    | 1 -
 8 files changed, 5 insertions(+), 13 deletions(-)

diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
index f0453f3f6ba6..5b2a5e254d6e 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/22000.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
  */
 #include <linux/module.h>
 #include <linux/stringify.h>
@@ -28,7 +28,6 @@ static const struct iwl_family_base_params iwl_22000_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 256,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
index f987ad3192c1..2936ccf1dbb2 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/7000.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2012-2014, 2018-2020, 2023, 2025 Intel Corporation
+ * Copyright (C) 2012-2014, 2018-2020, 2023, 2025-2026 Intel Corporation
  * Copyright (C) 2013-2014 Intel Mobile Communications GmbH
  * Copyright (C) 2015 Intel Deutschland GmbH
  */
@@ -54,7 +54,6 @@ static const struct iwl_family_base_params iwl7000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
index 3c844cd419e8..3e936ba7f871 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/8000.c
@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
- * Copyright (C) 2014, 2018-2020, 2023, 2025 Intel Corporation
+ * Copyright (C) 2014, 2018-2020, 2023, 2025-2026 Intel Corporation
  * Copyright (C) 2014-2015 Intel Mobile Communications GmbH
  * Copyright (C) 2016 Intel Deutschland GmbH
  */
@@ -40,7 +40,6 @@ static const struct iwl_family_base_params iwl8000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
index 5872fc9b8caf..7194f681cec2 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/9000.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2021, 2023, 2025 Intel Corporation
+ * Copyright (C) 2018-2021, 2023, 2025-2026 Intel Corporation
  */
 #include <linux/module.h>
 #include <linux/stringify.h>
@@ -31,7 +31,6 @@ static const struct iwl_family_base_params iwl9000_base = {
 	.num_of_queues = 31,
 	.max_tfd_queue_size = 256,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
index 582f61661062..1f862748e33d 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/ax210.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
 /*
  * Copyright (C) 2015-2017 Intel Deutschland GmbH
- * Copyright (C) 2018-2025 Intel Corporation
+ * Copyright (C) 2018-2026 Intel Corporation
  */
 #include <linux/module.h>
 #include <linux/stringify.h>
@@ -23,7 +23,6 @@ static const struct iwl_family_base_params iwl_ax210_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
index c060b12cc952..7b3837b2a8e5 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/bz.c
@@ -23,7 +23,6 @@ static const struct iwl_family_base_params iwl_bz_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
index 3ccbb21276c1..12feac3bc0a2 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/dr.c
@@ -24,7 +24,6 @@ static const struct iwl_family_base_params iwl_dr_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
diff --git a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
index 04c726e8c283..f82ba1d64b63 100644
--- a/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
+++ b/drivers/net/wireless/intel/iwlwifi/cfg/sc.c
@@ -29,7 +29,6 @@ static const struct iwl_family_base_params iwl_sc_base = {
 	.num_of_queues = 512,
 	.max_tfd_queue_size = 65536,
 	.shadow_ram_support = true,
-	.led_compensation = 57,
 	.wd_timeout = IWL_LONG_WD_TIMEOUT,
 	.max_event_log_size = 512,
 	.shadow_reg_enable = true,
-- 
2.34.1


^ permalink raw reply related

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

Hi,

Features, cleanups and fixes from our internal tree.

Thanks,
Miri
---

Avinash Bhatt (2):
  wifi: iwlwifi: mld: implement PSD/EIRP RSSI adjustment
  wifi: iwlwifi: mld: update link grading tables per bandwidth

Avraham Stern (1):
  wifi: iwlwifi: mld: add handler for NAN ULW attribute notification

Emmanuel Grumbach (4):
  wifi: iwlwifi: led_compensation is needed for iwldvm only
  wifi: iwlwifi: shadow_ram_support is needed for iwldvm only.
  wifi: iwlwifi: max_event_log_size is needed for iwldvm only
  wifi: iwlwifi: smem_offset smem_len are not needed from 22000 and up

Ilan Peer (2):
  wifi: iwlwifi: mld: Replace static declarations of IWL_MLD_ALLOC_FN
  wifi: iwlwifi: mld: Add support for NAN multicast data

Johannes Berg (4):
  wifi: iwlwifi: mld: support NPCA capability for UHR devices
  wifi: iwlwifi: mld: implement UHR DPS
  wifi: iwlwifi: mld: give link STA debugfs files a namespace
  wifi: iwlwifi: mld: set correct key mask for NAN

Miri Korenblit (2):
  wifi: iwlwifi: bump core version for BZ/SC/DR to 104
  wifi: iwlwifi: define MODULE_FIRMWARE with the correct API

 .../net/wireless/intel/iwlwifi/cfg/22000.c    |  23 +-
 drivers/net/wireless/intel/iwlwifi/cfg/7000.c |   5 +-
 drivers/net/wireless/intel/iwlwifi/cfg/8000.c |   5 +-
 drivers/net/wireless/intel/iwlwifi/cfg/9000.c |   5 +-
 .../net/wireless/intel/iwlwifi/cfg/ax210.c    |  38 +-
 drivers/net/wireless/intel/iwlwifi/cfg/bz.c   |  13 +-
 drivers/net/wireless/intel/iwlwifi/cfg/dr.c   |  13 +-
 .../net/wireless/intel/iwlwifi/cfg/rf-gf.c    |  13 -
 .../net/wireless/intel/iwlwifi/cfg/rf-hr.c    |  24 --
 drivers/net/wireless/intel/iwlwifi/cfg/sc.c   |  13 +-
 .../wireless/intel/iwlwifi/fw/api/mac-cfg.h   |  32 +-
 .../wireless/intel/iwlwifi/iwl-nvm-parse.c    |   4 +
 .../net/wireless/intel/iwlwifi/mld/debugfs.c  |  18 +-
 .../net/wireless/intel/iwlwifi/mld/iface.c    |  10 +-
 .../net/wireless/intel/iwlwifi/mld/iface.h    |   5 +
 drivers/net/wireless/intel/iwlwifi/mld/key.c  |  50 ++-
 drivers/net/wireless/intel/iwlwifi/mld/link.c | 396 +++++++++++++++---
 .../net/wireless/intel/iwlwifi/mld/mac80211.c |  72 +++-
 drivers/net/wireless/intel/iwlwifi/mld/mld.c  |   1 +
 drivers/net/wireless/intel/iwlwifi/mld/mld.h  |   3 +
 drivers/net/wireless/intel/iwlwifi/mld/nan.c  |  62 ++-
 drivers/net/wireless/intel/iwlwifi/mld/nan.h  |   7 +
 .../net/wireless/intel/iwlwifi/mld/notif.c    |   3 +
 drivers/net/wireless/intel/iwlwifi/mld/phy.c  |  24 +-
 drivers/net/wireless/intel/iwlwifi/mld/sta.c  | 104 ++++-
 drivers/net/wireless/intel/iwlwifi/mld/sta.h  |  11 +
 .../intel/iwlwifi/mld/tests/link-selection.c  |   6 +-
 .../wireless/intel/iwlwifi/mld/tests/utils.c  |   6 +-
 drivers/net/wireless/intel/iwlwifi/mld/tx.c   |  11 +-
 29 files changed, 780 insertions(+), 197 deletions(-)

-- 
2.34.1


^ 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