Linux wireless drivers development
 help / color / mirror / Atom feed
* Re: [PATCH net-next] net: remove unnecessary module_init/exit functions
From: patchwork-bot+netdevbpf @ 2026-02-03  1:50 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: netdev, linux-can, linux-wireless, m.grzeschik, andrew+netdev,
	davem, edumazet, kuba, pabeni, mkl, mailhol, idosch, petrm,
	sridhar.samudrala, toke, pkshih, tmuehlbacher, socketcan
In-Reply-To: <20260131004327.18112-1-enelsonmoore@gmail.com>

Hello:

This patch was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:

On Fri, 30 Jan 2026 16:42:56 -0800 you wrote:
> Many network drivers have unnecessary empty module_init and module_exit
> functions. Remove them (including some that just print a message). Note
> that if a module_init function exists, a module_exit function must also
> exist; otherwise, the module cannot be unloaded.
> 
> Signed-off-by: Ethan Nelson-Moore <enelsonmoore@gmail.com>
> 
> [...]

Here is the summary with links:
  - [net-next] net: remove unnecessary module_init/exit functions
    https://git.kernel.org/netdev/net-next/c/e0221553436b

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 net-next] net: remove unnecessary module_init/exit functions
From: Ethan Nelson-Moore @ 2026-02-03  0:56 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev, linux-can, linux-wireless, Michael Grzeschik, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Marc Kleine-Budde, Vincent Mailhol, Ido Schimmel, Petr Machata,
	Sridhar Samudrala, Toke Høiland-Jørgensen, Ping-Ke Shih,
	Thomas Mühlbacher, Oliver Hartkopp
In-Reply-To: <4b7b8238-3997-45d1-a8ee-b659afc0374c@lunn.ch>

On Mon, Feb 2, 2026 at 1:56 PM Andrew Lunn <andrew@lunn.ch> wrote:
> You need to be careful with commit messages. Reviewers read them, and
> think about the implications of what they say. As a result, you wasted
> some of my time looking for a driver which did not have an
> module_exit, and wondering if there was a legitimate reason for not
> having it, and had you just broken it....
Sorry about that. Should I send another version with a better commit
message or is this patch okay the way it is?

Ethan

^ permalink raw reply

* [wireless-next:main] BUILD SUCCESS 0d95280a2d54ebd3d38adc4ff67808009798978c
From: kernel test robot @ 2026-02-02 23:40 UTC (permalink / raw)
  To: Johannes Berg; +Cc: linux-wireless

tree/branch: https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git main
branch HEAD: 0d95280a2d54ebd3d38adc4ff67808009798978c  wifi: mac80211: Add eMLSR/eMLMR action frame parsing support

elapsed time: 726m

configs tested: 311
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                              alldefconfig    gcc-15.2.0
arc                              allmodconfig    clang-16
arc                              allmodconfig    gcc-15.2.0
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    clang-22
arc                              allyesconfig    gcc-15.2.0
arc                                 defconfig    gcc-15.2.0
arc                 nsimosci_hs_smp_defconfig    gcc-15.2.0
arc                   randconfig-001-20260202    gcc-14.3.0
arc                   randconfig-001-20260203    gcc-12.5.0
arc                   randconfig-002-20260202    gcc-14.3.0
arc                   randconfig-002-20260203    gcc-12.5.0
arm                               allnoconfig    clang-22
arm                               allnoconfig    gcc-15.2.0
arm                              allyesconfig    clang-16
arm                              allyesconfig    gcc-15.2.0
arm                     davinci_all_defconfig    clang-22
arm                                 defconfig    clang-22
arm                                 defconfig    gcc-15.2.0
arm                           h3600_defconfig    gcc-15.2.0
arm                            hisi_defconfig    gcc-15.2.0
arm                       netwinder_defconfig    gcc-15.2.0
arm                   randconfig-001-20260202    gcc-14.3.0
arm                   randconfig-001-20260203    gcc-12.5.0
arm                   randconfig-002-20260202    gcc-14.3.0
arm                   randconfig-002-20260203    gcc-12.5.0
arm                   randconfig-003-20260202    gcc-14.3.0
arm                   randconfig-003-20260203    gcc-12.5.0
arm                   randconfig-004-20260202    gcc-14.3.0
arm                   randconfig-004-20260203    gcc-12.5.0
arm                           sama7_defconfig    clang-22
arm                         socfpga_defconfig    gcc-15.2.0
arm64                            allmodconfig    clang-19
arm64                            allmodconfig    clang-22
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-001-20260203    gcc-15.2.0
arm64                 randconfig-002-20260203    gcc-15.2.0
arm64                 randconfig-003-20260203    gcc-15.2.0
arm64                 randconfig-004-20260203    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-20260203    gcc-15.2.0
csky                  randconfig-002-20260203    gcc-15.2.0
hexagon                          allmodconfig    clang-17
hexagon                          allmodconfig    gcc-15.2.0
hexagon                           allnoconfig    clang-22
hexagon                           allnoconfig    gcc-15.2.0
hexagon                             defconfig    clang-22
hexagon                             defconfig    gcc-15.2.0
hexagon               randconfig-001-20260202    clang-19
hexagon               randconfig-001-20260203    clang-22
hexagon               randconfig-002-20260202    clang-19
hexagon               randconfig-002-20260203    clang-22
i386                             allmodconfig    clang-20
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                              allnoconfig    gcc-15.2.0
i386                             allyesconfig    clang-20
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20260202    gcc-14
i386        buildonly-randconfig-001-20260203    clang-20
i386        buildonly-randconfig-002-20260202    gcc-14
i386        buildonly-randconfig-002-20260203    clang-20
i386        buildonly-randconfig-003-20260202    gcc-14
i386        buildonly-randconfig-003-20260203    clang-20
i386        buildonly-randconfig-004-20260202    gcc-14
i386        buildonly-randconfig-004-20260203    clang-20
i386        buildonly-randconfig-005-20260202    gcc-14
i386        buildonly-randconfig-005-20260203    clang-20
i386        buildonly-randconfig-006-20260202    gcc-14
i386        buildonly-randconfig-006-20260203    clang-20
i386                                defconfig    clang-20
i386                                defconfig    gcc-15.2.0
i386                  randconfig-001-20260202    gcc-14
i386                  randconfig-001-20260203    clang-20
i386                  randconfig-002-20260202    gcc-14
i386                  randconfig-002-20260203    clang-20
i386                  randconfig-003-20260202    gcc-14
i386                  randconfig-003-20260203    clang-20
i386                  randconfig-004-20260202    gcc-14
i386                  randconfig-004-20260203    clang-20
i386                  randconfig-005-20260202    gcc-14
i386                  randconfig-005-20260203    clang-20
i386                  randconfig-006-20260202    gcc-14
i386                  randconfig-006-20260203    clang-20
i386                  randconfig-007-20260202    gcc-14
i386                  randconfig-007-20260203    clang-20
i386                  randconfig-011-20260202    clang-20
i386                  randconfig-012-20260202    clang-20
i386                  randconfig-013-20260202    clang-20
i386                  randconfig-014-20260202    clang-20
i386                  randconfig-015-20260202    clang-20
i386                  randconfig-016-20260202    clang-20
i386                  randconfig-017-20260202    clang-20
loongarch                        alldefconfig    gcc-15.2.0
loongarch                        allmodconfig    clang-19
loongarch                        allmodconfig    clang-22
loongarch                         allnoconfig    clang-22
loongarch                         allnoconfig    gcc-15.2.0
loongarch                           defconfig    clang-19
loongarch             randconfig-001-20260202    clang-19
loongarch             randconfig-001-20260203    clang-22
loongarch             randconfig-002-20260202    clang-19
loongarch             randconfig-002-20260203    clang-22
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    clang-16
m68k                             allyesconfig    gcc-15.2.0
m68k                          atari_defconfig    gcc-15.2.0
m68k                       bvme6000_defconfig    gcc-15.2.0
m68k                                defconfig    clang-19
m68k                            mac_defconfig    gcc-15.2.0
m68k                           sun3_defconfig    gcc-15.2.0
m68k                           virt_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
mips                        bcm63xx_defconfig    clang-22
mips                        bcm63xx_defconfig    gcc-15.2.0
mips                  cavium_octeon_defconfig    clang-22
mips                     cu1000-neo_defconfig    gcc-15.2.0
mips                  decstation_64_defconfig    gcc-15.2.0
mips                          eyeq5_defconfig    gcc-15.2.0
mips                           ip32_defconfig    gcc-15.2.0
mips                      loongson3_defconfig    gcc-15.2.0
mips                        vocore2_defconfig    clang-22
nios2                         10m50_defconfig    clang-22
nios2                            allmodconfig    clang-22
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    clang-22
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    clang-19
nios2                 randconfig-001-20260202    clang-19
nios2                 randconfig-001-20260203    clang-22
nios2                 randconfig-002-20260202    clang-19
nios2                 randconfig-002-20260203    clang-22
openrisc                         allmodconfig    clang-22
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    clang-22
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    clang-22
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    clang-19
parisc                           allyesconfig    gcc-15.2.0
parisc                              defconfig    gcc-15.2.0
parisc                generic-64bit_defconfig    gcc-15.2.0
parisc                randconfig-001-20260202    gcc-8.5.0
parisc                randconfig-001-20260203    gcc-12.5.0
parisc                randconfig-002-20260202    gcc-8.5.0
parisc                randconfig-002-20260203    gcc-12.5.0
parisc64                            defconfig    clang-19
powerpc                     akebono_defconfig    gcc-15.2.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    clang-22
powerpc                           allnoconfig    gcc-15.2.0
powerpc                     mpc83xx_defconfig    gcc-15.2.0
powerpc                       ppc64_defconfig    gcc-15.2.0
powerpc               randconfig-001-20260202    gcc-14.3.0
powerpc               randconfig-001-20260202    gcc-8.5.0
powerpc               randconfig-001-20260203    gcc-12.5.0
powerpc               randconfig-002-20260202    clang-22
powerpc               randconfig-002-20260202    gcc-8.5.0
powerpc               randconfig-002-20260203    gcc-12.5.0
powerpc64             randconfig-001-20260202    gcc-12.5.0
powerpc64             randconfig-001-20260202    gcc-8.5.0
powerpc64             randconfig-001-20260203    gcc-12.5.0
powerpc64             randconfig-002-20260202    gcc-11.5.0
powerpc64             randconfig-002-20260202    gcc-8.5.0
powerpc64             randconfig-002-20260203    gcc-12.5.0
riscv                            allmodconfig    clang-22
riscv                             allnoconfig    clang-22
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    gcc-15.2.0
riscv                 randconfig-001-20260202    gcc-14.3.0
riscv                 randconfig-001-20260203    gcc-8.5.0
riscv                 randconfig-002-20260202    gcc-13.4.0
riscv                 randconfig-002-20260203    gcc-8.5.0
s390                             allmodconfig    clang-18
s390                             allmodconfig    clang-19
s390                              allnoconfig    clang-22
s390                             allyesconfig    gcc-15.2.0
s390                                defconfig    gcc-15.2.0
s390                  randconfig-001-20260202    clang-22
s390                  randconfig-001-20260203    gcc-8.5.0
s390                  randconfig-002-20260203    gcc-8.5.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    clang-22
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    clang-19
sh                               allyesconfig    gcc-15.2.0
sh                                  defconfig    gcc-14
sh                        edosk7705_defconfig    gcc-15.2.0
sh                          kfr2r09_defconfig    gcc-15.2.0
sh                          landisk_defconfig    gcc-15.2.0
sh                    randconfig-001-20260202    gcc-15.2.0
sh                    randconfig-001-20260203    gcc-8.5.0
sh                    randconfig-002-20260202    gcc-15.2.0
sh                    randconfig-002-20260203    gcc-8.5.0
sh                          rsk7203_defconfig    gcc-15.2.0
sh                          sdk7780_defconfig    gcc-15.2.0
sh                     sh7710voipgw_defconfig    gcc-15.2.0
sh                        sh7757lcr_defconfig    clang-22
sh                        sh7763rdp_defconfig    clang-22
sh                            shmin_defconfig    gcc-15.2.0
sparc                             allnoconfig    clang-22
sparc                             allnoconfig    gcc-15.2.0
sparc                               defconfig    gcc-15.2.0
sparc                 randconfig-001-20260202    gcc-12.5.0
sparc                 randconfig-001-20260203    gcc-13.4.0
sparc                 randconfig-002-20260202    gcc-12.5.0
sparc                 randconfig-002-20260203    gcc-13.4.0
sparc64                          allmodconfig    clang-22
sparc64                             defconfig    gcc-14
sparc64               randconfig-001-20260202    gcc-12.5.0
sparc64               randconfig-001-20260203    gcc-13.4.0
sparc64               randconfig-002-20260202    gcc-12.5.0
sparc64               randconfig-002-20260203    gcc-13.4.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-22
um                               allyesconfig    gcc-14
um                               allyesconfig    gcc-15.2.0
um                                  defconfig    gcc-14
um                             i386_defconfig    gcc-14
um                    randconfig-001-20260202    gcc-12.5.0
um                    randconfig-001-20260203    gcc-13.4.0
um                    randconfig-002-20260202    gcc-12.5.0
um                    randconfig-002-20260203    gcc-13.4.0
um                           x86_64_defconfig    gcc-14
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                            allnoconfig    clang-22
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260202    gcc-14
x86_64      buildonly-randconfig-001-20260203    clang-20
x86_64      buildonly-randconfig-002-20260202    gcc-14
x86_64      buildonly-randconfig-002-20260203    clang-20
x86_64      buildonly-randconfig-003-20260202    gcc-14
x86_64      buildonly-randconfig-003-20260203    clang-20
x86_64      buildonly-randconfig-004-20260202    gcc-14
x86_64      buildonly-randconfig-004-20260203    clang-20
x86_64      buildonly-randconfig-005-20260202    gcc-14
x86_64      buildonly-randconfig-005-20260203    clang-20
x86_64      buildonly-randconfig-006-20260202    gcc-14
x86_64      buildonly-randconfig-006-20260203    clang-20
x86_64                              defconfig    gcc-14
x86_64                                  kexec    clang-20
x86_64                randconfig-001-20260202    gcc-14
x86_64                randconfig-001-20260203    clang-20
x86_64                randconfig-002-20260202    gcc-14
x86_64                randconfig-002-20260203    clang-20
x86_64                randconfig-003-20260202    gcc-14
x86_64                randconfig-003-20260203    clang-20
x86_64                randconfig-004-20260202    gcc-14
x86_64                randconfig-004-20260203    clang-20
x86_64                randconfig-005-20260202    gcc-14
x86_64                randconfig-005-20260203    clang-20
x86_64                randconfig-006-20260202    gcc-14
x86_64                randconfig-006-20260203    clang-20
x86_64                randconfig-011-20260202    gcc-14
x86_64                randconfig-011-20260203    gcc-14
x86_64                randconfig-012-20260202    clang-20
x86_64                randconfig-012-20260202    gcc-14
x86_64                randconfig-012-20260203    gcc-14
x86_64                randconfig-013-20260202    clang-20
x86_64                randconfig-013-20260202    gcc-14
x86_64                randconfig-013-20260203    gcc-14
x86_64                randconfig-014-20260202    gcc-12
x86_64                randconfig-014-20260202    gcc-14
x86_64                randconfig-014-20260203    gcc-14
x86_64                randconfig-015-20260202    gcc-14
x86_64                randconfig-015-20260203    gcc-14
x86_64                randconfig-016-20260202    gcc-14
x86_64                randconfig-016-20260203    gcc-14
x86_64                randconfig-071-20260202    clang-20
x86_64                randconfig-071-20260203    gcc-14
x86_64                randconfig-072-20260202    clang-20
x86_64                randconfig-072-20260203    gcc-14
x86_64                randconfig-073-20260202    clang-20
x86_64                randconfig-073-20260203    gcc-14
x86_64                randconfig-074-20260202    clang-20
x86_64                randconfig-074-20260203    gcc-14
x86_64                randconfig-075-20260202    clang-20
x86_64                randconfig-075-20260203    gcc-14
x86_64                randconfig-076-20260202    clang-20
x86_64                randconfig-076-20260203    gcc-14
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-22
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    clang-22
xtensa                           allyesconfig    gcc-15.2.0
xtensa                randconfig-001-20260202    gcc-12.5.0
xtensa                randconfig-001-20260203    gcc-13.4.0
xtensa                randconfig-002-20260202    gcc-12.5.0
xtensa                randconfig-002-20260203    gcc-13.4.0

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH net-next] net: remove unnecessary module_init/exit functions
From: Andrew Lunn @ 2026-02-02 21:56 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: netdev, linux-can, linux-wireless, Michael Grzeschik, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Marc Kleine-Budde, Vincent Mailhol, Ido Schimmel, Petr Machata,
	Sridhar Samudrala, Toke Høiland-Jørgensen, Ping-Ke Shih,
	Thomas Mühlbacher, Oliver Hartkopp
In-Reply-To: <CADkSEUjEYY=Wwyumv3Ft_T=xWLJY2hiy4uw_YMus=4o=61H+BQ@mail.gmail.com>

On Mon, Feb 02, 2026 at 12:33:08PM -0800, Ethan Nelson-Moore wrote:
> Hi, Andrew,
> 
> On Mon, Feb 2, 2026 at 12:29 PM Andrew Lunn <andrew@lunn.ch> wrote:
> > I could be missing it, but which module does not have an module_exit
> > function?
> None of them. That sentence was just to explain why other instances of
> empty module_exit functions were not removed, in case someone else
> tries to do that. I didn't realize module_exit was required to unload
> the module at first, and other people might not either.

You need to be careful with commit messages. Reviewers read them, and
think about the implications of what they say. As a result, you wasted
some of my time looking for a driver which did not have an
module_exit, and wondering if there was a legitimate reason for not
having it, and had you just broken it....

       Andrew


^ permalink raw reply

* [PATCH AUTOSEL 6.18-5.10] wifi: cfg80211: Fix bitrate calculation overflow for HE rates
From: Sasha Levin @ 2026-02-02 21:46 UTC (permalink / raw)
  To: patches, stable
  Cc: Veerendranath Jakkam, Johannes Berg, Sasha Levin, johannes,
	linux-wireless
In-Reply-To: <20260202214643.212290-1-sashal@kernel.org>

From: Veerendranath Jakkam <veerendranath.jakkam@oss.qualcomm.com>

[ Upstream commit a3034bf0746d88a00cceda9541534a5721445a24 ]

An integer overflow occurs in cfg80211_calculate_bitrate_he() when
calculating bitrates for high throughput HE configurations.
For example, with 160 MHz bandwidth, HE-MCS 13, HE-NSS 4, and HE-GI 0,
the multiplication (result * rate->nss) overflows the 32-bit 'result'
variable before division by 8, leading to significantly underestimated
bitrate values.

The overflow occurs because the NSS multiplication operates on a 32-bit
integer that cannot accommodate intermediate values exceeding
4,294,967,295. When overflow happens, the value wraps around, producing
incorrect bitrates for high MCS and NSS combinations.

Fix this by utilizing the 64-bit 'tmp' variable for the NSS
multiplication and subsequent divisions via do_div(). This approach
preserves full precision throughout the entire calculation, with the
final value assigned to 'result' only after completing all operations.

Signed-off-by: Veerendranath Jakkam <veerendranath.jakkam@oss.qualcomm.com>
Link: https://patch.msgid.link/20260109-he_bitrate_overflow-v1-1-95575e466b6e@oss.qualcomm.com
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

I can see the buggy code is still present in this version (the fix
hasn't been applied yet to this version of util.c). This is the code
being patched. Let me double check the diff shows exactly what I expect:

Looking at the diff again:
```c
- result = tmp;

        /* and take NSS, DCM into account */
- result = (result * rate->nss) / 8;
+       tmp *= rate->nss;
+       do_div(tmp, 8);
        if (rate->he_dcm)
- result /= 2;
+               do_div(tmp, 2);
+
+       result = tmp;
```

The fix:
1. Removes `result = tmp` after the MCS division (keeps value in 64-bit
   `tmp`)
2. Multiplies NSS in 64-bit: `tmp *= rate->nss` instead of 32-bit
   `result * rate->nss`
3. Uses `do_div(tmp, 8)` instead of 32-bit division
4. Uses `do_div(tmp, 2)` for DCM instead of 32-bit division
5. Only assigns to 32-bit `result` at the end when the value is
   guaranteed to fit

This matches exactly the same fix pattern that was applied to
`cfg80211_calculate_bitrate_eht()` in commit 18429c51c7ff6.

## Summary Analysis

### 1. COMMIT MESSAGE ANALYSIS
- **Subject**: Clearly indicates a bug fix for bitrate calculation
  overflow in HE rates
- **Body**: Provides detailed technical explanation of the overflow
  scenario (160 MHz, MCS 13, NSS 4, GI 0)
- **Root cause**: 32-bit integer overflow when multiplying `result *
  rate->nss` before division by 8
- **Fix approach**: Use 64-bit `tmp` variable throughout the
  calculation, assign to 32-bit `result` only at the end
- **Tags**: Has Signed-off-by from both Qualcomm developer and Johannes
  Berg (wireless maintainer)

### 2. CODE CHANGE ANALYSIS
- **Bug mechanism**: When `result` (a u32) is large (e.g., 0x44b85dd4 =
  1,152,933,332), multiplying by NSS 4 produces 0x112e17750
  (4,611,733,328) which overflows u32 max (0xFFFFFFFF = 4,294,967,295)
- **Result of bug**: The overflow wraps to 0x12e17750, producing a
  bitrate of ~3,959 (400 Mbps) instead of correct ~57,646 (5.76 Gbps)
- **Fix correctness**: The fix keeps all arithmetic in 64-bit until the
  final assignment, preventing overflow
- **DCM handling**: Also moved to 64-bit for consistency and safety

### 3. CLASSIFICATION
- **Type**: Bug fix (integer overflow causing incorrect bitrate
  reporting)
- **Security**: Not a security issue, but affects user-visible data
  correctness
- **Exception categories**: Not applicable - this is a straightforward
  bug fix

### 4. SCOPE AND RISK ASSESSMENT
- **Lines changed**: ~10 lines, very small and localized
- **Files touched**: 1 file (net/wireless/util.c)
- **Subsystem**: WiFi cfg80211, mature and stable
- **Risk**: Very LOW - the exact same fix pattern was already applied to
  the EHT version of this function and has been in stable since 6.1
- **Could break something**: Extremely unlikely - only changes
  intermediate arithmetic precision, final result is more accurate

### 5. USER IMPACT
- **Who is affected**: Users with WiFi 6 (802.11ax) devices using high
  bandwidth (160 MHz), high MCS (12/13), and multiple spatial streams
  (NSS 3-8)
- **Visibility**: Users see incorrect bitrate reporting in tools like
  `iw`, network managers, etc.
- **Severity**: Low-medium - cosmetic but confusing to users (reported
  speed is much lower than actual)
- **Real-world scenario**: Modern high-end WiFi 6 devices can absolutely
  hit these configurations

### 6. STABILITY INDICATORS
- **Testing**: Qualcomm developer tested on their hardware
- **Review**: Accepted by Johannes Berg (long-time wireless maintainer)
- **Precedent**: Same fix was applied to EHT function years ago (commit
  18429c51c7ff6) and has proven stable

### 7. DEPENDENCY CHECK
- **Dependencies**: None - self-contained fix
- **Affected versions**: The HE MCS 12/13 support was added in v5.11, so
  stable trees 5.11+ are affected
- **Backport complexity**: Trivial - the affected code exists unchanged
  in all relevant stable trees

### Risk vs Benefit Trade-off
- **Benefit**: Corrects incorrect bitrate reporting for high-throughput
  WiFi 6 configurations
- **Risk**: Minimal - follows proven fix pattern already in production
  since kernel 6.1
- **Verdict**: HIGH benefit, VERY LOW risk

**YES**

 net/wireless/util.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

diff --git a/net/wireless/util.c b/net/wireless/util.c
index 4eb028ad16836..81d6d27d273cc 100644
--- a/net/wireless/util.c
+++ b/net/wireless/util.c
@@ -1561,12 +1561,14 @@ static u32 cfg80211_calculate_bitrate_he(struct rate_info *rate)
 	tmp = result;
 	tmp *= SCALE;
 	do_div(tmp, mcs_divisors[rate->mcs]);
-	result = tmp;
 
 	/* and take NSS, DCM into account */
-	result = (result * rate->nss) / 8;
+	tmp *= rate->nss;
+	do_div(tmp, 8);
 	if (rate->he_dcm)
-		result /= 2;
+		do_div(tmp, 2);
+
+	result = tmp;
 
 	return result / 10000;
 }
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.18-6.6] wifi: mac80211: correctly check if CSA is active
From: Sasha Levin @ 2026-02-02 21:46 UTC (permalink / raw)
  To: patches, stable
  Cc: Miri Korenblit, Johannes Berg, Sasha Levin, johannes,
	linux-wireless
In-Reply-To: <20260202214643.212290-1-sashal@kernel.org>

From: Miri Korenblit <miriam.rachel.korenblit@intel.com>

[ Upstream commit db1d0b6ab11f612ea8a327663a578c8946efeee9 ]

We are not adding an interface if an existing one is doing CSA.
But the check won't work for MLO station interfaces, since for those,
vif->bss_conf is zeroed out.
Fix this by checking if any link of the vif has an active CSA.

Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260111191912.7ceff62fc561.Ia38d27f42684d1cfd82d930d232bd5dea6ab9282@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

Now I have a complete picture. Let me analyze this commit
comprehensively.

## Analysis

### 1. COMMIT MESSAGE ANALYSIS

**Subject**: "wifi: mac80211: correctly check if CSA is active"

The commit clearly describes a bug fix - the existing CSA (Channel
Switch Announcement) check doesn't work properly for MLO (Multi-Link
Operation) station interfaces. The message explains:
- The problem: "the check won't work for MLO station interfaces, since
  for those, vif->bss_conf is zeroed out"
- The fix: "checking if any link of the vif has an active CSA"

**Tags present**:
- Reviewed-by: Johannes Berg (mac80211 maintainer) - strong credibility
  signal
- Signed-off-by: Miri Korenblit (Intel wireless developer)
- Link to mailing list

No explicit Fixes: tag, but that's expected for commits we're reviewing.

### 2. CODE CHANGE ANALYSIS

**The Bug:**
The original code at line 379:
```c
if (nsdata->vif.bss_conf.csa_active)
    return -EBUSY;
```

This check is used in `ieee80211_check_concurrent_iface()` to prevent
adding a new interface while an existing interface is performing a
channel switch operation.

**Why it's broken for MLO:**
For MLO (Multi-Link Operation) station interfaces introduced in WiFi 7
(802.11be):
- `vif->bss_conf` is zeroed out by design
- Each link has its own BSS configuration stored in `link_conf[link_id]`
- The CSA state (`csa_active`) is per-link, not per-VIF
- Checking `vif->bss_conf.csa_active` will always return `false` for MLO
  interfaces, even if one of the links is actively switching channels

**The Fix:**
```c
struct ieee80211_link_data *link;
...
for_each_link_data(nsdata, link) {
    if (link->conf->csa_active)
        return -EBUSY;
}
```

This properly iterates through all valid links and checks if ANY link
has an active CSA. The `for_each_link_data` macro:
- For non-MLO interfaces: iterates once with the single (deflink) link
- For MLO interfaces: iterates through all links with bits set in
  `valid_links`

**Technical mechanism**: The fix is correct because it unifies the check
- it works for both MLO and non-MLO interfaces while maintaining the
same semantics.

### 3. CLASSIFICATION

This is clearly a **bug fix**, not a new feature:
- The concurrent interface protection during CSA was always intended to
  work
- It just doesn't work for the newer MLO interface type
- This is a correctness fix for existing functionality

### 4. SCOPE AND RISK ASSESSMENT

**Lines changed**: Small - adds ~6 lines, removes 2 lines (net +4)
**Files touched**: 1 file (net/mac80211/iface.c)
**Complexity**: Low - simple loop iteration replacing a single field
access
**Subsystem**: mac80211 WiFi subsystem - widely used but WiFi-specific

**Risk level**: LOW
- The change is straightforward and the logic is sound
- The `for_each_link_data` macro is designed for exactly this use case
- Reviewed by Johannes Berg, the mac80211 maintainer
- Failure mode: If the fix doesn't work, we're no worse than before
  (still have the bug)

### 5. USER IMPACT

**Who is affected?**: Users with MLO-capable WiFi hardware (WiFi 7 /
802.11be devices)
**Severity**: Medium - Without this fix:
- A new interface could be incorrectly allowed to be added during an
  ongoing channel switch on an MLO interface
- This could cause interference, connectivity issues, or undefined
  behavior
- Channel switches are relatively rare events, so impact is somewhat
  limited

### 6. STABILITY INDICATORS

- **Reviewed-by**: Johannes Berg (mac80211 maintainer) - strong positive
  signal
- Author: Miri Korenblit from Intel - active wireless developer

### 7. DEPENDENCY CHECK

**Critical dependency**: This fix uses the `for_each_link_data` macro
which was introduced in commit f61c7b3d442be ("wifi: mac80211: Add link
iteration macro for link data") in kernel v6.16.

**Backport applicability**:
- **v6.16+**: Can be applied directly - has the macro
- **v6.1-v6.15**: Would require either:
  1. Backporting the `for_each_link_data` macro first, OR
  2. Writing an alternative fix using open-coded link iteration

MLO support was introduced in v6.1, so the bug exists in all kernels
v6.1 through current that have MLO station interface support.

### Summary

| Criteria | Assessment |
|----------|------------|
| Obviously correct | YES - simple iteration fix |
| Fixes real bug | YES - incorrect CSA check for MLO |
| Important issue | MEDIUM - affects interface addition during channel
switch |
| Small and contained | YES - 4 net lines changed |
| No new features | YES - fixes existing feature |
| Applies cleanly | DEPENDS - needs v6.16+ for macro dependency |

### VERDICT

This is a legitimate bug fix for MLO WiFi support:
- It fixes a real, demonstrable bug where CSA detection fails for MLO
  interfaces
- The fix is small, surgical, and well-reviewed
- It doesn't introduce new features or change APIs
- It improves correctness of existing functionality

**However**, there are important caveats:
1. The fix has a dependency on the `for_each_link_data` macro
   (introduced in v6.16)
2. For stable trees before v6.16, a backport would need the macro too or
   use an alternative approach
3. MLO is relatively new technology (WiFi 7), so the affected user base
   is smaller

Given that this fix:
- Is obviously correct and addresses a real bug
- Was reviewed by the subsystem maintainer
- Has low risk of regression
- Affects real user scenarios (channel switching during interface
  operations)

The fix is appropriate for stable backporting to kernels that have both
MLO support and the `for_each_link_data` macro (v6.16+). For older
stable trees (v6.1-v6.15), a modified backport with the macro or open-
coded iteration would be needed.

**YES**

 net/mac80211/iface.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index 0ca55b9655a7f..72c129478da08 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -350,6 +350,8 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 	/* we hold the RTNL here so can safely walk the list */
 	list_for_each_entry(nsdata, &local->interfaces, list) {
 		if (nsdata != sdata && ieee80211_sdata_running(nsdata)) {
+			struct ieee80211_link_data *link;
+
 			/*
 			 * Only OCB and monitor mode may coexist
 			 */
@@ -376,8 +378,10 @@ static int ieee80211_check_concurrent_iface(struct ieee80211_sub_if_data *sdata,
 			 * will not add another interface while any channel
 			 * switch is active.
 			 */
-			if (nsdata->vif.bss_conf.csa_active)
-				return -EBUSY;
+			for_each_link_data(nsdata, link) {
+				if (link->conf->csa_active)
+					return -EBUSY;
+			}
 
 			/*
 			 * The remaining checks are only performed for interfaces
-- 
2.51.0


^ permalink raw reply related

* [PATCH AUTOSEL 6.18-5.10] wifi: mac80211: don't increment crypto_tx_tailroom_needed_cnt twice
From: Sasha Levin @ 2026-02-02 21:46 UTC (permalink / raw)
  To: patches, stable
  Cc: Miri Korenblit, Johannes Berg, Sasha Levin, johannes,
	linux-wireless
In-Reply-To: <20260202214643.212290-1-sashal@kernel.org>

From: Miri Korenblit <miriam.rachel.korenblit@intel.com>

[ Upstream commit 3f3d8ff31496874a69b131866f62474eb24ed20a ]

In reconfig, in case the driver asks to disconnect during the reconfig,
all the keys of the interface are marked as tainted.
Then ieee80211_reenable_keys will loop over all the interface keys, and
for each one it will
a) increment crypto_tx_tailroom_needed_cnt
b) call ieee80211_key_enable_hw_accel, which in turn will detect that
this key is tainted, so it will mark it as "not in hardware", which is
paired with crypto_tx_tailroom_needed_cnt incrementation, so we get two
incrementations for each tainted key.
Then we get a warning in ieee80211_free_keys.

To fix it, don't increment the count in ieee80211_reenable_keys for
tainted keys

Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Link: https://patch.msgid.link/20260118092821.4ca111fddcda.Id6e554f4b1c83760aa02d5a9e4e3080edb197aa2@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

So KEY_FLAG_TAINTED was introduced in v4.20. The bug being fixed is
likely in all kernels from 4.20 onward. Let me verify the current state
after the patch would be applied.

The patch being analyzed changes:
```c
list_for_each_entry(key, &sdata->key_list, list) {
    increment_tailroom_need_count(sdata);  // OLD: unconditional
    ieee80211_key_enable_hw_accel(key);
}
```

to:
```c
list_for_each_entry(key, &sdata->key_list, list) {
    if (!(key->flags & KEY_FLAG_TAINTED))  // NEW: skip for tainted
        increment_tailroom_need_count(sdata);
    ieee80211_key_enable_hw_accel(key);
}
```

This is correct because:
- For non-tainted keys: increment once here, and if HW accel succeeds,
  it will be decremented in `ieee80211_key_enable_hw_accel()` (line
  187). Net result: proper accounting.
- For tainted keys: skip here, let `ieee80211_key_enable_hw_accel()`
  handle the increment (line 141) when clearing
  `KEY_FLAG_UPLOADED_TO_HARDWARE`. Net result: proper accounting.

## Analysis Summary

**1. COMMIT MESSAGE ANALYSIS:**
- Clear explanation of the problem: double increment of
  `crypto_tx_tailroom_needed_cnt` for tainted keys during reconfig
- The symptom is a warning in `ieee80211_free_keys`
- Reviewed-by from Johannes Berg (mac80211 maintainer) adds confidence

**2. CODE CHANGE ANALYSIS:**
- The bug: In `ieee80211_reenable_keys()`, for each key:
  1. `increment_tailroom_need_count(sdata)` is called unconditionally
  2. `ieee80211_key_enable_hw_accel(key)` is called

- For tainted keys (marked when driver requests disconnect during
  reconfig), `ieee80211_key_enable_hw_accel()` will:
  - Also call `increment_tailroom_need_count(sdata)` at line 141 if the
    key was uploaded to hardware
  - Clear the `KEY_FLAG_UPLOADED_TO_HARDWARE` flag

- Result: Two increments per tainted key instead of one

- The fix: Skip the first increment for tainted keys since they'll get
  their increment inside `ieee80211_key_enable_hw_accel()`

**3. CLASSIFICATION:**
- This is a clear BUG FIX for a reference counting error
- Not a feature addition
- Fixes a real warning that users would see in kernel logs

**4. SCOPE AND RISK ASSESSMENT:**
- Very small change: adds a simple conditional check (1 line changed)
- Localized to mac80211 key handling
- Low risk: the logic is straightforward and has been reviewed by the
  subsystem maintainer
- The worst-case if the fix is wrong would be the opposite accounting
  error

**5. USER IMPACT:**
- WiFi users doing rekeys or going through suspend/resume/HW restart
  with certain driver/firmware combinations could hit this
- The symptom is a kernel warning (WARN_ON_ONCE in
  `ieee80211_free_keys`)
- It causes incorrect tailroom accounting which could potentially lead
  to issues with software encryption

**6. STABILITY INDICATORS:**
- Reviewed-by: Johannes Berg (mac80211 maintainer)
- The code path and fix are straightforward

**7. DEPENDENCY CHECK:**
- KEY_FLAG_TAINTED exists since v4.20
- The function `ieee80211_reenable_keys()` exists in stable trees
- The code affected exists in all supported stable kernels
- No dependency on other commits - this is a standalone fix

The fix is small, surgical, reviewed by the subsystem maintainer, fixes
a real bug (warning + incorrect reference counting), and meets all
stable kernel criteria.

**YES**

 net/mac80211/key.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/net/mac80211/key.c b/net/mac80211/key.c
index d5da7ccea66e0..04c8809173d7f 100644
--- a/net/mac80211/key.c
+++ b/net/mac80211/key.c
@@ -987,7 +987,8 @@ void ieee80211_reenable_keys(struct ieee80211_sub_if_data *sdata)
 
 	if (ieee80211_sdata_running(sdata)) {
 		list_for_each_entry(key, &sdata->key_list, list) {
-			increment_tailroom_need_count(sdata);
+			if (!(key->flags & KEY_FLAG_TAINTED))
+				increment_tailroom_need_count(sdata);
 			ieee80211_key_enable_hw_accel(key);
 		}
 	}
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH net-next] net: remove unnecessary module_init/exit functions
From: Ethan Nelson-Moore @ 2026-02-02 20:33 UTC (permalink / raw)
  To: Andrew Lunn
  Cc: netdev, linux-can, linux-wireless, Michael Grzeschik, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Marc Kleine-Budde, Vincent Mailhol, Ido Schimmel, Petr Machata,
	Sridhar Samudrala, Toke Høiland-Jørgensen, Ping-Ke Shih,
	Thomas Mühlbacher, Oliver Hartkopp
In-Reply-To: <66924451-2b19-4a3b-ba99-16437dc79011@lunn.ch>

Hi, Andrew,

On Mon, Feb 2, 2026 at 12:29 PM Andrew Lunn <andrew@lunn.ch> wrote:
> I could be missing it, but which module does not have an module_exit
> function?
None of them. That sentence was just to explain why other instances of
empty module_exit functions were not removed, in case someone else
tries to do that. I didn't realize module_exit was required to unload
the module at first, and other people might not either.

Ethan

^ permalink raw reply

* Re: [PATCH net-next] net: remove unnecessary module_init/exit functions
From: Andrew Lunn @ 2026-02-02 20:29 UTC (permalink / raw)
  To: Ethan Nelson-Moore
  Cc: netdev, linux-can, linux-wireless, Michael Grzeschik, Andrew Lunn,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Marc Kleine-Budde, Vincent Mailhol, Ido Schimmel, Petr Machata,
	Sridhar Samudrala, Toke Høiland-Jørgensen, Ping-Ke Shih,
	Thomas Mühlbacher, Oliver Hartkopp
In-Reply-To: <20260131004327.18112-1-enelsonmoore@gmail.com>

On Fri, Jan 30, 2026 at 04:42:56PM -0800, Ethan Nelson-Moore wrote:
> Many network drivers have unnecessary empty module_init and module_exit
> functions. Remove them (including some that just print a message). Note
> that if a module_init function exists, a module_exit function must also
> exist; otherwise, the module cannot be unloaded.

I could be missing it, but which module does not have an module_exit
function?

I ask, because maybe the author does not want to allow the module to
be unloaded. We should look at the history of that module.

   Andrew

^ permalink raw reply

* Re: [PATCH] wifi: brcmfmac: Fix potential kernel oops when probe fails
From: Arend van Spriel @ 2026-02-02 18:31 UTC (permalink / raw)
  To: Marek Szyprowski, linux-wireless, brcm80211,
	brcm80211-dev-list.pdl
In-Reply-To: <062fde49-7438-4001-a06e-50175547b54c@samsung.com>

Op 15 januari 2026 00:16:31 schreef Marek Szyprowski 
<m.szyprowski@samsung.com>:

> On 14.01.2026 14:45, Arend van Spriel wrote:
>> On 12/31/2025 3:35 PM, Marek Szyprowski wrote:
>>> When probe of the sdio brcmfmac device fails for some reasons (i.e.
>>> missing firmware), the sdiodev->bus is set to error instead of NULL,
>>> thus
>>> the cleanup later in brcmf_sdio_remove() tries to free resources via
>>> invalid bus pointer. Fix this.
>>
>> Hi Marek,
>>
>> Thanks for the fix. Please consider my suggestion below...
>>
>>> Fixes: 0ff0843310b7 ("wifi: brcmfmac: Add optional lpo clock enable
>>> support")
>>> Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
>>> ---
>>>  drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 1 +
>>>  1 file changed, 1 insertion(+)
>>>
>>> diff --git
>>> a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
>>> b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
>>> index 6a3f187320fc..6615748fa5bb 100644
>>> --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
>>> +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c
>>> @@ -954,6 +954,7 @@ int brcmf_sdiod_probe(struct brcmf_sdio_dev
>>> *sdiodev)
>>
>> Maybe use a local variable bus and assign it only on success:
>>
>>>      bus = brcmf_sdio_probe(sdiodev);
>>>      if (IS_ERR(bus)) {
>>>          ret = PTR_ERR(bus);
>>>          goto out;
>>>      }
>>> +    sdiodev->bus = bus;
>>> brcmf_sdiod_host_fixup(sdiodev->func2->card->host);
> Well, that would look much better, but sdiodev->bus is also assigned
> inside brcmf_sdio_probe() and I didn't check if this is required by the
> functions called there or not. Maybe brcmf_sdio_probe() should simply
> return error code to make things easier to track?

Sorry for the late response. Indeed the bus instance is allocated and 
assigned to sdiodev. So that is something the caller needs to repeat. So 
changing the return type of brcmf_sdio_probe() makes sense. The only thing 
that should be taken care of in the failure path of brcmf_sdio_probe() is 
to set sdiodev->bus to NULL after calling brcmf_sdio_remove().

Regards,
Arend



^ permalink raw reply

* Re: [PATCH 00/13] Ranging support enhancements
From: Vasanthakumar Thiagarajan @ 2026-02-02 17:44 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-1-peddolla.reddy@oss.qualcomm.com>



On 1/30/2026 9:30 PM, Peddolla Harshavardhan Reddy wrote:
> This patch series introduces Fine Timing Measurement (FTM)
> enhancements and Proximity Detection (PD) capabilities. The
> implementation follows the Wi-Fi Alliance "PR Implementation
> Consideration Draft 1.9 Rev 1" specification and extends the
> existing peer measurement framework with advanced ranging
> features.
> 
> Kavita Kavita (1):
>    mac80211_hwsim: Add support for extended FTM ranging
> 
> Peddolla Harshavardhan Reddy (12):
>    wifi: nl80211/cfg80211: Allow RSTA role to be enabled without LMR
>      request
>    wifi: nl80211/cfg80211: add proximity detection capabilities to PMSR
>    wifi: nl80211/cfg80211: add continuous ranging and PD request support
>    wifi: nl80211/cfg80211: extend PMSR FTM response for proximity ranging
>    wifi: nl80211/cfg80211: add peer measurement abort command
>    wifi: nl80211/cfg80211: add role-based PD peer limits
>    wifi: nl80211/cfg80211: add ingress/egress distance thresholds for FTM
>    wifi: nl80211/cfg80211: add PD-specific bandwidth capabilities for FTM
>    wifi: nl80211/cfg80211: add FTM range report negotiation support
>    wifi: nl80211/cfg80211: add result reporting control for PD requests
>    wifi: nl80211/cfg80211: add MAC randomization support for PD requests
>    wifi: nl80211/cfg80211: add LTF keyseed support for secure ranging
> 
>   drivers/net/wireless/virtual/mac80211_hwsim.c | 141 +++++++++++++
>   include/net/cfg80211.h                        | 163 ++++++++++++++-
>   include/uapi/linux/nl80211.h                  | 177 +++++++++++++++-
>   net/wireless/nl80211.c                        |  87 ++++++++
>   net/wireless/nl80211.h                        |   1 +
>   net/wireless/pmsr.c                           | 194 ++++++++++++++++--
>   6 files changed, 738 insertions(+), 25 deletions(-)
> 

Pls add branch tag in all the patches in the series.

Vasanth

^ permalink raw reply

* Re: [PATCH 12/13] wifi: nl80211/cfg80211: add LTF keyseed support for secure ranging
From: Vasanthakumar Thiagarajan @ 2026-02-02 17:36 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-13-peddolla.reddy@oss.qualcomm.com>



On 1/30/2026 9:30 PM, Peddolla Harshavardhan Reddy wrote:
> Add NL80211_ATTR_LTF_KEYSEED attribute to support secure FTM
> measurements. This allows drivers to generate secure LTF keys
> for PHY-layer security in ranging operations.
> 
> The keyseed is used with trigger-based and non-trigger-based
> FTM requests to enable secure peer measurement sessions.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
> ---
>   include/net/cfg80211.h       |  2 ++
>   include/uapi/linux/nl80211.h | 15 ++++++++++++---
>   net/wireless/nl80211.c       |  7 +++++++
>   3 files changed, 21 insertions(+), 3 deletions(-)
> 
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index dd45dda7e619..ea6b9c994455 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -800,6 +800,8 @@ struct key_params {
>   	u16 vlan_id;
>   	u32 cipher;
>   	enum nl80211_key_mode mode;
> +	const u8 *ltf_keyseed;
> +	int ltf_keyseed_len;

Missing kernel-doc for newly added members.

Vasanth

^ permalink raw reply

* Re: [PATCH 11/13] wifi: nl80211/cfg80211: add MAC randomization support for PD requests
From: Vasanthakumar Thiagarajan @ 2026-02-02 17:33 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-12-peddolla.reddy@oss.qualcomm.com>



On 1/30/2026 9:30 PM, Peddolla Harshavardhan Reddy wrote:
> Add support for MAC address randomization in proximity detection
> (PD) requests. When enabled, the same randomized MAC address
> used for discovery and authentication phases will be used for
> the ranging measurements, maintaining privacy throughout the
> entire PD session workflow.
> 
> The implementation adds a capability flag for devices to
> advertise PD MAC randomization support and validates that
> randomization is only requested when the device supports it.
> This ensures consistent MAC address usage across all phases of
> proximity detection while preventing invalid configurations
> where randomization is requested but not supported by hardware.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
> ---
>   include/net/cfg80211.h       |  7 ++++++-
>   include/uapi/linux/nl80211.h |  5 +++++
>   net/wireless/nl80211.c       |  6 ++++++
>   net/wireless/pmsr.c          | 10 ++++++++++
>   4 files changed, 27 insertions(+), 1 deletion(-)
> 
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index 00ef211f20f1..dd45dda7e619 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -5734,6 +5734,10 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type);
>    *	multi-peer request this will indicate if the device can act
>    *	simultaneously as initiator and a responder. Only valid if @pd_support
>    *	is set.
> + * @pd_randomize_mac_addr: flag attribute in capability indicating that MAC
> + *	address randomization is supported for PD request. if capable a mac
> + *	address used for discovery, authentication will be used for ranging too.
> + *	only valid if @pd_support is set
>    * @pd_max_peer_ista_role: Maximum number of peers allowed for a device
>    *	operating in the ISTA role under proximity detection. Only valid if
>    *	@pd_support is set. Sum of both @pd_max_peer_ista_role and
> @@ -5795,7 +5799,8 @@ struct cfg80211_pmsr_capabilities {
>   	u8 report_ap_tsf:1,
>   	   randomize_mac_addr:1,
>   	   pd_support:1,
> -	   pd_concurrent_ista_rsta_support:1;
> +	   pd_concurrent_ista_rsta_support:1,
> +	   pd_randomize_mac_addr:1;
>   	u32 pd_max_peer_ista_role;
>   	u32 pd_max_peer_rsta_role;
>   
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index 85223b16eb84..c102a54ff335 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -7776,6 +7776,10 @@ enum nl80211_peer_measurement_peer_attrs {
>    *	NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE and
>    *	NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE is considered to enforce the
>    *	max peers supported in case the request is of peer-to-peer PD type
> + * @NL80211_PMSR_ATTR_PD_RANDOMIZE_MAC_ADDR: flag attribute in capability
> + *	indicating that MAC address randomization is supported for PD request.
> + *	if capable a mac address used for discovery, authentication will be
> + *	used for ranging too. only valid if %NL80211_PMSR_ATTR_PD_SUPPORT is set
>    *
>    * @NUM_NL80211_PMSR_ATTR: internal
>    * @NL80211_PMSR_ATTR_MAX: highest attribute number
> @@ -7792,6 +7796,7 @@ enum nl80211_peer_measurement_attrs {
>   	NL80211_PMSR_ATTR_PD_CONCURRENT_ISTA_RSTA_SUPPORT,
>   	NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE,
>   	NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE,
> +	NL80211_PMSR_ATTR_PD_RANDOMIZE_MAC_ADDR,
>   
>   	/* keep last */
>   	NUM_NL80211_PMSR_ATTR,
> diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c
> index 6d53eb3eb78c..2909520bb949 100644
> --- a/net/wireless/nl80211.c
> +++ b/net/wireless/nl80211.c
> @@ -414,6 +414,7 @@ nl80211_pmsr_attr_policy[NL80211_PMSR_ATTR_MAX + 1] = {
>   	},
>   	[NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE] = { .type = NLA_REJECT },
>   	[NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE] = { .type = NLA_REJECT },
> +	[NL80211_PMSR_ATTR_PD_RANDOMIZE_MAC_ADDR] = { .type = NLA_REJECT },
>   };
>   
>   static const struct nla_policy
> @@ -2441,6 +2442,11 @@ static int nl80211_send_pmsr_capa(struct cfg80211_registered_device *rdev,
>   		    nla_put_u32(msg, NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE,
>   				cap->pd_max_peer_rsta_role))
>   			return -ENOBUFS;
> +
> +		if (cap->pd_randomize_mac_addr &&
> +		    nla_put_flag(msg,
> +				 NL80211_PMSR_ATTR_PD_RANDOMIZE_MAC_ADDR))
> +			return -ENOBUFS;
>   	}
>   	caps = nla_nest_start_noflag(msg, NL80211_PMSR_ATTR_TYPE_CAPA);
>   	if (!caps)
> diff --git a/net/wireless/pmsr.c b/net/wireless/pmsr.c
> index a55eb73e6938..fcd7af0c61ba 100644
> --- a/net/wireless/pmsr.c
> +++ b/net/wireless/pmsr.c
> @@ -376,6 +376,7 @@ int nl80211_pmsr_start(struct sk_buff *skb, struct genl_info *info)
>   	struct cfg80211_pmsr_request *req;
>   	struct nlattr *peers, *peer;
>   	int count, rem, err, idx, pd_count, max_pd_peers;
> +	u8 use_random_mac = 0;

bool instead?

^ permalink raw reply

* Re: [PATCH 06/13] wifi: nl80211/cfg80211: add role-based PD peer limits
From: Vasanthakumar Thiagarajan @ 2026-02-02 17:22 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-7-peddolla.reddy@oss.qualcomm.com>



On 1/30/2026 9:30 PM, Peddolla Harshavardhan Reddy wrote:
> Currently, proximity detection capabilities only advertise a
> single maximum peer count that applies regardless of whether
> the request is of PD type. However, some devices may support
> different numbers of simultaneous peers depending on whether
> the request is of PD type or not.
> 
> Introduce separate capability fields to allow drivers to
> specify distinct peer limits for each request type. When a
> device operates as a PD initiator, it can now advertise how
> many responder peers it can measure simultaneously.
> Similarly, when operating as a PD responder, it can indicate
> how many initiator peers it can serve concurrently.
> 
> In scenarios where a device supports concurrent operation
> as both PD initiator and PD responder, the enforcement logic
> considers the sum of both role-specific limits to determine
> the total number of peers allowed in a single measurement
> request.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>
> ---
>   include/net/cfg80211.h       | 12 ++++++++++++
>   include/uapi/linux/nl80211.h | 16 ++++++++++++++++
>   net/wireless/nl80211.c       | 13 +++++++++++++
>   net/wireless/pmsr.c          | 32 ++++++++++++++++++++++++++++----
>   4 files changed, 69 insertions(+), 4 deletions(-)
> 
> diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
> index a82d1606345a..ae63a3ead165 100644
> --- a/include/net/cfg80211.h
> +++ b/include/net/cfg80211.h
> @@ -5716,6 +5716,16 @@ cfg80211_get_iftype_ext_capa(struct wiphy *wiphy, enum nl80211_iftype type);
>    *	multi-peer request this will indicate if the device can act
>    *	simultaneously as initiator and a responder. Only valid if @pd_support
>    *	is set.
> + * @pd_max_peer_ista_role: Maximum number of peers allowed for a device
> + *	operating in the ISTA role under proximity detection. Only valid if
> + *	@pd_support is set. Sum of both @pd_max_peer_ista_role and
> + *	@pd_max_peer_rsta_role is considered to enforce the max peers supported
> + *	in case the request is of peer-to-peer PD type.
> + * @pd_max_peer_rsta_role: Maximum number of peers allowed for a device
> + *	operating in the RSTA role under proximity detection. Only valid if
> + *	@pd_support is set. Sum of both @pd_max_peer_ista_role and
> + *	@pd_max_peer_rsta_role is considered to enforce the max peers supported
> + *	in case the request is of peer-to-peer PD type
>    * @ftm: FTM measurement data
>    * @ftm.supported: FTM measurement is supported
>    * @ftm.asap: ASAP-mode is supported
> @@ -5760,6 +5770,8 @@ struct cfg80211_pmsr_capabilities {
>   	   randomize_mac_addr:1,
>   	   pd_support:1,
>   	   pd_concurrent_ista_rsta_support:1;
> +	u32 pd_max_peer_ista_role;
> +	u32 pd_max_peer_rsta_role;
>   
>   	struct {
>   		u32 preambles;
> diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h
> index b2410d4f572c..b6c28c75e141 100644
> --- a/include/uapi/linux/nl80211.h
> +++ b/include/uapi/linux/nl80211.h
> @@ -7762,6 +7762,20 @@ enum nl80211_peer_measurement_peer_attrs {
>    *	multi-peer request, the device can act simultaneously as initiator and
>    *	a responder, where the multiple requests are being processed
>    *	simultaneously
> + * @NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE: u32 attribute indicating the
> + *	maximum number of peers allowed for a device operating in the ISTA
> + *	(Initiator STA) role under proximity detection. Only valid if
> + *	NL80211_PMSR_ATTR_PD_SUPPORT is set. Sum of both
> + *	NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE and
> + *	NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE is considered to enforce the
> + *	max peers supported in case the request is of peer-to-peer PD type
> + * @NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE: u32 attribute indicating the
> + *	maximum number of peers allowed for a device operating in the RSTA
> + *	(Responder STA) role under proximity detection. Only valid if
> + *	NL80211_PMSR_ATTR_PD_SUPPORT is set. Sum of both
> + *	NL80211_PMSR_ATTR_PD_MAX_PEER_ISTA_ROLE and
> + *	NL80211_PMSR_ATTR_PD_MAX_PEER_RSTA_ROLE is considered to enforce the

need to add % kernel-doc markup for enums.

Vasanth

^ permalink raw reply

* [PATCH 5.15.y 3/3] wifi: mac80211: move TDLS work to wiphy work
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:50 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Emmanuel Grumbach, Hanne-Lotta Mäenpää
In-Reply-To: <20260202165038.215693-1-hannelotta@gmail.com>

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

[ Upstream commit 777b26002b73127e81643d9286fadf3d41e0e477 ]

Again, to have the wiphy locked for it.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[ Summary of conflict resolutions:
  - In mlme.c, move only tdls_peer_del_work
    to wiphy work, and none the other works ]
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 net/mac80211/ieee80211_i.h |  4 ++--
 net/mac80211/mlme.c        |  7 ++++---
 net/mac80211/tdls.c        | 11 ++++++-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 8d6616f646e7..306359d43571 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -542,7 +542,7 @@ struct ieee80211_if_managed {
 
 	/* TDLS support */
 	u8 tdls_peer[ETH_ALEN] __aligned(2);
-	struct delayed_work tdls_peer_del_work;
+	struct wiphy_delayed_work tdls_peer_del_work;
 	struct sk_buff *orig_teardown_skb; /* The original teardown skb */
 	struct sk_buff *teardown_skb; /* A copy to send through the AP */
 	spinlock_t teardown_lock; /* To lock changing teardown_skb */
@@ -2494,7 +2494,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 			size_t extra_ies_len);
 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *peer, enum nl80211_tdls_operation oper);
-void ieee80211_tdls_peer_del_work(struct work_struct *wk);
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk);
 int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				  const u8 *addr, u8 oper_class,
 				  struct cfg80211_chan_def *chandef);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index d147760e8389..25468d5e874a 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -4890,8 +4890,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 	INIT_WORK(&ifmgd->csa_connection_drop_work,
 		  ieee80211_csa_connection_drop_work);
 	INIT_WORK(&ifmgd->request_smps_work, ieee80211_request_smps_mgd_work);
-	INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
-			  ieee80211_tdls_peer_del_work);
+	wiphy_delayed_work_init(&ifmgd->tdls_peer_del_work,
+				ieee80211_tdls_peer_del_work);
 	timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
 	timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
 	timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
@@ -6010,7 +6010,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 	cancel_work_sync(&ifmgd->request_smps_work);
 	cancel_work_sync(&ifmgd->csa_connection_drop_work);
 	cancel_work_sync(&ifmgd->chswitch_work);
-	cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
+	wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+				  &ifmgd->tdls_peer_del_work);
 
 	sdata_lock(sdata);
 	if (ifmgd->assoc_data) {
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 137be9ec94af..c2d7479c119a 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -21,7 +21,7 @@
 /* give usermode some time for retries in setting up the TDLS session */
 #define TDLS_PEER_SETUP_TIMEOUT	(15 * HZ)
 
-void ieee80211_tdls_peer_del_work(struct work_struct *wk)
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local;
@@ -1126,9 +1126,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
 		return ret;
 	}
 
-	ieee80211_queue_delayed_work(&sdata->local->hw,
-				     &sdata->u.mgd.tdls_peer_del_work,
-				     TDLS_PEER_SETUP_TIMEOUT);
+	wiphy_delayed_work_queue(sdata->local->hw.wiphy,
+				 &sdata->u.mgd.tdls_peer_del_work,
+				 TDLS_PEER_SETUP_TIMEOUT);
 	return 0;
 
 out_unlock:
@@ -1425,7 +1425,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 	}
 
 	if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
-		cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work);
+		wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+					  &sdata->u.mgd.tdls_peer_del_work);
 		eth_zero_addr(sdata->u.mgd.tdls_peer);
 	}
 
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH 5.15.y 2/3] wifi: mac80211: use wiphy work for sdata->work
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:50 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Hanne-Lotta Mäenpää
In-Reply-To: <20260202165038.215693-1-hannelotta@gmail.com>

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

[ Upstream commit 16114496d684a3df4ce09f7c6b7557a8b2922795 ]

We'll need this later to convert other works that might
be cancelled from here, so convert this one first.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 net/mac80211/ibss.c        |  8 ++++----
 net/mac80211/ieee80211_i.h |  2 +-
 net/mac80211/iface.c       | 10 +++++-----
 net/mac80211/mesh.c        | 10 +++++-----
 net/mac80211/mesh_hwmp.c   |  6 +++---
 net/mac80211/mlme.c        |  6 +++---
 net/mac80211/ocb.c         |  6 +++---
 net/mac80211/rx.c          |  2 +-
 net/mac80211/scan.c        |  2 +-
 net/mac80211/status.c      |  5 +++--
 net/mac80211/util.c        |  2 +-
 11 files changed, 30 insertions(+), 29 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 48e0260f3424..ce927c16a915 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -746,7 +746,7 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
 	skb_queue_purge(&sdata->skb_queue);
 
 	/* trigger a scan to find another IBSS network to join */
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 
 	sdata_unlock(sdata);
 }
@@ -1245,7 +1245,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 	spin_lock(&ifibss->incomplete_lock);
 	list_add(&sta->list, &ifibss->incomplete_stations);
 	spin_unlock(&ifibss->incomplete_lock);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
@@ -1726,7 +1726,7 @@ static void ieee80211_ibss_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.ibss.timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
@@ -1861,7 +1861,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 	sdata->needed_rx_chains = local->rx_chains;
 	sdata->control_port_over_nl80211 = params->control_port_over_nl80211;
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 
 	return 0;
 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 3b5350cfc0ee..8d6616f646e7 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -966,7 +966,7 @@ struct ieee80211_sub_if_data {
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
 
-	struct work_struct work;
+	struct wiphy_work work;
 	struct sk_buff_head skb_queue;
 	struct sk_buff_head status_queue;
 
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e437bcadf4a2..eb7de2d455e1 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -43,7 +43,7 @@
  * by either the RTNL, the iflist_mtx or RCU.
  */
 
-static void ieee80211_iface_work(struct work_struct *work);
+static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work);
 
 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
 {
@@ -539,7 +539,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
 		RCU_INIT_POINTER(local->p2p_sdata, NULL);
 		fallthrough;
 	default:
-		cancel_work_sync(&sdata->work);
+		wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
 		/*
 		 * When we get here, the interface is marked down.
 		 * Free the remaining keys, if there are any
@@ -1005,7 +1005,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 
 	skb_queue_head_init(&sdata->skb_queue);
 	skb_queue_head_init(&sdata->status_queue);
-	INIT_WORK(&sdata->work, ieee80211_iface_work);
+	wiphy_work_init(&sdata->work, ieee80211_iface_work);
 
 	return 0;
 }
@@ -1487,7 +1487,7 @@ static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
 	}
 }
 
-static void ieee80211_iface_work(struct work_struct *work)
+static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work)
 {
 	struct ieee80211_sub_if_data *sdata =
 		container_of(work, struct ieee80211_sub_if_data, work);
@@ -1590,7 +1590,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
 	skb_queue_head_init(&sdata->skb_queue);
 	skb_queue_head_init(&sdata->status_queue);
-	INIT_WORK(&sdata->work, ieee80211_iface_work);
+	wiphy_work_init(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->csa_finalize_work, ieee80211_csa_finalize_work);
 	INIT_WORK(&sdata->color_change_finalize_work, ieee80211_color_change_finalize_work);
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 6202157f467b..2f888cbe6e2b 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -44,7 +44,7 @@ static void ieee80211_mesh_housekeeping_timer(struct timer_list *t)
 
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 /**
@@ -642,7 +642,7 @@ static void ieee80211_mesh_path_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.mesh.mesh_path_timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_mesh_path_root_timer(struct timer_list *t)
@@ -653,7 +653,7 @@ static void ieee80211_mesh_path_root_timer(struct timer_list *t)
 
 	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -1018,7 +1018,7 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 	for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
 		set_bit(bit, &ifmsh->mbss_changed);
 	set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
@@ -1043,7 +1043,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	ifmsh->sync_offset_clockdrift_max = 0;
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 	ieee80211_mesh_root_setup(ifmsh);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 	sdata->vif.bss_conf.ht_operation_mode =
 				ifmsh->mshcfg.ht_opmode;
 	sdata->vif.bss_conf.enable_beacon = true;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index 8bf238afb544..a3522b21803f 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2019, 2021 Intel Corporation
+ * Copyright (C) 2019, 2021-2023 Intel Corporation
  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
  */
 
@@ -1020,14 +1020,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
 
 	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
-		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+		wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 
 	else if (time_before(jiffies, ifmsh->last_preq)) {
 		/* avoid long wait if did not send preqs for a long time
 		 * and jiffies wrapped around
 		 */
 		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
-		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+		wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	} else
 		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
 						min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 6e86a23c647d..d147760e8389 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -2509,7 +2509,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
 		sdata->u.mgd.probe_send_count = 0;
 	else
 		sdata->u.mgd.nullfunc_failed = true;
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
@@ -4415,7 +4415,7 @@ static void ieee80211_sta_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.mgd.timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
@@ -4559,7 +4559,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
 	sdata->u.mgd.status_acked = acked;
 	sdata->u.mgd.status_received = true;
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
index 7c1a735b9eee..9713e53f11b1 100644
--- a/net/mac80211/ocb.c
+++ b/net/mac80211/ocb.c
@@ -80,7 +80,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 	spin_lock(&ifocb->incomplete_lock);
 	list_add(&sta->list, &ifocb->incomplete_stations);
 	spin_unlock(&ifocb->incomplete_lock);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
@@ -156,7 +156,7 @@ static void ieee80211_ocb_housekeeping_timer(struct timer_list *t)
 
 	set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
@@ -196,7 +196,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
 	ifocb->joined = true;
 
 	set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 
 	netif_carrier_on(sdata->dev);
 	return 0;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 1c1660160787..15933e9abc9b 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -219,7 +219,7 @@ static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
 					   struct sk_buff *skb)
 {
 	skb_queue_tail(&sdata->skb_queue, skb);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	if (sta)
 		sta->rx_stats.packets++;
 }
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index 3bf3dd4bafa5..fd77c707e65c 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -498,7 +498,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 	 */
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (ieee80211_sdata_running(sdata))
-			ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+			wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	}
 
 	if (was_scanning)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index f6f63a0b1b72..017ea2d2f36f 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -5,6 +5,7 @@
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2008-2010	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
+ * Copyright 2021-2023  Intel Corporation
  */
 
 #include <linux/export.h>
@@ -716,8 +717,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
 					if (qskb) {
 						skb_queue_tail(&sdata->status_queue,
 							       qskb);
-						ieee80211_queue_work(&local->hw,
-								     &sdata->work);
+						wiphy_work_queue(local->hw.wiphy,
+								 &sdata->work);
 					}
 				}
 			} else {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index 07512f0d5576..5b1799dfa675 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2679,7 +2679,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
 		/* Requeue all works */
 		list_for_each_entry(sdata, &local->interfaces, list)
-			ieee80211_queue_work(&local->hw, &sdata->work);
+			wiphy_work_queue(local->hw.wiphy, &sdata->work);
 	}
 
 	ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH 5.15.y 1/3] wifi: cfg80211: add a work abstraction with special semantics
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:50 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Hanne-Lotta Mäenpää

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

[ Upstream commit a3ee4dc84c4e9d14cb34dad095fd678127aca5b6 ]

Add a work abstraction at the cfg80211 level that will always
hold the wiphy_lock() for any work executed and therefore also
can be canceled safely (without waiting) while holding that.
This improves on what we do now as with the new wiphy works we
don't have to worry about locking while cancelling them safely.

Also, don't let such works run while the device is suspended,
since they'll likely need to interact with the device. Flush
them before suspend though.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 include/net/cfg80211.h |  95 ++++++++++++++++++++++++++++++--
 net/wireless/core.c    | 121 +++++++++++++++++++++++++++++++++++++++++
 net/wireless/core.h    |   7 +++
 net/wireless/sysfs.c   |   8 ++-
 4 files changed, 226 insertions(+), 5 deletions(-)

diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h
index 66a75723f559..392576342661 100644
--- a/include/net/cfg80211.h
+++ b/include/net/cfg80211.h
@@ -5301,12 +5301,17 @@ struct cfg80211_cqm_config;
  * wiphy_lock - lock the wiphy
  * @wiphy: the wiphy to lock
  *
- * This is mostly exposed so it can be done around registering and
- * unregistering netdevs that aren't created through cfg80211 calls,
- * since that requires locking in cfg80211 when the notifiers is
- * called, but that cannot differentiate which way it's called.
+ * This is needed around registering and unregistering netdevs that
+ * aren't created through cfg80211 calls, since that requires locking
+ * in cfg80211 when the notifiers is called, but that cannot
+ * differentiate which way it's called.
+ *
+ * It can also be used by drivers for their own purposes.
  *
  * When cfg80211 ops are called, the wiphy is already locked.
+ *
+ * Note that this makes sure that no workers that have been queued
+ * with wiphy_queue_work() are running.
  */
 static inline void wiphy_lock(struct wiphy *wiphy)
 	__acquires(&wiphy->mtx)
@@ -5326,6 +5331,88 @@ static inline void wiphy_unlock(struct wiphy *wiphy)
 	mutex_unlock(&wiphy->mtx);
 }
 
+struct wiphy_work;
+typedef void (*wiphy_work_func_t)(struct wiphy *, struct wiphy_work *);
+
+struct wiphy_work {
+	struct list_head entry;
+	wiphy_work_func_t func;
+};
+
+static inline void wiphy_work_init(struct wiphy_work *work,
+				   wiphy_work_func_t func)
+{
+	INIT_LIST_HEAD(&work->entry);
+	work->func = func;
+}
+
+/**
+ * wiphy_work_queue - queue work for the wiphy
+ * @wiphy: the wiphy to queue for
+ * @work: the work item
+ *
+ * This is useful for work that must be done asynchronously, and work
+ * queued here has the special property that the wiphy mutex will be
+ * held as if wiphy_lock() was called, and that it cannot be running
+ * after wiphy_lock() was called. Therefore, wiphy_cancel_work() can
+ * use just cancel_work() instead of cancel_work_sync(), it requires
+ * being in a section protected by wiphy_lock().
+ */
+void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work);
+
+/**
+ * wiphy_work_cancel - cancel previously queued work
+ * @wiphy: the wiphy, for debug purposes
+ * @work: the work to cancel
+ *
+ * Cancel the work *without* waiting for it, this assumes being
+ * called under the wiphy mutex acquired by wiphy_lock().
+ */
+void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work);
+
+struct wiphy_delayed_work {
+	struct wiphy_work work;
+	struct wiphy *wiphy;
+	struct timer_list timer;
+};
+
+void wiphy_delayed_work_timer(struct timer_list *t);
+
+static inline void wiphy_delayed_work_init(struct wiphy_delayed_work *dwork,
+					   wiphy_work_func_t func)
+{
+	timer_setup(&dwork->timer, wiphy_delayed_work_timer, 0);
+	wiphy_work_init(&dwork->work, func);
+}
+
+/**
+ * wiphy_delayed_work_queue - queue delayed work for the wiphy
+ * @wiphy: the wiphy to queue for
+ * @dwork: the delayable worker
+ * @delay: number of jiffies to wait before queueing
+ *
+ * This is useful for work that must be done asynchronously, and work
+ * queued here has the special property that the wiphy mutex will be
+ * held as if wiphy_lock() was called, and that it cannot be running
+ * after wiphy_lock() was called. Therefore, wiphy_cancel_work() can
+ * use just cancel_work() instead of cancel_work_sync(), it requires
+ * being in a section protected by wiphy_lock().
+ */
+void wiphy_delayed_work_queue(struct wiphy *wiphy,
+			      struct wiphy_delayed_work *dwork,
+			      unsigned long delay);
+
+/**
+ * wiphy_delayed_work_cancel - cancel previously queued delayed work
+ * @wiphy: the wiphy, for debug purposes
+ * @dwork: the delayed work to cancel
+ *
+ * Cancel the work *without* waiting for it, this assumes being
+ * called under the wiphy mutex acquired by wiphy_lock().
+ */
+void wiphy_delayed_work_cancel(struct wiphy *wiphy,
+			       struct wiphy_delayed_work *dwork);
+
 /**
  * struct wireless_dev - wireless device state
  *
diff --git a/net/wireless/core.c b/net/wireless/core.c
index d51d27ff3729..788ca1055d6a 100644
--- a/net/wireless/core.c
+++ b/net/wireless/core.c
@@ -410,6 +410,34 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work)
 	rtnl_unlock();
 }
 
+static void cfg80211_wiphy_work(struct work_struct *work)
+{
+	struct cfg80211_registered_device *rdev;
+	struct wiphy_work *wk;
+
+	rdev = container_of(work, struct cfg80211_registered_device, wiphy_work);
+
+	wiphy_lock(&rdev->wiphy);
+	if (rdev->suspended)
+		goto out;
+
+	spin_lock_irq(&rdev->wiphy_work_lock);
+	wk = list_first_entry_or_null(&rdev->wiphy_work_list,
+				      struct wiphy_work, entry);
+	if (wk) {
+		list_del_init(&wk->entry);
+		if (!list_empty(&rdev->wiphy_work_list))
+			schedule_work(work);
+		spin_unlock_irq(&rdev->wiphy_work_lock);
+
+		wk->func(&rdev->wiphy, wk);
+	} else {
+		spin_unlock_irq(&rdev->wiphy_work_lock);
+	}
+out:
+	wiphy_unlock(&rdev->wiphy);
+}
+
 /* exported functions */
 
 struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
@@ -535,6 +563,9 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv,
 		return NULL;
 	}
 
+	INIT_WORK(&rdev->wiphy_work, cfg80211_wiphy_work);
+	INIT_LIST_HEAD(&rdev->wiphy_work_list);
+	spin_lock_init(&rdev->wiphy_work_lock);
 	INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);
 	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
 	INIT_WORK(&rdev->event_work, cfg80211_event_work);
@@ -1002,6 +1033,31 @@ void wiphy_rfkill_start_polling(struct wiphy *wiphy)
 }
 EXPORT_SYMBOL(wiphy_rfkill_start_polling);
 
+void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev)
+{
+	unsigned int runaway_limit = 100;
+	unsigned long flags;
+
+	lockdep_assert_held(&rdev->wiphy.mtx);
+
+	spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
+	while (!list_empty(&rdev->wiphy_work_list)) {
+		struct wiphy_work *wk;
+
+		wk = list_first_entry(&rdev->wiphy_work_list,
+				      struct wiphy_work, entry);
+		list_del_init(&wk->entry);
+		spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
+
+		wk->func(&rdev->wiphy, wk);
+
+		spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
+		if (WARN_ON(--runaway_limit == 0))
+			INIT_LIST_HEAD(&rdev->wiphy_work_list);
+	}
+	spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
+}
+
 void wiphy_unregister(struct wiphy *wiphy)
 {
 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
@@ -1040,9 +1096,14 @@ void wiphy_unregister(struct wiphy *wiphy)
 	cfg80211_rdev_list_generation++;
 	device_del(&rdev->wiphy.dev);
 
+	/* surely nothing is reachable now, clean up work */
+	cfg80211_process_wiphy_works(rdev);
 	wiphy_unlock(&rdev->wiphy);
 	rtnl_unlock();
 
+	/* this has nothing to do now but make sure it's gone */
+	cancel_work_sync(&rdev->wiphy_work);
+
 	flush_work(&rdev->scan_done_wk);
 	cancel_work_sync(&rdev->conn_work);
 	flush_work(&rdev->event_work);
@@ -1522,6 +1583,66 @@ static struct pernet_operations cfg80211_pernet_ops = {
 	.exit = cfg80211_pernet_exit,
 };
 
+void wiphy_work_queue(struct wiphy *wiphy, struct wiphy_work *work)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	unsigned long flags;
+
+	spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
+	if (list_empty(&work->entry))
+		list_add_tail(&work->entry, &rdev->wiphy_work_list);
+	spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
+
+	schedule_work(&rdev->wiphy_work);
+}
+EXPORT_SYMBOL_GPL(wiphy_work_queue);
+
+void wiphy_work_cancel(struct wiphy *wiphy, struct wiphy_work *work)
+{
+	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
+	unsigned long flags;
+
+	lockdep_assert_held(&wiphy->mtx);
+
+	spin_lock_irqsave(&rdev->wiphy_work_lock, flags);
+	if (!list_empty(&work->entry))
+		list_del_init(&work->entry);
+	spin_unlock_irqrestore(&rdev->wiphy_work_lock, flags);
+}
+EXPORT_SYMBOL_GPL(wiphy_work_cancel);
+
+void wiphy_delayed_work_timer(struct timer_list *t)
+{
+	struct wiphy_delayed_work *dwork = from_timer(dwork, t, timer);
+
+	wiphy_work_queue(dwork->wiphy, &dwork->work);
+}
+EXPORT_SYMBOL(wiphy_delayed_work_timer);
+
+void wiphy_delayed_work_queue(struct wiphy *wiphy,
+			      struct wiphy_delayed_work *dwork,
+			      unsigned long delay)
+{
+	if (!delay) {
+		wiphy_work_queue(wiphy, &dwork->work);
+		return;
+	}
+
+	dwork->wiphy = wiphy;
+	mod_timer(&dwork->timer, jiffies + delay);
+}
+EXPORT_SYMBOL_GPL(wiphy_delayed_work_queue);
+
+void wiphy_delayed_work_cancel(struct wiphy *wiphy,
+			       struct wiphy_delayed_work *dwork)
+{
+	lockdep_assert_held(&wiphy->mtx);
+
+	del_timer_sync(&dwork->timer);
+	wiphy_work_cancel(wiphy, &dwork->work);
+}
+EXPORT_SYMBOL_GPL(wiphy_delayed_work_cancel);
+
 static int __init cfg80211_init(void)
 {
 	int err;
diff --git a/net/wireless/core.h b/net/wireless/core.h
index 1720abf36f92..18d30f6fa7ca 100644
--- a/net/wireless/core.h
+++ b/net/wireless/core.h
@@ -103,6 +103,12 @@ struct cfg80211_registered_device {
 	/* lock for all wdev lists */
 	spinlock_t mgmt_registrations_lock;
 
+	struct work_struct wiphy_work;
+	struct list_head wiphy_work_list;
+	/* protects the list above */
+	spinlock_t wiphy_work_lock;
+	bool suspended;
+
 	/* must be last because of the way we do wiphy_priv(),
 	 * and it should at least be aligned to NETDEV_ALIGN */
 	struct wiphy wiphy __aligned(NETDEV_ALIGN);
@@ -457,6 +463,7 @@ int cfg80211_change_iface(struct cfg80211_registered_device *rdev,
 			  struct net_device *dev, enum nl80211_iftype ntype,
 			  struct vif_params *params);
 void cfg80211_process_rdev_events(struct cfg80211_registered_device *rdev);
+void cfg80211_process_wiphy_works(struct cfg80211_registered_device *rdev);
 void cfg80211_process_wdev_events(struct wireless_dev *wdev);
 
 bool cfg80211_does_bw_fit_range(const struct ieee80211_freq_range *freq_range,
diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c
index 0c3f05c9be27..4d3b65803010 100644
--- a/net/wireless/sysfs.c
+++ b/net/wireless/sysfs.c
@@ -5,7 +5,7 @@
  *
  * Copyright 2005-2006	Jiri Benc <jbenc@suse.cz>
  * Copyright 2006	Johannes Berg <johannes@sipsolutions.net>
- * Copyright (C) 2020-2021 Intel Corporation
+ * Copyright (C) 2020-2021, 2023 Intel Corporation
  */
 
 #include <linux/device.h>
@@ -105,14 +105,18 @@ static int wiphy_suspend(struct device *dev)
 			cfg80211_leave_all(rdev);
 			cfg80211_process_rdev_events(rdev);
 		}
+		cfg80211_process_wiphy_works(rdev);
 		if (rdev->ops->suspend)
 			ret = rdev_suspend(rdev, rdev->wiphy.wowlan_config);
 		if (ret == 1) {
 			/* Driver refuse to configure wowlan */
 			cfg80211_leave_all(rdev);
 			cfg80211_process_rdev_events(rdev);
+			cfg80211_process_wiphy_works(rdev);
 			ret = rdev_suspend(rdev, NULL);
 		}
+		if (ret == 0)
+			rdev->suspended = true;
 	}
 	wiphy_unlock(&rdev->wiphy);
 	rtnl_unlock();
@@ -132,6 +136,8 @@ static int wiphy_resume(struct device *dev)
 	wiphy_lock(&rdev->wiphy);
 	if (rdev->wiphy.registered && rdev->ops->resume)
 		ret = rdev_resume(rdev);
+	rdev->suspended = false;
+	schedule_work(&rdev->wiphy_work);
 	wiphy_unlock(&rdev->wiphy);
 
 	if (ret)
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH 6.1.y 2/2] wifi: mac80211: move TDLS work to wiphy work
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:49 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Emmanuel Grumbach, Hanne-Lotta Mäenpää
In-Reply-To: <20260202164924.215621-1-hannelotta@gmail.com>

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

[ Upstream commit 777b26002b73127e81643d9286fadf3d41e0e477 ]

Again, to have the wiphy locked for it.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
[ Summary of conflict resolutions:
  - In mlme.c, move only tdls_peer_del_work
    to wiphy work, and none the other works ]
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 net/mac80211/ieee80211_i.h |  4 ++--
 net/mac80211/mlme.c        |  7 ++++---
 net/mac80211/tdls.c        | 11 ++++++-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 6cc5bba2ba52..e94a370da4c4 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -531,7 +531,7 @@ struct ieee80211_if_managed {
 
 	/* TDLS support */
 	u8 tdls_peer[ETH_ALEN] __aligned(2);
-	struct delayed_work tdls_peer_del_work;
+	struct wiphy_delayed_work tdls_peer_del_work;
 	struct sk_buff *orig_teardown_skb; /* The original teardown skb */
 	struct sk_buff *teardown_skb; /* A copy to send through the AP */
 	spinlock_t teardown_lock; /* To lock changing teardown_skb */
@@ -2525,7 +2525,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 			size_t extra_ies_len);
 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *peer, enum nl80211_tdls_operation oper);
-void ieee80211_tdls_peer_del_work(struct work_struct *wk);
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk);
 int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				  const u8 *addr, u8 oper_class,
 				  struct cfg80211_chan_def *chandef);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 8824460a2060..30db27df6b79 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6517,8 +6517,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 		  ieee80211_beacon_connection_loss_work);
 	INIT_WORK(&ifmgd->csa_connection_drop_work,
 		  ieee80211_csa_connection_drop_work);
-	INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
-			  ieee80211_tdls_peer_del_work);
+	wiphy_delayed_work_init(&ifmgd->tdls_peer_del_work,
+				ieee80211_tdls_peer_del_work);
 	timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
 	timer_setup(&ifmgd->bcn_mon_timer, ieee80211_sta_bcn_mon_timer, 0);
 	timer_setup(&ifmgd->conn_mon_timer, ieee80211_sta_conn_mon_timer, 0);
@@ -7524,7 +7524,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 	cancel_work_sync(&ifmgd->monitor_work);
 	cancel_work_sync(&ifmgd->beacon_connection_loss_work);
 	cancel_work_sync(&ifmgd->csa_connection_drop_work);
-	cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
+	wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+				  &ifmgd->tdls_peer_del_work);
 
 	sdata_lock(sdata);
 	if (ifmgd->assoc_data)
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index 04531d18fa93..1f07b598a6a1 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -21,7 +21,7 @@
 /* give usermode some time for retries in setting up the TDLS session */
 #define TDLS_PEER_SETUP_TIMEOUT	(15 * HZ)
 
-void ieee80211_tdls_peer_del_work(struct work_struct *wk)
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local;
@@ -1128,9 +1128,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
 		return ret;
 	}
 
-	ieee80211_queue_delayed_work(&sdata->local->hw,
-				     &sdata->u.mgd.tdls_peer_del_work,
-				     TDLS_PEER_SETUP_TIMEOUT);
+	wiphy_delayed_work_queue(sdata->local->hw.wiphy,
+				 &sdata->u.mgd.tdls_peer_del_work,
+				 TDLS_PEER_SETUP_TIMEOUT);
 	return 0;
 
 out_unlock:
@@ -1427,7 +1427,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 	}
 
 	if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
-		cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work);
+		wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+					  &sdata->u.mgd.tdls_peer_del_work);
 		eth_zero_addr(sdata->u.mgd.tdls_peer);
 	}
 
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH 6.1.y 1/2] wifi: mac80211: use wiphy work for sdata->work
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:49 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Hanne-Lotta Mäenpää

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

[ Upstream commit 16114496d684a3df4ce09f7c6b7557a8b2922795 ]

We'll need this later to convert other works that might
be cancelled from here, so convert this one first.

Signed-off-by: Johannes Berg <johannes.berg@intel.com>
(cherry picked from commit 16114496d684a3df4ce09f7c6b7557a8b2922795)
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 net/mac80211/ibss.c        |  8 ++++----
 net/mac80211/ieee80211_i.h |  2 +-
 net/mac80211/iface.c       | 10 +++++-----
 net/mac80211/mesh.c        | 10 +++++-----
 net/mac80211/mesh_hwmp.c   |  6 +++---
 net/mac80211/mlme.c        |  6 +++---
 net/mac80211/ocb.c         |  6 +++---
 net/mac80211/rx.c          |  2 +-
 net/mac80211/scan.c        |  2 +-
 net/mac80211/status.c      |  6 +++---
 net/mac80211/util.c        |  2 +-
 11 files changed, 30 insertions(+), 30 deletions(-)

diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
index 79d2c5505289..363e7e4fdd02 100644
--- a/net/mac80211/ibss.c
+++ b/net/mac80211/ibss.c
@@ -741,7 +741,7 @@ static void ieee80211_csa_connection_drop_work(struct work_struct *work)
 	skb_queue_purge(&sdata->skb_queue);
 
 	/* trigger a scan to find another IBSS network to join */
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 
 	sdata_unlock(sdata);
 }
@@ -1242,7 +1242,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 	spin_lock(&ifibss->incomplete_lock);
 	list_add(&sta->list, &ifibss->incomplete_stations);
 	spin_unlock(&ifibss->incomplete_lock);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_ibss_sta_expire(struct ieee80211_sub_if_data *sdata)
@@ -1721,7 +1721,7 @@ static void ieee80211_ibss_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.ibss.timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
@@ -1856,7 +1856,7 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 	sdata->deflink.needed_rx_chains = local->rx_chains;
 	sdata->control_port_over_nl80211 = params->control_port_over_nl80211;
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 
 	return 0;
 }
diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 64f8d8f2b799..6cc5bba2ba52 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -1046,7 +1046,7 @@ struct ieee80211_sub_if_data {
 	/* used to reconfigure hardware SM PS */
 	struct work_struct recalc_smps;
 
-	struct work_struct work;
+	struct wiphy_work work;
 	struct sk_buff_head skb_queue;
 	struct sk_buff_head status_queue;
 
diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c
index e691ecdd2ad5..6818c9d852e8 100644
--- a/net/mac80211/iface.c
+++ b/net/mac80211/iface.c
@@ -43,7 +43,7 @@
  * by either the RTNL, the iflist_mtx or RCU.
  */
 
-static void ieee80211_iface_work(struct work_struct *work);
+static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work);
 
 bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
 {
@@ -650,7 +650,7 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata, bool going_do
 		RCU_INIT_POINTER(local->p2p_sdata, NULL);
 		fallthrough;
 	default:
-		cancel_work_sync(&sdata->work);
+		wiphy_work_cancel(sdata->local->hw.wiphy, &sdata->work);
 		/*
 		 * When we get here, the interface is marked down.
 		 * Free the remaining keys, if there are any
@@ -1224,7 +1224,7 @@ int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
 
 	skb_queue_head_init(&sdata->skb_queue);
 	skb_queue_head_init(&sdata->status_queue);
-	INIT_WORK(&sdata->work, ieee80211_iface_work);
+	wiphy_work_init(&sdata->work, ieee80211_iface_work);
 
 	return 0;
 }
@@ -1707,7 +1707,7 @@ static void ieee80211_iface_process_status(struct ieee80211_sub_if_data *sdata,
 	}
 }
 
-static void ieee80211_iface_work(struct work_struct *work)
+static void ieee80211_iface_work(struct wiphy *wiphy, struct wiphy_work *work)
 {
 	struct ieee80211_sub_if_data *sdata =
 		container_of(work, struct ieee80211_sub_if_data, work);
@@ -1819,7 +1819,7 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
 
 	skb_queue_head_init(&sdata->skb_queue);
 	skb_queue_head_init(&sdata->status_queue);
-	INIT_WORK(&sdata->work, ieee80211_iface_work);
+	wiphy_work_init(&sdata->work, ieee80211_iface_work);
 	INIT_WORK(&sdata->recalc_smps, ieee80211_recalc_smps_work);
 	INIT_WORK(&sdata->activate_links_work, ieee80211_activate_links_work);
 
diff --git a/net/mac80211/mesh.c b/net/mac80211/mesh.c
index 9c9b47d153c2..434efb30c75f 100644
--- a/net/mac80211/mesh.c
+++ b/net/mac80211/mesh.c
@@ -44,7 +44,7 @@ static void ieee80211_mesh_housekeeping_timer(struct timer_list *t)
 
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 /**
@@ -643,7 +643,7 @@ static void ieee80211_mesh_path_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.mesh.mesh_path_timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_mesh_path_root_timer(struct timer_list *t)
@@ -654,7 +654,7 @@ static void ieee80211_mesh_path_root_timer(struct timer_list *t)
 
 	set_bit(MESH_WORK_ROOT, &ifmsh->wrkq_flags);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_mesh_root_setup(struct ieee80211_if_mesh *ifmsh)
@@ -1018,7 +1018,7 @@ void ieee80211_mbss_info_change_notify(struct ieee80211_sub_if_data *sdata,
 	for_each_set_bit(bit, &bits, sizeof(changed) * BITS_PER_BYTE)
 		set_bit(bit, &ifmsh->mbss_changed);
 	set_bit(MESH_WORK_MBSS_CHANGED, &ifmsh->wrkq_flags);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
@@ -1043,7 +1043,7 @@ int ieee80211_start_mesh(struct ieee80211_sub_if_data *sdata)
 	ifmsh->sync_offset_clockdrift_max = 0;
 	set_bit(MESH_WORK_HOUSEKEEPING, &ifmsh->wrkq_flags);
 	ieee80211_mesh_root_setup(ifmsh);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 	sdata->vif.bss_conf.ht_operation_mode =
 				ifmsh->mshcfg.ht_opmode;
 	sdata->vif.bss_conf.enable_beacon = true;
diff --git a/net/mac80211/mesh_hwmp.c b/net/mac80211/mesh_hwmp.c
index da9e152a7aab..50dba479246b 100644
--- a/net/mac80211/mesh_hwmp.c
+++ b/net/mac80211/mesh_hwmp.c
@@ -1,7 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
  * Copyright (c) 2008, 2009 open80211s Ltd.
- * Copyright (C) 2019, 2021-2022 Intel Corporation
+ * Copyright (C) 2019, 2021-2023 Intel Corporation
  * Author:     Luis Carlos Cobo <luisca@cozybit.com>
  */
 
@@ -1025,14 +1025,14 @@ static void mesh_queue_preq(struct mesh_path *mpath, u8 flags)
 	spin_unlock_bh(&ifmsh->mesh_preq_queue_lock);
 
 	if (time_after(jiffies, ifmsh->last_preq + min_preq_int_jiff(sdata)))
-		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+		wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 
 	else if (time_before(jiffies, ifmsh->last_preq)) {
 		/* avoid long wait if did not send preqs for a long time
 		 * and jiffies wrapped around
 		 */
 		ifmsh->last_preq = jiffies - min_preq_int_jiff(sdata) - 1;
-		ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+		wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	} else
 		mod_timer(&ifmsh->mesh_path_timer, ifmsh->last_preq +
 						min_preq_int_jiff(sdata));
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index 1fb41e5cc577..8824460a2060 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -3168,7 +3168,7 @@ void ieee80211_sta_tx_notify(struct ieee80211_sub_if_data *sdata,
 		sdata->u.mgd.probe_send_count = 0;
 	else
 		sdata->u.mgd.nullfunc_failed = true;
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 static void ieee80211_mlme_send_probe_req(struct ieee80211_sub_if_data *sdata,
@@ -6031,7 +6031,7 @@ static void ieee80211_sta_timer(struct timer_list *t)
 	struct ieee80211_sub_if_data *sdata =
 		from_timer(sdata, t, u.mgd.timer);
 
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata,
@@ -6175,7 +6175,7 @@ void ieee80211_mgd_conn_tx_status(struct ieee80211_sub_if_data *sdata,
 	sdata->u.mgd.status_acked = acked;
 	sdata->u.mgd.status_received = true;
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_sta_work(struct ieee80211_sub_if_data *sdata)
diff --git a/net/mac80211/ocb.c b/net/mac80211/ocb.c
index a57dcbe99a0d..fcc326913391 100644
--- a/net/mac80211/ocb.c
+++ b/net/mac80211/ocb.c
@@ -81,7 +81,7 @@ void ieee80211_ocb_rx_no_sta(struct ieee80211_sub_if_data *sdata,
 	spin_lock(&ifocb->incomplete_lock);
 	list_add(&sta->list, &ifocb->incomplete_stations);
 	spin_unlock(&ifocb->incomplete_lock);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 static struct sta_info *ieee80211_ocb_finish_sta(struct sta_info *sta)
@@ -157,7 +157,7 @@ static void ieee80211_ocb_housekeeping_timer(struct timer_list *t)
 
 	set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
 
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 }
 
 void ieee80211_ocb_setup_sdata(struct ieee80211_sub_if_data *sdata)
@@ -197,7 +197,7 @@ int ieee80211_ocb_join(struct ieee80211_sub_if_data *sdata,
 	ifocb->joined = true;
 
 	set_bit(OCB_WORK_HOUSEKEEPING, &ifocb->wrkq_flags);
-	ieee80211_queue_work(&local->hw, &sdata->work);
+	wiphy_work_queue(local->hw.wiphy, &sdata->work);
 
 	netif_carrier_on(sdata->dev);
 	return 0;
diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c
index 42dd7d1dda39..a6636e9f5c08 100644
--- a/net/mac80211/rx.c
+++ b/net/mac80211/rx.c
@@ -229,7 +229,7 @@ static void __ieee80211_queue_skb_to_iface(struct ieee80211_sub_if_data *sdata,
 	}
 
 	skb_queue_tail(&sdata->skb_queue, skb);
-	ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+	wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	if (sta)
 		sta->deflink.rx_stats.packets++;
 }
diff --git a/net/mac80211/scan.c b/net/mac80211/scan.c
index f1147d156c1f..58da59836884 100644
--- a/net/mac80211/scan.c
+++ b/net/mac80211/scan.c
@@ -503,7 +503,7 @@ static void __ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 	 */
 	list_for_each_entry_rcu(sdata, &local->interfaces, list) {
 		if (ieee80211_sdata_running(sdata))
-			ieee80211_queue_work(&sdata->local->hw, &sdata->work);
+			wiphy_work_queue(sdata->local->hw.wiphy, &sdata->work);
 	}
 
 	if (was_scanning)
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 3a96aa306616..9a8fca897d9f 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -5,7 +5,7 @@
  * Copyright 2006-2007	Jiri Benc <jbenc@suse.cz>
  * Copyright 2008-2010	Johannes Berg <johannes@sipsolutions.net>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright 2021-2022  Intel Corporation
+ * Copyright 2021-2023  Intel Corporation
  */
 
 #include <linux/export.h>
@@ -747,8 +747,8 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
 					if (qskb) {
 						skb_queue_tail(&sdata->status_queue,
 							       qskb);
-						ieee80211_queue_work(&local->hw,
-								     &sdata->work);
+						wiphy_work_queue(local->hw.wiphy,
+								 &sdata->work);
 					}
 				}
 			} else {
diff --git a/net/mac80211/util.c b/net/mac80211/util.c
index e60c8607e4b6..116a3e70582b 100644
--- a/net/mac80211/util.c
+++ b/net/mac80211/util.c
@@ -2751,7 +2751,7 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
 		/* Requeue all works */
 		list_for_each_entry(sdata, &local->interfaces, list)
-			ieee80211_queue_work(&local->hw, &sdata->work);
+			wiphy_work_queue(local->hw.wiphy, &sdata->work);
 	}
 
 	ieee80211_wake_queues_by_reason(hw, IEEE80211_MAX_QUEUE_MAP,
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH 6.6.y] wifi: mac80211: move TDLS work to wiphy work
From: Hanne-Lotta Mäenpää @ 2026-02-02 16:47 UTC (permalink / raw)
  To: stable
  Cc: johannes, linux-wireless, linux-kernel, Johannes Berg,
	Emmanuel Grumbach, Hanne-Lotta Mäenpää

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

[ Upstream commit 777b26002b73127e81643d9286fadf3d41e0e477 ]

Again, to have the wiphy locked for it.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
(cherry picked from commit 777b26002b73127e81643d9286fadf3d41e0e477)
Signed-off-by: Hanne-Lotta Mäenpää <hannelotta@gmail.com>
---
 net/mac80211/ieee80211_i.h |  4 ++--
 net/mac80211/mlme.c        |  7 ++++---
 net/mac80211/tdls.c        | 11 ++++++-----
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h
index 44aad3394084..639268d70f96 100644
--- a/net/mac80211/ieee80211_i.h
+++ b/net/mac80211/ieee80211_i.h
@@ -530,7 +530,7 @@ struct ieee80211_if_managed {
 
 	/* TDLS support */
 	u8 tdls_peer[ETH_ALEN] __aligned(2);
-	struct delayed_work tdls_peer_del_work;
+	struct wiphy_delayed_work tdls_peer_del_work;
 	struct sk_buff *orig_teardown_skb; /* The original teardown skb */
 	struct sk_buff *teardown_skb; /* A copy to send through the AP */
 	spinlock_t teardown_lock; /* To lock changing teardown_skb */
@@ -2599,7 +2599,7 @@ int ieee80211_tdls_mgmt(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *extra_ies, size_t extra_ies_len);
 int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 			const u8 *peer, enum nl80211_tdls_operation oper);
-void ieee80211_tdls_peer_del_work(struct work_struct *wk);
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk);
 int ieee80211_tdls_channel_switch(struct wiphy *wiphy, struct net_device *dev,
 				  const u8 *addr, u8 oper_class,
 				  struct cfg80211_chan_def *chandef);
diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c
index aa7cee830b00..78b9206f99f4 100644
--- a/net/mac80211/mlme.c
+++ b/net/mac80211/mlme.c
@@ -6866,8 +6866,8 @@ void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 			ieee80211_beacon_connection_loss_work);
 	wiphy_work_init(&ifmgd->csa_connection_drop_work,
 			ieee80211_csa_connection_drop_work);
-	INIT_DELAYED_WORK(&ifmgd->tdls_peer_del_work,
-			  ieee80211_tdls_peer_del_work);
+	wiphy_delayed_work_init(&ifmgd->tdls_peer_del_work,
+				ieee80211_tdls_peer_del_work);
 	wiphy_delayed_work_init(&ifmgd->ml_reconf_work,
 				ieee80211_ml_reconf_work);
 	timer_setup(&ifmgd->timer, ieee80211_sta_timer, 0);
@@ -7881,7 +7881,8 @@ void ieee80211_mgd_stop(struct ieee80211_sub_if_data *sdata)
 			  &ifmgd->beacon_connection_loss_work);
 	wiphy_work_cancel(sdata->local->hw.wiphy,
 			  &ifmgd->csa_connection_drop_work);
-	cancel_delayed_work_sync(&ifmgd->tdls_peer_del_work);
+	wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+				  &ifmgd->tdls_peer_del_work);
 	wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
 				  &ifmgd->ml_reconf_work);
 
diff --git a/net/mac80211/tdls.c b/net/mac80211/tdls.c
index f3cdbd2133f6..0fd353fec9fc 100644
--- a/net/mac80211/tdls.c
+++ b/net/mac80211/tdls.c
@@ -21,7 +21,7 @@
 /* give usermode some time for retries in setting up the TDLS session */
 #define TDLS_PEER_SETUP_TIMEOUT	(15 * HZ)
 
-void ieee80211_tdls_peer_del_work(struct work_struct *wk)
+void ieee80211_tdls_peer_del_work(struct wiphy *wiphy, struct wiphy_work *wk)
 {
 	struct ieee80211_sub_if_data *sdata;
 	struct ieee80211_local *local;
@@ -1224,9 +1224,9 @@ ieee80211_tdls_mgmt_setup(struct wiphy *wiphy, struct net_device *dev,
 		return ret;
 	}
 
-	ieee80211_queue_delayed_work(&sdata->local->hw,
-				     &sdata->u.mgd.tdls_peer_del_work,
-				     TDLS_PEER_SETUP_TIMEOUT);
+	wiphy_delayed_work_queue(sdata->local->hw.wiphy,
+				 &sdata->u.mgd.tdls_peer_del_work,
+				 TDLS_PEER_SETUP_TIMEOUT);
 	return 0;
 
 out_unlock:
@@ -1526,7 +1526,8 @@ int ieee80211_tdls_oper(struct wiphy *wiphy, struct net_device *dev,
 	}
 
 	if (ret == 0 && ether_addr_equal(sdata->u.mgd.tdls_peer, peer)) {
-		cancel_delayed_work(&sdata->u.mgd.tdls_peer_del_work);
+		wiphy_delayed_work_cancel(sdata->local->hw.wiphy,
+					  &sdata->u.mgd.tdls_peer_del_work);
 		eth_zero_addr(sdata->u.mgd.tdls_peer);
 	}
 
-- 
2.53.0.rc2.2.g2258446484


^ permalink raw reply related

* [PATCH] wifi: ath12k: fix CMA error and MHI state mismatch during resume
From: Saikiran @ 2026-02-02 15:17 UTC (permalink / raw)
  To: jjohnson, kvalo
  Cc: quic_bqiang, linux-wireless, ath12k, linux-kernel, Saikiran

Commit 8d5f4da8d70b ("wifi: ath12k: support suspend/resume") introduced
system suspend/resume support but caused a critical regression where
CMA pages are corrupted during resume.

1. CMA page corruption:
   Calling mhi_unprepare_after_power_down() during suspend (via
   ATH12K_MHI_DEINIT) prematurely frees the fbc_image and rddm_image
   DMA buffers. When these pages are accessed during resume, the kernel
   detects corruption (Bad page state).

To fix this corruption, the driver must skip ATH12K_MHI_DEINIT during
suspend, preserving the DMA buffers. However, implementing this fix
exposes a second issue in the state machine:

2. Resume failure due to MHI state mismatch:
   When DEINIT is skipped during suspend to protect the memory, the
   ATH12K_MHI_INIT bit remains set. On resume, ath12k_mhi_start()
   blindly attempts to set INIT again, but the state machine rejects
   the transition:

   ath12k_wifi7_pci ...: failed to set mhi state INIT(0) in current
   mhi state (0x1)

Fix the corruption and enable the correct suspend flow by:

1. In ath12k_mhi_stop(), skipping ATH12K_MHI_DEINIT if suspending.
   This prevents the memory corruption by keeping the device context
   valid (MHI_POWER_OFF_KEEP_DEV).

2. In ath12k_mhi_start(), checking if MHI_INIT is already set.
   This accommodates the new suspend flow where the device remains
   initialized, allowing the driver to proceed directly to POWER_ON.

Tested with suspend/resume cycles on Qualcomm Snapdragon X Elite
(SC8380XP) with WCN7850 WiFi. No CMA corruption observed, WiFi resumes
successfully, and deep sleep works correctly.

Fixes: 8d5f4da8d70b ("wifi: ath12k: support suspend/resume")
Tested-on: WCN7850 hw2.0 PCI WLAN.HMT.1.1.c5-00302 (Lenovo Yoga Slim 7x)
Signed-off-by: Saikiran <bjsaikiran@gmail.com>
---
 drivers/net/wireless/ath/ath12k/mhi.c | 24 +++++++++++++++++-------
 1 file changed, 17 insertions(+), 7 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/mhi.c b/drivers/net/wireless/ath/ath12k/mhi.c
index 45c0f66dcc5e..1a0b3bcc6bbf 100644
--- a/drivers/net/wireless/ath/ath12k/mhi.c
+++ b/drivers/net/wireless/ath/ath12k/mhi.c
@@ -485,9 +485,14 @@ int ath12k_mhi_start(struct ath12k_pci *ab_pci)
 
 	ab_pci->mhi_ctrl->timeout_ms = MHI_TIMEOUT_DEFAULT_MS;
 
-	ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT);
-	if (ret)
-		goto out;
+	/* In case of suspend/resume, MHI INIT is already done.
+	 * So check if MHI INIT is set or not.
+	 */
+	if (!test_bit(ATH12K_MHI_INIT, &ab_pci->mhi_state)) {
+		ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_INIT);
+		if (ret)
+			goto out;
+	}
 
 	ret = ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_ON);
 	if (ret)
@@ -501,16 +506,21 @@ int ath12k_mhi_start(struct ath12k_pci *ab_pci)
 
 void ath12k_mhi_stop(struct ath12k_pci *ab_pci, bool is_suspend)
 {
-	/* During suspend we need to use mhi_power_down_keep_dev()
-	 * workaround, otherwise ath12k_core_resume() will timeout
-	 * during resume.
+	/* During suspend, we need to use mhi_power_down_keep_dev()
+	 * and avoid calling MHI_DEINIT. The deinit frees BHIE tables
+	 * which causes memory corruption when those pages are
+	 * accessed/freed again during resume. We want to keep the
+	 * device prepared for resume, otherwise ath12k_core_resume()
+	 * will timeout.
 	 */
 	if (is_suspend)
 		ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF_KEEP_DEV);
 	else
 		ath12k_mhi_set_state(ab_pci, ATH12K_MHI_POWER_OFF);
 
-	ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT);
+	/* Only deinit when doing full power down, not during suspend */
+	if (!is_suspend)
+		ath12k_mhi_set_state(ab_pci, ATH12K_MHI_DEINIT);
 }
 
 void ath12k_mhi_suspend(struct ath12k_pci *ab_pci)
-- 
2.51.0


^ permalink raw reply related

* Re: [PATCH 11/13] wifi: nl80211/cfg80211: add MAC randomization support for PD requests
From: Jeff Johnson @ 2026-02-02 14:59 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-12-peddolla.reddy@oss.qualcomm.com>

On 1/30/2026 8:00 AM, Peddolla Harshavardhan Reddy wrote:
> Add support for MAC address randomization in proximity detection
> (PD) requests. When enabled, the same randomized MAC address
> used for discovery and authentication phases will be used for
> the ranging measurements, maintaining privacy throughout the
> entire PD session workflow.

describe the problem first

> 
> The implementation adds a capability flag for devices to

use imperative tense

> advertise PD MAC randomization support and validates that
> randomization is only requested when the device supports it.
> This ensures consistent MAC address usage across all phases of
> proximity detection while preventing invalid configurations
> where randomization is requested but not supported by hardware.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH 10/13] wifi: nl80211/cfg80211: add result reporting control for PD requests
From: Jeff Johnson @ 2026-02-02 14:58 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-11-peddolla.reddy@oss.qualcomm.com>

On 1/30/2026 8:00 AM, Peddolla Harshavardhan Reddy wrote:
> Add optional result reporting control for proximity detection
> (PD) requests, allowing userspace to disable ranging result
> reports when measurement data is not needed. This reduces
> unnecessary data transfer and processing overhead for
> applications that only require proximity detection without
> detailed ranging measurements.

describe the problem first

> 
> The implementation validates that result reporting control is

use imperative tense

> only used with PD requests and ensures proper configuration
> when operating as responder (RSTA role). For RSTA operations
> requesting results, either LMR feedback or range report must
> be enabled to provide a mechanism for result delivery. This
> prevents invalid configurations where results are requested
> but no delivery method is available.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH 09/13] wifi: nl80211/cfg80211: add FTM range report negotiation support
From: Jeff Johnson @ 2026-02-02 14:57 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-10-peddolla.reddy@oss.qualcomm.com>

On 1/30/2026 8:00 AM, Peddolla Harshavardhan Reddy wrote:
> Add support for FTM range report negotiation in EDCA-based
> ranging operations. This allows devices to negotiate whether
> range measurement reports should be exchanged after the FTM
> session.

describe the problem first

> 
> The implementation adds a new capability flag and request

use imperative tense

> attribute for range report negotiation. Devices advertise
> range report support and userspace can request it for EDCA
> ranging sessions only.
> 
> Signed-off-by: Peddolla Harshavardhan Reddy <peddolla.reddy@oss.qualcomm.com>

^ permalink raw reply

* Re: [PATCH 08/13] wifi: nl80211/cfg80211: add PD-specific bandwidth capabilities for FTM
From: Jeff Johnson @ 2026-02-02 14:56 UTC (permalink / raw)
  To: Peddolla Harshavardhan Reddy, johannes; +Cc: linux-wireless
In-Reply-To: <20260130160039.2823409-9-peddolla.reddy@oss.qualcomm.com>

On 1/30/2026 8:00 AM, Peddolla Harshavardhan Reddy wrote:
> Add separate bandwidth capability reporting for proximity detection
> (PD) requests with EDCA and NTB-based ranging. This allows devices
> to advertise different supported bandwidths for PD operations
> versus regular FTM measurements, enabling more flexible capability
> negotiation for proximity ranging scenarios.

Normally in kernel commit text you describe the problem first, and then
describe how to solve the problem.



^ permalink raw reply


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