* [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
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox