Linux wireless drivers development
 help / color / mirror / Atom feed
* [patch 02/38] x86: Cleanup include recursion hell
From: Thomas Gleixner @ 2026-04-10 12:18 UTC (permalink / raw)
  To: LKML
  Cc: Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik, netdev,
	linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
	linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
	Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
	Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
	Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
	linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
	Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
	Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
	linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
	linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
	sparclinux
In-Reply-To: <20260410120044.031381086@kernel.org>

Including a random architecture specific header which requires global
headers just to avoid including that header at the two usage sites is
really beyond lazy and tasteless. Including global headers just to get the
__percpu macro from linux/compiler_types.h falls into the same category.

Remove the linux/percpu.h and asm/cpumask.h includes from msr.h and smp.h
and fix the resulting fallout by a simple forward struct declaration and by
including the x86 specific asm/cpumask.h header where it is actually
required.

Signed-off-by: Thomas Gleixner <tglx@kernel.org>
---
 arch/x86/include/asm/msr.h               |    5 +++--
 arch/x86/include/asm/pvclock.h           |    1 +
 arch/x86/include/asm/smp.h               |    2 --
 arch/x86/include/asm/vdso/gettimeofday.h |    5 ++---
 arch/x86/kernel/cpu/mce/core.c           |    1 +
 arch/x86/kernel/nmi.c                    |    1 +
 arch/x86/kernel/smpboot.c                |    1 +
 7 files changed, 9 insertions(+), 7 deletions(-)

--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -8,12 +8,11 @@
 
 #include <asm/asm.h>
 #include <asm/errno.h>
-#include <asm/cpumask.h>
 #include <uapi/asm/msr.h>
 #include <asm/shared/msr.h>
 
+#include <linux/compiler_types.h>
 #include <linux/types.h>
-#include <linux/percpu.h>
 
 struct msr_info {
 	u32			msr_no;
@@ -256,6 +255,8 @@ int msr_set_bit(u32 msr, u8 bit);
 int msr_clear_bit(u32 msr, u8 bit);
 
 #ifdef CONFIG_SMP
+struct cpumask;
+
 int rdmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 *l, u32 *h);
 int wrmsr_on_cpu(unsigned int cpu, u32 msr_no, u32 l, u32 h);
 int rdmsrq_on_cpu(unsigned int cpu, u32 msr_no, u64 *q);
--- a/arch/x86/include/asm/pvclock.h
+++ b/arch/x86/include/asm/pvclock.h
@@ -2,6 +2,7 @@
 #ifndef _ASM_X86_PVCLOCK_H
 #define _ASM_X86_PVCLOCK_H
 
+#include <asm/barrier.h>
 #include <asm/clocksource.h>
 #include <asm/pvclock-abi.h>
 
--- a/arch/x86/include/asm/smp.h
+++ b/arch/x86/include/asm/smp.h
@@ -5,8 +5,6 @@
 #include <linux/cpumask.h>
 #include <linux/thread_info.h>
 
-#include <asm/cpumask.h>
-
 DECLARE_PER_CPU_CACHE_HOT(int, cpu_number);
 
 DECLARE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_sibling_map);
--- a/arch/x86/include/asm/vdso/gettimeofday.h
+++ b/arch/x86/include/asm/vdso/gettimeofday.h
@@ -11,13 +11,12 @@
 #define __ASM_VDSO_GETTIMEOFDAY_H
 
 #ifndef __ASSEMBLER__
-
+#include <clocksource/hyperv_timer.h>
 #include <uapi/linux/time.h>
+
 #include <asm/vgtod.h>
 #include <asm/unistd.h>
-#include <asm/msr.h>
 #include <asm/pvclock.h>
-#include <clocksource/hyperv_timer.h>
 #include <asm/vdso/sys_call.h>
 
 #define VDSO_HAS_TIME 1
--- a/arch/x86/kernel/cpu/mce/core.c
+++ b/arch/x86/kernel/cpu/mce/core.c
@@ -48,6 +48,7 @@
 #include <linux/vmcore_info.h>
 
 #include <asm/fred.h>
+#include <asm/cpumask.h>
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/traps.h>
--- a/arch/x86/kernel/nmi.c
+++ b/arch/x86/kernel/nmi.c
@@ -26,6 +26,7 @@
 #include <linux/sched/clock.h>
 #include <linux/kvm_types.h>
 
+#include <asm/cpumask.h>
 #include <asm/cpu_entry_area.h>
 #include <asm/traps.h>
 #include <asm/mach_traps.h>
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -70,6 +70,7 @@
 #include <asm/irq.h>
 #include <asm/realmode.h>
 #include <asm/cpu.h>
+#include <asm/cpumask.h>
 #include <asm/numa.h>
 #include <asm/tlbflush.h>
 #include <asm/mtrr.h>


^ permalink raw reply

* [patch 01/38] percpu: Sanitize __percpu_qual include hell
From: Thomas Gleixner @ 2026-04-10 12:18 UTC (permalink / raw)
  To: LKML
  Cc: Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik, netdev,
	linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
	linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
	Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
	Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
	Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
	linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
	Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
	Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
	linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
	linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
	sparclinux
In-Reply-To: <20260410120044.031381086@kernel.org>

Slapping __percpu_qual into the next available header is sloppy at best.

It's required by __percpu which is defined in compiler_types.h and that is
meant to be included without requiring a boatload of other headers so that
a struct or function declaration can contain a __percpu qualifier w/o
further prerequisites.

This implicit dependency on linux/percpu.h makes that impossible and causes
a major problem when trying to seperate headers.

Create asm/percpu_types.h and move it there. Include that from
compiler_types.h and the whole recursion problem goes away.

Signed-off-by: Thomas Gleixner <tglx@kernel.org
Cc: Arnd Bergmann <arnd@arndb.de>
---
 arch/x86/include/asm/percpu.h       |    5 -----
 arch/x86/include/asm/percpu_types.h |   17 +++++++++++++++++
 include/asm-generic/Kbuild          |    1 +
 include/asm-generic/percpu_types.h  |   20 ++++++++++++++++++++
 include/linux/compiler_types.h      |    1 +
 5 files changed, 39 insertions(+), 5 deletions(-)

--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -40,12 +40,10 @@
 #endif
 
 #define __percpu_prefix
-#define __percpu_seg_override	CONCATENATE(__seg_, __percpu_seg)
 
 #else /* !CONFIG_CC_HAS_NAMED_AS: */
 
 #define __percpu_prefix		__force_percpu_prefix
-#define __percpu_seg_override
 
 #endif /* CONFIG_CC_HAS_NAMED_AS */
 
@@ -82,7 +80,6 @@
 
 #define __force_percpu_prefix
 #define __percpu_prefix
-#define __percpu_seg_override
 
 #define PER_CPU_VAR(var)	(var)__percpu_rel
 
@@ -92,8 +89,6 @@
 # define __my_cpu_type(var)	typeof(var)
 # define __my_cpu_ptr(ptr)	(ptr)
 # define __my_cpu_var(var)	(var)
-
-# define __percpu_qual		__percpu_seg_override
 #else
 # define __my_cpu_type(var)	typeof(var) __percpu_seg_override
 # define __my_cpu_ptr(ptr)	(__my_cpu_type(*(ptr))*)(__force uintptr_t)(ptr)
--- /dev/null
+++ b/arch/x86/include/asm/percpu_types.h
@@ -0,0 +1,17 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_PERCPU_TYPES_H
+#define _ASM_X86_PERCPU_TYPES_H
+
+#if defined(CONFIG_SMP) && defined(CONFIG_CC_HAS_NAMED_AS)
+#define __percpu_seg_override	CONCATENATE(__seg_, __percpu_seg)
+#else /* !CONFIG_CC_HAS_NAMED_AS: */
+#define __percpu_seg_override
+#endif
+
+#if defined(CONFIG_USE_X86_SEG_SUPPORT) && defined(USE_TYPEOF_UNQUAL)
+#define __percpu_qual		__percpu_seg_override
+#endif
+
+#include <asm-generic/percpu_types.h>
+
+#endif
--- a/include/asm-generic/Kbuild
+++ b/include/asm-generic/Kbuild
@@ -44,6 +44,7 @@ mandatory-y += module.lds.h
 mandatory-y += msi.h
 mandatory-y += pci.h
 mandatory-y += percpu.h
+mandatory-y += percpu_types.h
 mandatory-y += pgalloc.h
 mandatory-y += preempt.h
 mandatory-y += rqspinlock.h
--- /dev/null
+++ b/include/asm-generic/percpu_types.h
@@ -0,0 +1,20 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_GENERIC_PERCPU_TYPES_H_
+#define _ASM_GENERIC_PERCPU_TYPES_H_
+
+#ifndef __ASSEMBLER__
+/*
+ * __percpu_qual is the qualifier for the percpu named address space.
+ *
+ * Most arches use generic named address space for percpu variables but
+ * some arches define percpu variables in different named address space
+ * (on the x86 arch, percpu variable may be declared as being relative
+ * to the %fs or %gs segments using __seg_fs or __seg_gs named address
+ * space qualifier).
+ */
+#ifndef __percpu_qual
+# define __percpu_qual
+#endif
+
+#endif /* __ASSEMBLER__ */
+#endif /* _ASM_GENERIC_PERCPU_TYPES_H_ */
--- a/include/linux/compiler_types.h
+++ b/include/linux/compiler_types.h
@@ -41,6 +41,7 @@
 # define BTF_TYPE_TAG(value) /* nothing */
 #endif
 
+#include <asm/percpu_types.h>
 #include <linux/compiler-context-analysis.h>
 
 /* sparse defines __CHECKER__; see Documentation/dev-tools/sparse.rst */


^ permalink raw reply

* [patch 00/38] treewide: Cleanup LATCH, CLOCK_TICK_RATE and get_cycles() [ab]use
From: Thomas Gleixner @ 2026-04-10 12:18 UTC (permalink / raw)
  To: LKML
  Cc: Arnd Bergmann, x86, Lu Baolu, iommu, Michael Grzeschik, netdev,
	linux-wireless, Herbert Xu, linux-crypto, Vlastimil Babka,
	linux-mm, David Woodhouse, Bernie Thompson, linux-fbdev,
	Theodore Tso, linux-ext4, Andrew Morton, Uladzislau Rezki,
	Marco Elver, Dmitry Vyukov, kasan-dev, Andrey Ryabinin,
	Thomas Sailer, linux-hams, Jason A. Donenfeld, Richard Henderson,
	linux-alpha, Russell King, linux-arm-kernel, Catalin Marinas,
	Huacai Chen, loongarch, Geert Uytterhoeven, linux-m68k,
	Dinh Nguyen, Jonas Bonn, linux-openrisc, Helge Deller,
	linux-parisc, Michael Ellerman, linuxppc-dev, Paul Walmsley,
	linux-riscv, Heiko Carstens, linux-s390, David S. Miller,
	sparclinux

First of all sorry for the insanely big Cc list, but people can't make
their mind up whether they want to be Cc'ed on everything or not. So I'm
opting for the worst case to cater to the people who want to be Cc'ed on
everything and assume that the rest of you got used to it by now. I really
wanted this to be more confined but a treewide cleanup does not give a lot
of options.

That said, let me explain what this is about.

  1) LATCH

     The LATCH define goes back to Linux version 0.1 and has survived until
     today for the very wrong reasons.

     Initially it was based on the x86 PIT frequency and also steered the
     timekeeping conversions.

     With the arrival of non x86 architectures it got changed to be based
     on CLOCK_TICK_RATE in order not to change core code which depended on
     LATCH.

     That all got meaningless when timers, timekeeping and scheduling
     infrastructure got rewritten more than two decades ago.

     But there is still a lonely survivor in arch/x86/kernel/apm_32.c
     which dates back to Linux 1.3.46 (Dec. 1995)

     Which causes the next historical gem

  2) CLOCK_TICK_RATE

     When Linux got expanded beyond i386 LATCH was made "flexible" by
     basing it on CLOCK_TICK_RATE to adjust for other frequencies than the
     i386 PIT frequency.

     As LATCH this got meaningless long ago and for amusement value it got
     copied into new architectures arriving way after it got obsolete for
     no reason but with comments to the effect that it's meaningless

     And of course it had a lonely survivor in arch/x86/kernel/setup.c
     despite it being only an alias for PIT_TICK_RATE for a very long time.

  3) get_cycles()

     That was introduced in 2.1.133pre4 (Dec. 1998) to utilize the back
     then brand new TSC. The introduction broke everything except i386 SMP
     with a CPU having a TSC and got then fixed up within a couple of days
     with empty stubs returning 0 and #ifdeffery for CONFIG_TSC before the
     2.2.0 release.

     It's amusing that the naming deliberately ignored that TSC is the
     acronym for Time Stamp Counter and not Cycle Counter and rather went
     for the underlying coincidence that the TSC was running at the same
     fixed frequency as the CPU core.

     That turned out to be interesting when CPUs started to have frequency
     scaling as the TSC then turned into a variable frequency random number
     generator.

     A decade later CPU designers came to senses and made the TSC invariant
     usually running at the nominal CPU frequency, which allowed to use it
     for reliable timekeeping purposes.

     Non x86 architectures implemented get_cycles() based on whatever
     continuously running counter they had available in their CPUs. Some of
     them actual CPU cycle counters, but many of them running at a fixed
     frequency which was completely unrelated to CPU cycles.

     Around 2004/5 the timekeeping subsystem was completely rewritten and
     made generic along with the scheduling clock and other related
     infrastructure. With that rewrite get_cycles() got mostly obsolete,
     but despite it being on the todo list of quite some people it never
     ceased to exist and it was just a conveniance vehicle to base other
     things like the recent addition of random_get_entropy() on top with a
     hideous #ifdef/#define macro maze.

     The other remaining use cases are mostly debugging and testing
     code. Especially the usage in performance test code is hillarious at
     best. While the name get_cycles() suggests that it provides access to
     CPU cycles the reality is that it provides a unspecified counter for
     most systems, where a lot of architectures simply return 0 because
     they either do not have such a counter or did not bother to implement
     it at all.

     So in fact get_cycles() should have been renamed to get_bogo_cycles()
     long ago matching the BogoMIPS "impress your friends" printk which
     still exists for historical amusement value.

     But the real solution is to remove it all together instead of
     proliferating the bogosity.


This is what this series does with the following steps:

   1) Cleanup some header dependency hell which got unearthed by the
      restructuring and went unnoticed so far. It's amazing how the kernel
      build system magically "works". This affects not only x86, but the
      main fallout was observed and fixed there. ARM64 and MIPS are at
      least as bad as they silently rely on the accidental asm/timex.h
      include through a variety of generic headers to make their
      architecture code compile. See the changelog and patches specific to
      those two.

   2) Removal of LATCH

   3) Removal of CLOCK_TICK_RATE

   4) Consolidation of cycles_t which was a typedef in asm/timex.h

   5) Cleanup of read_current_timer() which is only used for delay
      calibration and has nothing to do with get_cycles()

   6) Cleanup of get_cycles() usage in debug and test code

   7) Decoupling of random_get_entropy() from get_cycles()

   8) Removal of asm/timex.h includes except for architecture internal
      usage where necessary.

At the end get_cycles() survives in a couple of architectures as a purely
architecture internal implementation detail.

This survives compile testing on all architectures except hexagon and nios2
because the current cross tools based on gcc15 do not offer a compiler for
them anymore. Boot tested on x86 and some qemu instances covering only a
few architectures.

The series applies on v7.0-rc7 and with very minor conflicts on -next. It
is also available from git:

    git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git getcycles-v1

Thanks,

	tglx
---
 arch/alpha/include/asm/timex.h                 |   33 --------
 arch/arc/include/asm/timex.h                   |   15 ---
 arch/arm/include/asm/timex.h                   |   16 ---
 arch/arm64/include/asm/timex.h                 |   18 ----
 arch/hexagon/include/asm/timex.h               |   23 -----
 arch/m68k/include/asm/timex.h                  |   42 ----------
 arch/microblaze/include/asm/timex.h            |   13 ---
 arch/mips/include/asm/timex.h                  |  102 -------------------------
 arch/sh/include/asm/timex.h                    |   24 -----
 arch/sparc/include/asm/timex.h                 |    9 --
 arch/sparc/include/asm/timex_32.h              |   14 ---
 arch/um/include/asm/timex.h                    |    9 --
 b/Documentation/fb/udlfb.rst                   |    4 
 b/arch/Kconfig                                 |   10 ++
 b/arch/alpha/Kconfig                           |    1 
 b/arch/alpha/include/asm/random.h              |   14 +++
 b/arch/arm/Kconfig                             |    2 
 b/arch/arm/include/asm/delay.h                 |    1 
 b/arch/arm/include/asm/random.h                |   14 +++
 b/arch/arm/lib/delay.c                         |   14 +--
 b/arch/arm/mach-omap1/Kconfig                  |    2 
 b/arch/arm64/Kconfig                           |    2 
 b/arch/arm64/include/asm/io.h                  |    5 -
 b/arch/arm64/include/asm/ptp_vmclock.h         |   12 ++
 b/arch/arm64/include/asm/random.h              |   11 ++
 b/arch/arm64/include/asm/rqspinlock.h          |    1 
 b/arch/arm64/kernel/time.c                     |    6 +
 b/arch/arm64/kernel/topology.c                 |    1 
 b/arch/arm64/kernel/traps.c                    |    1 
 b/arch/arm64/kvm/emulate-nested.c              |    1 
 b/arch/arm64/kvm/hyp/include/hyp/switch.h      |    1 
 b/arch/arm64/lib/delay.c                       |    1 
 b/arch/hexagon/Kconfig                         |    1 
 b/arch/hexagon/kernel/time.c                   |    8 +
 b/arch/loongarch/Kconfig                       |    1 
 b/arch/loongarch/include/asm/random.h          |   15 +++
 b/arch/loongarch/include/asm/timex.h           |    2 
 b/arch/loongarch/kernel/relocate.c             |    1 
 b/arch/loongarch/kernel/syscall.c              |    1 
 b/arch/loongarch/lib/delay.c                   |    2 
 b/arch/m68k/Kconfig                            |    1 
 b/arch/m68k/amiga/config.c                     |    1 
 b/arch/m68k/include/asm/random.h               |   14 +++
 b/arch/m68k/kernel/time.c                      |    2 
 b/arch/mips/Kconfig                            |    1 
 b/arch/mips/generic/init.c                     |    1 
 b/arch/mips/include/asm/random.h               |    7 +
 b/arch/mips/kernel/pm-cps.c                    |    1 
 b/arch/mips/kernel/proc.c                      |    1 
 b/arch/mips/kernel/relocate.c                  |    2 
 b/arch/mips/kernel/time.c                      |   53 ++++++++++++
 b/arch/mips/lib/dump_tlb.c                     |    1 
 b/arch/mips/mm/cache.c                         |    1 
 b/arch/nios2/Kconfig                           |    1 
 b/arch/nios2/include/asm/random.h              |   14 +++
 b/arch/nios2/include/asm/timex.h               |    7 -
 b/arch/nios2/kernel/time.c                     |    4 
 b/arch/openrisc/Kconfig                        |    2 
 b/arch/openrisc/include/asm/random.h           |   12 ++
 b/arch/openrisc/include/asm/timex.h            |   10 --
 b/arch/openrisc/lib/delay.c                    |    8 -
 b/arch/parisc/Kconfig                          |    1 
 b/arch/parisc/include/asm/random.h             |   12 ++
 b/arch/parisc/include/asm/timex.h              |   10 --
 b/arch/parisc/kernel/processor.c               |    1 
 b/arch/parisc/kernel/time.c                    |    1 
 b/arch/powerpc/Kconfig                         |    1 
 b/arch/powerpc/include/asm/random.h            |   13 +++
 b/arch/powerpc/include/asm/timex.h             |   25 ------
 b/arch/powerpc/platforms/cell/spufs/switch.c   |    5 -
 b/arch/riscv/Kconfig                           |    2 
 b/arch/riscv/include/asm/random.h              |   25 ++++++
 b/arch/riscv/include/asm/timex.h               |   23 -----
 b/arch/riscv/kernel/unaligned_access_speed.c   |    1 
 b/arch/riscv/kvm/vcpu_timer.c                  |    1 
 b/arch/riscv/lib/delay.c                       |    8 +
 b/arch/s390/Kconfig                            |    1 
 b/arch/s390/include/asm/random.h               |   12 ++
 b/arch/s390/include/asm/timex.h                |   10 --
 b/arch/s390/kernel/time.c                      |    1 
 b/arch/s390/kernel/vtime.c                     |    1 
 b/arch/sparc/Kconfig                           |    2 
 b/arch/sparc/include/asm/random.h              |   15 +++
 b/arch/sparc/include/asm/timex_64.h            |   20 ----
 b/arch/sparc/kernel/pcic.c                     |    1 
 b/arch/sparc/kernel/time_32.c                  |    1 
 b/arch/sparc/kernel/time_64.c                  |    4 
 b/arch/sparc/vdso/vclock_gettime.c             |    1 
 b/arch/x86/Kconfig                             |    4 
 b/arch/x86/include/asm/iommu.h                 |    3 
 b/arch/x86/include/asm/msr.h                   |    5 -
 b/arch/x86/include/asm/percpu.h                |    5 -
 b/arch/x86/include/asm/percpu_types.h          |   17 ++++
 b/arch/x86/include/asm/ptp_vmclock.h           |   12 ++
 b/arch/x86/include/asm/pvclock.h               |    1 
 b/arch/x86/include/asm/random.h                |   12 --
 b/arch/x86/include/asm/smp.h                   |    2 
 b/arch/x86/include/asm/tsc.h                   |   11 --
 b/arch/x86/include/asm/vdso/gettimeofday.h     |    5 -
 b/arch/x86/kernel/apm_32.c                     |    4 
 b/arch/x86/kernel/cpu/mce/core.c               |    1 
 b/arch/x86/kernel/nmi.c                        |    1 
 b/arch/x86/kernel/setup.c                      |    2 
 b/arch/x86/kernel/smpboot.c                    |    1 
 b/arch/x86/kernel/tsc.c                        |   12 +-
 b/arch/x86/lib/delay.c                         |    8 -
 b/crypto/jitterentropy-kcapi.c                 |    1 
 b/crypto/tcrypt.c                              |   84 ++++++++++----------
 b/drivers/iommu/intel/dmar.c                   |    4 
 b/drivers/iommu/intel/iommu.h                  |    8 +
 b/drivers/irqchip/irq-apple-aic.c              |    1 
 b/drivers/misc/sgi-gru/gruhandles.c            |   20 +---
 b/drivers/misc/sgi-gru/grukservices.c          |    3 
 b/drivers/misc/sgi-gru/grutlbpurge.c           |    5 -
 b/drivers/net/arcnet/arc-rimi.c                |    4 
 b/drivers/net/arcnet/arcdevice.h               |   20 ----
 b/drivers/net/arcnet/com20020.c                |    6 -
 b/drivers/net/arcnet/com90io.c                 |    6 -
 b/drivers/net/arcnet/com90xx.c                 |    4 
 b/drivers/net/hamradio/baycom_epp.c            |   51 ------------
 b/drivers/net/wireless/ath/wil6210/debugfs.c   |    2 
 b/drivers/net/wireless/ath/wil6210/txrx.c      |    6 -
 b/drivers/net/wireless/ath/wil6210/txrx_edma.c |    4 
 b/drivers/net/wireless/ath/wil6210/wil6210.h   |    3 
 b/drivers/ptp/Kconfig                          |    6 -
 b/drivers/ptp/ptp_vmclock.c                    |    6 -
 b/drivers/video/fbdev/udlfb.c                  |   24 ++---
 b/fs/ext4/mballoc.c                            |    4 
 b/include/asm-generic/Kbuild                   |    2 
 b/include/asm-generic/percpu_types.h           |   20 ++++
 b/include/linux/compiler_types.h               |    1 
 b/include/linux/delay.h                        |    2 
 b/include/linux/jiffies.h                      |    3 
 b/include/linux/random.h                       |   18 ++++
 b/include/linux/timex.h                        |   26 ------
 b/include/linux/types.h                        |    6 +
 b/init/calibrate.c                             |   19 ++--
 b/kernel/kcsan/core.c                          |    3 
 b/kernel/kcsan/debugfs.c                       |    8 -
 b/kernel/time/timer.c                          |    1 
 b/lib/interval_tree_test.c                     |   17 +---
 b/lib/rbtree_test.c                            |   47 +++++------
 b/lib/test_vmalloc.c                           |   10 +-
 b/mm/kasan/sw_tags.c                           |    2 
 b/mm/slub.c                                    |   37 +++++----
 include/asm-generic/timex.h                    |   23 -----
 146 files changed, 622 insertions(+), 796 deletions(-)



^ permalink raw reply

* Re: [PATCH] rtw88: add TX power limit support to 114 and 130 channels
From: Thadeu Lima de Souza Cascardo @ 2026-04-10 10:15 UTC (permalink / raw)
  To: Ping-Ke Shih
  Cc: Kalle Valo, Yan-Hsuan Chuang, linux-wireless@vger.kernel.org,
	kernel-dev@igalia.com
In-Reply-To: <55c23c5551354c6f8752d620f268b37b@realtek.com>

On Fri, Apr 10, 2026 at 03:56:11AM +0000, Ping-Ke Shih wrote:
> Thadeu Lima de Souza Cascardo <cascardo@igalia.com> wrote:
> > Though 114 and 130 are not usual channels, they are found in the wild with
> > setups using 5350MHz as the center frequency of a 80MHz setup.
> 
> What did the AP setup? channel 114 160MHz?
> I wonder why rtw88 can select a not usual channel 114 80MHz.
> 
> Please share your environment setup. 
> 

This is a Mikrotik that uses channel 130 at 80MHz.

> > 
> > rtw88 supports that, but issues a WARNING because it cannot find the TX
> > power limit for those channels.
> 
> Actually, rtw88 hardware can't support that, so we are working on patch
> to avoid selecting unusual channels. Can it work properly with
> the AP after this patch?
> 

It does work just fine even without the patch. The only issue is the
WARNING that is triggered.

Regards.
Cascardo.

> Ping-Ke
> 

^ permalink raw reply

* [bug report] wifi: mt76: mt7996: Integrate MT7990 dma configuration for NPU
From: Dan Carpenter @ 2026-04-10 10:13 UTC (permalink / raw)
  To: Lorenzo Bianconi; +Cc: linux-wireless, linux-mediatek

Hello Lorenzo Bianconi,

Commit cd7951f242a7 ("wifi: mt76: mt7996: Integrate MT7990 dma
configuration for NPU") from Jan 22, 2026 (linux-next), leads to the
following Smatch static checker warning:

	drivers/net/wireless/mediatek/mt76/mt7996/dma.c:683 mt7996_dma_init()
	error: NULL dereference inside function mt7996_init_tx_queues()

drivers/net/wireless/mediatek/mt76/mt7996/dma.c
    664 int mt7996_dma_init(struct mt7996_dev *dev)
    665 {
    666         struct mtk_wed_device *wed = &dev->mt76.mmio.wed;
    667         struct mtk_wed_device *wed_hif2 = &dev->mt76.mmio.wed_hif2;
    668         u32 rx_base;
    669         u32 hif1_ofs = 0;
    670         int ret;
    671 
    672         mt7996_dma_config(dev);
    673 
    674         mt76_dma_attach(&dev->mt76);
    675 
    676         if (dev->hif2)
    677                 hif1_ofs = MT_WFDMA0_PCIE1(0) - MT_WFDMA0(0);
    678 
    679         mt7996_dma_disable(dev, true);
    680 
    681         /* init tx queue */
    682         if (is_mt7996(&dev->mt76) && mt76_npu_device_active(&dev->mt76))
--> 683                 ret = mt7996_init_tx_queues(&dev->phy, MT_TXQ_ID(0),
    684                                             MT7996_NPU_TX_RING_SIZE,
    685                                             MT_TXQ_RING_BASE(0) + hif1_ofs,
    686                                             NULL);
                                                    ^^^^
Can't pass NULL here.  It leads to a crash.  Use wed?

    687         else
    688                 ret = mt7996_init_tx_queues(&dev->phy,
    689                                             MT_TXQ_ID(dev->mphy.band_idx),
    690                                             MT7996_TX_RING_SIZE,
    691                                             MT_TXQ_RING_BASE(0), wed);
    692         if (ret)
    693                 return ret;
    694 

This email is a free service from the Smatch-CI project [smatch.sf.net].

regards,
dan carpenter

^ permalink raw reply

* [bug report] wifi: mt76: mt7921: handle MT7902 irq_map quirk with mutable copy
From: Dan Carpenter @ 2026-04-10 10:13 UTC (permalink / raw)
  To: Sean Wang; +Cc: linux-wireless, linux-mediatek

Hello Sean Wang,

Commit 222606f43b58 ("wifi: mt76: mt7921: handle MT7902 irq_map quirk
with mutable copy") from Feb 18, 2026 (linux-next), leads to the
following Smatch static checker warning:

	drivers/net/wireless/mediatek/mt76/mt7921/pci.c:363 mt7921_pci_probe()
	warn: missing unwind goto?

drivers/net/wireless/mediatek/mt76/mt7921/pci.c
    258 static int mt7921_pci_probe(struct pci_dev *pdev,
    259                             const struct pci_device_id *id)
    260 {
    261         static const struct mt76_driver_ops drv_ops = {
    262                 /* txwi_size = txd size + txp size */
    263                 .txwi_size = MT_TXD_SIZE + sizeof(struct mt76_connac_hw_txp),
    264                 .drv_flags = MT_DRV_TXWI_NO_FREE | MT_DRV_HW_MGMT_TXQ |
    265                              MT_DRV_AMSDU_OFFLOAD,
    266                 .survey_flags = SURVEY_INFO_TIME_TX |
    267                                 SURVEY_INFO_TIME_RX |
    268                                 SURVEY_INFO_TIME_BSS_RX,
    269                 .token_size = MT7921_TOKEN_SIZE,
    270                 .tx_prepare_skb = mt7921e_tx_prepare_skb,
    271                 .tx_complete_skb = mt76_connac_tx_complete_skb,
    272                 .rx_check = mt7921_rx_check,
    273                 .rx_skb = mt7921_queue_rx_skb,
    274                 .rx_poll_complete = mt792x_rx_poll_complete,
    275                 .sta_add = mt7921_mac_sta_add,
    276                 .sta_event = mt7921_mac_sta_event,
    277                 .sta_remove = mt7921_mac_sta_remove,
    278                 .update_survey = mt792x_update_channel,
    279                 .set_channel = mt7921_set_channel,
    280         };
    281         static const struct mt792x_hif_ops mt7921_pcie_ops = {
    282                 .init_reset = mt7921e_init_reset,
    283                 .reset = mt7921e_mac_reset,
    284                 .mcu_init = mt7921e_mcu_init,
    285                 .drv_own = mt792xe_mcu_drv_pmctrl,
    286                 .fw_own = mt792xe_mcu_fw_pmctrl,
    287         };
    288         static const struct mt792x_irq_map irq_map = {
    289                 .host_irq_enable = MT_WFDMA0_HOST_INT_ENA,
    290                 .tx = {
    291                         .all_complete_mask = MT_INT_TX_DONE_ALL,
    292                         .mcu_complete_mask = MT_INT_TX_DONE_MCU,
    293                 },
    294                 .rx = {
    295                         .data_complete_mask = MT_INT_RX_DONE_DATA,
    296                         .wm_complete_mask = MT_INT_RX_DONE_WM,
    297                         .wm2_complete_mask = MT_INT_RX_DONE_WM2,
    298                 },
    299         };
    300         struct ieee80211_ops *ops;
    301         struct mt76_bus_ops *bus_ops;
    302         struct mt792x_dev *dev;
    303         struct mt76_dev *mdev;
    304         void __iomem *regs;
    305         u16 cmd, chipid;
    306         u8 features;
    307         int ret;
    308 
    309         ret = pcim_enable_device(pdev);
    310         if (ret)
    311                 return ret;
    312 
    313         pci_read_config_word(pdev, PCI_COMMAND, &cmd);
    314         if (!(cmd & PCI_COMMAND_MEMORY)) {
    315                 cmd |= PCI_COMMAND_MEMORY;
    316                 pci_write_config_word(pdev, PCI_COMMAND, cmd);
    317         }
    318         pci_set_master(pdev);
    319 
    320         ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
    321         if (ret < 0)
    322                 return ret;
    323 
    324         ret = dma_set_mask(&pdev->dev, DMA_BIT_MASK(32));
    325         if (ret)
    326                 goto err_free_pci_vec;
    327 
    328         if (mt7921_disable_aspm)
    329                 mt76_pci_disable_aspm(pdev);
    330 
    331         ops = mt792x_get_mac80211_ops(&pdev->dev, &mt7921_ops,
    332                                       (void *)id->driver_data, &features);
    333         if (!ops) {
    334                 ret = -ENOMEM;
    335                 goto err_free_pci_vec;
    336         }
    337 
    338         mdev = mt76_alloc_device(&pdev->dev, sizeof(*dev), ops, &drv_ops);
    339         if (!mdev) {
    340                 ret = -ENOMEM;
    341                 goto err_free_pci_vec;
    342         }
    343 
    344         pci_set_drvdata(pdev, mdev);
    345 
    346         regs =  pcim_iomap_region(pdev, 0, pci_name(pdev));
    347         if (IS_ERR(regs))
    348                 return PTR_ERR(regs);

Need to goto to err_free_pci_vec before returning

    349 
    350         dev = container_of(mdev, struct mt792x_dev, mt76);
    351         dev->fw_features = features;
    352         dev->hif_ops = &mt7921_pcie_ops;
    353         dev->irq_map = &irq_map;
    354         mt76_mmio_init(&dev->mt76, regs);
    355 
    356         if (id->device == 0x7902) {
    357                 struct mt792x_irq_map *map;
    358 
    359                 /* MT7902 needs a mutable copy because wm2_complete_mask differs */
    360                 map = devm_kmemdup(&pdev->dev, &irq_map,
    361                                    sizeof(irq_map), GFP_KERNEL);
    362                 if (!map)
--> 363                         return -ENOMEM;

Same.

    364 
    365                 map->rx.wm2_complete_mask = 0;
    366                 dev->irq_map = map;
    367         }
    368 
    369         tasklet_init(&mdev->irq_tasklet, mt792x_irq_tasklet, (unsigned long)dev);
    370 
    371         dev->phy.dev = dev;
    372         dev->phy.mt76 = &dev->mt76.phy;
    373         dev->mt76.phy.priv = &dev->phy;
    374         dev->bus_ops = dev->mt76.bus;
    375         bus_ops = devm_kmemdup(dev->mt76.dev, dev->bus_ops, sizeof(*bus_ops),
    376                                GFP_KERNEL);
    377         if (!bus_ops) {
    378                 ret = -ENOMEM;
    379                 goto err_free_dev;
    380         }
    381 
    382         bus_ops->rr = mt7921_rr;
    383         bus_ops->wr = mt7921_wr;
    384         bus_ops->rmw = mt7921_rmw;
    385         dev->mt76.bus = bus_ops;
    386 
    387         if (!mt7921_disable_aspm && mt76_pci_aspm_supported(pdev))
    388                 dev->aspm_supported = true;
    389 
    390         ret = mt792xe_mcu_fw_pmctrl(dev);
    391         if (ret)
    392                 goto err_free_dev;
    393 
    394         ret = __mt792xe_mcu_drv_pmctrl(dev);
    395         if (ret)
    396                 goto err_free_dev;
    397 
    398         chipid = mt7921_l1_rr(dev, MT_HW_CHIPID);
    399         if (chipid == 0x7961 && (mt7921_l1_rr(dev, MT_HW_BOUND) & BIT(7)))
    400                 chipid = 0x7920;
    401         mdev->rev = (chipid << 16) |
    402                     (mt7921_l1_rr(dev, MT_HW_REV) & 0xff);
    403         dev_info(mdev->dev, "ASIC revision: %04x\n", mdev->rev);
    404 
    405         ret = mt792x_wfsys_reset(dev);
    406         if (ret)
    407                 goto err_free_dev;
    408 
    409         mt76_wr(dev, irq_map.host_irq_enable, 0);
    410 
    411         mt76_wr(dev, MT_PCIE_MAC_INT_ENABLE, 0xff);
    412 
    413         ret = devm_request_irq(mdev->dev, pdev->irq, mt792x_irq_handler,
    414                                IRQF_SHARED, KBUILD_MODNAME, dev);
    415         if (ret)
    416                 goto err_free_dev;
    417 
    418         ret = mt7921_dma_init(dev);
    419         if (ret)
    420                 goto err_free_irq;
    421 
    422         ret = mt7921_register_device(dev);
    423         if (ret)
    424                 goto err_free_irq;
    425 
    426         if (of_property_read_bool(dev->mt76.dev->of_node, "wakeup-source"))
    427                 device_init_wakeup(dev->mt76.dev, true);
    428 
    429         return 0;
    430 
    431 err_free_irq:
    432         devm_free_irq(&pdev->dev, pdev->irq, dev);
    433 err_free_dev:
    434         mt76_free_device(&dev->mt76);
    435 err_free_pci_vec:
    436         pci_free_irq_vectors(pdev);
    437 
    438         return ret;
    439 }

This email is a free service from the Smatch-CI project [smatch.sf.net].

regards,
dan carpenter

^ permalink raw reply

* [PATCH 2/2] wifi: rtw89: phy: make RF calibration timeouts non-fatal on USB
From: Louis Kotze @ 2026-04-10  8:00 UTC (permalink / raw)
  To: linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel, Louis Kotze
In-Reply-To: <20260410080017.82946-1-loukot@gmail.com>

On USB adapters, RF calibration timeouts can still occasionally occur
despite the increased timeout values, particularly under system load
or USB bus contention. However, the radio typically continues to
operate correctly despite an incomplete calibration — the timeout
does not indicate a hardware failure.

Make calibration timeouts and bad state returns non-fatal on USB by
logging at debug level and continuing, rather than returning
-ETIMEDOUT/-EFAULT which can cascade into a connection failure or
disconnect.

PCIe error handling is unchanged — timeouts remain fatal on PCIe
where they indicate a real problem.

Signed-off-by: Louis Kotze <loukot@gmail.com>
---
 drivers/net/wireless/realtek/rtw89/phy.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index 4d809df8b..a06bea88e 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3972,9 +3972,21 @@ int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name,
 	time_left = wait_for_completion_timeout(&wait->completion,
 						msecs_to_jiffies(ms));
 	if (time_left == 0) {
+		if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) {
+			rtw89_debug(rtwdev, RTW89_DBG_RFK,
+				    "RF %s timeout (non-fatal on USB)\n",
+				    rfk_name);
+			goto out;
+		}
 		rtw89_warn(rtwdev, "failed to wait RF %s\n", rfk_name);
 		return -ETIMEDOUT;
 	} else if (wait->state != RTW89_RFK_STATE_OK) {
+		if (rtwdev->hci.type == RTW89_HCI_TYPE_USB) {
+			rtw89_debug(rtwdev, RTW89_DBG_RFK,
+				    "RF %s state %d (non-fatal on USB)\n",
+				    rfk_name, wait->state);
+			goto out;
+		}
 		rtw89_warn(rtwdev, "failed to do RF %s result from state %d\n",
 			   rfk_name, wait->state);
 		return -EFAULT;
-- 
2.53.0


^ permalink raw reply related

* [PATCH 1/2] wifi: rtw89: phy: increase RF calibration timeouts for USB transport
From: Louis Kotze @ 2026-04-10  8:00 UTC (permalink / raw)
  To: linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel, Louis Kotze
In-Reply-To: <20260410080017.82946-1-loukot@gmail.com>

USB transport adds significant latency to H2C/C2H round-trips used
by RF calibration. The existing timeout values were designed for PCIe
and are too tight for USB, causing "failed to wait RF DACK",
"failed to wait RF TSSI" and similar errors on USB adapters.

Apply a 4x timeout multiplier when the device uses USB transport.
The multiplier is applied in rtw89_phy_rfk_report_wait() so all
calibrations benefit without changing any call sites or PCIe
timeout values.

The 4x multiplier was chosen based on measured data from two
independent testers (RTL8922AU, 6GHz MLO and 2.4/5GHz):

  Calibration   PCIe timeout   Max measured (USB)   4x timeout
  PRE_NTFY           5ms              1ms              20ms
  DACK              58ms             72ms             232ms
  RX_DCK           128ms            374ms             512ms
  TSSI normal       20ms             24ms              80ms
  TSSI scan          6ms             14ms              24ms
  TXGAPK            54ms             18ms             216ms
  IQK               84ms             53ms             336ms
  DPK               34ms             30ms             136ms

Tested with RTL8922AU on 6GHz MLO (5GHz + 6GHz simultaneous):
25 connect/disconnect cycles with zero failures.

Signed-off-by: Louis Kotze <loukot@gmail.com>
---
 drivers/net/wireless/realtek/rtw89/phy.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/drivers/net/wireless/realtek/rtw89/phy.c b/drivers/net/wireless/realtek/rtw89/phy.c
index e70d0e283..4d809df8b 100644
--- a/drivers/net/wireless/realtek/rtw89/phy.c
+++ b/drivers/net/wireless/realtek/rtw89/phy.c
@@ -3956,6 +3956,13 @@ int rtw89_phy_rfk_report_wait(struct rtw89_dev *rtwdev, const char *rfk_name,
 	struct rtw89_rfk_wait_info *wait = &rtwdev->rfk_wait;
 	unsigned long time_left;
 
+	/* USB transport adds latency to H2C/C2H round-trips, so RF
+	 * calibrations take longer than on PCIe. Apply a 4x multiplier
+	 * to avoid spurious timeouts.
+	 */
+	if (rtwdev->hci.type == RTW89_HCI_TYPE_USB)
+		ms *= 4;
+
 	/* Since we can't receive C2H event during SER, use a fixed delay. */
 	if (test_bit(RTW89_FLAG_SER_HANDLING, rtwdev->flags)) {
 		fsleep(1000 * ms / 2);
-- 
2.53.0


^ permalink raw reply related

* [PATCH 0/2] wifi: rtw89: fix RF calibration for USB transport
From: Louis Kotze @ 2026-04-10  8:00 UTC (permalink / raw)
  To: linux-wireless; +Cc: pkshih, rtl8821cerfe2, linux-kernel, Louis Kotze
In-Reply-To: <795a8567fdbe48babc5cf0f2b5e10c0a@realtek.com>

RF calibration on USB adapters (RTL8922AU) fails frequently because the
timeout values in rtw89_phy_rfk_report_wait() are designed for PCIe and
too tight for USB H2C/C2H round-trip latency.

Patch 1 applies a 4x timeout multiplier for USB devices, based on
measured calibration times from two independent testers across 2.4GHz,
5GHz, and 6GHz bands.

Patch 2 makes calibration timeouts non-fatal on USB, since the radio
continues to operate correctly despite occasional incomplete
calibrations. PCIe error handling is unchanged.

This is based on Ping-Ke's suggestion in the RTL8922AU support thread:
https://lore.kernel.org/linux-wireless/795a8567fdbe48babc5cf0f2b5e10c0a@realtek.com/

Louis Kotze (2):
  wifi: rtw89: phy: increase RF calibration timeouts for USB transport
  wifi: rtw89: phy: make RF calibration timeouts non-fatal on USB

 drivers/net/wireless/realtek/rtw89/phy.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

-- 
2.53.0


^ permalink raw reply

* Re: [PATCH] ath10k: skip quiet mode for WCN3990 to prevent firmware crash
From: Baochen Qiang @ 2026-04-10  7:38 UTC (permalink / raw)
  To: Malte Schababerle; +Cc: ath10k, linux-wireless
In-Reply-To: <20260406221405.201848-1-m.schababerle@gmail.com>



On 4/7/2026 6:14 AM, Malte Schababerle wrote:
> On 3/22/2026, Baochen Qiang wrote:
>> Malte, the firmware team needs firmware dump to understand this issue,
>> would you be able to help collect it?
> 
> Sure. Attaching the full dmesg from a reproducible test run (kernel
> without the patch, upstream 6.17, postmarketOS on OnePlus 7T / SM8150).
> 
> Firmware: WLAN.HL.3.2.0.c2-00006
> 
> The crash triggers deterministically on every boot. Key lines:
> 
>   [25.122098] PDM: service 'wlan_process' crash:
>                'EX:wlan_process:0x1:WLAN RT:0x2076:PC=0xb0008e20'
>   [25.283364] ath10k_snoc 18800000.wifi: firmware crashed!
> 
> Full crash sequence repeats across subsequent recovery attempts at the
> same PC=0xb0008e20 (see attached dmesg.txt).
> 
> Note: I'm running an upstream kernel (6.17) on postmarketOS.
> CONFIG_QCOM_RAMDUMP and WCSS coredump tooling are not available here.
> If the firmware team needs a full Hexagon register dump, please advise
> how to collect it in this environment.

please follow below steps to collect firmware dump:

1. sudo modprobe -r ath10k_pci
2. sudo modprobe ath10k_core coredump_mask=7
3. sudo modprobe ath10k_pci
4. reproduce the crash issue
5. collect dump using a similar way to Intel chip [1]:

	You can now get the data from the devcoredump device and dump to a file:

	cat /sys/devices/virtual/devcoredump/devcdY/data > iwl.dump
	echo 1 > /sys/devices/virtual/devcoredump/devcdY/data
	(Y is incremented each time)

	The easiest is to define a udev rule to dump the data automatically as soon as
	dump is created:

	SUBSYSTEM=="devcoredump", ACTION=="add", RUN+="/sbin/iwlfwdump.sh"
	You’ll typically have to paste this into a new file called /etc/udev/rules.d/85-
	iwl-dump.rules. This location can vary between distributions.

	/sbin/iwlfwdump.sh can simply be:

	#!/bin/bash

	timestamp=$(date +%F_%H-%M-%S)
	filename=/var/log/iwl-fw-error_${timestamp}.dump
	cat /sys/${DEVPATH}/data > ${filename}
	echo 1 > /sys/${DEVPATH}/data

	This way, each time a dump is created it will automatically land on your file
	system. Remember to make the /sbin/iwlfwdump.sh file executable (i.e. chmod a+x
	/sbin/iwlfwdump.sh), so that the udev rule can execute it, otherwise it won’t
	work.

[1]
https://wireless.docs.kernel.org/en/latest/en/users/drivers/iwlwifi/debugging.html#how-to-provide-information-to-debug-the-firmware

> 
> Tested-by: Malte Schababerle <m.schababerle@gmail.com>
>   on OnePlus 7T (SM8150/WCN3990), kernel 6.17, FW WLAN.HL.3.2.0.c2-00006


^ permalink raw reply

* [PATCH ath-next] wifi: ath12k: fix OF node refcount imbalance in WSI graph traversal
From: Aaradhana Sahu @ 2026-04-10  7:13 UTC (permalink / raw)
  To: ath12k; +Cc: linux-wireless, Aaradhana Sahu

ath12k_core_get_wsi_info() traverses the WSI (Wired Serial Interface)
device graph starting from dev->of_node. The current code uses
dev->of_node directly as the local traversal pointer and calls
of_node_put() on error.

Since the driver does not own a reference to dev->of_node, dropping it
during traversal results in the following OF refcount underflow:

OF: ERROR: of_node_release() detected bad of_node_put() on /soc@0/wifi@c000000
CPU: 1 UID: 0 PID: 210 Comm: insmod Not tainted 6.19.0-rc4-next-20260109-00023-g797dd36dc178 #26 PREEMPT
Hardware name: Qualcomm Technologies, Inc. IPQ5332 MI01.2 (DT)
Call trace:
 show_stack+0x18/0x24 (C)
 dump_stack_lvl+0x60/0x80
 dump_stack+0x18/0x24
 of_node_release+0x164/0x1a0
 kobject_put+0xb4/0x278
 of_node_put+0x18/0x28
 ath12k_core_init+0x29c/0x5d4 [ath12k]
 ath12k_ahb_probe+0x950/0xc14 [ath12k]
 platform_probe+0x5c/0xa4
 really_probe+0xc0/0x3ec
 __driver_probe_device+0x80/0x170
 driver_probe_device+0x3c/0x120
 __driver_attach+0xc4/0x218
OF: ERROR: next of_node_put() on this node will result in a kobject warning 'refcount_t: underflow; use-after-free.'

Fix this by explicitly acquiring a reference to the starting node
using of_node_get() and attaching automatic cleanup via
__free(device_node).

Each discovered WSI node is stored in ag->wsi_node[] with its own
of_node_get() reference. These references are later released in
ath12k_core_free_wsi_info() during driver teardown.

Also remove unnecessary memset() of wsi_node array since cleanup now
explicitly sets pointers to NULL.

Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.6-01243-QCAHKSWPL_SILICONZ-1
Tested-on: IPQ5332 hw1.0 AHB WLAN.WBE.1.6-01275-QCAHKSWPL_SILICONZ-1

Fixes: 908c10c860e0 ("wifi: ath12k: parse multiple device information from Device Tree")
Signed-off-by: Aaradhana Sahu <aaradhana.sahu@oss.qualcomm.com>
---
 drivers/net/wireless/ath/ath12k/core.c | 77 ++++++++++++++++----------
 1 file changed, 48 insertions(+), 29 deletions(-)

diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
index 2519e2400d58..980a12fb2c6e 100644
--- a/drivers/net/wireless/ath/ath12k/core.c
+++ b/drivers/net/wireless/ath/ath12k/core.c
@@ -1838,10 +1838,22 @@ static struct ath12k_hw_group *ath12k_core_hw_group_alloc(struct ath12k_base *ab
 	return ag;
 }
 
+static void ath12k_core_free_wsi_info(struct ath12k_hw_group *ag)
+{
+	int i;
+
+	for (i = 0; i < ag->num_devices; i++) {
+		of_node_put(ag->wsi_node[i]);
+		ag->wsi_node[i] = NULL;
+	}
+	ag->num_devices = 0;
+}
+
 static void ath12k_core_hw_group_free(struct ath12k_hw_group *ag)
 {
 	mutex_lock(&ath12k_hw_group_mutex);
 
+	ath12k_core_free_wsi_info(ag);
 	list_del(&ag->list);
 	kfree(ag);
 
@@ -1867,52 +1879,59 @@ static struct ath12k_hw_group *ath12k_core_hw_group_find_by_dt(struct ath12k_bas
 static int ath12k_core_get_wsi_info(struct ath12k_hw_group *ag,
 				    struct ath12k_base *ab)
 {
-	struct device_node *wsi_dev = ab->dev->of_node, *next_wsi_dev;
-	struct device_node *tx_endpoint, *next_rx_endpoint;
-	int device_count = 0;
-
-	next_wsi_dev = wsi_dev;
+	struct device_node *next_wsi_dev;
+	int device_count = 0, ret = 0;
+	struct device_node *wsi_dev;
 
-	if (!next_wsi_dev)
+	wsi_dev = of_node_get(ab->dev->of_node);
+	if (!wsi_dev)
 		return -ENODEV;
 
 	do {
-		ag->wsi_node[device_count] = next_wsi_dev;
+		if (device_count >= ATH12K_MAX_DEVICES) {
+			ath12k_warn(ab, "device count in DT %d is more than limit %d\n",
+				    device_count, ATH12K_MAX_DEVICES);
+			ret = -EINVAL;
+			break;
+		}
+
+		ag->wsi_node[device_count++] = of_node_get(wsi_dev);
 
-		tx_endpoint = of_graph_get_endpoint_by_regs(next_wsi_dev, 0, -1);
+		struct device_node *tx_endpoint __free(device_node) =
+					of_graph_get_endpoint_by_regs(wsi_dev, 0, -1);
 		if (!tx_endpoint) {
-			of_node_put(next_wsi_dev);
-			return -ENODEV;
+			ret = -ENODEV;
+			break;
 		}
 
-		next_rx_endpoint = of_graph_get_remote_endpoint(tx_endpoint);
+		struct device_node *next_rx_endpoint __free(device_node) =
+					of_graph_get_remote_endpoint(tx_endpoint);
 		if (!next_rx_endpoint) {
-			of_node_put(next_wsi_dev);
-			of_node_put(tx_endpoint);
-			return -ENODEV;
+			ret = -ENODEV;
+			break;
 		}
 
-		of_node_put(tx_endpoint);
-		of_node_put(next_wsi_dev);
-
 		next_wsi_dev = of_graph_get_port_parent(next_rx_endpoint);
 		if (!next_wsi_dev) {
-			of_node_put(next_rx_endpoint);
-			return -ENODEV;
+			ret = -ENODEV;
+			break;
 		}
 
-		of_node_put(next_rx_endpoint);
+		of_node_put(wsi_dev);
+		wsi_dev = next_wsi_dev;
+	} while (ab->dev->of_node != wsi_dev);
 
-		device_count++;
-		if (device_count > ATH12K_MAX_DEVICES) {
-			ath12k_warn(ab, "device count in DT %d is more than limit %d\n",
-				    device_count, ATH12K_MAX_DEVICES);
-			of_node_put(next_wsi_dev);
-			return -EINVAL;
+	if (ret) {
+		while (--device_count >= 0) {
+			of_node_put(ag->wsi_node[device_count]);
+			ag->wsi_node[device_count] = NULL;
 		}
-	} while (wsi_dev != next_wsi_dev);
 
-	of_node_put(next_wsi_dev);
+		of_node_put(wsi_dev);
+		return ret;
+	}
+
+	of_node_put(wsi_dev);
 	ag->num_devices = device_count;
 
 	return 0;
@@ -1983,9 +2002,9 @@ static struct ath12k_hw_group *ath12k_core_hw_group_assign(struct ath12k_base *a
 		    ath12k_core_get_wsi_index(ag, ab)) {
 			ath12k_dbg(ab, ATH12K_DBG_BOOT,
 				   "unable to get wsi info from dt, grouping single device");
+			ath12k_core_free_wsi_info(ag);
 			ag->id = ATH12K_INVALID_GROUP_ID;
 			ag->num_devices = 1;
-			memset(ag->wsi_node, 0, sizeof(ag->wsi_node));
 			wsi->index = 0;
 		}
 

base-commit: ae530e0b135102c5fc08e64c39e7a18564a52b3e
-- 
2.34.1


^ permalink raw reply related

* Re: nl80211: missing minimum TX power attribute causes misleading userspace behavior
From: May @ 2026-04-10  6:55 UTC (permalink / raw)
  To: Ben Greear; +Cc: linux-wireless


Confirmed on two devices:

TP-Link Archer C7 v2 (QCA9558): txpower=1, iwinfo reports 5 dBm
Buffalo WZR-600DHP (AR7161): txpower=1, iwinfo reports 3 dBm

Reporting is accurate -- iwinfo reflects the actual hardware floor, not the requested value.

To clarify: this was never intended as a bug report but a feature request. The hardware floor is device-dependent and cannot be queried by userspace. It would be useful if this minimum were made available, so that LuCI can offer only values the hardware can actually deliver.

Steffen


Am 09.04.2026 um 17:27 schrieb Ben Greear <greearb@candelatech.com>:

On 4/9/26 01:05, Steffen May wrote:
> This issue was discovered during the analysis of two documented OpenWrt bugs. Bug 1 is a type comparison error in LuCI wireless.js that causes 0 dBm to be displayed incorrectly. Bug 2 is in ucode mac80211.sh where the value 0 is treated as falsy, causing the router to transmit at maximum power instead. Both bugs are proven and reported.
> During verification of Bug 2 on five devices with three different chipsets, it became apparent that the hardware floor is device-dependent and completely unknown to the stack. This is not a bug but a missing feature.
> Because the floor is unknown, iwinfo generates selection lists containing values that have no real effect on the actual output power. Userspace accepts configurations such as 0 dBm even though the hardware cannot apply them. The system reports success while the hardware remains at its minimum supported level. This creates false assumptions.
> Measurements
> The deviation between the requested transmit power and the actual hardware floor is not constant but depends on the hardware:
> Device                Chipset            Requested     Actual floor Difference
> Buffalo WZR-600DHP    Atheros AR7161     1 dBm         3 dBm          +2 dB
> TP-Link Archer C7     Qualcomm QCA9558   1 dBm         5 dBm          +4 dB
> OpenWrt One           MTK Filogic        1 dBm         1 dBm           0 dB
> Cudy WR3000           MTK Filogic        1 dBm         1 dBm           0 dB
> GL.iNet GL-MT6000     MTK Filogic        1 dBm         1 dBm           0 dB

If you set that tplink to 1dbm, and then read the reported power, does it properly show 5dbm?

If so, that seems good enough?

If not, then we should fix the reporting, but having a floor reported doesn't seem helpful
to me.  There are lots of things that can affect actual txpower.  User-space can at best
offer its suggestion of preferred txpower.  Kernel/driver/firmware/hardware then makes final
decision.

Thanks,
Ben

--
Ben Greear <greearb@candelatech.com>
Candela Technologies Inc  http://www.candelatech.com




^ permalink raw reply

* [GIT PULL] wireless-next-2026-04-10
From: Johannes Berg @ 2026-04-10  6:44 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless

Hi,

Final (obviously) pull request for now, the only thing to
note is the crypto changes, FWIW the change touching crypto
was acked by Herbert and he asked me to take it:
https://lore.kernel.org/r/adYNVB3n358xm_s8@gondor.apana.org.au/

Please pull and let us know if there's any problem.

Thanks,
johannes



The following changes since commit 8ffb33d7709b59ff60560f48960a73bd8a55be95:

  Merge git://git.kernel.org/pub/scm/linux/kernel/git/netdev/net (2026-04-02 11:03:13 -0700)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/wireless/wireless-next.git tags/wireless-next-2026-04-10

for you to fetch changes up to fa489a77e3267e05df95db96ba98e141ec07cbd9:

  wifi: cfg80211: Explicitly include <linux/export.h> in michael-mic.c (2026-04-09 08:54:43 +0200)

----------------------------------------------------------------
Final updates, notably:
 - crypto: move Michael MIC code into wireless (only)
 - mac80211:
   - multi-link 4-addr support
   - NAN data support (but no drivers yet)
 - ath10k: DT quirk to make it work on some devices
 - ath12k: IPQ5424 support
 - rtw89: USB improvements for performance

----------------------------------------------------------------
Alexander Stein (1):
      wifi: brcmfmac: silence warning for non-existent, optional firmware

Alexey Velichayshiy (1):
      wifi: rtw89: phy: fix uninitialized variable access in rtw89_phy_cfo_set_crystal_cap()

Amit Pundir (2):
      dt-bindings: wireless: ath10k: Add quirk to skip host cap QMI requests
      wifi: ath10k: Add device-tree quirk to skip host cap QMI requests

Avraham Stern (1):
      wifi: mac80211: allow add_key on NAN interfaces

Avula Sri Charan (1):
      wifi: ath12k: Skip adding inactive partner vdev info

Baochen Qiang (1):
      wifi: ath10k: fix station lookup failure during disconnect

Benjamin Berg (3):
      wifi: mac80211: add a TXQ for management frames on NAN devices
      wifi: ieee80211: add more NAN definitions
      wifi: mac80211: export ieee80211_calculate_rx_timestamp

Bitterblue Smith (5):
      wifi: rtw89: Turbo mode for RTL8851BU/RTL8852BU
      wifi: rtw88: TX QOS Null data the same way as Null data
      wifi: rtw88: coex: Ignore BT info byte 5 from RTL8821A
      wifi: rtw88: Fill fw_version member of struct wiphy
      wifi: rtw89: Fill fw_version member of struct wiphy

Brendan Jackman (2):
      wifi: iwlegacy: Fixup allocation failure log
      wifi: iwlegacy: Fix GFP flags in allocation loop

Chin-Yen Lee (3):
      wifi: rtw89: wow: add retry for ensuring packet are processed
      wifi: rtw89: wow: use struct style to fill WOW wakeup control H2C command
      wifi: rtw89: wow: enable MLD address for Magic packet wakeup

Ching-Te Ku (1):
      wifi: rtw88: coex: Solve LE-HID lag & update coex version to 26020420

Christian Hewitt (1):
      wifi: rtw89: retry efuse physical map dump on transient failure

Christos Longros (1):
      wifi: rtw89: fix typo "frome" -> "from" in rx_freq_frome_ie

Duoming Zhou (1):
      wifi: rtlwifi: pci: fix possible use-after-free caused by unfinished irq_prepare_bcn_tasklet

Eric Biggers (7):
      wifi: ipw2x00: Rename michael_mic() to libipw_michael_mic()
      wifi: mac80211, cfg80211: Export michael_mic() and move it to cfg80211
      wifi: ath11k: Use michael_mic() from cfg80211
      wifi: ath12k: Use michael_mic() from cfg80211
      wifi: ipw2x00: Use michael_mic() from cfg80211
      crypto: Remove michael_mic from crypto_shash API
      wifi: cfg80211: Explicitly include <linux/export.h> in michael-mic.c

Eric Huang (1):
      wifi: rtw89: phy: expand PHY page for RTL8922D

Ethan Tidmore (1):
      wifi: brcmfmac: Fix error pointer dereference

Fedor Pchelkin (1):
      wifi: rtw88: check for PCI upstream bridge existence

Harish Rachakonda (1):
      wifi: ath12k: Support channel change stats

J. Neuschäfer (1):
      wifi: rtl8xxxu: Mark RTL8188ETV (0bda:0179) as tested

Jaime Saguillo Revilla (1):
      wifi: rtlwifi: rtl8192d: fix typo in H2C wait counter names

Jiajia Liu (1):
      wifi: mac80211: remove unused variables in minstrel_ht_alloc_sta

Johan Hovold (8):
      wifi: rtl818x: drop redundant device reference
      wifi: rtl8xxxu: drop redundant device reference
      wifi: rtw88: fix device leak on probe failure
      wifi: rtw89: drop redundant device reference
      wifi: rtlwifi: usb: drop redundant device reference
      wifi: at76c50x: refactor endpoint lookup
      wifi: libertas: refactor endpoint lookup
      wifi: libertas_tf: refactor endpoint lookup

Johannes Berg (3):
      Merge tag 'rtw-next-2026-04-02' of https://github.com/pkshih/rtw into wireless-next
      Merge tag 'ath-next-20260407' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath
      Merge tag 'ath-next-20260408' of git://git.kernel.org/pub/scm/linux/kernel/git/ath/ath

Kuan-Chung Chen (1):
      wifi: rtw89: add H2C command to protect TX/RX for unused PHY

Lucid Duck (1):
      wifi: rtw89: usb: fix TX flow control by tracking in-flight URBs

Miri Korenblit (11):
      wifi: mac80211: run NAN DE code only when appropriate
      wifi: mac80211: add NAN local schedule support
      wifi: mac80211: support open and close for NAN_DATA interfaces
      wifi: mac80211: handle reconfig for NAN DATA interfaces
      wifi: mac80211: support NAN stations
      wifi: mac80211: add NAN peer schedule support
      wifi: mac80211: update NAN data path state on schedule changes
      wifi: mac80211: add support for TX over NAN_DATA interfaces
      wifi: mac80211: Accept frames on NAN DATA interfaces
      wifi: mac80211: allow block ack agreements in NAN Data
      wifi: mac80211: report and drop spurious NAN Data frames

Nicolas Escande (1):
      wifi: mac80211: handle VHT EXT NSS in ieee80211_determine_our_sta_mode()

Ping-Ke Shih (29):
      wifi: rtw89: fw: add fw_def struct to put firmware name and format version
      wifi: rtw89: fw: recognize firmware type B by AID
      wifi: rtw89: 8852b: update supported firmware format to 2
      wifi: rtw89: rfk: add hardware version to rtw89_fw_h2c_rf_pre_ntfy_mcc for new WiFi 7 firmware
      wifi: rtw89: pci: update SER parameters for suspend/resume
      wifi: rtw89: mac: remove A-die off setting for RTL8852C and RTL8922A
      wifi: rtw89: phy: limit AMPDU number for RA try rate
      wifi: rtw88: add quirks to disable PCI ASPM and deep LPS for HP P3S95EA#ACB
      wifi: rtw88: validate RX rate to prevent out-of-bound
      wifi: rtw89: 8922d: add definition of quota, registers and efuse block
      wifi: rtw89: 8922d: add power on/off functions
      wifi: rtw89: 8922d: define efuse map and read necessary fields
      wifi: rtw89: 8922d: read and configure RF by calibration data from efuse physical map
      wifi: rtw89: 8922d: add set channel of MAC part
      wifi: rtw89: 8922d: add set channel of BB part
      wifi: rtw89: 8922d: add set channel of RF part
      wifi: rtw89: pci: clear SER ISR when initial and leaving WoWLAN for WiFi 7 chips
      wifi: rtw89: mac: add specific case to dump mac memory for RTL8922D
      wifi: rtw89: mac: disable pre-load function for RTL8922DE
      wifi: rtw89: phy: load RF parameters relying on ACV for RTL8922D
      wifi: rtw89: 8922d: BB hardware pre-/post-init, TX/RX path and power settings
      wifi: rtw89: 8922d: add set channel with pre-/post- helpers
      wifi: rtw89: 8922d: add RF calibration ops
      wifi: rtw89: 8922d: add set TX power callback
      wifi: rtw89: 8922d: configure TX/RX path assisting in BT coexistence
      wifi: rtw89: 8922d: add RF ops of init hardware and get thermal
      wifi: rtw89: 8922d: add ops related to BT coexistence mechanism
      wifi: rtw89: 8922d: add chip_info and chip_ops struct
      wifi: rtw89: 8922d: add PCI ID of RTL8922DE and RTL8922DE-VS

Po-Hao Huang (2):
      wifi: rtw89: Drop malformed AMPDU frames with abnormal PN
      wifi: rtw89: Recalculate station aggregates when AMSDU length changes for MLO links

Raj Kumar Bhagat (2):
      dt-bindings: net: wireless: add ath12k wifi device IPQ5424
      wifi: ath12k: add ath12k_hw_version_map entry for IPQ5424

Ronald Claveau (1):
      dt-bindings: net: wireless: brcm: Add compatible for bcm43752

Roopni Devanathan (2):
      wifi: ath12k: Rename hw_link_id to radio_idx in ath12k_ah_to_ar()
      wifi: ath12k: Create symlink for each radio in a wiphy

Rosen Penev (2):
      wifi: brcmfmac: of: defer probe for MAC address
      wifi: wilc1000: use kzalloc_flex

Saravanakumar Duraisamy (3):
      wifi: ath12k: Add ath12k_hw_params for IPQ5424
      wifi: ath12k: add ath12k_hw_regs for IPQ5424
      wifi: ath12k: Add CE remap hardware parameters for IPQ5424

Shin-Yi Lin (1):
      wifi: rtw89: usb: Rx aggregation for RTL8832CU/RTL8851BU

Sowmiya Sree Elavalagan (1):
      wifi: ath12k: Enable IPQ5424 WiFi device support

Tamizh Chelvam Raja (3):
      wifi: mac80211: synchronize valid links for WDS AP_VLAN interfaces
      wifi: mac80211: use ap_addr for 4-address NULL frame destination
      wifi: mac80211: enable MLO support for 4-address mode interfaces

Yi Cong (1):
      wifi: rtl8xxxu: fix potential use of uninitialized value

Zenm Chen (3):
      wifi: rtw89: Add support for TP-Link Archer TX50U
      wifi: rtw89: Add support for Buffalo WI-U3-2400XE2
      wifi: rtw89: Add support for Elecom WDC-XE2402TU3-B

Zong-Zhe Yang (14):
      wifi: rtw89: add general way to generate module firmware string
      wifi: rtw89: 8852a: move DIG tables to rtw8852a.c
      wifi: rtw89: 8852a: update supported firmware format to 1
      wifi: rtw89: 8851b: update supported firmware format to 1
      wifi: rtw89: debug: add SER SW counters to count simulation
      wifi: rtw89: ser: Wi-Fi 7 reset HALT C2H after reading it
      wifi: rtw89: ser: post-recover DMAC state to prevent LPS
      wifi: rtw89: move disabling dynamic mechanism functions to core
      wifi: rtw89: tweak settings of TX power and channel for Wi-Fi 7
      wifi: rtw89: chan: simplify link handling related to ROC
      wifi: rtw89: chan: recalc MLO DBCC mode based on current entity mode
      wifi: rtw89: replace RF mutex with wiphy lock assertion
      wifi: rtw89: debug: simulate Wi-Fi 7 SER L0/L1 without PS mode
      wifi: rtw89: fw: load TX power elements according to AID

 .../bindings/net/wireless/brcm,bcm4329-fmac.yaml   |    1 +
 .../bindings/net/wireless/qcom,ath10k.yaml         |   11 +
 .../bindings/net/wireless/qcom,ipq5332-wifi.yaml   |    1 +
 arch/arm/configs/omap2plus_defconfig               |    1 -
 arch/arm/configs/spitz_defconfig                   |    1 -
 arch/arm64/configs/defconfig                       |    1 -
 arch/m68k/configs/amiga_defconfig                  |    1 -
 arch/m68k/configs/apollo_defconfig                 |    1 -
 arch/m68k/configs/atari_defconfig                  |    1 -
 arch/m68k/configs/bvme6000_defconfig               |    1 -
 arch/m68k/configs/hp300_defconfig                  |    1 -
 arch/m68k/configs/mac_defconfig                    |    1 -
 arch/m68k/configs/multi_defconfig                  |    1 -
 arch/m68k/configs/mvme147_defconfig                |    1 -
 arch/m68k/configs/mvme16x_defconfig                |    1 -
 arch/m68k/configs/q40_defconfig                    |    1 -
 arch/m68k/configs/sun3_defconfig                   |    1 -
 arch/m68k/configs/sun3x_defconfig                  |    1 -
 arch/mips/configs/bigsur_defconfig                 |    1 -
 arch/mips/configs/decstation_64_defconfig          |    1 -
 arch/mips/configs/decstation_defconfig             |    1 -
 arch/mips/configs/decstation_r4k_defconfig         |    1 -
 arch/mips/configs/gpr_defconfig                    |    1 -
 arch/mips/configs/ip32_defconfig                   |    1 -
 arch/mips/configs/lemote2f_defconfig               |    1 -
 arch/mips/configs/malta_qemu_32r6_defconfig        |    1 -
 arch/mips/configs/maltaaprp_defconfig              |    1 -
 arch/mips/configs/maltasmvp_defconfig              |    1 -
 arch/mips/configs/maltasmvp_eva_defconfig          |    1 -
 arch/mips/configs/maltaup_defconfig                |    1 -
 arch/mips/configs/mtx1_defconfig                   |    1 -
 arch/mips/configs/rm200_defconfig                  |    1 -
 arch/mips/configs/sb1250_swarm_defconfig           |    1 -
 arch/parisc/configs/generic-32bit_defconfig        |    1 -
 arch/parisc/configs/generic-64bit_defconfig        |    1 -
 arch/powerpc/configs/g5_defconfig                  |    1 -
 arch/powerpc/configs/linkstation_defconfig         |    1 -
 arch/powerpc/configs/mvme5100_defconfig            |    1 -
 arch/powerpc/configs/powernv_defconfig             |    1 -
 arch/powerpc/configs/ppc64_defconfig               |    1 -
 arch/powerpc/configs/ppc64e_defconfig              |    1 -
 arch/powerpc/configs/ppc6xx_defconfig              |    1 -
 arch/powerpc/configs/ps3_defconfig                 |    1 -
 arch/s390/configs/debug_defconfig                  |    1 -
 arch/s390/configs/defconfig                        |    1 -
 arch/sh/configs/sh2007_defconfig                   |    1 -
 arch/sh/configs/titan_defconfig                    |    1 -
 arch/sh/configs/ul2_defconfig                      |    1 -
 arch/sparc/configs/sparc32_defconfig               |    1 -
 arch/sparc/configs/sparc64_defconfig               |    1 -
 crypto/Kconfig                                     |   12 -
 crypto/Makefile                                    |    1 -
 crypto/michael_mic.c                               |  176 --
 crypto/tcrypt.c                                    |    4 -
 crypto/testmgr.c                                   |    6 -
 crypto/testmgr.h                                   |   50 -
 drivers/net/wireless/ath/ath10k/qmi.c              |   13 +-
 drivers/net/wireless/ath/ath10k/snoc.c             |    3 +
 drivers/net/wireless/ath/ath10k/snoc.h             |    1 +
 drivers/net/wireless/ath/ath10k/wmi-tlv.c          |   26 +-
 drivers/net/wireless/ath/ath11k/Kconfig            |    1 -
 drivers/net/wireless/ath/ath11k/dp.c               |    2 -
 drivers/net/wireless/ath/ath11k/dp_rx.c            |   60 +-
 drivers/net/wireless/ath/ath11k/peer.h             |    1 -
 drivers/net/wireless/ath/ath12k/Kconfig            |    1 -
 drivers/net/wireless/ath/ath12k/ahb.c              |   36 +-
 drivers/net/wireless/ath/ath12k/ahb.h              |    1 +
 drivers/net/wireless/ath/ath12k/ce.h               |   13 +-
 drivers/net/wireless/ath/ath12k/core.c             |    4 +-
 drivers/net/wireless/ath/ath12k/core.h             |   13 +-
 drivers/net/wireless/ath/ath12k/debugfs.c          |   29 +-
 .../net/wireless/ath/ath12k/debugfs_htt_stats.c    |   72 +
 .../net/wireless/ath/ath12k/debugfs_htt_stats.h    |   26 +
 drivers/net/wireless/ath/ath12k/dp.c               |    2 -
 drivers/net/wireless/ath/ath12k/dp_peer.h          |    1 -
 drivers/net/wireless/ath/ath12k/dp_rx.c            |   55 +-
 drivers/net/wireless/ath/ath12k/dp_rx.h            |    4 -
 drivers/net/wireless/ath/ath12k/mac.c              |    4 +-
 drivers/net/wireless/ath/ath12k/wifi7/ahb.c        |    8 +
 drivers/net/wireless/ath/ath12k/wifi7/dp_rx.c      |    7 +-
 drivers/net/wireless/ath/ath12k/wifi7/hal.c        |    7 +
 drivers/net/wireless/ath/ath12k/wifi7/hal.h        |    3 +
 .../net/wireless/ath/ath12k/wifi7/hal_qcn9274.c    |   88 +
 .../net/wireless/ath/ath12k/wifi7/hal_qcn9274.h    |    1 +
 drivers/net/wireless/ath/ath12k/wifi7/hw.c         |   97 +-
 drivers/net/wireless/atmel/at76c50x-usb.c          |   22 +-
 .../wireless/broadcom/brcm80211/brcmfmac/chip.c    |   15 +
 .../broadcom/brcm80211/brcmfmac/firmware.c         |   17 +-
 .../net/wireless/broadcom/brcm80211/brcmfmac/of.c  |    4 +-
 drivers/net/wireless/intel/ipw2x00/Kconfig         |    1 -
 .../wireless/intel/ipw2x00/libipw_crypto_tkip.c    |  120 +-
 drivers/net/wireless/intel/iwlegacy/3945-mac.c     |    7 +-
 drivers/net/wireless/marvell/libertas/if_usb.c     |   39 +-
 drivers/net/wireless/marvell/libertas_tf/if_usb.c  |   48 +-
 drivers/net/wireless/microchip/wilc1000/hif.c      |    8 +-
 drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c |    4 -
 drivers/net/wireless/realtek/rtl8xxxu/core.c       |   40 +-
 drivers/net/wireless/realtek/rtlwifi/pci.c         |    1 +
 .../wireless/realtek/rtlwifi/rtl8192d/fw_common.c  |   12 +-
 drivers/net/wireless/realtek/rtlwifi/usb.c         |    4 -
 drivers/net/wireless/realtek/rtw88/coex.c          |   47 +-
 drivers/net/wireless/realtek/rtw88/main.c          |    6 +
 drivers/net/wireless/realtek/rtw88/main.h          |    6 +
 drivers/net/wireless/realtek/rtw88/pci.c           |   34 +-
 drivers/net/wireless/realtek/rtw88/rtw8703b.c      |    5 +
 drivers/net/wireless/realtek/rtw88/rtw8723d.c      |    5 +
 drivers/net/wireless/realtek/rtw88/rtw8821a.c      |    7 +-
 drivers/net/wireless/realtek/rtw88/rtw8821c.c      |    7 +-
 drivers/net/wireless/realtek/rtw88/rtw8822b.c      |    5 +
 drivers/net/wireless/realtek/rtw88/rtw8822c.c      |    5 +-
 drivers/net/wireless/realtek/rtw88/rx.c            |    8 +
 drivers/net/wireless/realtek/rtw88/tx.c            |    2 +-
 drivers/net/wireless/realtek/rtw88/usb.c           |    3 +-
 drivers/net/wireless/realtek/rtw89/chan.c          |   72 +-
 drivers/net/wireless/realtek/rtw89/core.c          |  155 +-
 drivers/net/wireless/realtek/rtw89/core.h          |  105 +-
 drivers/net/wireless/realtek/rtw89/debug.c         |   53 +-
 drivers/net/wireless/realtek/rtw89/efuse.c         |   23 +-
 drivers/net/wireless/realtek/rtw89/fw.c            |  161 +-
 drivers/net/wireless/realtek/rtw89/fw.h            |  134 +-
 drivers/net/wireless/realtek/rtw89/mac.c           |   69 +-
 drivers/net/wireless/realtek/rtw89/mac.h           |   34 +-
 drivers/net/wireless/realtek/rtw89/mac80211.c      |   11 +
 drivers/net/wireless/realtek/rtw89/mac_be.c        |    2 +
 drivers/net/wireless/realtek/rtw89/pci.h           |    7 +
 drivers/net/wireless/realtek/rtw89/pci_be.c        |  104 +-
 drivers/net/wireless/realtek/rtw89/phy.c           |   71 +-
 drivers/net/wireless/realtek/rtw89/phy.h           |    5 +
 drivers/net/wireless/realtek/rtw89/phy_be.c        |    2 +-
 drivers/net/wireless/realtek/rtw89/ps.c            |    2 +
 drivers/net/wireless/realtek/rtw89/reg.h           |  285 +-
 drivers/net/wireless/realtek/rtw89/rtw8851b.c      |   49 +-
 drivers/net/wireless/realtek/rtw89/rtw8851bu.c     |    1 +
 drivers/net/wireless/realtek/rtw89/rtw8852a.c      |   68 +-
 .../net/wireless/realtek/rtw89/rtw8852a_table.c    |   51 -
 .../net/wireless/realtek/rtw89/rtw8852a_table.h    |    1 -
 drivers/net/wireless/realtek/rtw89/rtw8852au.c     |    1 +
 drivers/net/wireless/realtek/rtw89/rtw8852b.c      |   41 +-
 drivers/net/wireless/realtek/rtw89/rtw8852bt.c     |   15 +-
 drivers/net/wireless/realtek/rtw89/rtw8852bu.c     |    1 +
 drivers/net/wireless/realtek/rtw89/rtw8852c.c      |   17 +-
 drivers/net/wireless/realtek/rtw89/rtw8852cu.c     |    7 +
 drivers/net/wireless/realtek/rtw89/rtw8922a.c      |   18 +-
 drivers/net/wireless/realtek/rtw89/rtw8922d.c      | 3093 ++++++++++++++++++++
 drivers/net/wireless/realtek/rtw89/rtw8922d.h      |   83 +
 drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c  |  372 +++
 drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h  |   22 +
 drivers/net/wireless/realtek/rtw89/rtw8922de.c     |  119 +
 drivers/net/wireless/realtek/rtw89/ser.c           |    4 +-
 drivers/net/wireless/realtek/rtw89/usb.c           |  107 +-
 drivers/net/wireless/realtek/rtw89/usb.h           |   15 +
 drivers/net/wireless/realtek/rtw89/util.h          |   17 +
 drivers/net/wireless/realtek/rtw89/wow.c           |    2 +
 drivers/net/wireless/realtek/rtw89/wow.h           |    7 -
 include/linux/ieee80211-nan.h                      |   37 +
 include/linux/ieee80211.h                          |    6 +
 include/net/mac80211.h                             |  157 +-
 net/mac80211/Makefile                              |    3 +-
 net/mac80211/agg-tx.c                              |    3 +-
 net/mac80211/cfg.c                                 |  269 +-
 net/mac80211/chan.c                                |  140 +-
 net/mac80211/driver-ops.h                          |   21 +
 net/mac80211/he.c                                  |    7 +-
 net/mac80211/ht.c                                  |   19 +-
 net/mac80211/ibss.c                                |    2 +-
 net/mac80211/ieee80211_i.h                         |   52 +-
 net/mac80211/iface.c                               |  113 +-
 net/mac80211/link.c                                |   45 +-
 net/mac80211/main.c                                |    4 +-
 net/mac80211/mesh_sync.c                           |    2 +-
 net/mac80211/michael.h                             |   22 -
 net/mac80211/mlme.c                                |   11 +-
 net/mac80211/nan.c                                 |  710 +++++
 net/mac80211/rc80211_minstrel_ht.c                 |   15 +-
 net/mac80211/rx.c                                  |   61 +-
 net/mac80211/scan.c                                |    2 +-
 net/mac80211/sta_info.c                            |   29 +-
 net/mac80211/sta_info.h                            |    3 +-
 net/mac80211/trace.h                               |   31 +
 net/mac80211/tx.c                                  |   52 +-
 net/mac80211/util.c                                |  146 +-
 net/mac80211/vht.c                                 |   16 +-
 net/mac80211/wpa.c                                 |    1 -
 net/wireless/Makefile                              |    2 +-
 net/{mac80211/michael.c => wireless/michael-mic.c} |    6 +-
 185 files changed, 7462 insertions(+), 1301 deletions(-)
 delete mode 100644 crypto/michael_mic.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922d.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922d.h
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.c
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922d_rfk.h
 create mode 100644 drivers/net/wireless/realtek/rtw89/rtw8922de.c
 delete mode 100644 net/mac80211/michael.h
 create mode 100644 net/mac80211/nan.c
 rename net/{mac80211/michael.c => wireless/michael-mic.c} (95%)

^ permalink raw reply

* Re: [PATCH ath-next 0/2] wifi: ath12k: Consistently name struct ath12k_base pointers
From: Baochen Qiang @ 2026-04-10  6:41 UTC (permalink / raw)
  To: Jeff Johnson, Jeff Johnson; +Cc: linux-wireless, ath12k, linux-kernel
In-Reply-To: <20260409-ath12k-htc-proto-v1-0-cda86d6355f1@oss.qualcomm.com>



On 4/10/2026 2:44 AM, Jeff Johnson wrote:
> Per ath12k convention, a pointer to struct ath12k_base should be named
> 'ab', but there are a few places it is named 'ar', so fix them.
> 
> Note that one instance in ath12k_wmi_tlv_parse() is not modified since
> that instance is being removed as part of:
> 
> https://patch.msgid.link/20260407095426.3285574-1-nico.escande@gmail.com/
> 
> ---
> Jeff Johnson (2):
>       wifi: ath12k: Fix HTC prototype ath12k_base parameters
>       wifi: ath12k: Fix ath12k_dp_htt_tlv_iter()'s iter() signature
> 
>  drivers/net/wireless/ath/ath12k/dp_htt.c | 2 +-
>  drivers/net/wireless/ath/ath12k/dp_htt.h | 2 +-
>  drivers/net/wireless/ath/ath12k/htc.h    | 8 ++++----
>  3 files changed, 6 insertions(+), 6 deletions(-)
> ---
> base-commit: 15551ababf6d4e857f2101366a0c3eaa86dd822c
> change-id: 20260403-ath12k-htc-proto-9cdc961f39dc
> 
> 

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* [wireless-next:main] BUILD SUCCESS 8c6d03b7a249ffe85ba2bda09a2a7614c0ff03db
From: kernel test robot @ 2026-04-10  5:11 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: 8c6d03b7a249ffe85ba2bda09a2a7614c0ff03db  crypto: Remove michael_mic from crypto_shash API

elapsed time: 2681m

configs tested: 131
configs skipped: 20

The following configs have been built successfully.
More configs may be tested in the coming days.

tested configs:
alpha                             allnoconfig    gcc-15.2.0
alpha                            allyesconfig    gcc-15.2.0
alpha                               defconfig    gcc-15.2.0
arc                              allmodconfig    gcc-15.2.0
arc                               allnoconfig    gcc-15.2.0
arc                              allyesconfig    gcc-15.2.0
arc                                 defconfig    gcc-15.2.0
arc                   randconfig-001-20260408    gcc-8.5.0
arc                   randconfig-002-20260408    gcc-8.5.0
arm                               allnoconfig    clang-23
arm                              allyesconfig    gcc-15.2.0
arm                   randconfig-001-20260408    gcc-8.5.0
arm64                            allmodconfig    clang-19
arm64                             allnoconfig    gcc-15.2.0
arm64                               defconfig    gcc-15.2.0
arm64                 randconfig-002-20260409    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-20260409    gcc-15.2.0
csky                  randconfig-002-20260409    gcc-11.5.0
hexagon                          allmodconfig    clang-17
hexagon                           allnoconfig    clang-23
i386                             allmodconfig    gcc-14
i386                              allnoconfig    gcc-14
i386                             allyesconfig    gcc-14
i386        buildonly-randconfig-001-20260409    clang-20
i386        buildonly-randconfig-002-20260409    clang-20
i386        buildonly-randconfig-003-20260409    gcc-14
i386        buildonly-randconfig-004-20260409    gcc-14
i386                                defconfig    clang-20
i386                  randconfig-011-20260409    clang-20
i386                  randconfig-012-20260409    clang-20
i386                  randconfig-013-20260409    clang-20
i386                  randconfig-014-20260409    gcc-14
i386                  randconfig-015-20260409    gcc-14
i386                  randconfig-016-20260409    clang-20
i386                  randconfig-017-20260409    clang-20
loongarch                        allmodconfig    clang-19
loongarch                         allnoconfig    clang-23
loongarch             randconfig-001-20260409    clang-18
m68k                             allmodconfig    gcc-15.2.0
m68k                              allnoconfig    gcc-15.2.0
m68k                             allyesconfig    gcc-15.2.0
m68k                                defconfig    gcc-15.2.0
microblaze                        allnoconfig    gcc-15.2.0
microblaze                       allyesconfig    gcc-15.2.0
microblaze                          defconfig    gcc-15.2.0
mips                             allmodconfig    gcc-15.2.0
mips                              allnoconfig    gcc-15.2.0
mips                             allyesconfig    gcc-15.2.0
nios2                            allmodconfig    gcc-11.5.0
nios2                             allnoconfig    gcc-11.5.0
nios2                               defconfig    gcc-11.5.0
nios2                 randconfig-001-20260409    gcc-11.5.0
nios2                 randconfig-002-20260409    gcc-10.5.0
openrisc                         allmodconfig    gcc-15.2.0
openrisc                          allnoconfig    gcc-15.2.0
openrisc                            defconfig    gcc-15.2.0
parisc                           allmodconfig    gcc-15.2.0
parisc                            allnoconfig    gcc-15.2.0
parisc                           allyesconfig    gcc-15.2.0
parisc                              defconfig    gcc-15.2.0
parisc                randconfig-001-20260409    gcc-11.5.0
parisc                randconfig-002-20260409    gcc-11.5.0
powerpc                          allmodconfig    gcc-15.2.0
powerpc                           allnoconfig    gcc-15.2.0
powerpc                       ppc64_defconfig    clang-23
powerpc               randconfig-001-20260409    clang-16
powerpc               randconfig-002-20260409    gcc-8.5.0
powerpc64             randconfig-001-20260409    gcc-14.3.0
powerpc64             randconfig-002-20260409    gcc-10.5.0
riscv                            allmodconfig    clang-23
riscv                             allnoconfig    gcc-15.2.0
riscv                            allyesconfig    clang-16
riscv                               defconfig    clang-23
riscv                 randconfig-001-20260409    gcc-8.5.0
s390                             allmodconfig    clang-18
s390                              allnoconfig    clang-23
s390                             allyesconfig    gcc-15.2.0
sh                               allmodconfig    gcc-15.2.0
sh                                allnoconfig    gcc-15.2.0
sh                               allyesconfig    gcc-15.2.0
sh                                  defconfig    gcc-15.2.0
sh                    randconfig-001-20260409    gcc-15.2.0
sh                    randconfig-002-20260409    gcc-13.4.0
sparc                             allnoconfig    gcc-15.2.0
sparc                 randconfig-001-20260409    gcc-8.5.0
sparc                 randconfig-002-20260409    gcc-11.5.0
sparc64                          allmodconfig    clang-23
sparc64                             defconfig    clang-20
sparc64               randconfig-002-20260409    gcc-9.5.0
um                               allmodconfig    clang-19
um                                allnoconfig    clang-23
um                               allyesconfig    gcc-14
um                                  defconfig    clang-23
um                             i386_defconfig    gcc-14
um                    randconfig-002-20260409    gcc-14
um                           x86_64_defconfig    clang-23
x86_64                           allmodconfig    clang-20
x86_64                            allnoconfig    clang-20
x86_64                           allyesconfig    clang-20
x86_64      buildonly-randconfig-001-20260409    clang-20
x86_64      buildonly-randconfig-002-20260409    clang-20
x86_64      buildonly-randconfig-003-20260409    clang-20
x86_64      buildonly-randconfig-004-20260409    clang-20
x86_64      buildonly-randconfig-005-20260409    gcc-14
x86_64      buildonly-randconfig-006-20260409    gcc-14
x86_64                              defconfig    gcc-14
x86_64                randconfig-001-20260408    gcc-14
x86_64                randconfig-002-20260408    gcc-14
x86_64                randconfig-003-20260408    gcc-14
x86_64                randconfig-004-20260408    gcc-14
x86_64                randconfig-005-20260408    gcc-14
x86_64                randconfig-011-20260409    clang-20
x86_64                randconfig-012-20260409    gcc-14
x86_64                randconfig-013-20260409    gcc-14
x86_64                randconfig-014-20260409    clang-20
x86_64                randconfig-015-20260409    gcc-14
x86_64                randconfig-016-20260409    gcc-14
x86_64                randconfig-071-20260408    clang-20
x86_64                randconfig-072-20260408    clang-20
x86_64                randconfig-073-20260408    clang-20
x86_64                randconfig-074-20260408    gcc-14
x86_64                randconfig-075-20260408    gcc-14
x86_64                randconfig-076-20260408    clang-20
x86_64                          rhel-9.4-rust    clang-20
xtensa                            allnoconfig    gcc-15.2.0
xtensa                           allyesconfig    gcc-15.2.0
xtensa                randconfig-001-20260409    gcc-12.5.0
xtensa                randconfig-002-20260409    gcc-8.5.0

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

^ permalink raw reply

* RE: [PATCH] rtw88: add TX power limit support to 114 and 130 channels
From: Ping-Ke Shih @ 2026-04-10  3:56 UTC (permalink / raw)
  To: Thadeu Lima de Souza Cascardo, Kalle Valo, Yan-Hsuan Chuang
  Cc: linux-wireless@vger.kernel.org, kernel-dev@igalia.com
In-Reply-To: <20260306-rtw88_channel130-v1-1-ff25a5bc930a@igalia.com>

Thadeu Lima de Souza Cascardo <cascardo@igalia.com> wrote:
> Though 114 and 130 are not usual channels, they are found in the wild with
> setups using 5350MHz as the center frequency of a 80MHz setup.

What did the AP setup? channel 114 160MHz?
I wonder why rtw88 can select a not usual channel 114 80MHz.

Please share your environment setup. 

> 
> rtw88 supports that, but issues a WARNING because it cannot find the TX
> power limit for those channels.

Actually, rtw88 hardware can't support that, so we are working on patch
to avoid selecting unusual channels. Can it work properly with
the AP after this patch?

Ping-Ke


^ permalink raw reply

* Re: [PATCH v4 net-next] net: use get_random_u{16,32,64}() where appropriate
From: patchwork-bot+netdevbpf @ 2026-04-10  3:10 UTC (permalink / raw)
  To: David CARLIER
  Cc: kuba, davem, edumazet, pabeni, andrew+netdev, horms, idryomov,
	johannes, matttbe, martineau, geliang, aconole, i.maximets,
	marcelo.leitner, lucien.xin, jmaloy, netdev, linux-wireless,
	mptcp, dev, linux-sctp, tipc-discussion, linux-kernel
In-Reply-To: <20260407150758.5889-1-devnexen@gmail.com>

Hello:

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

On Tue,  7 Apr 2026 16:07:58 +0100 you wrote:
> Use the typed random integer helpers instead of
> get_random_bytes() when filling a single integer variable.
> The helpers return the value directly, require no pointer
> or size argument, and better express intent.
> 
> Skipped sites writing into __be16 (netdevsim) and __le64
> (ceph) fields where a direct assignment would trigger
> sparse endianness warnings.
> 
> [...]

Here is the summary with links:
  - [v4,net-next] net: use get_random_u{16,32,64}() where appropriate
    https://git.kernel.org/netdev/net-next/c/9addea5d44b6

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 ath-next 0/5] wifi: ath12k: thermal throttling and cooling device support
From: Baochen Qiang @ 2026-04-10  2:37 UTC (permalink / raw)
  To: Maharaja Kennadyrajan, ath12k; +Cc: linux-wireless
In-Reply-To: <20260331142446.2951809-1-maharaja.kennadyrajan@oss.qualcomm.com>



On 3/31/2026 10:24 PM, Maharaja Kennadyrajan wrote:
> Patch 1 handles the firmware stats event so we can track the current
> temperature and throttle level per pdev without spamming logs.
> 
> Patch 2 enables thermal throttling at bring-up and programs default level
> tables to firmware via WMI_THERM_THROT_SET_CONF_CMDID; the driver picks
> IPA/XFEM defaults based on the firmware WMI service bitmap, supports 4 or 5
> levels as advertised, and only fills optional fields (pout reduction,
> tx chain mask) when the corresponding WMI service bits are present.
> 
> Patch 3 refactors per-radio thermal hwmon cleanup to reduce code duplication and
> ensure consistent cleanup across thermal register and unregister paths.
> 
> Patch 4 reorders the group teardown logic symmetric for safe thermal sysfs cleanup.
> 
> Patch 5 exposes a thermal cooling device per radio so the kernel thermal
> framework or userspace can set the TX duty-cycle off percentage; writes
> are validated against the throttling state range and host state is kept in
> sync with successful firmware updates.
> 
> Examples:
> echo 40 > /sys/devices/pci0000:00/0000:00:1d.1/0000:58:00.0/ieee80211/phyX/cooling_device/cur_stat
> cat /sys/devices/pci0000:00/0000:00:1d.1/0000:58:00.0/ieee80211/phyX/cooling_device/cur_state
> cat /sys/devices/pci0000:00/0000:00:1d.1/0000:58:00.0/ieee80211/phyX/cooling_device/max_state
> 
> Maharaja Kennadyrajan (5):
>   wifi: ath12k: handle thermal throttle stats WMI event
>   wifi: ath12k: configure firmware thermal throttling via WMI
>   wifi: ath12k: refactor per-radio thermal hwmon setup and cleanup
>   wifi: ath12k: reorder group start/stop for safe thermal sysfs cleanup
>   wifi: ath12k: add thermal cooling device support
> 
>  drivers/net/wireless/ath/ath12k/core.c    |  50 +++--
>  drivers/net/wireless/ath/ath12k/mac.c     |   9 +
>  drivers/net/wireless/ath/ath12k/thermal.c | 252 ++++++++++++++++++----
>  drivers/net/wireless/ath/ath12k/thermal.h |  35 +++
>  drivers/net/wireless/ath/ath12k/wmi.c     | 107 +++++++++
>  drivers/net/wireless/ath/ath12k/wmi.h     |  50 +++++
>  6 files changed, 446 insertions(+), 57 deletions(-)
> 
> 
> base-commit: dbd94b9831bc52a1efb7ff3de841ffc3457428ce

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* Re: [PATCH ath-next v7] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Baochen Qiang @ 2026-04-10  2:30 UTC (permalink / raw)
  To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260407095426.3285574-1-nico.escande@gmail.com>



On 4/7/2026 5:54 PM, Nicolas Escande wrote:
> On each WMI message received from the hardware, we alloc a temporary array
> of WMI_TAG_MAX entries of type void *. This array is then populated with
> pointers of parsed structs depending on the WMI type, and then freed. This
> alloc can fail when memory pressure in the system is high enough.
> 
> Given the fact that it is scheduled in softirq with the system_bh_wq, we
> should not be able to parse more than one WMI message per CPU at any time.
> 
> So instead lets move to a per cpu allocated array, that is reused across
> calls. This memory is allocated as needed and refcounted to exist only
> as long as one struct ath12k_base lives.
> 
> ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
> together as it no longer allocs mem but returns the existing per-cpu one.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00218-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>

Reviewed-by: Baochen Qiang <baochen.qiang@oss.qualcomm.com>


^ permalink raw reply

* [PATCH net 4/4] nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req()
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu
In-Reply-To: <20260409223436.1887988-1-snowwlake@icloud.com>

digital_tg_recv_dep_req() guards against short frames with:

  if (resp->len < size ...)   /* size = sizeof(struct digital_dep_req_res) = 3 */

This guarantees resp->len >= 3 (dir + cmd + pfb).  However, when the
DID bit is set in pfb, the code immediately accesses resp->data[3] — the
DID byte — which is one byte past the guaranteed minimum:

  if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) {
      if (ddev->did && (ddev->did == resp->data[3])) {

A remote NFC-DEP initiator can trigger this with a 3-byte DEP_REQ frame
that has the DID bit set in the PFB field, causing a 1-byte
out-of-bounds read of kernel heap memory.

Increment the minimum required length to 4 when the DID bit is present
before accessing resp->data[3], mirroring the pattern used for the
size++ / check at the end of the DID block.

Fixes: 7d0911c07b44 ("NFC Digital: Implement NFC-DEP target TX and RX")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_dep.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -1117,6 +1117,11 @@ static int digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
 	pfb = dep_req->pfb;

 	if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb)) {
+		if (resp->len < size + 1) {
+			rc = -EIO;
+			goto exit;
+		}
+
 		if (ddev->did && (ddev->did == resp->data[3])) {
 			size++;
 		} else {
--
2.34.1

^ permalink raw reply

* [PATCH net 3/4] nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res()
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu
In-Reply-To: <20260409223436.1887988-1-snowwlake@icloud.com>

In the SUPERVISOR_PDU / timeout (RTOX) branch of digital_in_recv_dep_res(),
the RTOX value byte is read from resp->data[0] after skb_pull() has
stripped the 3-byte DEP_RES header:

  skb_pull(resp, size);   /* size = sizeof(struct digital_dep_req_res) = 3 */
  ...
  case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
      ...
      rtox = DIGITAL_NFC_DEP_RTOX_VALUE(resp->data[0]);

If the remote device sends a DEP_RES frame that is exactly the minimum
length (3 bytes -- dir + cmd + pfb only, no payload), the skb_pull leaves
resp->len == 0 and the read of resp->data[0] is a 1-byte out-of-bounds
read of kernel heap memory beyond the socket buffer.

The I-PDU and ACK/NACK branches are not affected because they either
pass resp directly to upper layers or perform a separate minimum-length
check before accessing payload bytes.  Only the RTOX branch is missing
its guard.

Add a resp->len >= 1 check before the RTOX value read.

Fixes: 4b60cfce7aba ("NFC Digital: Implement NFC-DEP initiator TX and RX")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_dep.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_dep.c b/net/nfc/digital_dep.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_dep.c
+++ b/net/nfc/digital_dep.c
@@ -866,6 +866,12 @@
 			goto error;
 		}
 
+		if (!resp->len) {
+			PROTOCOL_ERR("14.8.4.1");
+			rc = -EIO;
+			goto error;
+		}
+
 		rtox = DIGITAL_NFC_DEP_RTOX_VALUE(resp->data[0]);
 		if (!rtox || rtox > DIGITAL_NFC_DEP_RTOX_MAX) {
 			PROTOCOL_ERR("14.8.4.1");

--
2.34.1

^ permalink raw reply

* [PATCH net 2/4] nfc: digital: Fix check-after-read in digital_tg_recv_sens_req()
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu
In-Reply-To: <20260409223436.1887988-1-snowwlake@icloud.com>

digital_tg_recv_sens_req() reads resp->data[0] into sens_req at line
1092 before the !resp->len guard fires at line 1094.  A zero-length
frame causes an unconditional 1-byte out-of-bounds read before any
length check has taken place.

The root cause is that the assignment and the length check are split
across two statements: resp->data[0] is read unconditionally into
sens_req, and only then is resp->len tested as part of a compound
condition.  Even though the || operator correctly short-circuits, the
read on the previous line is already done.

Move the length guard before the data access by splitting the combined
condition into an early resp->len check followed by the data read and
the command comparison.

Fixes: 2e7a3e7ee80d ("NFC Digital: Add target mode for NFC-A/ISO14443A")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_technology.c | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -1090,11 +1090,14 @@ void digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg,
 	}

-	sens_req = resp->data[0];
-
-	if (!resp->len || (sens_req != DIGITAL_CMD_SENS_REQ &&
-	    sens_req != DIGITAL_CMD_ALL_REQ)) {
+	if (!resp->len) {
 		rc = -EINVAL;
 		goto exit;
 	}
+
+	sens_req = resp->data[0];
+	if (sens_req != DIGITAL_CMD_SENS_REQ && sens_req != DIGITAL_CMD_ALL_REQ) {
+		rc = -EINVAL;
+		goto exit;
+	}

 	rc = digital_tg_send_sens_res(ddev);
--
2.34.1

^ permalink raw reply

* [PATCH net 1/4] nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res()
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu
In-Reply-To: <20260409223436.1887988-1-snowwlake@icloud.com>

The function digital_in_recv_sensf_res() validates that the incoming
SENSF_RES frame is at least DIGITAL_SENSF_RES_MIN_LENGTH (17) bytes,
but does not check that it is at most NFC_SENSF_RES_MAXSIZE (18) bytes
before copying into the 18-byte target.sensf_res stack buffer.

After skb_pull(resp, 1) removes the framing byte, resp->len can range
from 16 up to 253 — an NFC-F frame carries a 1-byte length field with
maximum value 255, from which the driver status byte (pulled here) and
the protocol length byte are subtracted.  The memcpy() at line 775 then
writes up to 235 bytes past the end of target.sensf_res, overflowing
into adjacent stack data including saved registers and the return address.

A device in NFC-F polling mode can trigger this condition without any
prior pairing or authentication by responding to a SENSF_REQ with an
oversized frame.  No user interaction is required on the victim device
while NFC discovery is active.

The NCI code path handles this correctly; nci/ntf.c line 508:
  nfcf_poll->sensf_res_len = min_t(__u8, *data++, NFC_SENSF_RES_MAXSIZE);

Apply the equivalent upper-bound check to the digital protocol path by
rejecting frames whose post-strip length exceeds NFC_SENSF_RES_MAXSIZE.

Fixes: 8c0695e4998d ("NFC Digital: Add NFC-F technology support")
Cc: stable@vger.kernel.org
Signed-off-by: Lekë Hapçiu <snowwlake@icloud.com>
---
 net/nfc/digital_technology.c | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/net/nfc/digital_technology.c b/net/nfc/digital_technology.c
index XXXXXXX..XXXXXXX 100644
--- a/net/nfc/digital_technology.c
+++ b/net/nfc/digital_technology.c
@@ -768,6 +768,11 @@ static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg,

 	skb_pull(resp, 1);

+	if (resp->len > NFC_SENSF_RES_MAXSIZE) {
+		rc = -EIO;
+		goto exit;
+	}
+
 	memset(&target, 0, sizeof(struct nfc_target));

 	sensf_res = (struct digital_sensf_res *)resp->data;
--
2.34.1

^ permalink raw reply

* [PATCH net 0/4] nfc: digital: Fix missing and misplaced length checks
From: Lekë Hapçiu @ 2026-04-09 22:34 UTC (permalink / raw)
  To: netdev; +Cc: linux-wireless, stable, krzysztof.kozlowski,
	Lekë Hapçiu

This series fixes four length-check bugs in the NFC Digital Protocol stack.
All are reachable from RF without authentication:

  - Patch 1: Missing upper-bound check before memcpy into target.sensf_res
    in the NFC-F initiator polling path.  An oversized SENSF_RES overflows
    an 18-byte stack buffer by up to 235 bytes.  CVSS 8.1.

  - Patch 2: Check-after-read in the NFC-A target receive path.
    resp->data[0] is read before the resp->len != 0 guard fires.
    A zero-length frame triggers a 1-byte OOB read.

  - Patch 3: Missing post-pull length check in the RTOX handler inside
    digital_in_recv_dep_res().  After skb_pull strips the 3-byte DEP
    header, resp->data[0] is read with no guarantee that any payload byte
    remains.

  - Patch 4: DID byte accessed at resp->data[3] after only a
    sizeof(struct digital_dep_req_res) == 3 byte guard in
    digital_tg_recv_dep_req().  An attacker with DID bit set and a 3-byte
    frame triggers a 1-byte OOB read.

Patches 1-4 are independent and can be applied in any order.

Security Research (4):
  nfc: digital: Fix stack buffer overflow in digital_in_recv_sensf_res()
  nfc: digital: Fix check-after-read in digital_tg_recv_sens_req()
  nfc: digital: Fix OOB read of RTOX byte in digital_in_recv_dep_res()
  nfc: digital: Fix OOB read of DID byte in digital_tg_recv_dep_req()

 net/nfc/digital_dep.c        | 10 ++++++++--
 net/nfc/digital_technology.c | 13 ++++++++-----
 2 files changed, 16 insertions(+), 7 deletions(-)

^ permalink raw reply

* Re: [PATCH ath-next v7] wifi: ath12k: avoid dynamic alloc when parsing wmi tb
From: Rameshkumar Sundaram @ 2026-04-09 18:57 UTC (permalink / raw)
  To: Nicolas Escande, ath12k; +Cc: linux-wireless
In-Reply-To: <20260407095426.3285574-1-nico.escande@gmail.com>



On 4/7/2026 3:24 PM, Nicolas Escande wrote:
> On each WMI message received from the hardware, we alloc a temporary array
> of WMI_TAG_MAX entries of type void *. This array is then populated with
> pointers of parsed structs depending on the WMI type, and then freed. This
> alloc can fail when memory pressure in the system is high enough.
> 
> Given the fact that it is scheduled in softirq with the system_bh_wq, we
> should not be able to parse more than one WMI message per CPU at any time.
> 
> So instead lets move to a per cpu allocated array, that is reused across
> calls. This memory is allocated as needed and refcounted to exist only
> as long as one struct ath12k_base lives.
> 
> ath12k_wmi_tlv_parse_alloc() and ath12k_wmi_tlv_parse() are merged
> together as it no longer allocs mem but returns the existing per-cpu one.
> 
> Tested-on: QCN9274 hw2.0 PCI WLAN.WBE.1.3.1-00218-QCAHKSWPL_SILICONZ-1
> 
> Signed-off-by: Nicolas Escande <nico.escande@gmail.com>
> ---
> changes from v6:
>    - fix useless ath12k_wmi_tb NULL init
>    - do not use refcount_inc when refount is at 0, it can warn
> 
> changes from v5:
>    - use of the refount_t kernel api
> 
> changes from v4:
>    - moved to a single instance, refcounted per cpu memory alloc
>    
> changes from v3:
>    - simplified ath12k_core_init() with a single statement
>    - move perpcu.h include directly to wmi.c
> 
> changes from v2:
>    - removed now superfluous return in ath12k_wmi_event_teardown_complete()
>    - moved ath12k_wmi_tb declaration to wmi.c & added two functions to
>      alloc / free it
>    - removed useless error message on memory allocation failure
> 
> changes from v1:
>    - rebased on ath-next 27401c9b1432
>    - changed wording according to Jeff's comment
>    - moved alloc/cleanup to new module_init/exit functions in the
>      ath12k module as per Baochen's comment
> 
> changes from RFC:
>    - rebased on ath-next 8e0ab5b9adb7
>    - converted missing call sites ath12k_wmi_obss_color_collision_event()
>      & ath12k_wmi_pdev_temperature_event()
>    - changed alloc order & cleanup path in ath12k_core_alloc() as it seems
>      it confused people
>    - used sizeof(*tb) in ath12k_wmi_tlv_parse()
> ---
>   drivers/net/wireless/ath/ath12k/core.c |   6 +
>   drivers/net/wireless/ath/ath12k/wmi.c  | 217 +++++++++----------------
>   drivers/net/wireless/ath/ath12k/wmi.h  |   3 +
>   3 files changed, 87 insertions(+), 139 deletions(-)
> 
> diff --git a/drivers/net/wireless/ath/ath12k/core.c b/drivers/net/wireless/ath/ath12k/core.c
> index c31c47fb5a73..6f0f4bfbf699 100644
> --- a/drivers/net/wireless/ath/ath12k/core.c
> +++ b/drivers/net/wireless/ath/ath12k/core.c
> @@ -2256,6 +2256,7 @@ void ath12k_core_deinit(struct ath12k_base *ab)
>   void ath12k_core_free(struct ath12k_base *ab)
>   {
>   	timer_delete_sync(&ab->rx_replenish_retry);
> +	ath12k_wmi_free();
>   	destroy_workqueue(ab->workqueue_aux);
>   	destroy_workqueue(ab->workqueue);
>   	kfree(ab);
> @@ -2280,6 +2281,9 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>   	if (!ab->workqueue_aux)
>   		goto err_free_wq;
>   
> +	if (ath12k_wmi_alloc() < 0)
> +		goto err_free_wq_aux;
> +
>   	mutex_init(&ab->core_lock);
>   	spin_lock_init(&ab->base_lock);
>   	init_completion(&ab->reset_complete);
> @@ -2314,6 +2318,8 @@ struct ath12k_base *ath12k_core_alloc(struct device *dev, size_t priv_size,
>   
>   	return ab;
>   
> +err_free_wq_aux:
> +	destroy_workqueue(ab->workqueue_aux);
>   err_free_wq:
>   	destroy_workqueue(ab->workqueue);
>   err_sc_free:
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.c b/drivers/net/wireless/ath/ath12k/wmi.c
> index 65a05a9520ff..484fdd3b1b7f 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.c
> +++ b/drivers/net/wireless/ath/ath12k/wmi.c
> @@ -15,6 +15,8 @@
>   #include <linux/time.h>
>   #include <linux/of.h>
>   #include <linux/cleanup.h>
> +#include <linux/percpu.h>
> +#include <linux/refcount.h>
>   #include "core.h"
>   #include "debugfs.h"
>   #include "debug.h"
> @@ -134,6 +136,10 @@ struct wmi_pdev_set_obss_bitmap_arg {
>   	const char *label;
>   };
>   
> +static DEFINE_MUTEX(ath12k_wmi_mutex);
> +static refcount_t ath12k_wmi_refcount;
> +static void __percpu *ath12k_wmi_tb;
> +
>   static const struct ath12k_wmi_tlv_policy ath12k_wmi_tlv_policies[] = {
>   	[WMI_TAG_ARRAY_BYTE] = { .min_len = 0 },
>   	[WMI_TAG_ARRAY_UINT32] = { .min_len = 0 },
> @@ -289,29 +295,19 @@ static int ath12k_wmi_tlv_iter_parse(struct ath12k_base *ab, u16 tag, u16 len,
>   	return 0;
>   }
>   
> -static int ath12k_wmi_tlv_parse(struct ath12k_base *ar, const void **tb,
> -				const void *ptr, size_t len)
> -{
> -	return ath12k_wmi_tlv_iter(ar, ptr, len, ath12k_wmi_tlv_iter_parse,
> -				   (void *)tb);
> -}
> -
>   static const void **
> -ath12k_wmi_tlv_parse_alloc(struct ath12k_base *ab,
> -			   struct sk_buff *skb, gfp_t gfp)
> +ath12k_wmi_tlv_parse(struct ath12k_base *ab, struct sk_buff *skb)
>   {
>   	const void **tb;
>   	int ret;
>   
> -	tb = kzalloc_objs(*tb, WMI_TAG_MAX, gfp);
> -	if (!tb)
> -		return ERR_PTR(-ENOMEM);
> +	tb = this_cpu_ptr(ath12k_wmi_tb);
> +	memset(tb, 0, WMI_TAG_MAX * sizeof(*tb));
>   
> -	ret = ath12k_wmi_tlv_parse(ab, tb, skb->data, skb->len);
> -	if (ret) {
> -		kfree(tb);
> +	ret = ath12k_wmi_tlv_iter(ab, skb->data, skb->len,
> +				  ath12k_wmi_tlv_iter_parse, (void *)tb);
> +	if (ret)
>   		return ERR_PTR(ret);
> -	}
>   
>   	return tb;
>   }
> @@ -3911,9 +3907,10 @@ ath12k_wmi_obss_color_collision_event(struct ath12k_base *ab, struct sk_buff *sk
>   	const struct wmi_obss_color_collision_event *ev;
>   	struct ath12k_link_vif *arvif;
>   	u32 vdev_id, evt_type;
> +	const void **tb;
>   	u64 bitmap;
>   
> -	const void **tb __free(kfree) = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ath12k_warn(ab, "failed to parse OBSS color collision tlv %ld\n",
>   			    PTR_ERR(tb));
> @@ -5714,7 +5711,7 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf
>   	const struct wmi_vdev_start_resp_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -5724,13 +5721,11 @@ static int ath12k_pull_vdev_start_resp_tlv(struct ath12k_base *ab, struct sk_buf
>   	ev = tb[WMI_TAG_VDEV_START_RESPONSE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch vdev start resp ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
>   	*vdev_rsp = *ev;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -5809,7 +5804,7 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   
>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processing regulatory ext channel list\n");
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -5819,7 +5814,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_REG_CHAN_LIST_CC_EXT_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch reg chan list ext update ev\n");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -5849,7 +5843,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   	if (num_2g_reg_rules > MAX_REG_RULES || num_5g_reg_rules > MAX_REG_RULES) {
>   		ath12k_warn(ab, "Num reg rules for 2G/5G exceeds max limit (num_2g_reg_rules: %d num_5g_reg_rules: %d max_rules: %d)\n",
>   			    num_2g_reg_rules, num_5g_reg_rules, MAX_REG_RULES);
> -		kfree(tb);
>   		return -EINVAL;
>   	}
>   
> @@ -5859,7 +5852,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   		if (num_6g_reg_rules_ap[i] > MAX_6GHZ_REG_RULES) {
>   			ath12k_warn(ab, "Num 6G reg rules for AP mode(%d) exceeds max limit (num_6g_reg_rules_ap: %d, max_rules: %d)\n",
>   				    i, num_6g_reg_rules_ap[i], MAX_6GHZ_REG_RULES);
> -			kfree(tb);
>   			return -EINVAL;
>   		}
>   
> @@ -5884,14 +5876,12 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   		    num_6g_reg_rules_cl[WMI_REG_VLP_AP][i] >  MAX_6GHZ_REG_RULES) {
>   			ath12k_warn(ab, "Num 6g client reg rules exceeds max limit, for client(type: %d)\n",
>   				    i);
> -			kfree(tb);
>   			return -EINVAL;
>   		}
>   	}
>   
>   	if (!total_reg_rules) {
>   		ath12k_warn(ab, "No reg rules available\n");
> -		kfree(tb);
>   		return -EINVAL;
>   	}
>   
> @@ -5993,7 +5983,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   						      ext_wmi_reg_rule);
>   
>   		if (!reg_info->reg_rules_2g_ptr) {
> -			kfree(tb);
>   			ath12k_warn(ab, "Unable to Allocate memory for 2g rules\n");
>   			return -ENOMEM;
>   		}
> @@ -6027,7 +6016,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   						      ext_wmi_reg_rule);
>   
>   		if (!reg_info->reg_rules_5g_ptr) {
> -			kfree(tb);
>   			ath12k_warn(ab, "Unable to Allocate memory for 5g rules\n");
>   			return -ENOMEM;
>   		}
> @@ -6046,7 +6034,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   						      ext_wmi_reg_rule);
>   
>   		if (!reg_info->reg_rules_6g_ap_ptr[i]) {
> -			kfree(tb);
>   			ath12k_warn(ab, "Unable to Allocate memory for 6g ap rules\n");
>   			return -ENOMEM;
>   		}
> @@ -6061,7 +6048,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   							      ext_wmi_reg_rule);
>   
>   			if (!reg_info->reg_rules_6g_client_ptr[j][i]) {
> -				kfree(tb);
>   				ath12k_warn(ab, "Unable to Allocate memory for 6g client rules\n");
>   				return -ENOMEM;
>   			}
> @@ -6096,7 +6082,6 @@ static int ath12k_pull_reg_chan_list_ext_update_ev(struct ath12k_base *ab,
>   
>   	ath12k_dbg(ab, ATH12K_DBG_WMI, "processed regulatory ext channel list\n");
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6107,7 +6092,7 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
>   	const struct wmi_peer_delete_resp_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6117,7 +6102,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
>   	ev = tb[WMI_TAG_PEER_DELETE_RESP_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch peer delete resp ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6127,7 +6111,6 @@ static int ath12k_pull_peer_del_resp_ev(struct ath12k_base *ab, struct sk_buff *
>   	ether_addr_copy(peer_del_resp->peer_macaddr.addr,
>   			ev->peer_macaddr.addr);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6139,7 +6122,7 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
>   	const struct wmi_vdev_delete_resp_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6149,13 +6132,11 @@ static int ath12k_pull_vdev_del_resp_ev(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_VDEV_DELETE_RESP_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch vdev delete resp ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
>   	*vdev_id = le32_to_cpu(ev->vdev_id);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6167,7 +6148,7 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab,
>   	const struct wmi_bcn_tx_status_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6177,14 +6158,12 @@ static int ath12k_pull_bcn_tx_status_ev(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_OFFLOAD_BCN_TX_STATUS_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch bcn tx status ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
>   	*vdev_id = le32_to_cpu(ev->vdev_id);
>   	*tx_status = le32_to_cpu(ev->tx_status);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6195,7 +6174,7 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_
>   	const struct wmi_vdev_stopped_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6205,13 +6184,11 @@ static int ath12k_pull_vdev_stopped_param_tlv(struct ath12k_base *ab, struct sk_
>   	ev = tb[WMI_TAG_VDEV_STOPPED_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch vdev stop ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
>   	*vdev_id = le32_to_cpu(ev->vdev_id);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6350,7 +6327,7 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
>   	const struct wmi_mgmt_tx_compl_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6360,7 +6337,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_MGMT_TX_COMPL_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch mgmt tx compl ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6370,7 +6346,6 @@ static int ath12k_pull_mgmt_tx_compl_param_tlv(struct ath12k_base *ab,
>   	param->ppdu_id = ev->ppdu_id;
>   	param->ack_rssi = ev->ack_rssi;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6533,7 +6508,7 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	const struct wmi_scan_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6543,7 +6518,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	ev = tb[WMI_TAG_SCAN_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch scan ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6555,7 +6529,6 @@ static int ath12k_pull_scan_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	scan_evt_param->vdev_id = ev->vdev_id;
>   	scan_evt_param->tsf_timestamp = ev->tsf_timestamp;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6566,7 +6539,7 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
>   	const struct wmi_peer_sta_kickout_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6576,7 +6549,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
>   	ev = tb[WMI_TAG_PEER_STA_KICKOUT_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch peer sta kickout ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6584,7 +6556,6 @@ static int ath12k_pull_peer_sta_kickout_ev(struct ath12k_base *ab, struct sk_buf
>   	arg->reason = le32_to_cpu(ev->reason);
>   	arg->rssi = le32_to_cpu(ev->rssi);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6595,7 +6566,7 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	const struct wmi_roam_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6605,7 +6576,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	ev = tb[WMI_TAG_ROAM_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch roam ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6613,7 +6583,6 @@ static int ath12k_pull_roam_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	roam_ev->reason = ev->reason;
>   	roam_ev->rssi = ev->rssi;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6647,7 +6616,7 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	const struct wmi_chan_info_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6657,7 +6626,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	ev = tb[WMI_TAG_CHAN_INFO_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch chan info ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6674,7 +6642,6 @@ static int ath12k_pull_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	ch_info_ev->mac_clk_mhz = ev->mac_clk_mhz;
>   	ch_info_ev->vdev_id = ev->vdev_id;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6686,7 +6653,7 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	const struct wmi_pdev_bss_chan_info_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6696,7 +6663,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	ev = tb[WMI_TAG_PDEV_BSS_CHAN_INFO_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch pdev bss chan info ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6714,7 +6680,6 @@ ath12k_pull_pdev_bss_chan_info_ev(struct ath12k_base *ab, struct sk_buff *skb,
>   	bss_ch_info_ev->rx_bss_cycle_count_low = ev->rx_bss_cycle_count_low;
>   	bss_ch_info_ev->rx_bss_cycle_count_high = ev->rx_bss_cycle_count_high;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6726,7 +6691,7 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
>   	const struct wmi_vdev_install_key_compl_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6736,7 +6701,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
>   	ev = tb[WMI_TAG_VDEV_INSTALL_KEY_COMPLETE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch vdev install key compl ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
> @@ -6746,7 +6710,6 @@ ath12k_pull_vdev_install_key_compl_ev(struct ath12k_base *ab, struct sk_buff *sk
>   	arg->key_flags = le32_to_cpu(ev->key_flags);
>   	arg->status = le32_to_cpu(ev->status);
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6757,7 +6720,7 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
>   	const struct wmi_peer_assoc_conf_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6767,14 +6730,12 @@ static int ath12k_pull_peer_assoc_conf_ev(struct ath12k_base *ab, struct sk_buff
>   	ev = tb[WMI_TAG_PEER_ASSOC_CONF_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch peer assoc conf ev");
> -		kfree(tb);
>   		return -EPROTO;
>   	}
>   
>   	peer_assoc_conf->vdev_id = le32_to_cpu(ev->vdev_id);
>   	peer_assoc_conf->macaddr = ev->peer_macaddr.addr;
>   
> -	kfree(tb);
>   	return 0;
>   }
>   
> @@ -6792,7 +6753,7 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
>   	const void **tb;
>   	int ret, i;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -6801,7 +6762,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
>   
>   	ev = tb[WMI_TAG_11D_NEW_COUNTRY_EVENT];
>   	if (!ev) {
> -		kfree(tb);
>   		ath12k_warn(ab, "failed to fetch 11d new cc ev");
>   		return -EPROTO;
>   	}
> @@ -6814,8 +6774,6 @@ static int ath12k_reg_11d_new_cc_event(struct ath12k_base *ab, struct sk_buff *s
>   		   ab->new_alpha2[0],
>   		   ab->new_alpha2[1]);
>   
> -	kfree(tb);
> -
>   	for (i = 0; i < ab->num_radios; i++) {
>   		pdev = &ab->pdevs[i];
>   		ar = pdev->ar;
> @@ -8557,7 +8515,7 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
>   	const struct wmi_pdev_ctl_failsafe_chk_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -8567,7 +8525,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_PDEV_CTL_FAILSAFE_CHECK_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch pdev ctl failsafe check ev");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -8581,8 +8538,6 @@ static void ath12k_pdev_ctl_failsafe_check_event(struct ath12k_base *ab,
>   	if (ev->ctl_failsafe_status != 0)
>   		ath12k_warn(ab, "pdev ctl failsafe failure status %d",
>   			    ev->ctl_failsafe_status);
> -
> -	kfree(tb);
>   }
>   
>   static void
> @@ -8654,7 +8609,7 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
>   	const u32 *vdev_ids;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -8666,7 +8621,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
>   
>   	if (!ev || !vdev_ids) {
>   		ath12k_warn(ab, "failed to fetch pdev csa switch count ev");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -8676,8 +8630,6 @@ ath12k_wmi_pdev_csa_switch_count_status_event(struct ath12k_base *ab,
>   		   ev->num_vdevs);
>   
>   	ath12k_wmi_process_csa_switch_count_event(ab, ev, vdev_ids);
> -
> -	kfree(tb);
>   }
>   
>   static void
> @@ -8689,7 +8641,7 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
>   	struct ath12k *ar;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -8700,7 +8652,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
>   
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch pdev dfs radar detected ev");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -8739,8 +8690,6 @@ ath12k_wmi_pdev_dfs_radar_detected_event(struct ath12k_base *ab, struct sk_buff
>   
>   exit:
>   	rcu_read_unlock();
> -
> -	kfree(tb);
>   }
>   
>   static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
> @@ -8751,7 +8700,7 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
>   	int ret;
>   	u16 length;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
> @@ -8762,14 +8711,11 @@ static void ath12k_tm_wmi_event_segmented(struct ath12k_base *ab, u32 cmd_id,
>   	ev = tb[WMI_TAG_ARRAY_BYTE];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch ftm msg\n");
> -		kfree(tb);
>   		return;
>   	}
>   
>   	length = skb->len - TLV_HDR_SIZE;
>   	ath12k_tm_process_event(ab, cmd_id, ev, length);
> -	kfree(tb);
> -	tb = NULL;
>   }
>   
>   static void
> @@ -8782,7 +8728,7 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
>   	int temp;
>   	u32 pdev_id;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ath12k_warn(ab, "failed to parse tlv: %ld\n", PTR_ERR(tb));
>   		return;
> @@ -8791,15 +8737,12 @@ ath12k_wmi_pdev_temperature_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_PDEV_TEMPERATURE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch pdev temp ev\n");
> -		kfree(tb);
>   		return;
>   	}
>   
>   	temp = a_sle32_to_cpu(ev->temp);
>   	pdev_id = le32_to_cpu(ev->pdev_id);
>   
> -	kfree(tb);
> -
>   	ath12k_dbg(ab, ATH12K_DBG_WMI,
>   		   "pdev temperature ev temp %d pdev_id %u\n",
>   		   temp, pdev_id);
> @@ -8826,7 +8769,7 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab,
>   	const struct wmi_fils_discovery_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab,
> @@ -8838,15 +8781,12 @@ static void ath12k_fils_discovery_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_HOST_SWFDA_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch FILS discovery event\n");
> -		kfree(tb);
>   		return;
>   	}
>   
>   	ath12k_warn(ab,
>   		    "FILS discovery frame expected from host for vdev_id: %u, transmission scheduled at %u, next TBTT: %u\n",
>   		    ev->vdev_id, ev->fils_tt, ev->tbtt);
> -
> -	kfree(tb);
>   }
>   
>   static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
> @@ -8856,7 +8796,7 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
>   	const struct wmi_probe_resp_tx_status_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab,
> @@ -8869,7 +8809,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
>   	if (!ev) {
>   		ath12k_warn(ab,
>   			    "failed to fetch probe response transmission status event");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -8877,8 +8816,6 @@ static void ath12k_probe_resp_tx_status_event(struct ath12k_base *ab,
>   		ath12k_warn(ab,
>   			    "Probe response transmission failed for vdev_id %u, status %u\n",
>   			    ev->vdev_id, ev->tx_status);
> -
> -	kfree(tb);
>   }
>   
>   static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
> @@ -8890,7 +8827,7 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
>   	struct ath12k *ar;
>   	int ret, vdev_id;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse P2P NoA TLV: %d\n", ret);
> @@ -8900,10 +8837,8 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_P2P_NOA_EVENT];
>   	noa = tb[WMI_TAG_P2P_NOA_INFO];
>   
> -	if (!ev || !noa) {
> -		ret = -EPROTO;
> -		goto out;
> -	}
> +	if (!ev || !noa)
> +		return -EPROTO;
>   
>   	vdev_id = __le32_to_cpu(ev->vdev_id);
>   
> @@ -8926,8 +8861,6 @@ static int ath12k_wmi_p2p_noa_event(struct ath12k_base *ab,
>   
>   unlock:
>   	rcu_read_unlock();
> -out:
> -	kfree(tb);
>   	return ret;
>   }
>   
> @@ -8938,7 +8871,7 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
>   	const void **tb;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -8946,10 +8879,8 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
>   	}
>   
>   	ev = tb[WMI_TAG_RFKILL_EVENT];
> -	if (!ev) {
> -		kfree(tb);
> +	if (!ev)
>   		return;
> -	}
>   
>   	ath12k_dbg(ab, ATH12K_DBG_MAC,
>   		   "wmi tlv rfkill state change gpio %d type %d radio_state %d\n",
> @@ -8962,7 +8893,6 @@ static void ath12k_rfkill_state_change_event(struct ath12k_base *ab,
>   	spin_unlock_bh(&ab->base_lock);
>   
>   	queue_work(ab->workqueue, &ab->rfkill_work);
> -	kfree(tb);
>   }
>   
>   static void
> @@ -8978,7 +8908,7 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab,
>   	const struct wmi_twt_enable_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse wmi twt enable status event tlv: %d\n",
> @@ -8989,15 +8919,12 @@ static void ath12k_wmi_twt_enable_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_TWT_ENABLE_COMPLETE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch twt enable wmi event\n");
> -		goto exit;
> +		return;
>   	}
>   
>   	ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt enable event pdev id %u status %u\n",
>   		   le32_to_cpu(ev->pdev_id),
>   		   le32_to_cpu(ev->status));
> -
> -exit:
> -	kfree(tb);
>   }
>   
>   static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
> @@ -9007,7 +8934,7 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
>   	const struct wmi_twt_disable_event *ev;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse wmi twt disable status event tlv: %d\n",
> @@ -9018,15 +8945,12 @@ static void ath12k_wmi_twt_disable_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_TWT_DISABLE_COMPLETE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch twt disable wmi event\n");
> -		goto exit;
> +		return;
>   	}
>   
>   	ath12k_dbg(ab, ATH12K_DBG_MAC, "wmi twt disable event pdev id %d status %u\n",
>   		   le32_to_cpu(ev->pdev_id),
>   		   le32_to_cpu(ev->status));
> -
> -exit:
> -	kfree(tb);
>   }
>   
>   static int ath12k_wmi_wow_wakeup_host_parse(struct ath12k_base *ab,
> @@ -9099,7 +9023,7 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
>   	const void **tb;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse tlv: %d\n", ret);
> @@ -9109,7 +9033,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_GTK_OFFLOAD_STATUS_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch gtk offload status ev");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -9119,7 +9042,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
>   		rcu_read_unlock();
>   		ath12k_warn(ab, "failed to get arvif for vdev_id:%d\n",
>   			    le32_to_cpu(ev->vdev_id));
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -9135,8 +9057,6 @@ static void ath12k_wmi_gtk_offload_status_event(struct ath12k_base *ab,
>   				   (void *)&replay_ctr_be, GFP_ATOMIC);
>   
>   	rcu_read_unlock();
> -
> -	kfree(tb);
>   }
>   
>   static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
> @@ -9148,7 +9068,7 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
>   	const void **tb;
>   	int ret, i;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse mlo setup complete event tlv: %d\n",
> @@ -9159,7 +9079,6 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
>   	ev = tb[WMI_TAG_MLO_SETUP_COMPLETE_EVENT];
>   	if (!ev) {
>   		ath12k_warn(ab, "failed to fetch mlo setup complete event\n");
> -		kfree(tb);
>   		return;
>   	}
>   
> @@ -9178,14 +9097,11 @@ static void ath12k_wmi_event_mlo_setup_complete(struct ath12k_base *ab,
>   	if (!ar) {
>   		ath12k_warn(ab, "invalid pdev_id %d status %u in setup complete event\n",
>   			    ev->pdev_id, ev->status);
> -		goto out;
> +		return;
>   	}
>   
>   	ar->mlo_setup_status = le32_to_cpu(ev->status);
>   	complete(&ar->mlo_setup_done);
> -
> -out:
> -	kfree(tb);
>   }
>   
>   static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
> @@ -9195,7 +9111,7 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
>   	const void **tb;
>   	int ret;
>   
> -	tb = ath12k_wmi_tlv_parse_alloc(ab, skb, GFP_ATOMIC);
> +	tb = ath12k_wmi_tlv_parse(ab, skb);
>   	if (IS_ERR(tb)) {
>   		ret = PTR_ERR(tb);
>   		ath12k_warn(ab, "failed to parse teardown complete event tlv: %d\n", ret);
> @@ -9203,13 +9119,8 @@ static void ath12k_wmi_event_teardown_complete(struct ath12k_base *ab,
>   	}
>   
>   	ev = tb[WMI_TAG_MLO_TEARDOWN_COMPLETE];
> -	if (!ev) {
> +	if (!ev)
>   		ath12k_warn(ab, "failed to fetch teardown complete event\n");
> -		kfree(tb);
> -		return;
> -	}
> -
> -	kfree(tb);
>   }
>   
>   #ifdef CONFIG_ATH12K_DEBUGFS
> @@ -11239,3 +11150,31 @@ int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
>   	dev_kfree_skb(skb);
>   	return ret;
>   }
> +
> +int ath12k_wmi_alloc(void)
> +{
> +	guard(mutex)(&ath12k_wmi_mutex);
> +
> +	if (!ath12k_wmi_tb) {
> +		ath12k_wmi_tb = __alloc_percpu(WMI_TAG_MAX * sizeof(void *),
> +					       __alignof__(void *));
> +		if (!ath12k_wmi_tb)
> +			return -ENOMEM;
> +
> +		refcount_set(&ath12k_wmi_refcount, 1);
> +	} else {
> +		refcount_inc(&ath12k_wmi_refcount);
> +	}
> +
> +	return 0;
> +}
> +
> +void ath12k_wmi_free(void)
> +{
> +	guard(mutex)(&ath12k_wmi_mutex);
> +
> +	if (refcount_dec_and_test(&ath12k_wmi_refcount)) {
> +		free_percpu(ath12k_wmi_tb);
> +		ath12k_wmi_tb = NULL;
> +	}
> +}
> diff --git a/drivers/net/wireless/ath/ath12k/wmi.h b/drivers/net/wireless/ath/ath12k/wmi.h
> index 5ba9b7d3a888..4a34b2ca99ea 100644
> --- a/drivers/net/wireless/ath/ath12k/wmi.h
> +++ b/drivers/net/wireless/ath/ath12k/wmi.h
> @@ -6576,4 +6576,7 @@ int ath12k_wmi_send_vdev_set_tpc_power(struct ath12k *ar,
>   				       struct ath12k_reg_tpc_power_info *param);
>   int ath12k_wmi_send_mlo_link_set_active_cmd(struct ath12k_base *ab,
>   					    struct wmi_mlo_link_set_active_arg *param);
> +int ath12k_wmi_alloc(void);
> +void ath12k_wmi_free(void);
> +
>   #endif

Reviewed-by: Rameshkumar Sundaram <rameshkumar.sundaram@oss.qualcomm.com>



^ 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