* [wireless:for-next] BUILD SUCCESS d5ad6ab61cbd89afdb60881f6274f74328af3ee9
From: kernel test robot @ 2026-03-19 4:42 UTC (permalink / raw)
To: Johannes Berg; +Cc: linux-wireless
tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless.git for-next
branch HEAD: d5ad6ab61cbd89afdb60881f6274f74328af3ee9 wifi: mac80211: always free skb on ieee80211_tx_prepare_skb() failure
elapsed time: 754m
configs tested: 163
configs skipped: 2
The following configs have been built successfully.
More configs may be tested in the coming days.
tested configs:
alpha allnoconfig gcc-15.2.0
alpha allyesconfig gcc-15.2.0
alpha defconfig gcc-15.2.0
arc allmodconfig clang-16
arc allnoconfig gcc-15.2.0
arc allyesconfig clang-23
arc defconfig gcc-15.2.0
arc randconfig-001-20260319 gcc-11.5.0
arc randconfig-002-20260319 gcc-11.5.0
arm allnoconfig gcc-15.2.0
arm allyesconfig clang-16
arm defconfig gcc-15.2.0
arm randconfig-001-20260319 gcc-11.5.0
arm randconfig-002-20260319 gcc-11.5.0
arm randconfig-003-20260319 gcc-11.5.0
arm randconfig-004-20260319 gcc-11.5.0
arm64 allmodconfig clang-23
arm64 allnoconfig gcc-15.2.0
arm64 defconfig gcc-15.2.0
arm64 randconfig-001-20260319 gcc-15.2.0
arm64 randconfig-002-20260319 gcc-15.2.0
arm64 randconfig-003-20260319 gcc-15.2.0
arm64 randconfig-004-20260319 gcc-15.2.0
csky allmodconfig gcc-15.2.0
csky allnoconfig gcc-15.2.0
csky defconfig gcc-15.2.0
csky randconfig-001-20260319 gcc-15.2.0
csky randconfig-002-20260319 gcc-15.2.0
hexagon allmodconfig gcc-15.2.0
hexagon allnoconfig gcc-15.2.0
hexagon defconfig gcc-15.2.0
hexagon randconfig-001-20260319 gcc-11.5.0
hexagon randconfig-002-20260319 gcc-11.5.0
i386 allmodconfig clang-20
i386 allnoconfig gcc-15.2.0
i386 allyesconfig clang-20
i386 buildonly-randconfig-001-20260319 gcc-14
i386 buildonly-randconfig-002-20260319 gcc-14
i386 buildonly-randconfig-003-20260319 gcc-14
i386 buildonly-randconfig-004-20260319 gcc-14
i386 buildonly-randconfig-005-20260319 gcc-14
i386 buildonly-randconfig-006-20260319 gcc-14
i386 defconfig gcc-15.2.0
i386 randconfig-001-20260319 gcc-14
i386 randconfig-002-20260319 gcc-14
i386 randconfig-003-20260319 gcc-14
i386 randconfig-004-20260319 gcc-14
i386 randconfig-005-20260319 gcc-14
i386 randconfig-006-20260319 gcc-14
i386 randconfig-007-20260319 gcc-14
i386 randconfig-011-20260319 clang-20
i386 randconfig-012-20260319 clang-20
i386 randconfig-013-20260319 clang-20
i386 randconfig-014-20260319 clang-20
i386 randconfig-015-20260319 clang-20
i386 randconfig-016-20260319 clang-20
i386 randconfig-017-20260319 clang-20
loongarch allmodconfig clang-23
loongarch allnoconfig gcc-15.2.0
loongarch defconfig clang-19
loongarch randconfig-001-20260319 gcc-11.5.0
loongarch randconfig-002-20260319 gcc-11.5.0
m68k allmodconfig gcc-15.2.0
m68k allnoconfig gcc-15.2.0
m68k allyesconfig clang-16
m68k defconfig clang-19
m68k mac_defconfig gcc-15.2.0
microblaze allnoconfig gcc-15.2.0
microblaze allyesconfig gcc-15.2.0
microblaze defconfig clang-19
mips allmodconfig gcc-15.2.0
mips allnoconfig gcc-15.2.0
mips allyesconfig gcc-15.2.0
nios2 allmodconfig clang-23
nios2 allnoconfig clang-23
nios2 defconfig clang-19
nios2 randconfig-001-20260319 gcc-11.5.0
nios2 randconfig-002-20260319 gcc-11.5.0
openrisc allmodconfig clang-23
openrisc allnoconfig clang-23
openrisc defconfig gcc-15.2.0
parisc allmodconfig gcc-15.2.0
parisc allnoconfig clang-23
parisc allyesconfig clang-19
parisc defconfig gcc-15.2.0
parisc randconfig-001-20260319 clang-19
parisc randconfig-002-20260319 clang-19
parisc64 defconfig clang-19
powerpc allmodconfig gcc-15.2.0
powerpc allnoconfig clang-23
powerpc chrp32_defconfig clang-19
powerpc randconfig-001-20260319 clang-19
powerpc randconfig-002-20260319 clang-19
powerpc64 randconfig-001-20260319 clang-19
powerpc64 randconfig-002-20260319 clang-19
riscv allmodconfig clang-23
riscv allnoconfig clang-23
riscv allyesconfig clang-16
riscv defconfig gcc-15.2.0
s390 allmodconfig clang-19
s390 allnoconfig clang-23
s390 allyesconfig gcc-15.2.0
s390 defconfig gcc-15.2.0
sh allmodconfig gcc-15.2.0
sh allnoconfig clang-23
sh allyesconfig clang-19
sh defconfig gcc-14
sparc allnoconfig clang-23
sparc defconfig gcc-15.2.0
sparc randconfig-001-20260319 gcc-8.5.0
sparc randconfig-002-20260319 gcc-8.5.0
sparc64 allmodconfig clang-23
sparc64 defconfig gcc-14
sparc64 randconfig-001-20260319 gcc-8.5.0
sparc64 randconfig-002-20260319 gcc-8.5.0
um allmodconfig clang-19
um allnoconfig clang-23
um allyesconfig gcc-15.2.0
um defconfig gcc-14
um i386_defconfig gcc-14
um randconfig-001-20260319 gcc-8.5.0
um randconfig-002-20260319 gcc-8.5.0
um x86_64_defconfig gcc-14
x86_64 allmodconfig clang-20
x86_64 allnoconfig clang-23
x86_64 allyesconfig clang-20
x86_64 buildonly-randconfig-001-20260319 clang-20
x86_64 buildonly-randconfig-002-20260319 clang-20
x86_64 buildonly-randconfig-003-20260319 clang-20
x86_64 buildonly-randconfig-004-20260319 clang-20
x86_64 buildonly-randconfig-005-20260319 clang-20
x86_64 buildonly-randconfig-006-20260319 clang-20
x86_64 defconfig gcc-14
x86_64 kexec clang-20
x86_64 randconfig-001-20260319 gcc-14
x86_64 randconfig-002-20260319 gcc-14
x86_64 randconfig-003-20260319 gcc-14
x86_64 randconfig-004-20260319 gcc-14
x86_64 randconfig-005-20260319 gcc-14
x86_64 randconfig-006-20260319 gcc-14
x86_64 randconfig-011-20260319 gcc-13
x86_64 randconfig-012-20260319 gcc-13
x86_64 randconfig-013-20260319 gcc-13
x86_64 randconfig-014-20260319 gcc-13
x86_64 randconfig-015-20260319 gcc-13
x86_64 randconfig-016-20260319 gcc-13
x86_64 randconfig-071-20260319 clang-20
x86_64 randconfig-072-20260319 clang-20
x86_64 randconfig-073-20260319 clang-20
x86_64 randconfig-074-20260319 clang-20
x86_64 randconfig-075-20260319 clang-20
x86_64 randconfig-076-20260319 clang-20
x86_64 rhel-9.4 clang-20
x86_64 rhel-9.4-bpf gcc-14
x86_64 rhel-9.4-func clang-20
x86_64 rhel-9.4-kselftests clang-20
x86_64 rhel-9.4-kunit gcc-14
x86_64 rhel-9.4-ltp gcc-14
x86_64 rhel-9.4-rust clang-20
xtensa allnoconfig clang-23
xtensa allyesconfig clang-23
xtensa randconfig-001-20260319 gcc-8.5.0
xtensa randconfig-002-20260319 gcc-8.5.0
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH ath-current] wifi: ath12k: prepare REO update element only for primary link
From: Vasanthakumar Thiagarajan @ 2026-03-19 3:46 UTC (permalink / raw)
To: Baochen Qiang, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260210-ath12k-rxtid-double-free-v1-1-8b523fb2886d@oss.qualcomm.com>
On 2/10/2026 8:37 AM, Baochen Qiang wrote:
> Commit [1] introduces dp->reo_cmd_update_rx_queue_list for the purpose
> of tracking all pending REO queue flush commands. The helper
> ath12k_dp_prepare_reo_update_elem() allocates an element and populates
> it with REO queue information, then add it to the list. The element would
> be helpful during clean up stage to finally unmap/free the corresponding
> REO queue buffer.
>
> In MLO scenarios with more than one links, for non dp_primary_link_only
> chips like WCN7850, that helper is called for each link peer. This
> results in multiple elements added to the list but all of them pointing
> to the same REO queue buffer. Consequently the same buffer gets
> unmap/freed multiple times:
>
> BUG kmalloc-2k (Tainted: G B W O ): Object already free
> -----------------------------------------------------------------------------
> Allocated in ath12k_wifi7_dp_rx_assign_reoq+0xce/0x280 [ath12k_wifi7] age=7436 cpu=10 pid=16130
> __kmalloc_noprof
> ath12k_wifi7_dp_rx_assign_reoq
> ath12k_dp_rx_peer_tid_setup
> ath12k_dp_peer_setup
> ath12k_mac_station_add
> ath12k_mac_op_sta_state
> [...]
> Freed in ath12k_dp_rx_tid_cleanup.part.0+0x25/0x40 [ath12k] age=1 cpu=27 pid=16137
> kfree
> ath12k_dp_rx_tid_cleanup.part.0
> ath12k_dp_rx_reo_cmd_list_cleanup
> ath12k_dp_cmn_device_deinit
> ath12k_core_stop
> ath12k_core_hw_group_cleanup
> ath12k_pci_remove
>
> Fix this by allowing list addition for primary link only. Note
> dp_primary_link_only chips like QCN9274 are not affected by this change,
> because that's what they were doing in the first place.
>
> Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302-QCAHMTSWPL_V1.0_V2.0_SILICONZ-1.115823.3
>
> Fixes: 3bf2e57e7d6c ("wifi: ath12k: Add Retry Mechanism for REO RX Queue Update Failures") # [1]
> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=221011
> Signed-off-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
Vasanthakumar Thiagarajan <vasanthakumar.thiagarajan@oss.qualcomm.com>
^ permalink raw reply
* Re: [PATCH] wifi: ath12k: fix MAC address copy on big endian
From: Baochen Qiang @ 2026-03-19 3:00 UTC (permalink / raw)
To: Alexander Wilhelm, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260317-fix-mac-addr-copy-on-big-endian-v1-1-b7b6c49cb07f@westermo.com>
On 3/17/2026 7:22 PM, Alexander Wilhelm wrote:
> The ath12k_dp_get_mac_addr function performs a simple memcpy from a
> CPU-native data types into an u8 array. On a big-endian architecture, this
> later results in a null‑pointer dereference. Convert the data to
curious how could this happen? how matter the endian, it is just six bytes which are not a
pointer hence can not be dereferenced, no?
> little‑endian first, then copy it into the target array.
>
> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
> ---
> drivers/net/wireless/ath/ath12k/dp.h | 7 +++++--
> 1 file changed, 5 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/dp.h b/drivers/net/wireless/ath/ath12k/dp.h
> index f8cfc7bb29dd..50957915dbf4 100644
> --- a/drivers/net/wireless/ath/ath12k/dp.h
> +++ b/drivers/net/wireless/ath/ath12k/dp.h
> @@ -647,8 +647,11 @@ int ath12k_dp_arch_rx_tid_delete_handler(struct ath12k_dp *dp,
>
> static inline void ath12k_dp_get_mac_addr(u32 addr_l32, u16 addr_h16, u8 *addr)
> {
> - memcpy(addr, &addr_l32, 4);
> - memcpy(addr + 4, &addr_h16, ETH_ALEN - 4);
> + __le32 le_addr_l32 = cpu_to_le32(addr_l32);
> + __le16 le_addr_h16 = cpu_to_le16(addr_h16);
> +
> + memcpy(addr, &le_addr_l32, 4);
> + memcpy(addr + 4, &le_addr_h16, ETH_ALEN - 4);
> }
>
> static inline struct ath12k_dp *
>
> ---
> base-commit: 702847e8cfd51856836a282db2073defd7cfd80c
> change-id: 20260317-fix-mac-addr-copy-on-big-endian-f1a4fea40184
>
> Best regards,
^ permalink raw reply
* Re: [PATCH] wifi: ath12k: fix channel list copy on big endian
From: Baochen Qiang @ 2026-03-19 2:47 UTC (permalink / raw)
To: Alexander Wilhelm, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260317-fix-channel-list-copy-v1-1-5e1e5ae1c5d5@westermo.com>
On 3/17/2026 8:54 PM, Alexander Wilhelm wrote:
> The ath12k_wmi_scan_req_arg structure defines the channel list in
> CPU-native order, while wmi_start_scan_cmd expects the values in
> little-endian format. The simple memcpy causes the hardware scan to fail on
> big-endian architectures. Set __le32* type for the tmp_ptr and swap channel
> values to support both architectures correctly.
>
> Signed-off-by: Alexander Wilhelm <alexander.wilhelm@westermo.com>
> ---
> drivers/net/wireless/ath/ath12k/wmi.c | 8 +++++---
> 1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 65a05a9520ff..9e1d3c662852 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -2571,7 +2571,8 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
> struct wmi_tlv *tlv;
> void *ptr;
> int i, ret, len;
> - u32 *tmp_ptr, extraie_len_with_pad = 0;
> + __le32 *tmp_ptr;
> + u32 extraie_len_with_pad = 0;
> struct ath12k_wmi_hint_short_ssid_arg *s_ssid = NULL;
> struct ath12k_wmi_hint_bssid_arg *hint_bssid = NULL;
>
> @@ -2656,9 +2657,10 @@ int ath12k_wmi_send_scan_start_cmd(struct ath12k *ar,
> tlv = ptr;
> tlv->header = ath12k_wmi_tlv_hdr(WMI_TAG_ARRAY_UINT32, len);
> ptr += TLV_HDR_SIZE;
> - tmp_ptr = (u32 *)ptr;
> + tmp_ptr = (__le32 *)ptr;
>
> - memcpy(tmp_ptr, arg->chan_list, arg->num_chan * 4);
> + for (i = 0; i < arg->num_chan; i++)
> + tmp_ptr[i] = cpu_to_le32(arg->chan_list[i]);
>
> ptr += len;
>
>
> ---
> base-commit: 702847e8cfd51856836a282db2073defd7cfd80c
> change-id: 20260317-fix-channel-list-copy-cef5cad24fb6
>
> Best regards,
Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>
^ permalink raw reply
* [PATCH v2] wireless-regdb: Add regulatory info for CEPT countries FO, GI, IM, SM and VA listed by WiFi Alliance
From: Ping-Ke Shih @ 2026-03-19 2:35 UTC (permalink / raw)
To: wens; +Cc: linux-wireless, wireless-regdb
From: Ping-Ke Shih <pkshih@realtek.com>
In commit 5a8ced5ad313 ("wireless-regdb: Update regulatory info for CEPT
countries for 6GHz listed by WiFi Alliance"), the following are skipped as
they do not have corresponding entries in the database yet.
- Faroe Islands (FO)
- Gibraltar (GI)
- Isle of Man (IM)
- San Marino (SM)
- Holy See (Vatican City State) (VA)
Look up the CEPT decisions [2], and add entries along with decisions [3],
[4] and [5] for 2/5/6 GHz regulations.
The 2 GHz band is now governed by ERC Recommendation 70-03 [6] with the
withdrawal of ERC Decision ERC/DEC/(01)07 by ECC Decision (11)05 [3].
By ERC Recommendation 70-03 annex 3 (WIDEBAND DATA TRANSMISSION SYSTEMS):
* 2400-2483.5 MHz
- 100 mW
The 5 GHz band by ECC Decision (04)08 [4]:
* 5150-5250 MHz
- 200 mW
- Indoor use
* 5250-5350 MHz
- 200 mW (due to TPC required, -3dBm, 100 mW is adopted)
- DFS, TPC
- Indoor use
* 5470-5725 MHz
- 1 W (due to TPC required, -3dBm, 500 mW is adopted)
- DFS, TPC
- Indoor and outdoor use
The 6 GHz band by ECC Decision (20)01 [5]:
* LPI devices (adopted)
- 5945-6425 MHz
- Restricted to indoor use only
- Maximum mean e.i.r.p.: 23 dBm
- Maximum mean e.i.r.p. density: 10 dBm/MHz
* VLP devices
- 5945-6425 MHz
- Indoors and outdoors
- Maximum mean e.i.r.p.: 14 dBm
- Maximum mean e.i.r.p. density: 1 dBm/MHz
[1] https://www.wi-fi.org/regulations-enabling-6-ghz-wi-fi
[2] https://docdb.cept.org/document/category/ECC_Decisions?status=ACTIVE
[3] https://docdb.cept.org/download/1535
[4] https://docdb.cept.org/download/4501
[5] https://docdb.cept.org/download/4685
[6] https://docdb.cept.org/download/4916
Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
---
v2:
- rephrase commit message of 2GHz part
- update ERC Recommendation 70-03 [6] link to the latest
https://docdb.cept.org/download/4916
- fix 2GHz freqnecy range starting from 2400MHz
---
db.txt | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/db.txt b/db.txt
index d54ef78e0da8..343b256063a9 100644
--- a/db.txt
+++ b/db.txt
@@ -731,6 +731,13 @@ country FM: DFS-FCC
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
+country FO: DFS-ETSI
+ (2400 - 2483.5 @ 40), (100 mW)
+ (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+ (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
+ (5470 - 5725 @ 160), (500 mW), DFS
+ (5945 - 6425 @ 320), (23), NO-OUTDOOR
+
# FR as part of EU/CEPT accepted decisions 2005/513/EC (5GHz RLAN, EN 301 893)
# and 2006/771/EC (amended by 2008/432/EC, Short-Range Devices, EN 300 440)
# EU decision 2005/513/EC: https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:02005D0513-20070213
@@ -801,6 +808,13 @@ country GH: DFS-FCC
(5490 - 5730 @ 160), (24), DFS
(5735 - 5835 @ 80), (30)
+country GI: DFS-ETSI
+ (2400 - 2483.5 @ 40), (100 mW)
+ (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+ (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
+ (5470 - 5725 @ 160), (500 mW), DFS
+ (5945 - 6425 @ 320), (23), NO-OUTDOOR
+
country GL: DFS-ETSI
(2402 - 2482 @ 40), (20)
(5170 - 5250 @ 80), (20), AUTO-BW, wmmrule=ETSI
@@ -976,6 +990,13 @@ country IL: DFS-ETSI
(5725 - 5875 @ 80), (25 mW), AUTO-BW
(5945 - 6425 @ 320), (200 mW), NO-OUTDOOR
+country IM: DFS-ETSI
+ (2400 - 2483.5 @ 40), (100 mW)
+ (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+ (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
+ (5470 - 5725 @ 160), (500 mW), DFS
+ (5945 - 6425 @ 320), (23), NO-OUTDOOR
+
# Source:
# https://dot.gov.in/spectrummanagement/delicensing-24-24835-ghz-band-gsr-45-e-5150-5350-ghz-gsr-46-e-and-5725-5875-ghz
# https://dot.gov.in/spectrummanagement/license-exemption-5-ghz-gsr-1048e-dated-22102018
@@ -1855,6 +1876,13 @@ country SK: DFS-ETSI
# 60 GHz band channels 1-4 (ETSI EN 302 567)
(57000 - 66000 @ 2160), (40)
+country SM: DFS-ETSI
+ (2400 - 2483.5 @ 40), (100 mW)
+ (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+ (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
+ (5470 - 5725 @ 160), (500 mW), DFS
+ (5945 - 6425 @ 320), (23), NO-OUTDOOR
+
# Source:
# Regulation N° 2004-005 ART/DG/DRC/D.Rég
country SN: DFS-FCC
@@ -2072,6 +2100,13 @@ country UZ: DFS-ETSI
(5170 - 5250 @ 80), (20), AUTO-BW
(5250 - 5330 @ 80), (20), DFS, AUTO-BW
+country VA: DFS-ETSI
+ (2400 - 2483.5 @ 40), (100 mW)
+ (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
+ (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
+ (5470 - 5725 @ 160), (500 mW), DFS
+ (5945 - 6425 @ 320), (23), NO-OUTDOOR
+
# Source:
# http://www.ntrc.vc/regulations/Jun_2006_Spectrum_Managment_Regulations.pdf
country VC: DFS-ETSI
--
2.25.1
^ permalink raw reply related
* Re: [PATCH] wireless-regdb: Add regulatory info for CEPT countries FO, GI, IM, SM and VA listed by WiFi Alliance
From: Ping-Ke Shih @ 2026-03-19 2:33 UTC (permalink / raw)
To: wens; +Cc: linux-wireless, wireless-regdb
In-Reply-To: <CAGb2v65PcZcBYg7qaeFaVH0=1fowOkW+7gL5wWA0wTMBu74JHg@mail.gmail.com>
Chen-Yu Tsai <wens@kernel.org> wrote:
>
> On Wed, Mar 18, 2026 at 2:48 PM Ping-Ke Shih <pkshih@gmail.com> wrote:
> >
> > From: Ping-Ke Shih <pkshih@realtek.com>
> >
> > In commit 5a8ced5ad313 ("wireless-regdb: Update regulatory info for CEPT
> > countries for 6GHz listed by WiFi Alliance"), the following are skipped as
> > they do not have corresponding entries in the database yet.
> >
> > - Faroe Islands (FO)
> > - Gibraltar (GI)
> > - Isle of Man (IM)
> > - San Marino (SM)
> > - Holy See (Vatican City State) (VA)
>
> Confirmed the list. Also checked against another source [1].
>
> [1] https://help.ui.com/hc/en-us/articles/8691786444567-Regions-Supporting-6-GHz
>
> > Look up the CEPT decisions [2], and add entries along with decisions [3],
> > [4] and [5] for 2/5/6 GHz regulations.
> >
> > The 2 GHz band by ECC Decision (11)05 [3], which the adoption of ERC
> > Recommendation 70-03 [6], the regulations and the frequency bands to be
> > used for Short Range Devices (SRDs) are included in specific annexes to
>
> The 2 GHz band is now governed by ERC Recommendation 70-03 [6] with the
> withdrawal of ERC Decision ERC/DEC/(01)07 by ECC Decision (11)05 [3].
will update by v2.
>
> > this Recommendation. By ERC Recommendation 70-03 annex 3 (WIDEBAND DATA
> > TRANSMISSION SYSTEMS):
> >
> > * 2400-2483.5 MHz
> > - 100 mW
>
> Looks correct.
>
> ERC Recommendation 70-03 annex 3 also includes the 60GHz range (57-71 GHz).
> Can you check that? We would need some other source of information like
> the WiFi Alliance page to verify that the countries have adopted the
> decision. I don't think the CEPT decisions are directly binding.
>
> The end of the document also has a table of the implementation status
> of some bands in some countries. It is obvious the table is not complete.
For 60GHz, it looks like EU implementation deadline on 1 January 2020 [1], but
CEPT countries aren't all EU. I only found ECC Report 288 [2] [3], but it isn't
decision (so it must not have a implementation deadline). I think we can't fill
60GHz entries for now.
[1] https://eur-lex.europa.eu/eli/dec_impl/2019/1345/oj/eng
[2] https://docdb.cept.org/document/8213
[3] https://docdb.cept.org/download/1365
>
> > The 5 GHz band by ECC Decision (04)08 [4]:
> >
> > * 5150-5250 MHz
> > - 200 mW
> > - Indoor use
> > * 5250-5350 MHz
> > - 200 mW (due to TPC required, -3dBm, 100 mW is adopted)
> > - DFS, TPC
> > - Indoor use
> > * 5470-5725 MHz
> > - 1 W (due to TPC required, -3dBm, 500 mW is adopted)
> > - DFS, TPC
> > - Indoor and outdoor use
> >
> > The 6 GHz band by ECC Decision (20)01 [5]:
> >
> > * LPI devices (adopted)
> > - 5945-6425 MHz
> > - Restricted to indoor use only
> > - Maximum mean e.i.r.p.: 23 dBm
> > - Maximum mean e.i.r.p. density: 10 dBm/MHz
> > * VLP devices
> > - 5945-6425 MHz
> > - Indoors and outdoors
> > - Maximum mean e.i.r.p.: 14 dBm
> > - Maximum mean e.i.r.p. density: 1 dBm/MHz
>
> Looks correct.
>
> > [1] https://www.wi-fi.org/regulations-enabling-6-ghz-wi-fi
> > [2] https://docdb.cept.org/document/category/ECC_Decisions?status=ACTIVE
> > [3] https://docdb.cept.org/download/1535
> > [4] https://docdb.cept.org/download/4501
> > [5] https://docdb.cept.org/download/4685
> > [6] https://docdb.cept.org/download/3700
>
> This doesn't seem to be the latest version. The online version is here:
>
> https://docdb.cept.org/document/845
>
> and shows the latest revision was published on Feb 13, 2026.
will update to https://docdb.cept.org/download/4916 by v2.
>
> > Signed-off-by: Ping-Ke Shih <pkshih@realtek.com>
> > ---
> > db.txt | 35 +++++++++++++++++++++++++++++++++++
> > 1 file changed, 35 insertions(+)
> >
> > diff --git a/db.txt b/db.txt
> > index d54ef78e0da8..e2afb145ede5 100644
> > --- a/db.txt
> > +++ b/db.txt
> > @@ -731,6 +731,13 @@ country FM: DFS-FCC
> > (5490 - 5730 @ 160), (24), DFS
> > (5735 - 5835 @ 80), (30)
> >
> > +country FO: DFS-ETSI
> > + (2402 - 2483.5 @ 40), (100 mW)
>
> This should start at 2400 for all the newly added countries.
Oops. Sorry for the mistakes.
>
> > + (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
> > + (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
> > + (5470 - 5725 @ 160), (500 mW), DFS
> > + (5945 - 6425 @ 320), (23), NO-OUTDOOR
> > +
> > # FR as part of EU/CEPT accepted decisions 2005/513/EC (5GHz RLAN, EN 301 893)
> > # and 2006/771/EC (amended by 2008/432/EC, Short-Range Devices, EN 300 440)
> > # EU decision 2005/513/EC: https://eur-lex.europa.eu/legal-content/EN/TXT/?uri=CELEX:02005D0513-20070213
> > @@ -801,6 +808,13 @@ country GH: DFS-FCC
> > (5490 - 5730 @ 160), (24), DFS
> > (5735 - 5835 @ 80), (30)
> >
> > +country GI: DFS-ETSI
> > + (2402 - 2483.5 @ 40), (100 mW)
> > + (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
> > + (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
> > + (5470 - 5725 @ 160), (500 mW), DFS
> > + (5945 - 6425 @ 320), (23), NO-OUTDOOR
> > +
> > country GL: DFS-ETSI
> > (2402 - 2482 @ 40), (20)
> > (5170 - 5250 @ 80), (20), AUTO-BW, wmmrule=ETSI
> > @@ -976,6 +990,13 @@ country IL: DFS-ETSI
> > (5725 - 5875 @ 80), (25 mW), AUTO-BW
> > (5945 - 6425 @ 320), (200 mW), NO-OUTDOOR
> >
> > +country IM: DFS-ETSI
> > + (2402 - 2483.5 @ 40), (100 mW)
> > + (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
> > + (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
> > + (5470 - 5725 @ 160), (500 mW), DFS
> > + (5945 - 6425 @ 320), (23), NO-OUTDOOR
> > +
> > # Source:
> > # https://dot.gov.in/spectrummanagement/delicensing-24-24835-ghz-band-gsr-45-e-5150-5350-ghz-gsr-46-e-and-5725-5875-ghz
> > # https://dot.gov.in/spectrummanagement/license-exemption-5-ghz-gsr-1048e-dated-22102018
> > @@ -1855,6 +1876,13 @@ country SK: DFS-ETSI
> > # 60 GHz band channels 1-4 (ETSI EN 302 567)
> > (57000 - 66000 @ 2160), (40)
> >
> > +country SM: DFS-ETSI
> > + (2402 - 2483.5 @ 40), (100 mW)
> > + (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
> > + (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
> > + (5470 - 5725 @ 160), (500 mW), DFS
> > + (5945 - 6425 @ 320), (23), NO-OUTDOOR
> > +
> > # Source:
> > # Regulation N° 2004-005 ART/DG/DRC/D.Rég
> > country SN: DFS-FCC
> > @@ -2072,6 +2100,13 @@ country UZ: DFS-ETSI
> > (5170 - 5250 @ 80), (20), AUTO-BW
> > (5250 - 5330 @ 80), (20), DFS, AUTO-BW
> >
> > +country VA: DFS-ETSI
> > + (2402 - 2483.5 @ 40), (100 mW)
> > + (5150 - 5250 @ 80), (200 mW), NO-OUTDOOR, AUTO-BW
> > + (5250 - 5350 @ 80), (100 mW), DFS, NO-OUTDOOR, AUTO-BW
> > + (5470 - 5725 @ 160), (500 mW), DFS
> > + (5945 - 6425 @ 320), (23), NO-OUTDOOR
> > +
> > # Source:
> > # http://www.ntrc.vc/regulations/Jun_2006_Spectrum_Managment_Regulations.pdf
> > country VC: DFS-ETSI
> > --
> > 2.25.1
> >
^ permalink raw reply
* Re: [GIT PULL] wireless-2026-03-18
From: patchwork-bot+netdevbpf @ 2026-03-19 2:30 UTC (permalink / raw)
To: Johannes Berg; +Cc: netdev, linux-wireless
In-Reply-To: <20260318172515.381148-3-johannes@sipsolutions.net>
Hello:
This pull request was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 18 Mar 2026 18:20:49 +0100 you wrote:
> Hi,
>
> So maybe a couple more fixes than I'd like, but here we
> are, and it's small. I also failed to notice the missing
> "wifi:" subject for one of the commits, but didn't rebase
> just because of that now.
>
> [...]
Here is the summary with links:
- [GIT,PULL] wireless-2026-03-18
https://git.kernel.org/netdev/net/c/7c46bd845d89
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* RE: [PATCH rtw-next v2] wifi: rtw88: TX QOS Null data the same way as Null data
From: Ping-Ke Shih @ 2026-03-19 1:29 UTC (permalink / raw)
To: Bitterblue Smith, linux-wireless@vger.kernel.org
In-Reply-To: <2b53fb0d-b1ed-47b6-8caa-2bb9ae2acb80@gmail.com>
Bitterblue Smith <rtl8821cerfe2@gmail.com> wrote:
> When filling out the TX descriptor, Null data frames are treated like
> management frames, but QOS Null data frames are treated like normal
> data frames. Somehow this causes a problem for the firmware.
>
> When connected to a network in the 2.4 GHz band, wpa_supplicant (or
> NetworkManager?) triggers a scan every five minutes. During these scans
> mac80211 transmits many QOS Null frames in quick succession. Because
> these frames are marked with IEEE80211_TX_CTL_REQ_TX_STATUS, rtw88
> asks the firmware to report the TX ACK status for each of these frames.
> Sometimes the firmware can't process the TX status requests quickly
> enough, they add up, it only processes some of them, and then marks
> every subsequent TX status report with the wrong number.
>
> The symptom is that after a while the warning "failed to get tx report
> from firmware" appears every five minutes.
>
> This problem apparently happens only with the older RTL8723D, RTL8821A,
> RTL8812A, and probably RTL8703B chips.
>
> Treat QOS Null data frames the same way as Null data frames. This seems
> to avoid the problem.
>
> Tested with RTL8821AU, RTL8723DU, RTL8811CU, and RTL8812BU.
>
> Signed-off-by: Bitterblue Smith <rtl8821cerfe2@gmail.com>
Acked-by: Ping-Ke Shih <pkshih@realtek.com>
^ permalink raw reply
* RE: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: Ping-Ke Shih @ 2026-03-19 1:24 UTC (permalink / raw)
To: LB F; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqQ3tS_aQpmf7xLkaCG9W55ATQXP=tnRNdjBAG8waqg8yA@mail.gmail.com>
LB F <goainwo@gmail.com> wrote:
> Ping-Ke Shih <pkshih@realtek.com> wrote:
> > I add a printk to show the case VHT and NSS==0 as below. Please help to
> > collect the output, and then I can see what it happened.
>
> Hi Ping-Ke,
>
> I applied your diagnostic patch (using pr_err for maximum log
> visibility) and spent the last couple of days testing it on the
> affected hardware. The results answer both open questions cleanly.
>
> ---
>
> Regarding your earlier question:
> > Not sure if this is because PCIE bridge has no ASPM capability?
>
> You were correct. The very beginning of the boot log shows:
>
> [0.177872] ACPI FADT declares the system doesn't support PCIe ASPM,
> so disable it
> [15.157752] r8169 0000:07:00.0: can't disable ASPM; OS doesn't have
> ASPM control
>
> The BIOS on this HP laptop uses the ACPI FADT table to globally revoke
> OS control over PCIe ASPM before Linux even takes over. This has an
> important implication: since ASPM is already disabled at the hardware
> level by firmware, the instability on this specific SKU is caused
> entirely by LPS Deep Mode, not ASPM itself.
Checking rtw88 code related to rtw_pci_disable_aspm, I found that driver
does check device ASPM capability before configuring ASPM. It looks
a little weird why OS doesn't turn off these capabilities of device.
Maybe we should check the capabilities of PCI bridge side?
>
> This explains why the ASPM-only quirk (v1 patch) did not stop the h2c
> timeouts -- ASPM was never actually active on this machine to begin
> with. Disabling LPS Deep Mode via the v2 quirk is what eliminates the
> firmware timeout loop entirely.
I think there are two problems. One is ASPM causing system frozen, and
the other is LPS deep mode causing H2C timeouts. If you turn on ASPM
and disable LPS deep mode, I feel H2C timeout can disappear, but it
might go frozen first though.
Ping-Ke
^ permalink raw reply
* RE: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: Ping-Ke Shih @ 2026-03-19 0:49 UTC (permalink / raw)
To: LB F; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqS-wYLsH8zuW-Kbd6OqEuwXOaBWLTupMD8tpekagj=jjA@mail.gmail.com>
LB F <goainwo@gmail.com> wrote:
> Hi Ping-Ke,
>
> I successfully collected the output with your diagnostic printk.
>
> Here is the exact log entry triggered when the warning fires:
>
> [ 180.424146] VHT NSS=0 pkt_stat->rate=0x65 rx_status->band=1
> rx_status->rate_idx=0
> [ 180.424157] WARNING: net/mac80211/rx.c:5491 at
> ieee80211_rx_list+0x177/0x1020 [mac80211]
>
> Looking at the rtw88 source code, this perfectly explains why `nss` is 0:
> 1. The hardware/firmware reports `pkt_stat->rate = 0x65` (101 in decimal).
> 2. `rtw_rx_fill_rx_status()` checks if `pkt_stat->rate >=
> DESC_RATEVHT1SS_MCS0` (which is `0x2c`). Since `0x65 >= 0x2c`, it
> correctly sets `rx_status->encoding = RX_ENC_VHT`.
> 3. It then calls `rtw_desc_to_mcsrate(pkt_stat->rate,
> &rx_status->rate_idx, &rx_status->nss)`.
> 4. Inside `rtw_desc_to_mcsrate()`, the value `0x65` falls completely
> outside any known bounds. The highest defined rate in `enum
> rtw_trx_desc_rate` is `DESC_RATEVHT4SS_MCS9` (`0x53`). The HT range
> (`DESC_RATEMCS0` to `DESC_RATEMCS31`) ends at `0x2b`.
> 5. Because `0x65` matches absolutely none of the `if/else` brackets in
> `rtw_desc_to_mcsrate()`, the function simply returns without mutating
> `mcs` and `nss`.
> 6. Since `rx_status` was initialized with `memset(rx_status, 0, ...)`
> at the beginning of the function, `rx_status->nss` remains `0`.
>
> So mac80211 complains because the rtw88 driver doesn't know what rate
> `0x65` means, leaves NSS at 0, but still flags it as a VHT packet.
>
> Any idea what `0x65` represents from the hardware's perspective? Is it
> a firmware bug or a proprietary control/management frame rate index?
>
> Looking forward to your thoughts!
Not sure what hardware get wrong. Let's validate rate when reading from
hardware. Since 1M rate can only 20MHz, I set it together.
Please help to test below. I suppose you can see "weird rate=xxx", but
"WARNING: net/mac80211/rx.c:5491" disappears.
diff --git a/drivers/net/wireless/realtek/rtw88/rx.c b/drivers/net/wireless/realtek/rtw88/rx.c
index 8b0afaaffaa0..3d5e48264fc5 100644
--- a/drivers/net/wireless/realtek/rtw88/rx.c
+++ b/drivers/net/wireless/realtek/rtw88/rx.c
@@ -295,6 +295,12 @@ void rtw_rx_query_rx_desc(struct rtw_dev *rtwdev, void *rx_desc8,
pkt_stat->tsf_low = le32_get_bits(rx_desc->w5, RTW_RX_DESC_W5_TSFL);
+ if (pkt_stat->rate >= DESC_RATE_MAX) {
+ printk("weird rate=%d\n", pkt_stat->rate);
+ pkt_stat->rate = DESC_RATE1M;
+ pkt_stat->bw = RTW_CHANNEL_WIDTH_20;
+ }
+
/* drv_info_sz is in unit of 8-bytes */
pkt_stat->drv_info_sz *= 8;
Ping-Ke
^ permalink raw reply related
* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-03-19 0:22 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <CALdGYqQ3tS_aQpmf7xLkaCG9W55ATQXP=tnRNdjBAG8waqg8yA@mail.gmail.com>
Hi Ping-Ke,
I successfully collected the output with your diagnostic printk.
Here is the exact log entry triggered when the warning fires:
[ 180.424146] VHT NSS=0 pkt_stat->rate=0x65 rx_status->band=1
rx_status->rate_idx=0
[ 180.424157] WARNING: net/mac80211/rx.c:5491 at
ieee80211_rx_list+0x177/0x1020 [mac80211]
Looking at the rtw88 source code, this perfectly explains why `nss` is 0:
1. The hardware/firmware reports `pkt_stat->rate = 0x65` (101 in decimal).
2. `rtw_rx_fill_rx_status()` checks if `pkt_stat->rate >=
DESC_RATEVHT1SS_MCS0` (which is `0x2c`). Since `0x65 >= 0x2c`, it
correctly sets `rx_status->encoding = RX_ENC_VHT`.
3. It then calls `rtw_desc_to_mcsrate(pkt_stat->rate,
&rx_status->rate_idx, &rx_status->nss)`.
4. Inside `rtw_desc_to_mcsrate()`, the value `0x65` falls completely
outside any known bounds. The highest defined rate in `enum
rtw_trx_desc_rate` is `DESC_RATEVHT4SS_MCS9` (`0x53`). The HT range
(`DESC_RATEMCS0` to `DESC_RATEMCS31`) ends at `0x2b`.
5. Because `0x65` matches absolutely none of the `if/else` brackets in
`rtw_desc_to_mcsrate()`, the function simply returns without mutating
`mcs` and `nss`.
6. Since `rx_status` was initialized with `memset(rx_status, 0, ...)`
at the beginning of the function, `rx_status->nss` remains `0`.
So mac80211 complains because the rtw88 driver doesn't know what rate
`0x65` means, leaves NSS at 0, but still flags it as a VHT packet.
Any idea what `0x65` represents from the hardware's perspective? Is it
a firmware bug or a proprietary control/management frame rate index?
Looking forward to your thoughts!
Best regards,
Oleksandr
^ permalink raw reply
* Re: [BUG] wifi: rtw88: Hard system freeze on RTL8821CE when power_save is enabled (LPS/ASPM conflict)
From: LB F @ 2026-03-18 23:55 UTC (permalink / raw)
To: Ping-Ke Shih; +Cc: linux-wireless@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <cb32c1eefb614a8bb96ef6fe2c4f4989@realtek.com>
Ping-Ke Shih <pkshih@realtek.com> wrote:
> I add a printk to show the case VHT and NSS==0 as below. Please help to
> collect the output, and then I can see what it happened.
Hi Ping-Ke,
I applied your diagnostic patch (using pr_err for maximum log
visibility) and spent the last couple of days testing it on the
affected hardware. The results answer both open questions cleanly.
---
Regarding your earlier question:
> Not sure if this is because PCIE bridge has no ASPM capability?
You were correct. The very beginning of the boot log shows:
[0.177872] ACPI FADT declares the system doesn't support PCIe ASPM,
so disable it
[15.157752] r8169 0000:07:00.0: can't disable ASPM; OS doesn't have
ASPM control
The BIOS on this HP laptop uses the ACPI FADT table to globally revoke
OS control over PCIe ASPM before Linux even takes over. This has an
important implication: since ASPM is already disabled at the hardware
level by firmware, the instability on this specific SKU is caused
entirely by LPS Deep Mode, not ASPM itself.
This explains why the ASPM-only quirk (v1 patch) did not stop the h2c
timeouts -- ASPM was never actually active on this machine to begin
with. Disabling LPS Deep Mode via the v2 quirk is what eliminates the
firmware timeout loop entirely.
---
Regarding the VHT NSS=0 diagnostic patch:
During normal idle, active pinging, and heavy VHT throughput
(175.5 Mb/s), the pr_err condition never triggered -- no
"VHT NSS=0" lines appeared in dmesg during active use.
However, the standard WARNING at mac80211/rx.c:5491 does reliably
appear exactly once after a fresh full stack reload (including
mac80211.ko and cfg80211.ko) or after resume from suspend:
[167.708201] WARNING: net/mac80211/rx.c:5491 at
ieee80211_rx_list+0x177/0x1020 [mac80211]
This suggests the hardware reports a malformed nss=0 VHT rate only
during initial link establishment. Since mac80211 uses WARN_ONCE, it
is suppressed on all subsequent packets.
The diagnostic module remains installed. I will report back
immediately if the pr_err condition is caught, or if any other
relevant symptoms appear.
Best regards,
Oleksandr Havrylov
^ permalink raw reply
* [PATCH iwlwifi-next 15/15] wifi: iwlwifi: acpi: add support for PPAG rev5
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
This adds support for UNII9 which requires to add a subband.
Just increase the number of subbands that we need to read.
Replace the usage of the IWL_NUM_SUB_BANDS_VX macros in acpi.h since
those macros are defined in the firmware API and ACPI declarations have
nothing to do the firmware API.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 16 ++++++++++++++++
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 16 +++++++++-------
2 files changed, 25 insertions(+), 7 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index de30799519cd..4d0a93832336 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -916,6 +916,22 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
if (IS_ERR(data))
return PTR_ERR(data);
+ /* try to read ppag table rev 5 */
+ wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
+ ACPI_PPAG_WIFI_DATA_SIZE_V3, &tbl_rev);
+ if (!IS_ERR(wifi_pkg)) {
+ if (tbl_rev == 5) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V3;
+ IWL_DEBUG_RADIO(fwrt,
+ "Reading PPAG table (tbl_rev=%d)\n",
+ tbl_rev);
+ goto read_table;
+ } else {
+ ret = -EINVAL;
+ goto out_free;
+ }
+ }
+
/* try to read ppag table rev 1 to 4 (all have the same data size) */
wifi_pkg = iwl_acpi_get_wifi_pkg(fwrt->dev, data,
ACPI_PPAG_WIFI_DATA_SIZE_V2, &tbl_rev);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index c34dc17ff608..138fdb9a5273 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -8,11 +8,6 @@
#include <linux/acpi.h>
#include "fw/regulatory.h"
-#include "fw/api/commands.h"
-#include "fw/api/power.h"
-#include "fw/api/phy.h"
-#include "fw/api/nvm-reg.h"
-#include "fw/api/config.h"
#include "fw/img.h"
#include "iwl-trans.h"
@@ -97,10 +92,17 @@
#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX)
#define ACPI_PPAG_NUM_CHAINS 2
+#define ACPI_PPAG_NUM_BANDS_V1 5
+#define ACPI_PPAG_NUM_BANDS_V2 11
+#define ACPI_PPAG_NUM_BANDS_V3 12
#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((ACPI_PPAG_NUM_CHAINS * \
- IWL_NUM_SUB_BANDS_V1) + 2)
+ ACPI_PPAG_NUM_BANDS_V1) + 2)
#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((ACPI_PPAG_NUM_CHAINS * \
- IWL_NUM_SUB_BANDS_V2) + 2)
+ ACPI_PPAG_NUM_BANDS_V2) + 2)
+
+/* used for ACPI PPAG table rev 5 */
+#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
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 14/15] wifi: iwlwifi: acpi: check the size of the ACPI PPAG tables
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
We need to make sure we don't have a buffer overflow while reading the
PPAG tables from ACPI into the firmware runtime object.
Add an ACPI specific define for the number of chains in order to
decouple the ACPI layout from the other objects.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 11 ++++++++++-
drivers/net/wireless/intel/iwlwifi/fw/acpi.h | 5 +++--
2 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index d00191e84f20..de30799519cd 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -951,6 +951,15 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
goto out_free;
read_table:
+ if (WARN_ON_ONCE(num_sub_bands >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands))) {
+ ret = -EINVAL;
+ goto out_free;
+ }
+
+ BUILD_BUG_ON(ACPI_PPAG_NUM_CHAINS >
+ ARRAY_SIZE(fwrt->ppag_chains));
+
fwrt->ppag_bios_rev = tbl_rev;
flags = &wifi_pkg->package.elements[1];
@@ -967,7 +976,7 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
* first sub-band (j=0) corresponds to Low-Band (2.4GHz), and the
* following sub-bands to High-Band (5GHz).
*/
- for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
+ for (i = 0; i < ACPI_PPAG_NUM_CHAINS; i++) {
for (j = 0; j < num_sub_bands; j++) {
union acpi_object *ent;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
index 06cece4ea6d9..c34dc17ff608 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.h
@@ -96,9 +96,10 @@
*/
#define ACPI_WTAS_WIFI_DATA_SIZE (3 + IWL_WTAS_BLACK_LIST_MAX)
-#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((IWL_NUM_CHAIN_LIMITS * \
+#define ACPI_PPAG_NUM_CHAINS 2
+#define ACPI_PPAG_WIFI_DATA_SIZE_V1 ((ACPI_PPAG_NUM_CHAINS * \
IWL_NUM_SUB_BANDS_V1) + 2)
-#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((IWL_NUM_CHAIN_LIMITS * \
+#define ACPI_PPAG_WIFI_DATA_SIZE_V2 ((ACPI_PPAG_NUM_CHAINS * \
IWL_NUM_SUB_BANDS_V2) + 2)
#define IWL_SAR_ENABLE_MSK BIT(0)
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 13/15] wifi: iwlwifi: regulatory: support a new command for PPAG
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Per Platform Antenna Gain is getting support for UNII-9.
Add a new version of PER_PLATFORM_ANT_GAIN_CMD.
This requires to increase the number of subbands in the firmware runtime
object.
Pass the number of subbands to iwl_bios_print_ppag to avoid printing
invalid values.
Introduce BIOS_PPAG_MAX_SUB_BANDS_NUM to avoid impacting
BIOS_SAR_MAX_SUB_BANDS_NUM which was used until now for PPAG as well.
SAR will get support for the new subband in future patches.
While at it, print the PPAG table as it was read from BIOS.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 1 +
.../net/wireless/intel/iwlwifi/fw/api/power.h | 8 +++
.../wireless/intel/iwlwifi/fw/regulatory.c | 21 ++++++
.../wireless/intel/iwlwifi/fw/regulatory.h | 6 +-
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 1 +
.../wireless/intel/iwlwifi/mld/regulatory.c | 66 +++++++++++++++----
6 files changed, 91 insertions(+), 12 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index b64abb8439b7..d00191e84f20 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -981,6 +981,7 @@ int iwl_acpi_get_ppag_table(struct iwl_fw_runtime *fwrt)
}
}
+ iwl_bios_print_ppag(fwrt, num_sub_bands);
fwrt->ppag_bios_source = BIOS_SOURCE_ACPI;
ret = 0;
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
index 0cd8a12e0f7c..118c08f95649 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/power.h
@@ -269,6 +269,7 @@ enum iwl_dev_tx_power_cmd_mode {
#define IWL_NUM_CHAIN_LIMITS 2
#define IWL_NUM_SUB_BANDS_V1 5
#define IWL_NUM_SUB_BANDS_V2 11
+#define IWL_NUM_SUB_BANDS_V3 12
/**
* struct iwl_dev_tx_power_common - Common part of the TX power reduction cmd
@@ -573,6 +574,7 @@ enum iwl_ppag_flags {
* @v1: command version 1 structure.
* @v5: command version 5 structure.
* @v7: command version 7 structure.
+ * @v8: command version 8 structure.
* @v1.flags: values from &enum iwl_ppag_flags
* @v1.gain: table of antenna gain values per chain and sub-band
* @v1.reserved: reserved
@@ -581,6 +583,8 @@ enum iwl_ppag_flags {
* @v7.ppag_config_info: see @struct bios_value_u32
* @v7.gain: table of antenna gain values per chain and sub-band
* @v7.reserved: reserved
+ * @v8.ppag_config_info: see @struct bios_value_u32
+ * @v8.gain: table of antenna gain values per chain and sub-band
*/
union iwl_ppag_table_cmd {
struct {
@@ -598,6 +602,10 @@ union iwl_ppag_table_cmd {
s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V2];
s8 reserved[2];
} __packed v7; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_7 */
+ struct {
+ struct bios_value_u32 ppag_config_info;
+ s8 gain[IWL_NUM_CHAIN_LIMITS][IWL_NUM_SUB_BANDS_V3];
+ } __packed v8; /* PER_PLAT_ANTENNA_GAIN_CMD_API_S_VER_8 */
} __packed;
#define IWL_PPAG_CMD_V1_MASK (IWL_PPAG_ETSI_MASK | IWL_PPAG_CHINA_MASK)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 9e834cc1b054..55128caac7ed 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -318,6 +318,27 @@ bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
}
IWL_EXPORT_SYMBOL(iwl_is_ppag_approved);
+/* Print the PPAG table as read from BIOS */
+void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands)
+{
+ int i, j;
+
+ IWL_DEBUG_RADIO(fwrt, "PPAG table as read from BIOS:\n");
+ IWL_DEBUG_RADIO(fwrt, "PPAG revision = %d\n", fwrt->ppag_bios_rev);
+ IWL_DEBUG_RADIO(fwrt, "PPAG flags = 0x%x\n", fwrt->ppag_flags);
+
+ if (WARN_ON_ONCE(n_subbands >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands)))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(fwrt->ppag_chains); i++)
+ for (j = 0; j < n_subbands; j++)
+ IWL_DEBUG_RADIO(fwrt,
+ "ppag_chains[%d].subbands[%d] = %d\n",
+ i, j,
+ fwrt->ppag_chains[i].subbands[j]);
+}
+
bool iwl_is_tas_approved(void)
{
return dmi_check_system(dmi_tas_approved_list);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 8e04b0e2d507..446c8a2c4f9d 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -22,6 +22,7 @@
#define BIOS_SAR_MAX_CHAINS_PER_PROFILE 4
#define BIOS_SAR_NUM_CHAINS 2
#define BIOS_SAR_MAX_SUB_BANDS_NUM 11
+#define BIOS_PPAG_MAX_SUB_BANDS_NUM 12
#define BIOS_GEO_NUM_CHAINS 2
#define BIOS_GEO_MAX_NUM_BANDS 3
@@ -100,7 +101,7 @@ struct iwl_geo_profile {
/* Same thing as with SAR, all revisions fit in revision 2 */
struct iwl_ppag_chain {
- s8 subbands[BIOS_SAR_MAX_SUB_BANDS_NUM];
+ s8 subbands[BIOS_PPAG_MAX_SUB_BANDS_NUM];
};
struct iwl_tas_data {
@@ -180,6 +181,9 @@ enum iwl_dsm_masks_reg {
struct iwl_fw_runtime;
+/* Print the PPAG table as read from BIOS */
+void iwl_bios_print_ppag(struct iwl_fw_runtime *fwrt, int n_subbands);
+
bool iwl_sar_geo_support(struct iwl_fw_runtime *fwrt);
int iwl_sar_geo_fill_table(struct iwl_fw_runtime *fwrt,
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index 38f9d9adf90e..fba41976be6b 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -607,6 +607,7 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
data->vals[chain * UEFI_PPAG_SUB_BANDS_NUM + subband];
}
+ iwl_bios_print_ppag(fwrt, UEFI_PPAG_SUB_BANDS_NUM);
fwrt->ppag_bios_source = BIOS_SOURCE_UEFI;
out:
kfree(data);
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
index d1a55b565898..27059ec93847 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/regulatory.c
@@ -166,30 +166,74 @@ static int iwl_mld_ppag_send_cmd(struct iwl_mld *mld)
{
struct iwl_fw_runtime *fwrt = &mld->fwrt;
union iwl_ppag_table_cmd cmd = {
- .v7.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source,
- .v7.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev,
- .v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags),
+ /* v7 and v8 have the same layout for the ppag_config_info */
+ .v8.ppag_config_info.hdr.table_source = fwrt->ppag_bios_source,
+ .v8.ppag_config_info.hdr.table_revision = fwrt->ppag_bios_rev,
+ .v8.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags),
};
+ int cmd_ver =
+ iwl_fw_lookup_cmd_ver(mld->fw,
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_PLATFORM_ANT_GAIN_CMD), 1);
+ int cmd_len = sizeof(cmd.v8);
int ret;
+ BUILD_BUG_ON(offsetof(typeof(cmd), v8.ppag_config_info.hdr) !=
+ offsetof(typeof(cmd), v7.ppag_config_info.hdr));
+ BUILD_BUG_ON(offsetof(typeof(cmd), v8.gain) !=
+ offsetof(typeof(cmd), v7.gain));
+
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain) > ARRAY_SIZE(fwrt->ppag_chains));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v7.gain[0]) >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain) > ARRAY_SIZE(fwrt->ppag_chains));
+ BUILD_BUG_ON(ARRAY_SIZE(cmd.v8.gain[0]) >
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands));
+
IWL_DEBUG_RADIO(fwrt,
"PPAG MODE bits going to be sent: %d\n",
fwrt->ppag_flags);
- for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) {
- for (int subband = 0; subband < IWL_NUM_SUB_BANDS_V2; subband++) {
- cmd.v7.gain[chain][subband] =
- fwrt->ppag_chains[chain].subbands[subband];
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table: chain[%d] band[%d]: gain = %d\n",
- chain, subband, cmd.v7.gain[chain][subband]);
+ /* Since ver 7 will be deprecated at some point, don't bother making
+ * this code generic for both ver 7 and ver 8: duplicate the code.
+ */
+ if (cmd_ver == 7) {
+ for (int chain = 0; chain < ARRAY_SIZE(cmd.v7.gain); chain++) {
+ for (int subband = 0;
+ subband < ARRAY_SIZE(cmd.v7.gain[0]);
+ subband++) {
+ cmd.v7.gain[chain][subband] =
+ fwrt->ppag_chains[chain].subbands[subband];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ chain, subband,
+ cmd.v7.gain[chain][subband]);
+ }
}
+ cmd_len = sizeof(cmd.v7);
+ } else if (cmd_ver == 8) {
+ for (int chain = 0; chain < ARRAY_SIZE(cmd.v8.gain); chain++) {
+ for (int subband = 0;
+ subband < ARRAY_SIZE(cmd.v8.gain[0]);
+ subband++) {
+ cmd.v8.gain[chain][subband] =
+ fwrt->ppag_chains[chain].subbands[subband];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ chain, subband,
+ cmd.v8.gain[chain][subband]);
+ }
+ }
+ } else {
+ WARN(1, "Bad version for PER_PLATFORM_ANT_GAIN_CMD %d\n",
+ cmd_ver);
+ return -EINVAL;
}
IWL_DEBUG_RADIO(mld, "Sending PER_PLATFORM_ANT_GAIN_CMD\n");
ret = iwl_mld_send_cmd_pdu(mld, WIDE_ID(PHY_OPS_GROUP,
PER_PLATFORM_ANT_GAIN_CMD),
- &cmd, sizeof(cmd.v7));
+ &cmd, cmd_len);
if (ret < 0)
IWL_ERR(mld, "failed to send PER_PLATFORM_ANT_GAIN_CMD (%d)\n",
ret);
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 12/15] wifi: iwlwifi: mld: correctly set wifi generation data
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Johannes Berg <johannes.berg@intel.com>
In each MAC context, the firmware expects the wifi generation
data, i.e. whether or not HE/EHT (and in the future UHR) is
enabled on that MAC.
However, this is currently handled wrong in two ways:
- EHT is only enabled when the interface is also an MLD, but
we currently allow (despite the spec) connecting with EHT
but without MLO.
- when HE or EHT are used by TDLS peers, the firmware needs
to have them enabled regardless of the AP
Fix this by iterating setting up the data depending on the
interface type:
- for AP, just set it according to the BSS configuration
- for monitor, set it according to HW capabilities
- otherwise, particularly for client, iterate all stations
and then their links on the interface in question and set
according to their capabilities, this handles the AP and
TDLS peers. Re-calculate this whenever a TDLS station is
marked associated or removed so that it's kept updated,
for the AP it's already updated on assoc/disassoc.
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/mld/iface.c | 101 ++++++++++++------
.../net/wireless/intel/iwlwifi/mld/mac80211.c | 19 ++++
2 files changed, 88 insertions(+), 32 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/iface.c b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
index 29df747c8938..9215fc7e2eca 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/iface.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/iface.c
@@ -111,14 +111,75 @@ static bool iwl_mld_is_nic_ack_enabled(struct iwl_mld *mld,
IEEE80211_HE_MAC_CAP2_ACK_EN);
}
-static void iwl_mld_set_he_support(struct iwl_mld *mld,
- struct ieee80211_vif *vif,
- struct iwl_mac_config_cmd *cmd)
+struct iwl_mld_mac_wifi_gen_sta_iter_data {
+ struct ieee80211_vif *vif;
+ struct iwl_mac_wifi_gen_support *support;
+};
+
+static void iwl_mld_mac_wifi_gen_sta_iter(void *_data,
+ struct ieee80211_sta *sta)
{
- if (vif->type == NL80211_IFTYPE_AP)
- cmd->wifi_gen.he_ap_support = 1;
- else
- cmd->wifi_gen.he_support = 1;
+ struct iwl_mld_sta *mld_sta = iwl_mld_sta_from_mac80211(sta);
+ struct iwl_mld_mac_wifi_gen_sta_iter_data *data = _data;
+ struct ieee80211_link_sta *link_sta;
+ unsigned int link_id;
+
+ if (mld_sta->vif != data->vif)
+ return;
+
+ for_each_sta_active_link(data->vif, sta, link_sta, link_id) {
+ if (link_sta->he_cap.has_he)
+ data->support->he_support = 1;
+ if (link_sta->eht_cap.has_eht)
+ data->support->eht_support = 1;
+ }
+}
+
+static void iwl_mld_set_wifi_gen(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ struct iwl_mac_wifi_gen_support *support)
+{
+ struct iwl_mld_mac_wifi_gen_sta_iter_data sta_iter_data = {
+ .vif = vif,
+ .support = support,
+ };
+ struct ieee80211_bss_conf *link_conf;
+ unsigned int link_id;
+
+ switch (vif->type) {
+ case NL80211_IFTYPE_MONITOR:
+ /* for sniffer, set to HW capabilities */
+ support->he_support = 1;
+ support->eht_support = mld->trans->cfg->eht_supported;
+ break;
+ case NL80211_IFTYPE_AP:
+ /* for AP set according to the link configs */
+ for_each_vif_active_link(vif, link_conf, link_id) {
+ support->he_ap_support |= link_conf->he_support;
+ support->eht_support |= link_conf->eht_support;
+ }
+ break;
+ default:
+ /*
+ * If we have MLO enabled, then the firmware needs to enable
+ * address translation for the station(s) we add. That depends
+ * on having EHT enabled in firmware, which in turn depends on
+ * mac80211 in the iteration below.
+ * However, mac80211 doesn't enable capabilities on the AP STA
+ * until it has parsed the association response successfully,
+ * so set EHT (and HE as a pre-requisite for EHT) when the vif
+ * is an MLD.
+ */
+ if (ieee80211_vif_is_mld(vif)) {
+ support->he_support = 1;
+ support->eht_support = 1;
+ }
+
+ ieee80211_iterate_stations_mtx(mld->hw,
+ iwl_mld_mac_wifi_gen_sta_iter,
+ &sta_iter_data);
+ break;
+ }
}
/* fill the common part for all interface types */
@@ -128,8 +189,6 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
u32 action)
{
struct iwl_mld_vif *mld_vif = iwl_mld_vif_from_mac80211(vif);
- struct ieee80211_bss_conf *link_conf;
- unsigned int link_id;
lockdep_assert_wiphy(mld->wiphy);
@@ -147,29 +206,7 @@ static void iwl_mld_mac_cmd_fill_common(struct iwl_mld *mld,
cmd->nic_not_ack_enabled =
cpu_to_le32(!iwl_mld_is_nic_ack_enabled(mld, vif));
- /* If we have MLO enabled, then the firmware needs to enable
- * address translation for the station(s) we add. That depends
- * on having EHT enabled in firmware, which in turn depends on
- * mac80211 in the code below.
- * However, mac80211 doesn't enable HE/EHT until it has parsed
- * the association response successfully, so just skip all that
- * and enable both when we have MLO.
- */
- if (ieee80211_vif_is_mld(vif)) {
- iwl_mld_set_he_support(mld, vif, cmd);
- cmd->wifi_gen.eht_support = 1;
- return;
- }
-
- for_each_vif_active_link(vif, link_conf, link_id) {
- if (!link_conf->he_support)
- continue;
-
- iwl_mld_set_he_support(mld, vif, cmd);
-
- /* EHT, if supported, was already set above */
- break;
- }
+ iwl_mld_set_wifi_gen(mld, vif, &cmd->wifi_gen);
}
static void iwl_mld_fill_mac_cmd_sta(struct iwl_mld *mld,
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
index 0c53d6bd9651..71a9a72c9ac0 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mac80211.c
@@ -1761,6 +1761,16 @@ static int iwl_mld_move_sta_state_up(struct iwl_mld *mld,
if (vif->type == NL80211_IFTYPE_STATION)
iwl_mld_link_set_2mhz_block(mld, vif, sta);
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on association to the AP via the
+ * vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
+
/* Now the link_sta's capabilities are set, update the FW */
iwl_mld_config_tlc(mld, vif, sta);
@@ -1873,6 +1883,15 @@ static int iwl_mld_move_sta_state_down(struct iwl_mld *mld,
/* just removed last TDLS STA, so enable PM */
iwl_mld_update_mac_power(mld, vif, false);
}
+
+ if (sta->tdls) {
+ /*
+ * update MAC since wifi generation flags may change,
+ * we also update MAC on disassociation to the AP via
+ * the vif assoc change
+ */
+ iwl_mld_mac_fw_action(mld, vif, FW_CTXT_ACTION_MODIFY);
+ }
} else {
return -EINVAL;
}
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 11/15] wifi: iwlwifi: mld: add support for sta command version 3
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Johannes Berg
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
In this version, the link_id becomes a link_mask to support multiple
links that are used to communicate with the station in question.
This is needed for NAN, in which we can communicate on multiple channels
with the same station.
Also add a new STA type - NAN peer.
Reviewed-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 | 94 ++++++++++++++++++-
drivers/net/wireless/intel/iwlwifi/mld/sta.c | 42 +++++++--
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 6 +-
3 files changed, 129 insertions(+), 13 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 c7a833f8041a..444d60a05a98 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
@@ -42,7 +42,8 @@ enum iwl_mac_conf_subcmd_ids {
*/
LINK_CONFIG_CMD = 0x9,
/**
- * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd
+ * @STA_CONFIG_CMD: &struct iwl_sta_cfg_cmd_v1,
+ * &struct iwl_sta_cfg_cmd_v2, or struct iwl_sta_cfg_cmd
*/
STA_CONFIG_CMD = 0xA,
/**
@@ -664,13 +665,21 @@ struct iwl_link_config_cmd {
* power save state and the DTIM timing
* @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.
+ * @STATION_TYPE_NAN_PEER_NMI: NAN management peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
+ * @STATION_TYPE_NAN_PEER_NDI: NAN data peer station type. A station
+ * of this type can have any number of links (even none) set in the
+ * link_mask. (Supported since version 3.)
*/
enum iwl_fw_sta_type {
STATION_TYPE_PEER,
STATION_TYPE_BCAST_MGMT,
STATION_TYPE_MCAST,
STATION_TYPE_AUX,
-}; /* STATION_TYPE_E_VER_1 */
+ STATION_TYPE_NAN_PEER_NMI,
+ STATION_TYPE_NAN_PEER_NDI,
+}; /* STATION_TYPE_E_VER_1, _VER_2 */
/**
* struct iwl_sta_cfg_cmd_v1 - cmd structure to add a peer sta to the uCode's
@@ -729,7 +738,7 @@ struct iwl_sta_cfg_cmd_v1 {
} __packed; /* STA_CMD_API_S_VER_1 */
/**
- * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * struct iwl_sta_cfg_cmd_v2 - cmd structure to add a peer sta to the uCode's
* station table
* ( STA_CONFIG_CMD = 0xA )
*
@@ -769,7 +778,7 @@ struct iwl_sta_cfg_cmd_v1 {
* @mic_compute_pad_delay: MIC compute time padding
* @reserved: Reserved for alignment
*/
-struct iwl_sta_cfg_cmd {
+struct iwl_sta_cfg_cmd_v2 {
__le32 sta_id;
__le32 link_id;
u8 peer_mld_address[ETH_ALEN];
@@ -799,6 +808,83 @@ struct iwl_sta_cfg_cmd {
u8 reserved[2];
} __packed; /* STA_CMD_API_S_VER_2 */
+/**
+ * struct iwl_sta_cfg_cmd - cmd structure to add a peer sta to the uCode's
+ * station table
+ * ( STA_CONFIG_CMD = 0xA )
+ *
+ * @sta_id: index of station in uCode's station table
+ * @link_mask: bitmap of link FW IDs used with this STA
+ * @peer_mld_address: the peers mld address
+ * @reserved_for_peer_mld_address: reserved
+ * @peer_link_address: the address of the link that is used to communicate
+ * with this sta
+ * @reserved_for_peer_link_address: reserved
+ * @station_type: type of this station. See &enum iwl_fw_sta_type
+ * @assoc_id: for GO only
+ * @beamform_flags: beam forming controls
+ * @mfp: indicates whether the STA uses management frame protection or not.
+ * @mimo: indicates whether the sta uses mimo or not
+ * @mimo_protection: indicates whether the sta uses mimo protection or not
+ * @ack_enabled: indicates that the AP supports receiving ACK-
+ * enabled AGG, i.e. both BACK and non-BACK frames in a single AGG
+ * @trig_rnd_alloc: indicates that trigger based random allocation
+ * is enabled according to UORA element existence
+ * @tx_ampdu_spacing: minimum A-MPDU spacing:
+ * 4 - 2us density, 5 - 4us density, 6 - 8us density, 7 - 16us density
+ * @tx_ampdu_max_size: maximum A-MPDU length: 0 - 8K, 1 - 16K, 2 - 32K,
+ * 3 - 64K, 4 - 128K, 5 - 256K, 6 - 512K, 7 - 1024K.
+ * @sp_length: the size of the SP in actual number of frames
+ * @uapsd_acs: 4 LS bits are trigger enabled ACs, 4 MS bits are the deliver
+ * enabled ACs.
+ * @pkt_ext: optional, exists according to PPE-present bit in the HE/EHT-PHY
+ * capa
+ * @htc_flags: which features are supported in HTC
+ * @use_ldpc_x2_cw: Indicates whether to use LDPC with double CW
+ * @use_icf: Indicates whether to use ICF instead of RTS
+ * @dps_pad_time: DPS (Dynamic Power Save) padding delay resolution to ensure
+ * proper timing alignment
+ * @dps_trans_delay: DPS minimal time that takes the peer to return to low power
+ * @dps_enabled: flag indicating whether or not DPS is enabled
+ * @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
+ * @reserved: Reserved for alignment
+ */
+struct iwl_sta_cfg_cmd {
+ __le32 sta_id;
+ __le32 link_mask;
+ u8 peer_mld_address[ETH_ALEN];
+ __le16 reserved_for_peer_mld_address;
+ u8 peer_link_address[ETH_ALEN];
+ __le16 reserved_for_peer_link_address;
+ __le32 station_type;
+ __le32 assoc_id;
+ __le32 beamform_flags;
+ __le32 mfp;
+ __le32 mimo;
+ __le32 mimo_protection;
+ __le32 ack_enabled;
+ __le32 trig_rnd_alloc;
+ __le32 tx_ampdu_spacing;
+ __le32 tx_ampdu_max_size;
+ __le32 sp_length;
+ __le32 uapsd_acs;
+ struct iwl_he_pkt_ext_v2 pkt_ext;
+ __le32 htc_flags;
+ u8 use_ldpc_x2_cw;
+ u8 use_icf;
+ u8 dps_pad_time;
+ u8 dps_trans_delay;
+ u8 dps_enabled;
+ u8 mic_prep_pad_delay;
+ u8 mic_compute_pad_delay;
+ u8 nmi_sta_id;
+ u8 ndi_local_addr[ETH_ALEN];
+ u8 reserved[2];
+} __packed; /* STA_CMD_API_S_VER_3 */
+
/**
* struct iwl_aux_sta_cmd - command for AUX STA configuration
* ( AUX_STA_CMD = 0xB )
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/sta.c b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
index 6b7a89e050e6..f40c49377466 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/sta.c
@@ -398,12 +398,42 @@ static u32 iwl_mld_get_htc_flags(struct ieee80211_link_sta *link_sta)
return htc_flags;
}
+/* Note: modifies the command depending on FW command version */
static int iwl_mld_send_sta_cmd(struct iwl_mld *mld,
- const struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd *cmd)
{
- int ret = iwl_mld_send_cmd_pdu(mld,
- WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD),
- cmd);
+ int cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
+ int cmd_ver = iwl_fw_lookup_cmd_ver(mld->fw, cmd_id, 0);
+ int len = sizeof(*cmd);
+ int ret;
+
+ if (cmd_ver < 2) {
+ IWL_ERR(mld, "Unsupported STA_CONFIG_CMD version %d\n",
+ cmd_ver);
+ return -EINVAL;
+ } else if (cmd_ver == 2) {
+ struct iwl_sta_cfg_cmd_v2 *cmd_v2 = (void *)cmd;
+
+ 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) ||
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1))
+ return -EINVAL;
+ /*
+ * These fields are located in a different place in the struct of v2.
+ * The assumption is that UHR won't be used with FW that has v2.
+ */
+ if (WARN_ON(cmd->mic_prep_pad_delay || cmd->mic_compute_pad_delay))
+ return -EINVAL;
+
+ len = sizeof(struct iwl_sta_cfg_cmd_v2);
+ cmd_v2->link_id = cpu_to_le32(__ffs(le32_to_cpu(cmd->link_mask)));
+ } 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) &&
+ hweight32(le32_to_cpu(cmd->link_mask)) != 1)) {
+ return -EINVAL;
+ }
+
+ ret = iwl_mld_send_cmd_pdu(mld, cmd_id, cmd, len);
if (ret)
IWL_ERR(mld, "STA_CONFIG_CMD send failed, ret=0x%x\n", ret);
return ret;
@@ -431,8 +461,8 @@ iwl_mld_add_modify_sta_cmd(struct iwl_mld *mld,
return -EINVAL;
cmd.sta_id = cpu_to_le32(fw_id);
+ cmd.link_mask = cpu_to_le32(BIT(mld_link->fw_id));
cmd.station_type = cpu_to_le32(mld_sta->sta_type);
- cmd.link_id = cpu_to_le32(mld_link->fw_id);
memcpy(&cmd.peer_mld_address, sta->addr, ETH_ALEN);
memcpy(&cmd.peer_link_address, link_sta->addr, ETH_ALEN);
@@ -982,7 +1012,7 @@ iwl_mld_add_internal_sta_to_fw(struct iwl_mld *mld,
return iwl_mld_send_aux_sta_cmd(mld, internal_sta);
cmd.sta_id = cpu_to_le32((u8)internal_sta->sta_id);
- cmd.link_id = cpu_to_le32(fw_link_id);
+ cmd.link_mask = cpu_to_le32(BIT(fw_link_id));
cmd.station_type = cpu_to_le32(internal_sta->sta_type);
/* FW doesn't allow to add a IGTK/BIGTK if the sta isn't marked as MFP.
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 44e16ee9514e..da7ed4639a93 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -20,7 +20,7 @@ u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
static int iwl_mvm_mld_send_sta_cmd(struct iwl_mvm *mvm,
- struct iwl_sta_cfg_cmd *cmd)
+ struct iwl_sta_cfg_cmd_v2 *cmd)
{
u32 cmd_id = WIDE_ID(MAC_CONF_GROUP, STA_CONFIG_CMD);
int cmd_len = iwl_fw_lookup_cmd_ver(mvm->fw, cmd_id, 0) > 1 ?
@@ -41,7 +41,7 @@ static int iwl_mvm_mld_add_int_sta_to_fw(struct iwl_mvm *mvm,
struct iwl_mvm_int_sta *sta,
const u8 *addr, int link_id)
{
- struct iwl_sta_cfg_cmd cmd;
+ struct iwl_sta_cfg_cmd_v2 cmd;
lockdep_assert_held(&mvm->mutex);
@@ -416,7 +416,7 @@ static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_mvm_vif_link_info *link_info =
mvm_vif->link[link_conf->link_id];
- struct iwl_sta_cfg_cmd cmd = {
+ struct iwl_sta_cfg_cmd_v2 cmd = {
.sta_id = cpu_to_le32(mvm_link_sta->sta_id),
.station_type = cpu_to_le32(mvm_sta->sta_type),
};
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 10/15] wifi: iwlwifi: bring iwl_fill_ppag_table to the iwlmvm
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
iwl_fill_ppag_table fills a command that is sent to the firmware. This
command has several versions and handling those different versions is
the responsibility of the op_mode.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../wireless/intel/iwlwifi/fw/regulatory.c | 126 -----------------
.../wireless/intel/iwlwifi/fw/regulatory.h | 4 -
drivers/net/wireless/intel/iwlwifi/mvm/fw.c | 129 +++++++++++++++++-
3 files changed, 128 insertions(+), 131 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
index 5793c267daf7..9e834cc1b054 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.c
@@ -304,132 +304,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
}
IWL_EXPORT_SYMBOL(iwl_sar_fill_profile);
-static bool iwl_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
- int subband)
-{
- s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
-
- if ((subband == 0 &&
- (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
- (subband != 0 &&
- (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
- IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
- return false;
- }
- return true;
-}
-
-/* Utility function for iwlmvm and iwlxvt */
-int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
- union iwl_ppag_table_cmd *cmd, int *cmd_size)
-{
- u8 cmd_ver;
- int i, j, num_sub_bands;
- s8 *gain;
- bool send_ppag_always;
-
- /* many firmware images for JF lie about this */
- if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==
- CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
- return -EOPNOTSUPP;
-
- if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
- IWL_DEBUG_RADIO(fwrt,
- "PPAG capability not supported by FW, command not sent.\n");
- return -EINVAL;
- }
-
- cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
- WIDE_ID(PHY_OPS_GROUP,
- PER_PLATFORM_ANT_GAIN_CMD), 1);
- /*
- * Starting from ver 4, driver needs to send the PPAG CMD regardless
- * if PPAG is enabled/disabled or valid/invalid.
- */
- send_ppag_always = cmd_ver > 3;
-
- /* Don't send PPAG if it is disabled */
- if (!send_ppag_always && !fwrt->ppag_flags) {
- IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
- return -EINVAL;
- }
-
- IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
- if (cmd_ver == 1) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V1;
- gain = cmd->v1.gain[0];
- *cmd_size = sizeof(cmd->v1);
- cmd->v1.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK);
- if (fwrt->ppag_bios_rev >= 1) {
- /* in this case FW supports revision 0 */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table rev is %d, send truncated table\n",
- fwrt->ppag_bios_rev);
- }
- } else if (cmd_ver == 5) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V2;
- gain = cmd->v5.gain[0];
- *cmd_size = sizeof(cmd->v5);
- cmd->v5.flags = cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK);
- if (fwrt->ppag_bios_rev == 0) {
- /* in this case FW supports revisions 1,2 or 3 */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table rev is 0, send padded table\n");
- }
- } else if (cmd_ver == 7) {
- num_sub_bands = IWL_NUM_SUB_BANDS_V2;
- gain = cmd->v7.gain[0];
- *cmd_size = sizeof(cmd->v7);
- cmd->v7.ppag_config_info.hdr.table_source =
- fwrt->ppag_bios_source;
- cmd->v7.ppag_config_info.hdr.table_revision =
- fwrt->ppag_bios_rev;
- cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
- } else {
- IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
- return -EINVAL;
- }
-
- /* ppag mode */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG MODE bits were read from bios: %d\n",
- fwrt->ppag_flags);
-
- if (cmd_ver == 1 &&
- !fw_has_capa(&fwrt->fw->ucode_capa,
- IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) {
- cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
- IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
- } else {
- IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
- }
-
- /* The 'flags' field is the same in v1 and v5 so we can just
- * use v1 to access it.
- */
- IWL_DEBUG_RADIO(fwrt,
- "PPAG MODE bits going to be sent: %d\n",
- (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
- le32_to_cpu(cmd->v7.ppag_config_info.value));
-
- for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
- for (j = 0; j < num_sub_bands; j++) {
- if (!send_ppag_always &&
- !iwl_ppag_value_valid(fwrt, i, j))
- return -EINVAL;
-
- gain[i * num_sub_bands + j] =
- fwrt->ppag_chains[i].subbands[j];
- IWL_DEBUG_RADIO(fwrt,
- "PPAG table: chain[%d] band[%d]: gain = %d\n",
- i, j, gain[i * num_sub_bands + j]);
- }
- }
-
- return 0;
-}
-IWL_EXPORT_SYMBOL(iwl_fill_ppag_table);
-
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt)
{
if (!dmi_check_system(dmi_ppag_approved_list)) {
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
index 1489031687b7..8e04b0e2d507 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/regulatory.h
@@ -190,10 +190,6 @@ int iwl_sar_fill_profile(struct iwl_fw_runtime *fwrt,
__le16 *per_chain, u32 n_tables, u32 n_subbands,
int prof_a, int prof_b);
-int iwl_fill_ppag_table(struct iwl_fw_runtime *fwrt,
- union iwl_ppag_table_cmd *cmd,
- int *cmd_size);
-
bool iwl_is_ppag_approved(struct iwl_fw_runtime *fwrt);
bool iwl_is_tas_approved(void);
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
index f5e5c10cc581..d46715abd7a5 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/fw.c
@@ -1034,12 +1034,139 @@ static int iwl_mvm_sar_geo_init(struct iwl_mvm *mvm)
return iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, len, &cmd);
}
+static bool iwl_mvm_ppag_value_valid(struct iwl_fw_runtime *fwrt, int chain,
+ int subband)
+{
+ s8 ppag_val = fwrt->ppag_chains[chain].subbands[subband];
+
+ if ((subband == 0 &&
+ (ppag_val > IWL_PPAG_MAX_LB || ppag_val < IWL_PPAG_MIN_LB)) ||
+ (subband != 0 &&
+ (ppag_val > IWL_PPAG_MAX_HB || ppag_val < IWL_PPAG_MIN_HB))) {
+ IWL_DEBUG_RADIO(fwrt, "Invalid PPAG value: %d\n", ppag_val);
+ return false;
+ }
+ return true;
+}
+
+static int iwl_mvm_fill_ppag_table(struct iwl_fw_runtime *fwrt,
+ union iwl_ppag_table_cmd *cmd,
+ int *cmd_size)
+{
+ u8 cmd_ver;
+ int i, j, num_sub_bands;
+ s8 *gain;
+ bool send_ppag_always;
+
+ /* many firmware images for JF lie about this */
+ if (CSR_HW_RFID_TYPE(fwrt->trans->info.hw_rf_id) ==
+ CSR_HW_RFID_TYPE(CSR_HW_RF_ID_TYPE_JF))
+ return -EOPNOTSUPP;
+
+ if (!fw_has_capa(&fwrt->fw->ucode_capa, IWL_UCODE_TLV_CAPA_SET_PPAG)) {
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG capability not supported by FW, command not sent.\n");
+ return -EINVAL;
+ }
+
+ cmd_ver = iwl_fw_lookup_cmd_ver(fwrt->fw,
+ WIDE_ID(PHY_OPS_GROUP,
+ PER_PLATFORM_ANT_GAIN_CMD), 1);
+ /*
+ * Starting from ver 4, driver needs to send the PPAG CMD regardless
+ * if PPAG is enabled/disabled or valid/invalid.
+ */
+ send_ppag_always = cmd_ver > 3;
+
+ /* Don't send PPAG if it is disabled */
+ if (!send_ppag_always && !fwrt->ppag_flags) {
+ IWL_DEBUG_RADIO(fwrt, "PPAG not enabled, command not sent.\n");
+ return -EINVAL;
+ }
+
+ IWL_DEBUG_RADIO(fwrt, "PPAG cmd ver is %d\n", cmd_ver);
+ if (cmd_ver == 1) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V1;
+ gain = cmd->v1.gain[0];
+ *cmd_size = sizeof(cmd->v1);
+ cmd->v1.flags =
+ cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V1_MASK);
+ if (fwrt->ppag_bios_rev >= 1) {
+ /* in this case FW supports revision 0 */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table rev is %d, send truncated table\n",
+ fwrt->ppag_bios_rev);
+ }
+ } else if (cmd_ver == 5) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2;
+ gain = cmd->v5.gain[0];
+ *cmd_size = sizeof(cmd->v5);
+ cmd->v5.flags =
+ cpu_to_le32(fwrt->ppag_flags & IWL_PPAG_CMD_V5_MASK);
+ if (fwrt->ppag_bios_rev == 0) {
+ /* in this case FW supports revisions 1,2 or 3 */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table rev is 0, send padded table\n");
+ }
+ } else if (cmd_ver == 7) {
+ num_sub_bands = IWL_NUM_SUB_BANDS_V2;
+ gain = cmd->v7.gain[0];
+ *cmd_size = sizeof(cmd->v7);
+ cmd->v7.ppag_config_info.hdr.table_source =
+ fwrt->ppag_bios_source;
+ cmd->v7.ppag_config_info.hdr.table_revision =
+ fwrt->ppag_bios_rev;
+ cmd->v7.ppag_config_info.value = cpu_to_le32(fwrt->ppag_flags);
+ } else {
+ IWL_DEBUG_RADIO(fwrt, "Unsupported PPAG command version\n");
+ return -EINVAL;
+ }
+
+ /* ppag mode */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG MODE bits were read from bios: %d\n",
+ fwrt->ppag_flags);
+
+ if (cmd_ver == 1 &&
+ !fw_has_capa(&fwrt->fw->ucode_capa,
+ IWL_UCODE_TLV_CAPA_PPAG_CHINA_BIOS_SUPPORT)) {
+ cmd->v1.flags &= cpu_to_le32(IWL_PPAG_ETSI_MASK);
+ IWL_DEBUG_RADIO(fwrt, "masking ppag China bit\n");
+ } else {
+ IWL_DEBUG_RADIO(fwrt, "isn't masking ppag China bit\n");
+ }
+
+ /* The 'flags' field is the same in v1 and v5 so we can just
+ * use v1 to access it.
+ */
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG MODE bits going to be sent: %d\n",
+ (cmd_ver < 7) ? le32_to_cpu(cmd->v1.flags) :
+ le32_to_cpu(cmd->v7.ppag_config_info.value));
+
+ for (i = 0; i < IWL_NUM_CHAIN_LIMITS; i++) {
+ for (j = 0; j < num_sub_bands; j++) {
+ if (!send_ppag_always &&
+ !iwl_mvm_ppag_value_valid(fwrt, i, j))
+ return -EINVAL;
+
+ gain[i * num_sub_bands + j] =
+ fwrt->ppag_chains[i].subbands[j];
+ IWL_DEBUG_RADIO(fwrt,
+ "PPAG table: chain[%d] band[%d]: gain = %d\n",
+ i, j, gain[i * num_sub_bands + j]);
+ }
+ }
+
+ return 0;
+}
+
int iwl_mvm_ppag_send_cmd(struct iwl_mvm *mvm)
{
union iwl_ppag_table_cmd cmd;
int ret, cmd_size;
- ret = iwl_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size);
+ ret = iwl_mvm_fill_ppag_table(&mvm->fwrt, &cmd, &cmd_size);
/* Not supporting PPAG table is a valid scenario */
if (ret < 0)
return 0;
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 09/15] wifi: iwlwifi: uefi: open code the PPAG table store operation
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
The structure in firmware runtime will need to grow because we're adding
a subband for UNII-9.
This means that we will soon no longer be able to just memcpy the data
from the UEFI table. The layout of the array will change.
Tediously copy the data byte-byte to make sure things get to the right
place even when we'll increase the number of subbands.
Make it easier for the uefi_cnv_var_ppag structure to grow by
simpiflying the layout it becomes an array of s8.
The layout of the structure becomes less obvious from the structure's
declaration, but then the code is more flexible.
Don't use UEFI_SAR_MAX_SUB_BANDS_NUM for the number of bands for PPAG.
Of course, SAR related structures will grow in future patches, but
decouple SAR and PPAG to make the work easier.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.c | 23 ++++++++++++++++----
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 16 +++++---------
2 files changed, 25 insertions(+), 14 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
index d4e1ab1f7c84..38f9d9adf90e 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.c
@@ -571,9 +571,11 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
{
struct uefi_cnv_var_ppag *data;
int ret = 0;
+ int data_sz = sizeof(*data) + sizeof(data->vals[0]) *
+ IWL_NUM_CHAIN_LIMITS * UEFI_PPAG_SUB_BANDS_NUM;
data = iwl_uefi_get_verified_variable(fwrt->trans, IWL_UEFI_PPAG_NAME,
- "PPAG", sizeof(*data), NULL);
+ "PPAG", data_sz, NULL);
if (IS_ERR(data))
return -EINVAL;
@@ -589,9 +591,22 @@ int iwl_uefi_get_ppag_table(struct iwl_fw_runtime *fwrt)
fwrt->ppag_flags = iwl_bios_get_ppag_flags(data->ppag_modes,
fwrt->ppag_bios_rev);
- BUILD_BUG_ON(sizeof(fwrt->ppag_chains) != sizeof(data->ppag_chains));
- memcpy(&fwrt->ppag_chains, &data->ppag_chains,
- sizeof(data->ppag_chains));
+ /*
+ * Make sure fwrt has enough room to hold
+ * data coming from the UEFI table
+ */
+ BUILD_BUG_ON(ARRAY_SIZE(fwrt->ppag_chains) *
+ ARRAY_SIZE(fwrt->ppag_chains[0].subbands) <
+ IWL_NUM_CHAIN_LIMITS * UEFI_PPAG_SUB_BANDS_NUM);
+
+ for (int chain = 0; chain < IWL_NUM_CHAIN_LIMITS; chain++) {
+ for (int subband = 0;
+ subband < UEFI_PPAG_SUB_BANDS_NUM;
+ subband++)
+ fwrt->ppag_chains[chain].subbands[subband] =
+ data->vals[chain * UEFI_PPAG_SUB_BANDS_NUM + subband];
+ }
+
fwrt->ppag_bios_source = BIOS_SOURCE_UEFI;
out:
kfree(data);
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index c6940a3c03ea..4f0ce068a589 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -77,6 +77,7 @@ struct uefi_cnv_common_step_data {
} __packed;
#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
+#define UEFI_PPAG_SUB_BANDS_NUM 11
#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
/*
@@ -136,24 +137,19 @@ struct uefi_cnv_var_wgds {
struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
} __packed;
-/*
- * struct uefi_ppag_chain - PPAG table for a specific chain
- * @subbands: the PPAG values for band
- */
-struct uefi_ppag_chain {
- s8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
-};
-
/*
* struct uefi_cnv_var_ppag - PPAG table as defined in UEFI
* @revision: the revision of the table
* @ppag_modes: values from &enum iwl_ppag_flags
- * @ppag_chains: the PPAG values per chain and band
+ * @vals: the PPAG values per chain and band as an array.
+ * vals[chain * num_of_subbands + subband] will return the right value.
+ * num_of_subbands is %UEFI_PPAG_SUB_BANDS_NUM.
+ * the max number of chains is currently 2
*/
struct uefi_cnv_var_ppag {
u8 revision;
u32 ppag_modes;
- struct uefi_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
+ s8 vals[];
} __packed;
/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 08/15] wifi: iwlwifi: mld: Introduce scan command version 18
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ilan Peer
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Ilan Peer <ilan.peer@intel.com>
The FW scan logic was extended to support new channels in the
7 GHz band, as such, the scan command was modified to support
scanning more PSC channels.
Introduce scan command version 18 handling, which is different
from scan command version 17 only in the number of supported
channel configurations.
Signed-off-by: Ilan Peer <ilan.peer@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/fw/api/scan.h | 45 ++++++++++
drivers/net/wireless/intel/iwlwifi/mld/scan.c | 87 +++++++++++++++----
2 files changed, 115 insertions(+), 17 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
index 60f0a4924ddf..c2bb400c834c 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/api/scan.h
@@ -985,6 +985,7 @@ struct iwl_scan_probe_params_v4 {
} __packed; /* SCAN_PROBE_PARAMS_API_S_VER_4 */
#define SCAN_MAX_NUM_CHANS_V3 67
+#define SCAN_MAX_NUM_CHANS_V4 68
/**
* struct iwl_scan_channel_params_v4 - channel params
@@ -1027,6 +1028,24 @@ struct iwl_scan_channel_params_v7 {
struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V3];
} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_6 */
+/**
+ * struct iwl_scan_channel_params_v8 - channel params
+ * @flags: channel flags &enum iwl_scan_channel_flags
+ * @count: num of channels in scan request
+ * @n_aps_override: override the number of APs the FW uses to calculate dwell
+ * time when adaptive dwell is used.
+ * Channel k will use n_aps_override[i] when BIT(20 + i) is set in
+ * channel_config[k].flags
+ * @channel_config: array of explicit channel configurations
+ * for 2.4Ghz and 5.2Ghz bands
+ */
+struct iwl_scan_channel_params_v8 {
+ u8 flags;
+ u8 count;
+ u8 n_aps_override[2];
+ struct iwl_scan_channel_cfg_umac channel_config[SCAN_MAX_NUM_CHANS_V4];
+} __packed; /* SCAN_CHANNEL_PARAMS_API_S_VER_8 */
+
/**
* struct iwl_scan_general_params_v11 - channel params
* @flags: &enum iwl_umac_scan_general_flags_v2
@@ -1109,6 +1128,20 @@ struct iwl_scan_req_params_v17 {
struct iwl_scan_probe_params_v4 probe_params;
} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_17 - 14 */
+/**
+ * struct iwl_scan_req_params_v18 - scan request parameters (v18)
+ * @general_params: &struct iwl_scan_general_params_v11
+ * @channel_params: &struct iwl_scan_channel_params_v8
+ * @periodic_params: &struct iwl_scan_periodic_parms_v1
+ * @probe_params: &struct iwl_scan_probe_params_v4
+ */
+struct iwl_scan_req_params_v18 {
+ struct iwl_scan_general_params_v11 general_params;
+ struct iwl_scan_channel_params_v8 channel_params;
+ struct iwl_scan_periodic_parms_v1 periodic_params;
+ struct iwl_scan_probe_params_v4 probe_params;
+} __packed; /* SCAN_REQUEST_PARAMS_API_S_VER_18 */
+
/**
* struct iwl_scan_req_umac_v12 - scan request command (v12)
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
@@ -1133,6 +1166,18 @@ struct iwl_scan_req_umac_v17 {
struct iwl_scan_req_params_v17 scan_params;
} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_17 - 14 */
+/**
+ * struct iwl_scan_req_umac_v18 - scan request command (v18)
+ * @uid: scan id, &enum iwl_umac_scan_uid_offsets
+ * @ooc_priority: out of channel priority - &enum iwl_scan_priority
+ * @scan_params: scan parameters
+ */
+struct iwl_scan_req_umac_v18 {
+ __le32 uid;
+ __le32 ooc_priority;
+ struct iwl_scan_req_params_v18 scan_params;
+} __packed; /* SCAN_REQUEST_CMD_UMAC_API_S_VER_18 */
+
/**
* struct iwl_umac_scan_abort - scan abort command
* @uid: scan id, &enum iwl_umac_scan_uid_offsets
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index 7f4679134def..96cd970cceb4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -118,7 +118,7 @@ struct iwl_mld_scan_params {
struct iwl_scan_req_params_ptrs {
struct iwl_scan_general_params_v11 *general_params;
- struct iwl_scan_channel_params_v7 *channel_params;
+ struct iwl_scan_channel_params_v8 *channel_params;
struct iwl_scan_periodic_parms_v1 *periodic_params;
struct iwl_scan_probe_params_v4 *probe_params;
};
@@ -840,7 +840,7 @@ iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld,
int n_channels, u32 flags,
enum nl80211_iftype vif_type)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
for (int i = 0; i < n_channels; i++) {
enum nl80211_band band = channels[i]->band;
@@ -883,7 +883,7 @@ iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld,
enum nl80211_iftype vif_type)
{
struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
u32 i;
@@ -1083,7 +1083,7 @@ iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,
struct ieee80211_vif *vif,
struct iwl_scan_req_params_ptrs *scan_ptrs)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
/* Explicitly clear the flags since most of them are not
* relevant for 6 GHz scan.
@@ -1111,7 +1111,7 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
enum iwl_mld_scan_status scan_status,
u32 channel_cfg_flags)
{
- struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+ struct iwl_scan_channel_params_v8 *cp = scan_ptrs->channel_params;
struct ieee80211_supported_band *sband =
&mld->nvm_data->bands[NL80211_BAND_6GHZ];
@@ -1173,39 +1173,89 @@ struct iwl_scan_umac_handler {
.handler = iwl_mld_scan_umac_v##_ver, \
}
-static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+static int iwl_mld_scan_umac_common(struct iwl_mld *mld,
+ struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
+ enum iwl_mld_scan_status scan_status,
+ bool low_latency)
+{
+ u32 bitmap_ssid = 0;
+ int ret;
+
+ iwl_mld_scan_cmd_set_gen_params(mld, params, vif, scan_ptrs,
+ scan_status);
+
+ ret = iwl_mld_scan_cmd_set_sched_params(params, scan_ptrs);
+ if (ret)
+ return ret;
+
+ iwl_mld_scan_cmd_set_probe_params(params, scan_ptrs, &bitmap_ssid);
+
+ return iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_ptrs,
+ low_latency, scan_status,
+ bitmap_ssid);
+}
+
+static int iwl_mld_scan_umac_v18(struct iwl_mld *mld, struct ieee80211_vif *vif,
struct iwl_mld_scan_params *params,
enum iwl_mld_scan_status scan_status,
int uid, u32 ooc_priority, bool low_latency)
{
- struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
+ struct iwl_scan_req_umac_v18 *cmd = mld->scan.cmd;
struct iwl_scan_req_params_ptrs scan_ptrs = {
.general_params = &cmd->scan_params.general_params,
.probe_params = &cmd->scan_params.probe_params,
.channel_params = &cmd->scan_params.channel_params,
.periodic_params = &cmd->scan_params.periodic_params
};
- u32 bitmap_ssid = 0;
int ret;
- if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V4))
return -EINVAL;
cmd->uid = cpu_to_le32(uid);
cmd->ooc_priority = cpu_to_le32(ooc_priority);
- iwl_mld_scan_cmd_set_gen_params(mld, params, vif, &scan_ptrs,
- scan_status);
-
- ret = iwl_mld_scan_cmd_set_sched_params(params, &scan_ptrs);
+ ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs,
+ scan_status, low_latency);
if (ret)
return ret;
- iwl_mld_scan_cmd_set_probe_params(params, &scan_ptrs, &bitmap_ssid);
+ return uid;
+}
+
+static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ int uid, u32 ooc_priority, bool low_latency)
+{
+ struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
+ struct iwl_scan_req_params_ptrs scan_ptrs = {
+ .general_params = &cmd->scan_params.general_params,
+ .probe_params = &cmd->scan_params.probe_params,
+
+ /* struct iwl_scan_channel_params_v8 and struct
+ * iwl_scan_channel_params_v7 are almost identical. The only
+ * difference is that the newer version allows configuration of
+ * more channels. So casting here is ok as long as we ensure
+ * that we don't exceed the max number of channels supported by
+ * the older version (see the WARN_ON below).
+ */
+ .channel_params = (struct iwl_scan_channel_params_v8 *)
+ &cmd->scan_params.channel_params,
+ .periodic_params = &cmd->scan_params.periodic_params
+ };
+ int ret;
+
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ return -EINVAL;
+
+ cmd->uid = cpu_to_le32(uid);
+ cmd->ooc_priority = cpu_to_le32(ooc_priority);
- ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, &scan_ptrs,
- low_latency, scan_status,
- bitmap_ssid);
+ ret = iwl_mld_scan_umac_common(mld, vif, params, &scan_ptrs,
+ scan_status, low_latency);
if (ret)
return ret;
@@ -1214,6 +1264,7 @@ static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
/* set the newest version first to shorten the list traverse time */
+ IWL_SCAN_UMAC_HANDLER(18),
IWL_SCAN_UMAC_HANDLER(17),
};
@@ -2095,6 +2146,8 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld)
if (scan_cmd_ver == 17) {
scan_cmd_size = sizeof(struct iwl_scan_req_umac_v17);
+ } else if (scan_cmd_ver == 18) {
+ scan_cmd_size = sizeof(struct iwl_scan_req_umac_v18);
} else {
IWL_ERR(mld, "Unexpected scan cmd version %d\n", scan_cmd_ver);
return -EINVAL;
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 07/15] wifi: iwlwifi: mld: Refactor scan command handling
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Ilan Peer
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Ilan Peer <ilan.peer@intel.com>
As a preparation for a new scan command version, refactor
the scan command building such that it would allow introducing
new scan command structures in a simpler way.
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/scan.c | 159 ++++++++++++------
drivers/net/wireless/intel/iwlwifi/mld/scan.h | 2 +
2 files changed, 114 insertions(+), 47 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.c b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
index a1a4cf3ab3d3..7f4679134def 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.c
@@ -116,6 +116,13 @@ struct iwl_mld_scan_params {
u8 bssid[ETH_ALEN] __aligned(2);
};
+struct iwl_scan_req_params_ptrs {
+ struct iwl_scan_general_params_v11 *general_params;
+ struct iwl_scan_channel_params_v7 *channel_params;
+ struct iwl_scan_periodic_parms_v1 *periodic_params;
+ struct iwl_scan_probe_params_v4 *probe_params;
+};
+
struct iwl_mld_scan_respect_p2p_go_iter_data {
struct ieee80211_vif *current_vif;
bool p2p_go;
@@ -512,9 +519,10 @@ iwl_mld_scan_get_cmd_gen_flags2(struct iwl_mld *mld,
static void
iwl_mld_scan_cmd_set_dwell(struct iwl_mld *mld,
- struct iwl_scan_general_params_v11 *gp,
- struct iwl_mld_scan_params *params)
+ struct iwl_mld_scan_params *params,
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
+ struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params;
const struct iwl_mld_scan_timing_params *timing =
&scan_timing[params->type];
@@ -551,9 +559,10 @@ static void
iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_general_params_v11 *gp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
enum iwl_mld_scan_status scan_status)
{
+ struct iwl_scan_general_params_v11 *gp = scan_ptrs->general_params;
u16 gen_flags = iwl_mld_scan_get_cmd_gen_flags(mld, params, vif,
scan_status);
u8 gen_flags2 = iwl_mld_scan_get_cmd_gen_flags2(mld, params, vif,
@@ -566,7 +575,7 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
gp->flags = cpu_to_le16(gen_flags);
gp->flags2 = gen_flags2;
- iwl_mld_scan_cmd_set_dwell(mld, gp, params);
+ iwl_mld_scan_cmd_set_dwell(mld, params, scan_ptrs);
if (gen_flags & IWL_UMAC_SCAN_GEN_FLAGS_V2_FRAGMENTED_LMAC1)
gp->num_of_fragments[SCAN_LB_LMAC_IDX] = IWL_SCAN_NUM_OF_FRAGS;
@@ -577,9 +586,12 @@ iwl_mld_scan_cmd_set_gen_params(struct iwl_mld *mld,
static int
iwl_mld_scan_cmd_set_sched_params(struct iwl_mld_scan_params *params,
- struct iwl_scan_umac_schedule *schedule,
- __le16 *delay)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
+ struct iwl_scan_umac_schedule *schedule =
+ scan_ptrs->periodic_params->schedule;
+ __le16 *delay = &scan_ptrs->periodic_params->delay;
+
if (WARN_ON(!params->n_scan_plans ||
params->n_scan_plans > IWL_MAX_SCHED_SCAN_PLANS))
return -EINVAL;
@@ -657,11 +669,12 @@ iwl_mld_scan_cmd_build_ssids(struct iwl_mld_scan_params *params,
static void
iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params,
- struct iwl_scan_probe_params_v4 *pp)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
int j, idex_s = 0, idex_b = 0;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
for (j = 0;
j < params->n_ssids && idex_s < SCAN_SHORT_SSID_MAX_SIZE;
@@ -725,13 +738,15 @@ iwl_mld_scan_fill_6g_chan_list(struct iwl_mld_scan_params *params,
static void
iwl_mld_scan_cmd_set_probe_params(struct iwl_mld_scan_params *params,
- struct iwl_scan_probe_params_v4 *pp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
u32 *bitmap_ssid)
{
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
+
pp->preq = params->preq;
if (params->scan_6ghz) {
- iwl_mld_scan_fill_6g_chan_list(params, pp);
+ iwl_mld_scan_fill_6g_chan_list(params, scan_ptrs);
return;
}
@@ -821,10 +836,12 @@ static u32 iwl_mld_scan_ch_n_aps_flag(enum nl80211_iftype vif_type, u8 ch_id)
static void
iwl_mld_scan_cmd_set_channels(struct iwl_mld *mld,
struct ieee80211_channel **channels,
- struct iwl_scan_channel_params_v7 *cp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
int n_channels, u32 flags,
enum nl80211_iftype vif_type)
{
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
+
for (int i = 0; i < n_channels; i++) {
enum nl80211_band band = channels[i]->band;
struct iwl_scan_channel_cfg_umac *cfg = &cp->channel_config[i];
@@ -862,10 +879,11 @@ static u8
iwl_mld_scan_cfg_channels_6g(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
u32 n_channels,
- struct iwl_scan_probe_params_v4 *pp,
- struct iwl_scan_channel_params_v7 *cp,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
enum nl80211_iftype vif_type)
{
+ struct iwl_scan_probe_params_v4 *pp = scan_ptrs->probe_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
struct cfg80211_scan_6ghz_params *scan_6ghz_params =
params->scan_6ghz_params;
u32 i;
@@ -1063,25 +1081,23 @@ static int
iwl_mld_scan_cmd_set_6ghz_chan_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_req_params_v17 *scan_p)
+ struct iwl_scan_req_params_ptrs *scan_ptrs)
{
- struct iwl_scan_channel_params_v7 *chan_p = &scan_p->channel_params;
- struct iwl_scan_probe_params_v4 *probe_p = &scan_p->probe_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
/* Explicitly clear the flags since most of them are not
* relevant for 6 GHz scan.
*/
- chan_p->flags = 0;
- chan_p->count = iwl_mld_scan_cfg_channels_6g(mld, params,
- params->n_channels,
- probe_p, chan_p,
- vif->type);
- if (!chan_p->count)
+ cp->flags = 0;
+ cp->count = iwl_mld_scan_cfg_channels_6g(mld, params,
+ params->n_channels,
+ scan_ptrs, vif->type);
+ if (!cp->count)
return -EINVAL;
if (!params->n_ssids ||
(params->n_ssids == 1 && !params->ssids[0].ssid_len))
- chan_p->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER;
+ cp->flags |= IWL_SCAN_CHANNEL_FLAG_6G_PSC_NO_FILTER;
return 0;
}
@@ -1090,12 +1106,12 @@ static int
iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
struct iwl_mld_scan_params *params,
struct ieee80211_vif *vif,
- struct iwl_scan_req_params_v17 *scan_p,
+ struct iwl_scan_req_params_ptrs *scan_ptrs,
bool low_latency,
enum iwl_mld_scan_status scan_status,
u32 channel_cfg_flags)
{
- struct iwl_scan_channel_params_v7 *cp = &scan_p->channel_params;
+ struct iwl_scan_channel_params_v7 *cp = scan_ptrs->channel_params;
struct ieee80211_supported_band *sband =
&mld->nvm_data->bands[NL80211_BAND_6GHZ];
@@ -1107,14 +1123,14 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
if (params->scan_6ghz)
return iwl_mld_scan_cmd_set_6ghz_chan_params(mld, params,
- vif, scan_p);
+ vif, scan_ptrs);
/* relevant only for 2.4 GHz/5 GHz scan */
cp->flags = iwl_mld_scan_cmd_set_chan_flags(mld, params, vif,
low_latency);
cp->count = params->n_channels;
- iwl_mld_scan_cmd_set_channels(mld, params->channels, cp,
+ iwl_mld_scan_cmd_set_channels(mld, params->channels, scan_ptrs,
params->n_channels, channel_cfg_flags,
vif->type);
@@ -1144,41 +1160,50 @@ iwl_mld_scan_cmd_set_chan_params(struct iwl_mld *mld,
return 0;
}
-static int
-iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
+struct iwl_scan_umac_handler {
+ u8 version;
+ int (*handler)(struct iwl_mld *mld, struct ieee80211_vif *vif,
struct iwl_mld_scan_params *params,
enum iwl_mld_scan_status scan_status,
- bool low_latency)
+ int uid, u32 ooc_priority, bool low_latency);
+};
+
+#define IWL_SCAN_UMAC_HANDLER(_ver) { \
+ .version = _ver, \
+ .handler = iwl_mld_scan_umac_v##_ver, \
+}
+
+static int iwl_mld_scan_umac_v17(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ int uid, u32 ooc_priority, bool low_latency)
{
struct iwl_scan_req_umac_v17 *cmd = mld->scan.cmd;
- struct iwl_scan_req_params_v17 *scan_p = &cmd->scan_params;
+ struct iwl_scan_req_params_ptrs scan_ptrs = {
+ .general_params = &cmd->scan_params.general_params,
+ .probe_params = &cmd->scan_params.probe_params,
+ .channel_params = &cmd->scan_params.channel_params,
+ .periodic_params = &cmd->scan_params.periodic_params
+ };
u32 bitmap_ssid = 0;
- int uid, ret;
-
- memset(mld->scan.cmd, 0, mld->scan.cmd_size);
+ int ret;
- /* find a free UID entry */
- uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE);
- if (uid < 0)
- return uid;
+ if (WARN_ON(params->n_channels > SCAN_MAX_NUM_CHANS_V3))
+ return -EINVAL;
cmd->uid = cpu_to_le32(uid);
- cmd->ooc_priority =
- cpu_to_le32(iwl_mld_scan_ooc_priority(scan_status));
+ cmd->ooc_priority = cpu_to_le32(ooc_priority);
- iwl_mld_scan_cmd_set_gen_params(mld, params, vif,
- &scan_p->general_params, scan_status);
+ iwl_mld_scan_cmd_set_gen_params(mld, params, vif, &scan_ptrs,
+ scan_status);
- ret = iwl_mld_scan_cmd_set_sched_params(params,
- scan_p->periodic_params.schedule,
- &scan_p->periodic_params.delay);
+ ret = iwl_mld_scan_cmd_set_sched_params(params, &scan_ptrs);
if (ret)
return ret;
- iwl_mld_scan_cmd_set_probe_params(params, &scan_p->probe_params,
- &bitmap_ssid);
+ iwl_mld_scan_cmd_set_probe_params(params, &scan_ptrs, &bitmap_ssid);
- ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, scan_p,
+ ret = iwl_mld_scan_cmd_set_chan_params(mld, params, vif, &scan_ptrs,
low_latency, scan_status,
bitmap_ssid);
if (ret)
@@ -1187,6 +1212,45 @@ iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
return uid;
}
+static const struct iwl_scan_umac_handler iwl_scan_umac_handlers[] = {
+ /* set the newest version first to shorten the list traverse time */
+ IWL_SCAN_UMAC_HANDLER(17),
+};
+
+static int
+iwl_mld_scan_build_cmd(struct iwl_mld *mld, struct ieee80211_vif *vif,
+ struct iwl_mld_scan_params *params,
+ enum iwl_mld_scan_status scan_status,
+ bool low_latency)
+{
+ int uid, err;
+ u32 ooc_priority;
+
+ memset(mld->scan.cmd, 0, mld->scan.cmd_size);
+ uid = iwl_mld_scan_uid_by_status(mld, IWL_MLD_SCAN_NONE);
+ if (uid < 0)
+ return uid;
+
+ ooc_priority = iwl_mld_scan_ooc_priority(scan_status);
+
+ for (size_t i = 0; i < ARRAY_SIZE(iwl_scan_umac_handlers); i++) {
+ const struct iwl_scan_umac_handler *ver_handler =
+ &iwl_scan_umac_handlers[i];
+
+ if (ver_handler->version != mld->scan.cmd_ver)
+ continue;
+
+ err = ver_handler->handler(mld, vif, params, scan_status,
+ uid, ooc_priority, low_latency);
+ return err ? : uid;
+ }
+
+ IWL_ERR(mld, "No handler for UMAC scan cmd version %d\n",
+ mld->scan.cmd_ver);
+
+ return -EINVAL;
+}
+
static bool
iwl_mld_scan_pass_all(struct iwl_mld *mld,
struct cfg80211_sched_scan_request *req)
@@ -2041,6 +2105,7 @@ int iwl_mld_alloc_scan_cmd(struct iwl_mld *mld)
return -ENOMEM;
mld->scan.cmd_size = scan_cmd_size;
+ mld->scan.cmd_ver = scan_cmd_ver;
return 0;
}
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/scan.h b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
index 69110f0cfc8e..772b3a02c4c4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/scan.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/scan.h
@@ -109,6 +109,7 @@ enum iwl_mld_traffic_load {
* @traffic_load.status: The current traffic load status, see
* &enum iwl_mld_traffic_load
* @cmd_size: size of %cmd.
+ * @cmd_ver: version of the scan command format.
* @cmd: pointer to scan cmd buffer (allocated once in op mode start).
* @last_6ghz_passive_jiffies: stores the last 6GHz passive scan time
* in jiffies.
@@ -134,6 +135,7 @@ struct iwl_mld_scan {
/* And here fields that survive a fw restart */
size_t cmd_size;
void *cmd;
+ u8 cmd_ver;
unsigned long last_6ghz_passive_jiffies;
unsigned long last_start_time_jiffies;
u64 last_mlo_scan_time;
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 06/15] wifi: iwlwifi: mld: remove unused scan expire time constants
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Pagadala Yesu Anjaneyulu, Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Remove the unused IWL_MLD_SCAN_EXPIRE_TIME_SEC constant from
constants.h and its corresponding IWL_MLD_SCAN_EXPIRE_TIME
macro definition from mlo.c. These definitions are no longer
referenced.
Signed-off-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/mld/constants.h | 1 -
drivers/net/wireless/intel/iwlwifi/mld/mlo.c | 1 -
2 files changed, 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/constants.h b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
index 5d23a618ae3c..e2a5eecc18c3 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/constants.h
+++ b/drivers/net/wireless/intel/iwlwifi/mld/constants.h
@@ -36,7 +36,6 @@
#define IWL_MLD_PS_HEAVY_RX_THLD_PACKETS 8
#define IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC 30
-#define IWL_MLD_SCAN_EXPIRE_TIME_SEC 20
#define IWL_MLD_TPT_COUNT_WINDOW (5 * HZ)
diff --git a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
index f842f5183223..f693f92e42b4 100644
--- a/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
+++ b/drivers/net/wireless/intel/iwlwifi/mld/mlo.c
@@ -110,7 +110,6 @@ void iwl_mld_emlsr_tmp_non_bss_done_wk(struct wiphy *wiphy,
}
#define IWL_MLD_TRIGGER_LINK_SEL_TIME (HZ * IWL_MLD_TRIGGER_LINK_SEL_TIME_SEC)
-#define IWL_MLD_SCAN_EXPIRE_TIME (HZ * IWL_MLD_SCAN_EXPIRE_TIME_SEC)
/* Exit reasons that can cause longer EMLSR prevention */
#define IWL_MLD_PREVENT_EMLSR_REASONS (IWL_MLD_EMLSR_EXIT_MISSED_BEACON | \
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 05/15] wifi: iwlwifi: mvm: cleanup some more MLO code
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Nidhish A N, Pagadala Yesu Anjaneyulu
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Nidhish A N <nidhish.a.n@intel.com>
iwlmld is now the op mode that is used for EHT devices,
so iwlmvm code can never run in MLO.
Clean up some more MLO code.
Signed-off-by: Nidhish A N <nidhish.a.n@intel.com>
Reviewed-by: Pagadala Yesu Anjaneyulu <pagadala.yesu.anjaneyulu@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
.../net/wireless/intel/iwlwifi/mvm/mld-key.c | 46 ---
.../wireless/intel/iwlwifi/mvm/mld-mac80211.c | 132 --------
.../net/wireless/intel/iwlwifi/mvm/mld-sta.c | 285 ------------------
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h | 5 -
drivers/net/wireless/intel/iwlwifi/mvm/sta.h | 4 -
5 files changed, 472 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
index 9bb253dcf4a7..4869a5fa8abc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-key.c
@@ -121,52 +121,6 @@ struct iwl_mvm_sta_key_update_data {
int err;
};
-static void iwl_mvm_mld_update_sta_key(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- struct ieee80211_key_conf *key,
- void *_data)
-{
- u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, SEC_KEY_CMD);
- struct iwl_mvm_sta_key_update_data *data = _data;
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_sec_key_cmd cmd = {
- .action = cpu_to_le32(FW_CTXT_ACTION_MODIFY),
- .u.modify.old_sta_mask = cpu_to_le32(data->old_sta_mask),
- .u.modify.new_sta_mask = cpu_to_le32(data->new_sta_mask),
- .u.modify.key_id = cpu_to_le32(key->keyidx),
- .u.modify.key_flags =
- cpu_to_le32(iwl_mvm_get_sec_flags(mvm, vif, sta, key)),
- };
- int err;
-
- /* only need to do this for pairwise keys (link_id == -1) */
- if (sta != data->sta || key->link_id >= 0)
- return;
-
- err = iwl_mvm_send_cmd_pdu(mvm, cmd_id, 0, sizeof(cmd), &cmd);
-
- if (err)
- data->err = err;
-}
-
-int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_mvm_sta_key_update_data data = {
- .sta = sta,
- .old_sta_mask = old_sta_mask,
- .new_sta_mask = new_sta_mask,
- };
-
- ieee80211_iter_keys(mvm->hw, vif, iwl_mvm_mld_update_sta_key,
- &data);
- return data.err;
-}
-
static int __iwl_mvm_sec_key_del(struct iwl_mvm *mvm, u32 sta_mask,
u32 key_flags, u32 keyidx, u32 flags)
{
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
index 896ed9823021..f1dbfeae20bc 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
@@ -886,133 +886,6 @@ static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
}
-static int
-iwl_mvm_mld_change_vif_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- u16 old_links, u16 new_links,
- struct ieee80211_bss_conf *old[IEEE80211_MLD_MAX_NUM_LINKS])
-{
- struct iwl_mvm_vif_link_info *new_link[IEEE80211_MLD_MAX_NUM_LINKS] = {};
- struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- u16 removed = old_links & ~new_links;
- u16 added = new_links & ~old_links;
- int err, i;
-
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
- break;
-
- if (!(added & BIT(i)))
- continue;
- new_link[i] = kzalloc_obj(*new_link[i]);
- if (!new_link[i]) {
- err = -ENOMEM;
- goto free;
- }
-
- new_link[i]->fw_link_id = IWL_MVM_FW_LINK_ID_INVALID;
- iwl_mvm_init_link(new_link[i]);
- }
-
- mutex_lock(&mvm->mutex);
-
- /* If we're in RESTART flow, the default link wasn't added in
- * drv_add_interface(), and link[0] doesn't point to it.
- */
- if (old_links == 0 && !test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
- &mvm->status)) {
- err = iwl_mvm_disable_link(mvm, vif, &vif->bss_conf);
- if (err)
- goto out_err;
- mvmvif->link[0] = NULL;
- }
-
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++) {
- if (removed & BIT(i)) {
- struct ieee80211_bss_conf *link_conf = old[i];
-
- err = iwl_mvm_disable_link(mvm, vif, link_conf);
- if (err)
- goto out_err;
- kfree(mvmvif->link[i]);
- mvmvif->link[i] = NULL;
- } else if (added & BIT(i)) {
- struct ieee80211_bss_conf *link_conf;
-
- link_conf = link_conf_dereference_protected(vif, i);
- if (WARN_ON(!link_conf))
- continue;
-
- if (!test_bit(IWL_MVM_STATUS_IN_HW_RESTART,
- &mvm->status))
- mvmvif->link[i] = new_link[i];
- new_link[i] = NULL;
- err = iwl_mvm_add_link(mvm, vif, link_conf);
- if (err)
- goto out_err;
- }
- }
-
- err = 0;
- if (new_links == 0) {
- mvmvif->link[0] = &mvmvif->deflink;
- err = iwl_mvm_add_link(mvm, vif, &vif->bss_conf);
- }
-
-out_err:
- /* we really don't have a good way to roll back here ... */
- mutex_unlock(&mvm->mutex);
-
-free:
- for (i = 0; i < IEEE80211_MLD_MAX_NUM_LINKS; i++)
- kfree(new_link[i]);
- return err;
-}
-
-static int
-iwl_mvm_mld_change_sta_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links)
-{
- struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
-
- guard(mvm)(mvm);
- return iwl_mvm_mld_update_sta_links(mvm, vif, sta, old_links, new_links);
-}
-
-static bool iwl_mvm_mld_can_activate_links(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- u16 desired_links)
-{
- int n_links = hweight16(desired_links);
-
- if (n_links <= 1)
- return true;
-
- WARN_ON(1);
- return false;
-}
-
-static enum ieee80211_neg_ttlm_res
-iwl_mvm_mld_can_neg_ttlm(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
- struct ieee80211_neg_ttlm *neg_ttlm)
-{
- u16 map;
- u8 i;
-
- /* Verify all TIDs are mapped to the same links set */
- map = neg_ttlm->downlink[0];
- for (i = 0; i < IEEE80211_TTLM_NUM_TIDS; i++) {
- if (neg_ttlm->downlink[i] != neg_ttlm->uplink[i] ||
- neg_ttlm->uplink[i] != map)
- return NEG_TTLM_RES_REJECT;
- }
-
- return NEG_TTLM_RES_ACCEPT;
-}
-
const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.tx = iwl_mvm_mac_tx,
.wake_tx_queue = iwl_mvm_mac_wake_tx_queue,
@@ -1102,9 +975,4 @@ const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
.link_sta_add_debugfs = iwl_mvm_link_sta_add_debugfs,
#endif
.set_hw_timestamp = iwl_mvm_set_hw_timestamp,
-
- .change_vif_links = iwl_mvm_mld_change_vif_links,
- .change_sta_links = iwl_mvm_mld_change_sta_links,
- .can_activate_links = iwl_mvm_mld_can_activate_links,
- .can_neg_ttlm = iwl_mvm_mld_can_neg_ttlm,
};
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
index 3359e02e151f..44e16ee9514e 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
@@ -913,288 +913,3 @@ void iwl_mvm_mld_modify_all_sta_disable_tx(struct iwl_mvm *mvm,
rcu_read_unlock();
}
-
-static int iwl_mvm_mld_update_sta_queues(struct iwl_mvm *mvm,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_scd_queue_cfg_cmd cmd = {
- .operation = cpu_to_le32(IWL_SCD_QUEUE_MODIFY),
- .u.modify.old_sta_mask = cpu_to_le32(old_sta_mask),
- .u.modify.new_sta_mask = cpu_to_le32(new_sta_mask),
- };
- struct iwl_host_cmd hcmd = {
- .id = WIDE_ID(DATA_PATH_GROUP, SCD_QUEUE_CONFIG_CMD),
- .len[0] = sizeof(cmd),
- .data[0] = &cmd
- };
- int tid;
- int ret;
-
- lockdep_assert_held(&mvm->mutex);
-
- for (tid = 0; tid <= IWL_MAX_TID_COUNT; tid++) {
- struct iwl_mvm_tid_data *tid_data = &mvm_sta->tid_data[tid];
- int txq_id = tid_data->txq_id;
-
- if (txq_id == IWL_MVM_INVALID_QUEUE)
- continue;
-
- if (tid == IWL_MAX_TID_COUNT)
- cmd.u.modify.tid = cpu_to_le32(IWL_MGMT_TID);
- else
- cmd.u.modify.tid = cpu_to_le32(tid);
-
- ret = iwl_mvm_send_cmd(mvm, &hcmd);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int iwl_mvm_mld_update_sta_baids(struct iwl_mvm *mvm,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- struct iwl_rx_baid_cfg_cmd cmd = {
- .action = cpu_to_le32(IWL_RX_BAID_ACTION_MODIFY),
- .modify.old_sta_id_mask = cpu_to_le32(old_sta_mask),
- .modify.new_sta_id_mask = cpu_to_le32(new_sta_mask),
- };
- u32 cmd_id = WIDE_ID(DATA_PATH_GROUP, RX_BAID_ALLOCATION_CONFIG_CMD);
- int baid;
-
- /* mac80211 will remove sessions later, but we ignore all that */
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status))
- return 0;
-
- BUILD_BUG_ON(sizeof(struct iwl_rx_baid_cfg_resp) != sizeof(baid));
-
- for (baid = 0; baid < ARRAY_SIZE(mvm->baid_map); baid++) {
- struct iwl_mvm_baid_data *data;
- int ret;
-
- data = rcu_dereference_protected(mvm->baid_map[baid],
- lockdep_is_held(&mvm->mutex));
- if (!data)
- continue;
-
- if (!(data->sta_mask & old_sta_mask))
- continue;
-
- WARN_ONCE(data->sta_mask != old_sta_mask,
- "BAID data for %d corrupted - expected 0x%x found 0x%x\n",
- baid, old_sta_mask, data->sta_mask);
-
- cmd.modify.tid = cpu_to_le32(data->tid);
-
- ret = iwl_mvm_send_cmd_pdu(mvm, cmd_id, CMD_SEND_IN_RFKILL,
- sizeof(cmd), &cmd);
- data->sta_mask = new_sta_mask;
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int iwl_mvm_mld_update_sta_resources(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask)
-{
- int ret;
-
- ret = iwl_mvm_mld_update_sta_queues(mvm, sta,
- old_sta_mask,
- new_sta_mask);
- if (ret)
- return ret;
-
- ret = iwl_mvm_mld_update_sta_keys(mvm, vif, sta,
- old_sta_mask,
- new_sta_mask);
- if (ret)
- return ret;
-
- return iwl_mvm_mld_update_sta_baids(mvm, old_sta_mask, new_sta_mask);
-}
-
-int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links)
-{
- struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
- struct iwl_mvm_vif *mvm_vif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm_link_sta *mvm_sta_link;
- struct iwl_mvm_vif_link_info *mvm_vif_link;
- unsigned long links_to_add = ~old_links & new_links;
- unsigned long links_to_rem = old_links & ~new_links;
- unsigned long old_links_long = old_links;
- u32 current_sta_mask = 0, sta_mask_added = 0, sta_mask_to_rem = 0;
- unsigned long link_sta_added_to_fw = 0, link_sta_allocated = 0;
- unsigned int link_id;
- int ret;
-
- lockdep_assert_wiphy(mvm->hw->wiphy);
- lockdep_assert_held(&mvm->mutex);
-
- for_each_set_bit(link_id, &old_links_long,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- if (WARN_ON(!mvm_sta_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- current_sta_mask |= BIT(mvm_sta_link->sta_id);
- if (links_to_rem & BIT(link_id))
- sta_mask_to_rem |= BIT(mvm_sta_link->sta_id);
- }
-
- if (sta_mask_to_rem) {
- ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
- current_sta_mask,
- current_sta_mask &
- ~sta_mask_to_rem);
- if (WARN_ON(ret))
- goto err;
-
- current_sta_mask &= ~sta_mask_to_rem;
- }
-
- for_each_set_bit(link_id, &links_to_rem, IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
- mvm_vif_link = mvm_vif->link[link_id];
-
- if (WARN_ON(!mvm_sta_link || !mvm_vif_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- ret = iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
- if (WARN_ON(ret))
- goto err;
-
- if (vif->type == NL80211_IFTYPE_STATION)
- mvm_vif_link->ap_sta_id = IWL_INVALID_STA;
-
- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
- }
-
- for_each_set_bit(link_id, &links_to_add, IEEE80211_MLD_MAX_NUM_LINKS) {
- struct ieee80211_bss_conf *link_conf =
- link_conf_dereference_protected(vif, link_id);
- struct ieee80211_link_sta *link_sta =
- link_sta_dereference_protected(sta, link_id);
- mvm_vif_link = mvm_vif->link[link_id];
-
- if (WARN_ON(!mvm_vif_link || !link_conf || !link_sta)) {
- ret = -EINVAL;
- goto err;
- }
-
- if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
- struct iwl_mvm_link_sta *mvm_link_sta =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
- u32 sta_id;
-
- if (WARN_ON(!mvm_link_sta)) {
- ret = -EINVAL;
- goto err;
- }
-
- sta_id = mvm_link_sta->sta_id;
-
- rcu_assign_pointer(mvm->fw_id_to_mac_id[sta_id], sta);
- rcu_assign_pointer(mvm->fw_id_to_link_sta[sta_id],
- link_sta);
- } else {
- if (WARN_ON(mvm_sta->link[link_id])) {
- ret = -EINVAL;
- goto err;
- }
- ret = iwl_mvm_mld_alloc_sta_link(mvm, vif, sta,
- link_id);
- if (WARN_ON(ret))
- goto err;
- }
-
- link_sta->agg.max_rc_amsdu_len = 1;
- ieee80211_sta_recalc_aggregates(sta);
-
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- if (WARN_ON(!mvm_sta_link)) {
- ret = -EINVAL;
- goto err;
- }
-
- if (vif->type == NL80211_IFTYPE_STATION)
- iwl_mvm_mld_set_ap_sta_id(sta, mvm_vif_link,
- mvm_sta_link);
-
- link_sta_allocated |= BIT(link_id);
-
- sta_mask_added |= BIT(mvm_sta_link->sta_id);
-
- ret = iwl_mvm_mld_cfg_sta(mvm, sta, vif, link_sta, link_conf,
- mvm_sta_link);
- if (WARN_ON(ret))
- goto err;
-
- link_sta_added_to_fw |= BIT(link_id);
-
- iwl_mvm_rs_add_sta_link(mvm, mvm_sta_link);
-
- iwl_mvm_rs_rate_init(mvm, vif, sta, link_conf, link_sta,
- link_conf->chanreq.oper.chan->band);
- }
-
- if (sta_mask_added) {
- ret = iwl_mvm_mld_update_sta_resources(mvm, vif, sta,
- current_sta_mask,
- current_sta_mask |
- sta_mask_added);
- if (WARN_ON(ret))
- goto err;
- }
-
- return 0;
-
-err:
- /* remove all already allocated stations in FW */
- for_each_set_bit(link_id, &link_sta_added_to_fw,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- iwl_mvm_mld_rm_sta_from_fw(mvm, mvm_sta_link->sta_id);
- }
-
- /* remove all already allocated station links in driver */
- for_each_set_bit(link_id, &link_sta_allocated,
- IEEE80211_MLD_MAX_NUM_LINKS) {
- mvm_sta_link =
- rcu_dereference_protected(mvm_sta->link[link_id],
- lockdep_is_held(&mvm->mutex));
-
- iwl_mvm_mld_free_sta_link(mvm, mvm_sta, mvm_sta_link, link_id);
- }
-
- return ret;
-}
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
index 46a9dfa58a53..402ba5dee8b2 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
@@ -2450,11 +2450,6 @@ void iwl_mvm_sec_key_remove_ap(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct iwl_mvm_vif_link_info *link,
unsigned int link_id);
-int iwl_mvm_mld_update_sta_keys(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u32 old_sta_mask,
- u32 new_sta_mask);
int iwl_mvm_mld_send_key(struct iwl_mvm *mvm, u32 sta_mask, u32 key_flags,
struct ieee80211_key_conf *keyconf);
u32 iwl_mvm_get_sec_flags(struct iwl_mvm *mvm,
diff --git a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
index c25edc7c1813..ff099aec7886 100644
--- a/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
+++ b/drivers/net/wireless/intel/iwlwifi/mvm/sta.h
@@ -637,10 +637,6 @@ void iwl_mvm_mld_free_sta_link(struct iwl_mvm *mvm,
struct iwl_mvm_link_sta *mvm_sta_link,
unsigned int link_id);
int iwl_mvm_mld_rm_sta_id(struct iwl_mvm *mvm, u8 sta_id);
-int iwl_mvm_mld_update_sta_links(struct iwl_mvm *mvm,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- u16 old_links, u16 new_links);
u32 iwl_mvm_sta_fw_id_mask(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int filter_link_id);
int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 04/15] wifi: iwlwifi: acpi: better use ARRAY_SIZE than a define
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Since we'll have to change things in this area, use the safer option to
define the size of an array.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/acpi.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
index de9aef0d924c..b64abb8439b7 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
+++ b/drivers/net/wireless/intel/iwlwifi/fw/acpi.c
@@ -504,7 +504,8 @@ iwl_acpi_parse_chains_table(union acpi_object *table,
u8 num_chains, u8 num_sub_bands)
{
for (u8 chain = 0; chain < num_chains; chain++) {
- for (u8 subband = 0; subband < BIOS_SAR_MAX_SUB_BANDS_NUM;
+ for (u8 subband = 0;
+ subband < ARRAY_SIZE(chains[chain].subbands);
subband++) {
/* if we don't have the values, use the default */
if (subband >= num_sub_bands) {
--
2.34.1
^ permalink raw reply related
* [PATCH iwlwifi-next 03/15] wifi: iwlwifi: uefi: decouple UEFI and firmware APIs
From: Miri Korenblit @ 2026-03-18 20:54 UTC (permalink / raw)
To: linux-wireless; +Cc: Emmanuel Grumbach
In-Reply-To: <20260318205430.614577-1-miriam.rachel.korenblit@intel.com>
From: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
The APIs in uefi.h are not firmware API files nor are they pure software
objects. They really reflect a specific layout we expect to see in the
UEFI tables.
Since the UEFI objects are encoded into the BIOS, we can't use the same
values for the declaration of the UEFI objects and for the pure software
object like iwl_sar_profile in the firmware runtime object.
Decouple the two types.
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
---
drivers/net/wireless/intel/iwlwifi/fw/uefi.h | 23 ++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
diff --git a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
index 99170a72c3f1..c6940a3c03ea 100644
--- a/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
+++ b/drivers/net/wireless/intel/iwlwifi/fw/uefi.h
@@ -76,13 +76,24 @@ struct uefi_cnv_common_step_data {
u8 radio2;
} __packed;
+#define UEFI_SAR_MAX_SUB_BANDS_NUM 11
+#define UEFI_SAR_MAX_CHAINS_PER_PROFILE 4
+
+/*
+ * struct uefi_sar_profile_chain - per-chain values of a SAR profile
+ * @subbands: the SAR value for each subband
+ */
+struct uefi_sar_profile_chain {
+ u8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
+};
+
/*
* struct uefi_sar_profile - a SAR profile as defined in UEFI
*
* @chains: a per-chain table of SAR values
*/
struct uefi_sar_profile {
- struct iwl_sar_profile_chain chains[BIOS_SAR_MAX_CHAINS_PER_PROFILE];
+ struct uefi_sar_profile_chain chains[UEFI_SAR_MAX_CHAINS_PER_PROFILE];
} __packed;
/*
@@ -125,6 +136,14 @@ struct uefi_cnv_var_wgds {
struct iwl_geo_profile geo_profiles[BIOS_GEO_MAX_PROFILE_NUM];
} __packed;
+/*
+ * struct uefi_ppag_chain - PPAG table for a specific chain
+ * @subbands: the PPAG values for band
+ */
+struct uefi_ppag_chain {
+ s8 subbands[UEFI_SAR_MAX_SUB_BANDS_NUM];
+};
+
/*
* struct uefi_cnv_var_ppag - PPAG table as defined in UEFI
* @revision: the revision of the table
@@ -134,7 +153,7 @@ struct uefi_cnv_var_wgds {
struct uefi_cnv_var_ppag {
u8 revision;
u32 ppag_modes;
- struct iwl_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
+ struct uefi_ppag_chain ppag_chains[IWL_NUM_CHAIN_LIMITS];
} __packed;
/* struct uefi_cnv_var_wtas - WTAS tabled as defined in UEFI
--
2.34.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox