Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] Documentation/devicetree/bindings: update Sudeep Holla's email address
From: Laszlo Ersek @ 2026-07-20 16:02 UTC (permalink / raw)
  To: laszlo.ersek
  Cc: Conor Dooley, Cristian Marussi, Jassi Brar, Krzysztof Kozlowski,
	Linus Walleij, Liviu Dudau, Lorenzo Pieralisi, Rob Herring,
	Sudeep Holla, arm-scmi, devicetree, linux-arm-kernel,
	linux-kernel

MAINTAINERS disagrees with Documentation/devicetree/bindings on Sudeep's
email address; fix the latter.

Cc: Conor Dooley <conor+dt@kernel.org>
Cc: Cristian Marussi <cristian.marussi@arm.com>
Cc: Jassi Brar <jassisinghbrar@gmail.com>
Cc: Krzysztof Kozlowski <krzk+dt@kernel.org>
Cc: Linus Walleij <linusw@kernel.org>
Cc: Liviu Dudau <liviu.dudau@arm.com>
Cc: Lorenzo Pieralisi <lpieralisi@kernel.org>
Cc: Rob Herring <robh@kernel.org>
Cc: Sudeep Holla <sudeep.holla@kernel.org>
Cc: arm-scmi@vger.kernel.org
Cc: devicetree@vger.kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: linux-kernel@vger.kernel.org
Fixes: 59e82a4237cf ("MAINTAINERS: Change Sudeep Holla's email address")
Signed-off-by: Laszlo Ersek <laszlo.ersek@arm.com>
---
 Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml | 2 +-
 Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml      | 2 +-
 Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml       | 2 +-
 Documentation/devicetree/bindings/dvfs/performance-domain.yaml    | 2 +-
 Documentation/devicetree/bindings/firmware/arm,scmi.yaml          | 2 +-
 Documentation/devicetree/bindings/firmware/arm,scpi.yaml          | 2 +-
 Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml          | 2 +-
 7 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml b/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
index ce5f2e1ec1ea..4ae7dc706b84 100644
--- a/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,juno-fpga-apb-regs.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: ARM Juno FPGA APB Registers
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
 
 properties:
   compatible:
diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
index 95d4baa85506..30cc534a91ee 100644
--- a/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,vexpress-juno.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: ARM Versatile Express and Juno Boards
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
   - Linus Walleij <linusw@kernel.org>
 
 description: |+
diff --git a/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml b/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
index 9b8f7e0c4ea0..060c0bc58a15 100644
--- a/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
+++ b/Documentation/devicetree/bindings/arm/arm,vexpress-scc.yaml
@@ -8,7 +8,7 @@ title: ARM Versatile Express Serial Configuration Controller
 
 maintainers:
   - Liviu Dudau <liviu.dudau@arm.com>
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
 
 description: |
   Test chips for ARM Versatile Express platform implement SCC (Serial
diff --git a/Documentation/devicetree/bindings/dvfs/performance-domain.yaml b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
index cc930660b794..09bbd2e33786 100644
--- a/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
+++ b/Documentation/devicetree/bindings/dvfs/performance-domain.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: Generic performance domains
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
 
 description: |+
   This binding is intended for performance management of groups of devices or
diff --git a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
index d06cca9273c4..6fc44105f1c3 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scmi.yaml
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: System Control and Management Interface (SCMI) Message Protocol
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
 
 description: |
   The SCMI is intended to allow agents such as OSPM to manage various functions
diff --git a/Documentation/devicetree/bindings/firmware/arm,scpi.yaml b/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
index 241317239ffc..08c7e05c577c 100644
--- a/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
+++ b/Documentation/devicetree/bindings/firmware/arm,scpi.yaml
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: System Control and Power Interface (SCPI) Message Protocol
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
 
 description: |
   Firmware implementing the SCPI described in ARM document number ARM DUI
diff --git a/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml b/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
index 449b55afeb7d..025a5c55b284 100644
--- a/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
+++ b/Documentation/devicetree/bindings/mailbox/arm,mhuv3.yaml
@@ -7,7 +7,7 @@ $schema: http://devicetree.org/meta-schemas/core.yaml#
 title: ARM MHUv3 Mailbox Controller
 
 maintainers:
-  - Sudeep Holla <sudeep.holla@arm.com>
+  - Sudeep Holla <sudeep.holla@kernel.org>
   - Cristian Marussi <cristian.marussi@arm.com>
 
 description: |

^ permalink raw reply related

* [PATCH v6 0/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-20 16:03 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida

Hi folks,

This is my take on implementing the new vDSO for unlocking a robust futex in
arm64. If you don't know what's that, Thomas wrote a good summary,
including the motivation for this work and the x86 implementation:

   https://lore.kernel.org/lkml/878qb89g7b.ffs@tglx/

* Testing

There's one selftest proposed [1] that tests precisely if the task is
interrupted during the critical section, if the kernel will clear op_pending
pointer. I've adapted to arm64 [2] and it works as expected. This test is not
being upstreamed right now because it depends on a better way to expose
vdso.so.dbg [3].

I also used gdb to manually check if the address is cleared when the kernel
interrupts the critical section.

Thanks!
	André

[1] https://lore.kernel.org/lkml/20260404093939.7XgeW_54@linutronix.de/
[2] https://lore.kernel.org/lkml/20260529-tonyk-robust_arm-v3-3-a6f02684d4fe@igalia.com/
[3] https://lore.kernel.org/lkml/20260602090536.045586688@kernel.org/

Changes in v6:
- Reorganized the patchset, better split for helpers functions vs aarch64 vs
arm32 code
- Use "full name" for labels instead of macros
- Completely reworded "Implement __vdso_futex_robust_try_unlock()" to make it
more obvious what's the bug and how does this fix it
v5: https://patch.msgid.link/20260717-tonyk-robust_arm-v5-0-ffd1ad318d17@igalia.com

Changes in v5:
 - Drop unneeded commit "arm64/entry: Unify user mode handling"
 - Replace "_success" with "_start" labels in vdso_futex_robust_unlock_update_ips
 - Added "cc" to the asm clobberlist
v4: https://patch.msgid.link/20260705-tonyk-robust_arm-v4-0-e0fd0fa259d3@igalia.com

Changes in v4:
 - Added commit "arm64/entry: Unify user mode handling"
 - Added missing ifdef FUTEX_ROBUST_UNLOCK guards
 - Fixed the position of _start and _success labels in the critical section
 - Instead of checking the zero flag, check the result register to decide if the
 op_pending needs to be cleared
v3: https://patch.msgid.link/20260529-tonyk-robust_arm-v3-0-a6f02684d4fe@igalia.com

Changes in v3:
 - Change asm to always use x2 to store *pop
 - Fix clang asm errors
 - Moved 32 bit entry point to vdso32/ and use littlearm asm
 - Adapted Sebastians test for arm
v2: https://patch.msgid.link/20260424-tonyk-robust_arm-v2-0-db4e46f752cf@igalia.com

Changes in v2:
 - s/CONFIG_COMPAT/CONFIG_COMPAT_VDSO (Thomas Weißschuh)
 - Fixed linker not finding the symbols (Thomas Weißschuh)
v1: https://patch.msgid.link/20260417-tonyk-robust_arm-v1-0-03aa64e2ff1a@igalia.com

---
André Almeida (4):
      arm64: vdso: Prepare for robust futex unlock support
      arm64: vdso: Implement __vdso_futex_robust_try_unlock()
      arm64: vdso32: Bring vdso32-offsets.h back
      arm64: vdso32: Implement __vdso_futex_robust_try_unlock()

 arch/arm64/Kconfig                    |  1 +
 arch/arm64/Makefile                   |  2 +-
 arch/arm64/include/asm/futex_robust.h | 19 ++++++++++++
 arch/arm64/include/asm/vdso.h         |  3 ++
 arch/arm64/kernel/vdso.c              | 54 ++++++++++++++++++++++++++++++++++-
 arch/arm64/kernel/vdso/Makefile       | 10 +++++++
 arch/arm64/kernel/vdso/vdso.lds.S     |  9 ++++++
 arch/arm64/kernel/vdso/vfutex.c       | 35 +++++++++++++++++++++++
 arch/arm64/kernel/vdso32/Makefile     | 12 ++++++++
 arch/arm64/kernel/vdso32/vdso.lds.S   |  9 ++++++
 arch/arm64/kernel/vdso32/vfutex.c     | 34 ++++++++++++++++++++++
 11 files changed, 186 insertions(+), 2 deletions(-)
---
base-commit: af5e34a41cd607c00ef752e00331736570992354
change-id: 20260416-tonyk-robust_arm-54ff77d2c4e4

Best regards,
--  
André Almeida <andrealmeid@igalia.com>



^ permalink raw reply

* [PATCH v6 2/4] arm64: vdso: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-20 16:03 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida
In-Reply-To: <20260720-tonyk-robust_arm-v6-0-7e68c122047e@igalia.com>

The futex's robust list uAPI has a struct robust_list_head::list_op_pending
pointer used by userspace as a temporary variable while the mutex unlock is
happening. User sets it to the futex address that's about to be released
and removed from the robust list, and list_op_pending is cleared after.
After a thread dies, the kernel checks it's list_op_pending and wakes the
mutex in that address, to prevent starvation, and flip a bit in the mutex
word (FUTEX_OWNER_DIED).

However, there's a critical section where the user thread dies after the
mutex is released but before list_op_pending is cleared. If that happens,
another thread can wake up, use the lock, release it, and free its
memory. Now, if the robust list cleanup happens after this, the
killed thread's list_op_pending becomes a dandling pointer. The
kernel wrongly treats this address as a mutex, calls a futex_wake()
on it and flips a bit, causing a memory corruption.

To avoid using the dangling pointer, implement
__vdso_futex_robust_try_unlock() for arm64. Make the VDSO release the mutex
and clear the list_op_pending fields, just as is done in userspace right
now. But having it in a VDSO means that, in the case of a killed user
thread, the kernel can know exactly in which part of the release process
the thread was interrupt, check the registers for the operation success and
clears the list_op_pending on behalf of the user thread to prevent the
use-after-free bug.

The need for checking the instructions addresses and the register makes
this mechanism arch-dependent. Implement it using LL/SC semantics. If the
user instruction pointer is between the labels
__futex_list64_try_unlock_cs_start and __futex_list64_try_unlock_cs_end,
the critical section was interrupted. The kernel checks for the result
register (always w3) of the stlxr instruction used for atomically releasing
the mutex. If it's 1, the release happened and the kernel should clear the
list_op_pending field (always stored at x2).

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
v6:
 - Complete reword of commit message to make it clear
 - Better commit split, only the specific aarch64 things here
 - Use explicity labels instead of macros

v4:
 - Guard makefile for vfutex.o with ifdef
 - Moved _start label one instruction above
 - Use results register (w3) to check for store success instead of using zero
   flag

v3:
 - Managed to get pop to always be stored at x2
---
 arch/arm64/Kconfig                |  1 +
 arch/arm64/kernel/vdso.c          | 13 +++++++++++++
 arch/arm64/kernel/vdso/Makefile   | 10 ++++++++++
 arch/arm64/kernel/vdso/vdso.lds.S |  9 +++++++++
 arch/arm64/kernel/vdso/vfutex.c   | 35 +++++++++++++++++++++++++++++++++++
 5 files changed, 68 insertions(+)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index b3afe0688919..0582172811d9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -221,6 +221,7 @@ config ARM64
 	select HAVE_RELIABLE_STACKTRACE
 	select HAVE_POSIX_CPU_TIMERS_TASK_WORK
 	select HAVE_FUNCTION_ARG_ACCESS_API
+	select HAVE_FUTEX_ROBUST_UNLOCK
 	select MMU_GATHER_RCU_TABLE_FREE
 	select HAVE_RSEQ
 	select HAVE_RUST if RUSTC_SUPPORTS_ARM64
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 3ef331b5b240..1d1633e8339b 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -74,11 +74,22 @@ static inline void __vdso_futex_update_ips(struct mm_struct *mm, bool is_32bit,
 					   void *endp)
 #endif /* CONFIG_FUTEX_ROBUST_UNLOCK */
 
+static inline void vdso_futex_update_ips(struct mm_struct *mm)
+{
+	unsigned long vdso = (unsigned long) mm->context.vdso;
+
+	__vdso_futex_update_ips(mm, false,
+				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_start),
+				VDSO_SYMBOL(vdso, futex_list64_try_unlock_cs_end));
+}
+
 static int vdso_mremap(const struct vm_special_mapping *sm,
 		struct vm_area_struct *new_vma)
 {
 	current->mm->context.vdso = (void *)new_vma->vm_start;
 
+	vdso_futex_update_ips(current->mm);
+
 	return 0;
 }
 
@@ -366,5 +377,7 @@ int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	ret = __setup_additional_pages(VDSO_ABI_AA64, mm, bprm, uses_interp);
 	mmap_write_unlock(mm);
 
+	vdso_futex_update_ips(mm);
+
 	return ret;
 }
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..985346c7a0bb 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -11,6 +11,10 @@ include $(srctree)/lib/vdso/Makefile.include
 
 obj-vdso := vgettimeofday.o note.o sigreturn.o vgetrandom.o vgetrandom-chacha.o
 
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+  obj-vdso += vfutex.o
+endif
+
 # Build rules
 targets := $(obj-vdso) vdso.so vdso.so.dbg
 obj-vdso := $(addprefix $(obj)/, $(obj-vdso))
@@ -45,9 +49,11 @@ CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
 
 CFLAGS_REMOVE_vgettimeofday.o = $(CC_FLAGS_REMOVE_VDSO)
 CFLAGS_REMOVE_vgetrandom.o = $(CC_FLAGS_REMOVE_VDSO)
+CFLAGS_REMOVE_vfutex.o = $(CC_FLAGS_REMOVE_VDSO)
 
 CFLAGS_vgettimeofday.o = $(CC_FLAGS_ADD_VDSO)
 CFLAGS_vgetrandom.o = $(CC_FLAGS_ADD_VDSO)
+CFLAGS_vfutex.o = $(CC_FLAGS_ADD_VDSO)
 
 ifneq ($(c-gettimeofday-y),)
   CFLAGS_vgettimeofday.o += -include $(c-gettimeofday-y)
@@ -57,6 +63,10 @@ ifneq ($(c-getrandom-y),)
   CFLAGS_vgetrandom.o += -include $(c-getrandom-y)
 endif
 
+ifneq ($(c-futex-y),)
+  CFLAGS_vfutex.o += -include $(c-futex-y)
+endif
+
 targets += vdso.lds
 CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
 
diff --git a/arch/arm64/kernel/vdso/vdso.lds.S b/arch/arm64/kernel/vdso/vdso.lds.S
index 52314be29191..225f59bb81d1 100644
--- a/arch/arm64/kernel/vdso/vdso.lds.S
+++ b/arch/arm64/kernel/vdso/vdso.lds.S
@@ -104,6 +104,9 @@ VERSION
 		__kernel_clock_gettime;
 		__kernel_clock_getres;
 		__kernel_getrandom;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+		__vdso_futex_robust_list64_try_unlock;
+#endif
 	local: *;
 	};
 }
@@ -112,3 +115,9 @@ VERSION
  * Make the sigreturn code visible to the kernel.
  */
 VDSO_sigtramp		= __kernel_rt_sigreturn;
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list64_try_unlock_cs_start = __futex_list64_try_unlock_cs_start;
+VDSO_futex_list64_try_unlock_cs_success = __futex_list64_try_unlock_cs_success;
+VDSO_futex_list64_try_unlock_cs_end = __futex_list64_try_unlock_cs_end;
+#endif
diff --git a/arch/arm64/kernel/vdso/vfutex.c b/arch/arm64/kernel/vdso/vfutex.c
new file mode 100644
index 000000000000..83efd5e5896f
--- /dev/null
+++ b/arch/arm64/kernel/vdso/vfutex.c
@@ -0,0 +1,35 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+__u32 __vdso_futex_robust_list64_try_unlock(__u32 *lock, __u32 tid, __u64 *pop)
+{
+	register __u64 *pop_reg asm("x2") = pop;
+	register __u32 result_reg asm("w3") = 0;
+	__u32 val;
+
+	asm volatile (
+		".globl						  "
+		"__futex_list64_try_unlock_cs_start,		  "
+		"__futex_list64_try_unlock_cs_success,		  "
+		"__futex_list64_try_unlock_cs_end		\n"
+
+		"	prfm pstl1strm, %[lock]			\n"
+		"retry:						\n"
+		"	ldxr %w[val], %[lock]			\n"
+		"	cmp %w[tid], %w[val]			\n"
+		"	bne __futex_list64_try_unlock_cs_end	\n"
+		"	stlxr %w[result], wzr, %[lock]		\n"
+		"__futex_list64_try_unlock_cs_start:		\n"
+		"	cbnz %w[result], retry			\n"
+		"__futex_list64_try_unlock_cs_success:		\n"
+		"	str xzr, %[pop_reg]			\n"
+		"__futex_list64_try_unlock_cs_end:		\n"
+
+		: [val] "=&r" (val), [result] "=&r" (result_reg)
+		: [tid] "r" (tid), [lock] "Q" (*lock), [pop_reg] "Q" (*pop_reg)
+		: "cc", "memory"
+	);
+
+	return val;
+}

-- 
2.55.0



^ permalink raw reply related

* [PATCH v6 3/4] arm64: vdso32: Bring vdso32-offsets.h back
From: André Almeida @ 2026-07-20 16:03 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida
In-Reply-To: <20260720-tonyk-robust_arm-v6-0-7e68c122047e@igalia.com>

Commit c7767f5c43df ("arm64: vdso32: Remove unused vdso32-offsets.h")
removed vdso32-offsets.h because it was empty and therefore useless.

With the introduction of __vdso_futex_robust_try_unlock(), there is the
need to expose offsets again.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
 arch/arm64/Makefile               | 2 +-
 arch/arm64/include/asm/vdso.h     | 3 +++
 arch/arm64/kernel/vdso32/Makefile | 8 ++++++++
 3 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 6b005c8fef70..265716644193 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -211,7 +211,7 @@ vdso_prepare: prepare0
 	include/generated/vdso-offsets.h arch/arm64/kernel/vdso/vdso.so
 ifdef CONFIG_COMPAT_VDSO
 	$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
-	arch/arm64/kernel/vdso32/vdso.so
+	include/generated/vdso32-offsets.h arch/arm64/kernel/vdso32/vdso.so
 endif
 endif
 
diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 232b46969088..43a214b93524 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -10,6 +10,9 @@
 #ifndef __ASSEMBLER__
 
 #include <generated/vdso-offsets.h>
+#ifdef CONFIG_COMPAT_VDSO
+#include <generated/vdso32-offsets.h>
+#endif
 
 #define VDSO_SYMBOL(base, name)						   \
 ({									   \
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index bea3675fa668..4bd60f059f4a 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -135,6 +135,14 @@ $(c-obj-vdso-gettimeofday): %.o: %.c FORCE
 $(asm-obj-vdso): %.o: %.S FORCE
 	$(call if_changed_dep,vdsoas)
 
+# Generate VDSO offsets using helper script
+gen-vdsosym := $(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+      cmd_vdsosym = $(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+
+include/generated/vdso32-offsets.h: $(obj)/vdso32.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
 # Actual build commands
 quiet_cmd_vdsold_and_vdso_check = LD32    $@
       cmd_vdsold_and_vdso_check = $(cmd_vdsold); $(cmd_vdso_check)

-- 
2.55.0



^ permalink raw reply related

* [PATCH v6 4/4] arm64: vdso32: Implement __vdso_futex_robust_try_unlock()
From: André Almeida @ 2026-07-20 16:03 UTC (permalink / raw)
  To: Catalin Marinas, Will Deacon, Thomas Gleixner, Mark Rutland,
	Mathieu Desnoyers, Sebastian Andrzej Siewior, Peter Zijlstra,
	Florian Weimer, Darren Hart, Ingo Molnar, Davidlohr Bueso,
	Arnd Bergmann, Uros Bizjak, Thomas Weißschuh
  Cc: linux-arm-kernel, linux-kernel, linux-arch, kernel-dev, LKML,
	André Almeida
In-Reply-To: <20260720-tonyk-robust_arm-v6-0-7e68c122047e@igalia.com>

Based on aarch64 implementation, provide a 32 bit entry point for
this vDSO.

In order to keep compatibility with arm64_futex_robust_unlock_get_pop(),
make sure to store the pop address at r2 and the compare result value
at r3.

Signed-off-by: André Almeida <andrealmeid@igalia.com>
---
 arch/arm64/kernel/vdso.c            | 14 ++++++++++++++
 arch/arm64/kernel/vdso32/Makefile   |  4 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S |  9 +++++++++
 arch/arm64/kernel/vdso32/vfutex.c   | 34 ++++++++++++++++++++++++++++++++++
 4 files changed, 61 insertions(+)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 1d1633e8339b..d9b86f9a0db6 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -182,6 +182,15 @@ enum aarch32_map {
 static struct page *aarch32_vectors_page __ro_after_init;
 static struct page *aarch32_sig_page __ro_after_init;
 
+static inline void aarch32_vdso_futex_update_ips(struct mm_struct *mm)
+{
+	unsigned long vdso = (unsigned long) mm->context.vdso;
+
+	__vdso_futex_update_ips(mm, true,
+				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_start),
+				VDSO_SYMBOL(vdso, futex_list32_try_unlock_cs_end));
+}
+
 static int aarch32_sigpage_mremap(const struct vm_special_mapping *sm,
 				  struct vm_area_struct *new_vma)
 {
@@ -195,6 +204,8 @@ static int aarch32_mremap(const struct vm_special_mapping *sm,
 {
 	current->mm->context.vdso = (void *)new_vma->vm_start;
 
+	aarch32_vdso_futex_update_ips(current->mm);
+
 	return 0;
 }
 
@@ -327,6 +338,7 @@ static int aarch32_sigreturn_setup(struct mm_struct *mm)
 	return PTR_ERR_OR_ZERO(ret);
 }
 
+
 int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
@@ -347,6 +359,8 @@ int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 	}
 
 	ret = aarch32_sigreturn_setup(mm);
+
+	aarch32_vdso_futex_update_ips(mm);
 out:
 	mmap_write_unlock(mm);
 	return ret;
diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
index 4bd60f059f4a..f3190125c68b 100644
--- a/arch/arm64/kernel/vdso32/Makefile
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -97,6 +97,10 @@ munge := ../../../arm/vdso/vdsomunge
 hostprogs := $(munge)
 
 c-obj-vdso := note.o
+ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+  c-obj-vdso += vfutex.o
+endif
+
 c-obj-vdso-gettimeofday := vgettimeofday.o
 
 ifneq ($(c-gettimeofday-y),)
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
index c374fb0146f3..46c0123b2684 100644
--- a/arch/arm64/kernel/vdso32/vdso.lds.S
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -87,6 +87,15 @@ VERSION
 		__vdso_clock_getres;
 		__vdso_clock_gettime64;
 		__vdso_clock_getres_time64;
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+		__vdso_futex_robust_list32_try_unlock;
+#endif
 	local: *;
 	};
 }
+
+#ifdef CONFIG_FUTEX_ROBUST_UNLOCK
+VDSO_futex_list32_try_unlock_cs_success = __futex_list32_try_unlock_cs_success;
+VDSO_futex_list32_try_unlock_cs_start = __futex_list32_try_unlock_cs_start;
+VDSO_futex_list32_try_unlock_cs_end = __futex_list32_try_unlock_cs_end;
+#endif
diff --git a/arch/arm64/kernel/vdso32/vfutex.c b/arch/arm64/kernel/vdso32/vfutex.c
new file mode 100644
index 000000000000..030eb767b8d6
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vfutex.c
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+#include <linux/stringify.h>
+#include <vdso/futex.h>
+
+__u32 __vdso_futex_robust_list32_try_unlock(__u32 *lock, __u32 tid, __u32 *pop)
+{
+	register __u32 *pop_reg asm("r2") = pop, result_reg asm("r3") = 0;
+	__u32 val, zero = 0;
+
+	asm volatile (
+		".globl						  "
+		"__futex_list32_try_unlock_cs_start,		  "
+		"__futex_list32_try_unlock_cs_success,		  "
+		"__futex_list32_try_unlock_cs_end		\n"
+
+		"retry:						\n"
+		"	ldrex %[val], %[lock]			\n"
+		"	cmp %[tid], %[val]			\n"
+		"	bne __futex_list32_try_unlock_cs_end	\n"
+		"	strex %[result], %[zero], %[lock]	\n"
+		"__futex_list32_try_unlock_cs_start:		\n"
+		"	cmp %[result], #0			\n"
+		"	bne retry				\n"
+		"__futex_list32_try_unlock_cs_success:		\n"
+		"	str %[zero], %[pop_reg]			\n"
+		"__futex_list32_try_unlock_cs_end:		\n"
+
+		: [val] "=&r" (val), [result] "=r" (result_reg)
+		: [tid] "r" (tid), [lock] "Q" (*lock), [pop_reg] "Q" (*pop_reg), [zero] "r" (zero)
+		: "cc", "memory"
+	);
+
+	return val;
+}

-- 
2.55.0



^ permalink raw reply related

* Re: [PATCH v2] cpufreq: apple-soc: Calculate frequency as a 64-bit value
From: Joshua Peisach @ 2026-07-20 16:05 UTC (permalink / raw)
  To: Sasha Finkelstein, Sven Peter, Janne Grunau, Neal Gompa,
	Rafael J. Wysocki, Viresh Kumar
  Cc: asahi, linux-arm-kernel, linux-pm, linux-kernel
In-Reply-To: <20260720-cpufreq-64-v2-1-72bd9b4e5ca0@chaosmail.tech>

On Mon Jul 20, 2026 at 3:25 AM EDT, Sasha Finkelstein wrote:
> The current frequency calculation is done in 32 bit, causing problems
> if run on a future SoC that can boost higher than 4.2GHz. Ideally, we
> should use a true u64 instead of unsigned long and "knowning" that this
> only runs on 64 bit machines, but the core code uses ulong everywhere,
> so this should be good enough.
>
> Signed-off-by: Sasha Finkelstein <k@chaosmail.tech>
> ---
> Changes in v2:
> - Minor style fixes
> - Link to v1: https://patch.msgid.link/20260703-cpufreq-64-v1-1-c406c705319a@chaosmail.tech
> ---
>  drivers/cpufreq/apple-soc-cpufreq.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/cpufreq/apple-soc-cpufreq.c b/drivers/cpufreq/apple-soc-cpufreq.c
> index 638e5bf72185..5ad274a1e6ae 100644
> --- a/drivers/cpufreq/apple-soc-cpufreq.c
> +++ b/drivers/cpufreq/apple-soc-cpufreq.c
> @@ -288,7 +288,7 @@ static int apple_soc_cpufreq_init(struct cpufreq_policy *policy)
>  
>  	/* Get OPP levels (p-state indexes) and stash them in driver_data */
>  	for (i = 0; freq_table[i].frequency != CPUFREQ_TABLE_END; i++) {
> -		unsigned long rate = freq_table[i].frequency * 1000 + 999;
> +		unsigned long rate = freq_table[i].frequency * 1000UL + 999;
>  		struct dev_pm_opp *opp = dev_pm_opp_find_freq_floor(cpu_dev, &rate);
>  
>  		if (IS_ERR(opp)) {
>
> ---
> base-commit: 4a50a141f05a8d1737661b19ee22ff8455b94409
> change-id: 20260703-cpufreq-64-2a23d7261e09
>
> Best regards,
> --  
> Sasha Finkelstein <k@chaosmail.tech>

Reviewed-by: Joshua Peisach <jpeisach@ubuntu.com>


^ permalink raw reply

* Re: [PATCH v3 07/16] arm_mpam: __ris_msmon_read(): get rid of nrdy special handling
From: Ben Horgan @ 2026-07-20 16:09 UTC (permalink / raw)
  To: Andre Przywara, Lorenzo Pieralisi, Hanjun Guo, Sudeep Holla,
	Catalin Marinas, Will Deacon, Rafael J . Wysocki, Len Brown,
	James Morse, Reinette Chatre, Fenghua Yu
  Cc: Jonathan Cameron, Srivathsa L Rao, Ganapatrao Kulkarni,
	Trilok Soni, Srinivas Ramana, Niyas Sait, linux-acpi,
	linux-arm-kernel, linux-kernel
In-Reply-To: <c2c995a2-6834-4210-a9ee-60f8983be135@arm.com>

Hi Andre,

On 7/20/26 16:58, Andre Przywara wrote:
> Hi Ben,
> 
> thanks for having a look!
> 
> On 7/15/26 15:39, Ben Horgan wrote:
>> Hi Andre,
>>
>> On 7/10/26 15:45, Andre Przywara wrote:
>>> Although so far MSC accesses couldn't fail, there is one special
>>> condition that would create an error: when the MBWU counter wouldn't be
>>> able to read a stable value, we were setting bit 63 to mark this value
>>> as unstable, and return this as an error later.
>>> Now since the functions can return a proper error value, we can get rid of
>>> this kludge and use the return value directly.
>>>
>>> Remove the "nrdy" error flag variable, and assign -EBUSY to "ret" to handle
>>> this case.
>>
>> I don't think we want this patch. The h/w can still return (as much as it ever could) and so we
>> still need to handle it even if we are no longer augmenting its meaning in software to also indicate
>> an unstable 64 bit value.
> 
> Mmh, not sure I understand your concern: to me it looks like nrdy is some kind of error flag, that
> we used in absence of a proper error return value. Now we have "int ret;", so can use that directly?
> But to me it looks like nothing really changes, or did I miss something?
> 
> I have no really strong opinion of this patch, it was more an pportunity to consolidate the crude
> error handling in this function. I am happy to drop it, if you like, maybe we can revisit this later.

What I was trying to say is that mpam_msc_read_mbwu_l() could previously return a value with bit 63,
MSMON__L_NRDY set in two cases, one set by s/w and one set by h/w. Either when it reads that
directly from the hardware or when it is set in the function to indicate an unstable value. The h/w
case is the same for 31 bit counters too except in that case the h/w sets bit 31, MSMON_NRDY. Using
'ret' to directly return -EBUSY for the s/w case where a stable value is not reached for 44 or 63
bit counters doesn't mean that the h/w case won't happen.


Thanks,

Ben

> 
> Cheers,
> Andre
> 
>>
>> Thanks,
>>
>> Ben
>>
>>>
>>> Signed-off-by: Andre Przywara <andre.przywara@arm.com>
>>> ---
>>>   drivers/resctrl/mpam_devices.c | 38 +++++++++++++++-------------------
>>>   1 file changed, 17 insertions(+), 21 deletions(-)
>>>
>>> diff --git a/drivers/resctrl/mpam_devices.c b/drivers/resctrl/mpam_devices.c
>>> index 84a8715464be..530ac0fe97b5 100644
>>> --- a/drivers/resctrl/mpam_devices.c
>>> +++ b/drivers/resctrl/mpam_devices.c
>>> @@ -1306,7 +1306,6 @@ static void __ris_msmon_read(void *arg)
>>>       u64 now;
>>>       int ret;
>>>       u32 now32;
>>> -    bool nrdy = false;
>>>       bool config_mismatch;
>>>       bool overflow = false;
>>>       struct mon_read *m = arg;
>>> @@ -1371,14 +1370,18 @@ static void __ris_msmon_read(void *arg)
>>>       switch (m->type) {
>>>       case mpam_feat_msmon_csu:
>>>           ret = mpam_read_monsel_reg(msc, CSU, &now32);
>>> +        if (!ret) {
>>> +            if ((now32 & MSMON___NRDY))
>>> +                ret = -EBUSY;
>>> +
>>> +            if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) &&
>>> +                m->waited_timeout)
>>> +                ret = 0;
>>> +        }
>>>           if (ret)
>>>               goto out_unlock;
>>> -        nrdy = now32 & MSMON___NRDY;
>>> -        now = FIELD_GET(MSMON___VALUE, now32);
>>> -
>>> -        if (mpam_has_quirk(IGNORE_CSU_NRDY, msc) && m->waited_timeout)
>>> -            nrdy = false;
>>>   +        now = FIELD_GET(MSMON___VALUE, now32);
>>>           break;
>>>       case mpam_feat_msmon_mbwu_31counter:
>>>       case mpam_feat_msmon_mbwu_44counter:
>>> @@ -1394,9 +1397,11 @@ static void __ris_msmon_read(void *arg)
>>>                   now = FIELD_GET(MSMON___L_VALUE, now);
>>>           } else {
>>>               ret = mpam_read_monsel_reg(msc, MBWU, &now32);
>>> +            if (!ret && (now32 & MSMON___NRDY))
>>> +                ret = -EBUSY;
>>>               if (ret)
>>>                   goto out_unlock;
>>> -            nrdy = now32 & MSMON___NRDY;
>>> +
>>>               now = FIELD_GET(MSMON___VALUE, now32);
>>>           }
>>>   @@ -1404,9 +1409,6 @@ static void __ris_msmon_read(void *arg)
>>>               m->type != mpam_feat_msmon_mbwu_63counter)
>>>               now *= 64;
>>>   -        if (nrdy)
>>> -            break;
>>> -
>>>           mbwu_state = &ris->mbwu_state[ctx->mon];
>>>             if (overflow)
>>> @@ -1419,22 +1421,16 @@ static void __ris_msmon_read(void *arg)
>>>           now += mbwu_state->correction;
>>>           break;
>>>       default:
>>> -        m->err = -EINVAL;
>>> +        ret = -EINVAL;
>>>       }
>>> -    mpam_mon_sel_unlock(msc);
>>> -
>>> -    if (nrdy)
>>> -        m->err = -EBUSY;
>>> -
>>> -    if (!m->err)
>>> -        *m->val += now;
>>> -
>>> -    return;
>>>     out_unlock:
>>>       mpam_mon_sel_unlock(msc);
>>>   -    m->err = ret;
>>> +    if (ret)
>>> +        m->err = ret;
>>> +    else
>>> +        *m->val += now;
>>>   }
>>>     static int _msmon_read(struct mpam_component *comp, struct mon_read *arg)
>>
> 



^ permalink raw reply

* Patch "net: ethernet: ti: icssg: guard PA stat lookups" has been added to the 7.1-stable tree
From: gregkh @ 2026-07-20 15:55 UTC (permalink / raw)
  To: danishanwar, gregkh, horms, kuba, linux-arm-kernel,
	philippe.schenker, rogerq
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    net: ethernet: ti: icssg: guard PA stat lookups

to the 7.1-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     net-ethernet-ti-icssg-guard-pa-stat-lookups.patch
and it can be found in the queue-7.1 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From 27b9daba50609335db6ca81e4cccf50ded21ec76 Mon Sep 17 00:00:00 2001
From: Philippe Schenker <philippe.schenker@impulsing.ch>
Date: Thu, 18 Jun 2026 11:30:24 +0200
Subject: net: ethernet: ti: icssg: guard PA stat lookups

From: Philippe Schenker <philippe.schenker@impulsing.ch>

commit 27b9daba50609335db6ca81e4cccf50ded21ec76 upstream.

icssg_ndo_get_stats64() unconditionally calls emac_get_stat_by_name()
with FW PA stat names regardless of whether the PA stats block is
present on the hardware.  emac_get_stat_by_name() already guards the
PA stats lookup with `if (emac->prueth->pa_stats)`; when that pointer
is NULL the lookup falls through to netdev_err() and returns -EINVAL.
Because ndo_get_stats64 is polled regularly by the networking stack
this produces thousands of log entries of the form:

  icssg-prueth icssg1-eth end0: Invalid stats FW_RX_ERROR

A secondary consequence is that the int(-EINVAL) return value is
implicitly widened to a near-ULLONG_MAX unsigned value when accumulated
into the __u64 fields of rtnl_link_stats64, silently corrupting the
rx_errors, rx_dropped and tx_dropped counters reported by `ip -s link`.

Every other PA-aware code path in the driver is already guarded with
the same `if (emac->prueth->pa_stats)` check.  Apply the same guard
here.

Fixes: 0d15a26b247d ("net: ti: icssg-prueth: Add ICSSG FW Stats")
Signed-off-by: Philippe Schenker <philippe.schenker@impulsing.ch>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Cc: danishanwar@ti.com
Cc: rogerq@kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260618093037.3448858-1-dev@pschenker.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/net/ethernet/ti/icssg/icssg_common.c |   49 +++++++++++++++------------
 1 file changed, 28 insertions(+), 21 deletions(-)

--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -1651,28 +1651,35 @@ void icssg_ndo_get_stats64(struct net_de
 	stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");
 	stats->multicast      = emac_get_stat_by_name(emac, "rx_multicast_frames");
 
-	stats->rx_errors  = ndev->stats.rx_errors +
-			    emac_get_stat_by_name(emac, "FW_RX_ERROR") +
-			    emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") +
-			    emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") +
-			    emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") +
-			    emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN");
-	stats->rx_dropped = ndev->stats.rx_dropped +
-			    emac_get_stat_by_name(emac, "FW_DROPPED_PKT") +
-			    emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") +
-			    emac_get_stat_by_name(emac, "FW_INF_SAV") +
-			    emac_get_stat_by_name(emac, "FW_INF_SA_DL") +
-			    emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+	stats->rx_errors  = ndev->stats.rx_errors;
+	stats->rx_dropped = ndev->stats.rx_dropped;
 	stats->tx_errors  = ndev->stats.tx_errors;
-	stats->tx_dropped = ndev->stats.tx_dropped +
-			    emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
-			    emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") +
-			    emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") +
-			    emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF");
+	stats->tx_dropped = ndev->stats.tx_dropped;
+
+	if (!emac->prueth->pa_stats)
+		return;
+
+	stats->rx_errors  +=
+			emac_get_stat_by_name(emac, "FW_RX_ERROR") +
+			emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") +
+			emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") +
+			emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") +
+			emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN");
+	stats->rx_dropped +=
+			emac_get_stat_by_name(emac, "FW_DROPPED_PKT") +
+			emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") +
+			emac_get_stat_by_name(emac, "FW_INF_SAV") +
+			emac_get_stat_by_name(emac, "FW_INF_SA_DL") +
+			emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+	stats->tx_dropped +=
+			emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
+			emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") +
+			emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") +
+			emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF");
 }
 EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64);
 


Patches currently in stable-queue which might be from philippe.schenker@impulsing.ch are

queue-7.1/net-ethernet-ti-icssg-guard-pa-stat-lookups.patch


^ permalink raw reply

* Patch "net: ethernet: ti: icssg: guard PA stat lookups" has been added to the 6.18-stable tree
From: gregkh @ 2026-07-20 16:11 UTC (permalink / raw)
  To: danishanwar, gregkh, horms, kuba, linux-arm-kernel,
	philippe.schenker, rogerq
  Cc: stable-commits


This is a note to let you know that I've just added the patch titled

    net: ethernet: ti: icssg: guard PA stat lookups

to the 6.18-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     net-ethernet-ti-icssg-guard-pa-stat-lookups.patch
and it can be found in the queue-6.18 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@vger.kernel.org> know about it.


From 27b9daba50609335db6ca81e4cccf50ded21ec76 Mon Sep 17 00:00:00 2001
From: Philippe Schenker <philippe.schenker@impulsing.ch>
Date: Thu, 18 Jun 2026 11:30:24 +0200
Subject: net: ethernet: ti: icssg: guard PA stat lookups

From: Philippe Schenker <philippe.schenker@impulsing.ch>

commit 27b9daba50609335db6ca81e4cccf50ded21ec76 upstream.

icssg_ndo_get_stats64() unconditionally calls emac_get_stat_by_name()
with FW PA stat names regardless of whether the PA stats block is
present on the hardware.  emac_get_stat_by_name() already guards the
PA stats lookup with `if (emac->prueth->pa_stats)`; when that pointer
is NULL the lookup falls through to netdev_err() and returns -EINVAL.
Because ndo_get_stats64 is polled regularly by the networking stack
this produces thousands of log entries of the form:

  icssg-prueth icssg1-eth end0: Invalid stats FW_RX_ERROR

A secondary consequence is that the int(-EINVAL) return value is
implicitly widened to a near-ULLONG_MAX unsigned value when accumulated
into the __u64 fields of rtnl_link_stats64, silently corrupting the
rx_errors, rx_dropped and tx_dropped counters reported by `ip -s link`.

Every other PA-aware code path in the driver is already guarded with
the same `if (emac->prueth->pa_stats)` check.  Apply the same guard
here.

Fixes: 0d15a26b247d ("net: ti: icssg-prueth: Add ICSSG FW Stats")
Signed-off-by: Philippe Schenker <philippe.schenker@impulsing.ch>
Reviewed-by: Simon Horman <horms@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

Cc: danishanwar@ti.com
Cc: rogerq@kernel.org
Cc: linux-arm-kernel@lists.infradead.org
Cc: stable@vger.kernel.org
Link: https://patch.msgid.link/20260618093037.3448858-1-dev@pschenker.ch
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
---
 drivers/net/ethernet/ti/icssg/icssg_common.c |   49 +++++++++++++++------------
 1 file changed, 28 insertions(+), 21 deletions(-)

--- a/drivers/net/ethernet/ti/icssg/icssg_common.c
+++ b/drivers/net/ethernet/ti/icssg/icssg_common.c
@@ -1315,28 +1315,35 @@ void icssg_ndo_get_stats64(struct net_de
 	stats->rx_over_errors = emac_get_stat_by_name(emac, "rx_over_errors");
 	stats->multicast      = emac_get_stat_by_name(emac, "rx_multicast_frames");
 
-	stats->rx_errors  = ndev->stats.rx_errors +
-			    emac_get_stat_by_name(emac, "FW_RX_ERROR") +
-			    emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") +
-			    emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") +
-			    emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") +
-			    emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN");
-	stats->rx_dropped = ndev->stats.rx_dropped +
-			    emac_get_stat_by_name(emac, "FW_DROPPED_PKT") +
-			    emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") +
-			    emac_get_stat_by_name(emac, "FW_INF_SAV") +
-			    emac_get_stat_by_name(emac, "FW_INF_SA_DL") +
-			    emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
-			    emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+	stats->rx_errors  = ndev->stats.rx_errors;
+	stats->rx_dropped = ndev->stats.rx_dropped;
 	stats->tx_errors  = ndev->stats.tx_errors;
-	stats->tx_dropped = ndev->stats.tx_dropped +
-			    emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
-			    emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") +
-			    emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") +
-			    emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF");
+	stats->tx_dropped = ndev->stats.tx_dropped;
+
+	if (!emac->prueth->pa_stats)
+		return;
+
+	stats->rx_errors  +=
+			emac_get_stat_by_name(emac, "FW_RX_ERROR") +
+			emac_get_stat_by_name(emac, "FW_RX_EOF_SHORT_FRMERR") +
+			emac_get_stat_by_name(emac, "FW_RX_B0_DROP_EARLY_EOF") +
+			emac_get_stat_by_name(emac, "FW_RX_EXP_FRAG_Q_DROP") +
+			emac_get_stat_by_name(emac, "FW_RX_FIFO_OVERRUN");
+	stats->rx_dropped +=
+			emac_get_stat_by_name(emac, "FW_DROPPED_PKT") +
+			emac_get_stat_by_name(emac, "FW_INF_PORT_DISABLED") +
+			emac_get_stat_by_name(emac, "FW_INF_SAV") +
+			emac_get_stat_by_name(emac, "FW_INF_SA_DL") +
+			emac_get_stat_by_name(emac, "FW_INF_PORT_BLOCKED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_TAGGED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_PRIOTAGGED") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_NOTAG") +
+			emac_get_stat_by_name(emac, "FW_INF_DROP_NOTMEMBER");
+	stats->tx_dropped +=
+			emac_get_stat_by_name(emac, "FW_RTU_PKT_DROP") +
+			emac_get_stat_by_name(emac, "FW_TX_DROPPED_PACKET") +
+			emac_get_stat_by_name(emac, "FW_TX_TS_DROPPED_PACKET") +
+			emac_get_stat_by_name(emac, "FW_TX_JUMBO_FRM_CUTOFF");
 }
 EXPORT_SYMBOL_GPL(icssg_ndo_get_stats64);
 


Patches currently in stable-queue which might be from philippe.schenker@impulsing.ch are

queue-6.18/net-ethernet-ti-icssg-guard-pa-stat-lookups.patch


^ permalink raw reply

* [PATCH v1 01/11] tracing: Include linux/types.h in trace_remote_event.h
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

trace_remote_event.h uses bool without including linux/types.h, so a
translation unit that includes it ahead of anything else that pulls
types.h in fails to build, as with nvhe/trace.h at EL2.

Fixes: 072529158e60 ("tracing: Add events to trace remotes")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 include/linux/trace_remote_event.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/include/linux/trace_remote_event.h b/include/linux/trace_remote_event.h
index c8ae1e1f5e721..e4cc2d4497bcf 100644
--- a/include/linux/trace_remote_event.h
+++ b/include/linux/trace_remote_event.h
@@ -3,6 +3,8 @@
 #ifndef _LINUX_TRACE_REMOTE_EVENTS_H
 #define _LINUX_TRACE_REMOTE_EVENTS_H
 
+#include <linux/types.h>
+
 struct trace_remote;
 struct trace_event_fields;
 struct trace_seq;
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 02/11] KVM: arm64: nVHE: Share the stacktrace per-CPU declarations with EL2
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

The declarations for overflow_stack, kvm_stacktrace_info and
pkvm_stacktrace are only visible to the host (the first two sit in the
host-only section of stacktrace/nvhe.h, the last is private to
kvm/stacktrace.c), so the definitions in nvhe/stacktrace.c compile
with no declaration in sight and sparse suggests making them static.
DECLARE_KVM_NVHE_PER_CPU() resolves to the right symbol name on both
sides of the build: move the declarations where both can see them and
include the header from the EL2 side unconditionally.

No functional change intended.

Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/stacktrace/nvhe.h | 10 ++++++++--
 arch/arm64/kvm/hyp/nvhe/stacktrace.c     |  3 +--
 arch/arm64/kvm/stacktrace.c              |  3 ---
 3 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/stacktrace/nvhe.h b/arch/arm64/include/asm/stacktrace/nvhe.h
index 171f9edef49fc..a631a577cbe5d 100644
--- a/arch/arm64/include/asm/stacktrace/nvhe.h
+++ b/arch/arm64/include/asm/stacktrace/nvhe.h
@@ -37,6 +37,14 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state,
 	state->pc = pc;
 }
 
+DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
+DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info);
+
+#ifdef CONFIG_PKVM_STACKTRACE
+DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)],
+			 pkvm_stacktrace);
+#endif
+
 #ifndef __KVM_NVHE_HYPERVISOR__
 /*
  * Conventional (non-protected) nVHE HYP stack unwinder
@@ -45,8 +53,6 @@ static inline void kvm_nvhe_unwind_init(struct unwind_state *state,
  * (by the host in EL1).
  */
 
-DECLARE_KVM_NVHE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack);
-DECLARE_KVM_NVHE_PER_CPU(struct kvm_nvhe_stacktrace_info, kvm_stacktrace_info);
 DECLARE_PER_CPU(unsigned long, kvm_arm_hyp_stack_base);
 
 void kvm_nvhe_dump_backtrace(unsigned long hyp_offset);
diff --git a/arch/arm64/kvm/hyp/nvhe/stacktrace.c b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
index 7c832d60d22bb..11fadbebbf1d6 100644
--- a/arch/arm64/kvm/hyp/nvhe/stacktrace.c
+++ b/arch/arm64/kvm/hyp/nvhe/stacktrace.c
@@ -8,6 +8,7 @@
 #include <asm/kvm_hyp.h>
 #include <asm/memory.h>
 #include <asm/percpu.h>
+#include <asm/stacktrace/nvhe.h>
 
 DEFINE_PER_CPU(unsigned long [OVERFLOW_STACK_SIZE/sizeof(long)], overflow_stack)
 	__aligned(16);
@@ -35,8 +36,6 @@ static void hyp_prepare_backtrace(unsigned long fp, unsigned long pc)
 }
 
 #ifdef CONFIG_PKVM_STACKTRACE
-#include <asm/stacktrace/nvhe.h>
-
 DEFINE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)], pkvm_stacktrace);
 
 static struct stack_info stackinfo_get_overflow(void)
diff --git a/arch/arm64/kvm/stacktrace.c b/arch/arm64/kvm/stacktrace.c
index 9724c320126b7..69377195e18b7 100644
--- a/arch/arm64/kvm/stacktrace.c
+++ b/arch/arm64/kvm/stacktrace.c
@@ -198,9 +198,6 @@ static void hyp_dump_backtrace(unsigned long hyp_offset)
 }
 
 #ifdef CONFIG_PKVM_STACKTRACE
-DECLARE_KVM_NVHE_PER_CPU(unsigned long [NVHE_STACKTRACE_SIZE/sizeof(long)],
-			 pkvm_stacktrace);
-
 /*
  * pkvm_dump_backtrace - Dump the protected nVHE HYP backtrace.
  *
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 03/11] KVM: arm64: nVHE: Declare the hyp event IDs before defining them
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

The defining expansion of HYP_EVENT() in events.c is the first time
its translation unit meets hyp_event_id_<name>, so sparse suggests
making the symbols static. Include kvm_hypevents.h ahead of
define_events.h so the extern declarations come first, as with the
tracepoint headers.

No functional change intended.

Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/events.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/events.c b/arch/arm64/kvm/hyp/nvhe/events.c
index add9383aadb5a..b845be0acd117 100644
--- a/arch/arm64/kvm/hyp/nvhe/events.c
+++ b/arch/arm64/kvm/hyp/nvhe/events.c
@@ -7,6 +7,8 @@
 #include <nvhe/mm.h>
 #include <nvhe/trace.h>
 
+#include <asm/kvm_hypevents.h>
+
 #include <nvhe/define_events.h>
 
 int __tracing_enable_event(unsigned short id, bool enable)
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 04/11] KVM: arm64: nVHE: Use NULL to reset the trace buffer backing pointer
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

bpages_backing_start is a pointer; resetting it to plain 0 triggers a
sparse warning.

No functional change intended.

Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/trace.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index e7e150ab265ff..177fe3d8fbb13 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -93,7 +93,7 @@ static void hyp_trace_buffer_unload_bpage_backing(struct hyp_trace_buffer *trace
 
 	__release_host_mem(start, size);
 
-	trace_buffer->bpages_backing_start = 0;
+	trace_buffer->bpages_backing_start = NULL;
 	trace_buffer->bpages_backing_size = 0;
 }
 
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 05/11] KVM: arm64: nVHE: Run the source checker under C=2
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

The custom %.nvhe.o rule reuses rule_cc_o_c, which hooks the source
checker only for C=1, and that only when the object is rebuilt. The
C=2 hook, cmd_force_checksrc, hangs off the standard %.o rule that
nVHE objects do not use, so "make C=2" silently skips every nVHE
source file. Call cmd_force_checksrc after the compile rule, as the
standard rule does.

Fixes: 7621712918ad4 ("KVM: arm64: Add build rules for separate VHE/nVHE object files")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/nvhe/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kvm/hyp/nvhe/Makefile b/arch/arm64/kvm/hyp/nvhe/Makefile
index f57450ebcb498..ccc1fe8394094 100644
--- a/arch/arm64/kvm/hyp/nvhe/Makefile
+++ b/arch/arm64/kvm/hyp/nvhe/Makefile
@@ -49,6 +49,7 @@ targets += $(hyp-obj) kvm_nvhe.tmp.o kvm_nvhe.rel.o hyp.lds hyp-reloc.S hyp-relo
 #    avoids file name clashes for files shared with VHE.
 $(obj)/%.nvhe.o: $(src)/%.c FORCE
 	$(call if_changed_rule,cc_o_c)
+	$(call cmd,force_checksrc)
 $(obj)/%.nvhe.o: $(src)/%.S FORCE
 	$(call if_changed_rule,as_o_S)
 
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 06/11] arm64: pi: Run the source checker on the libfdt objects under C=2
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

The custom lib-%.o rule reuses rule_cc_o_c, which hooks the source
checker only for C=1, and that only when the object is rebuilt. The
C=2 hook, cmd_force_checksrc, hangs off the standard %.o rule, so
"make C=2" silently skips the two libfdt objects. Call
cmd_force_checksrc after the compile rule, as the standard rule does.

Fixes: aacd149b6238 ("arm64: head: avoid relocating the kernel twice for KASLR")
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kernel/pi/Makefile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm64/kernel/pi/Makefile b/arch/arm64/kernel/pi/Makefile
index be92d73c25b21..96243c291e39d 100644
--- a/arch/arm64/kernel/pi/Makefile
+++ b/arch/arm64/kernel/pi/Makefile
@@ -34,6 +34,7 @@ $(obj)/lib-%.pi.o: OBJCOPYFLAGS += --prefix-alloc-sections=.init
 
 $(obj)/lib-%.o: $(srctree)/lib/%.c FORCE
 	$(call if_changed_rule,cc_o_c)
+	$(call cmd,force_checksrc)
 
 obj-y					:= idreg-override.pi.o \
 					   map_kernel.pi.o map_range.pi.o \
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 07/11] KVM: arm64: nVHE: Pass host VA arguments as pointers
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

Four hypercalls take host VAs as unsigned long: the donated vm, pgd
and vcpu regions, and the tracing descriptor. Retype the arguments
and their EL2 consumers as void *, so that the typed hypercall
declarations introduced later in the series can attach a sparse
address space to them; an address space attaches only to pointers.

No functional change intended.

Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/kvm/hyp/include/nvhe/pkvm.h  |  5 ++---
 arch/arm64/kvm/hyp/include/nvhe/trace.h |  4 ++--
 arch/arm64/kvm/hyp/nvhe/hyp-main.c      |  8 ++++----
 arch/arm64/kvm/hyp/nvhe/pkvm.c          | 11 +++++------
 arch/arm64/kvm/hyp/nvhe/trace.c         |  4 ++--
 5 files changed, 15 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
index c904647d2f760..2643a1a819668 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/pkvm.h
@@ -69,10 +69,9 @@ void pkvm_hyp_vm_table_init(void *tbl);
 
 int __pkvm_reserve_vm(void);
 void __pkvm_unreserve_vm(pkvm_handle_t handle);
-int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
-		   unsigned long pgd_hva);
+int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva);
 int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
-		     unsigned long vcpu_hva);
+		     void *vcpu_hva);
 
 int __pkvm_reclaim_dying_guest_page(pkvm_handle_t handle, u64 gfn);
 int __pkvm_start_teardown_vm(pkvm_handle_t handle);
diff --git a/arch/arm64/kvm/hyp/include/nvhe/trace.h b/arch/arm64/kvm/hyp/include/nvhe/trace.h
index 8813ff250f8e0..4aa36fd76b9e2 100644
--- a/arch/arm64/kvm/hyp/include/nvhe/trace.h
+++ b/arch/arm64/kvm/hyp/include/nvhe/trace.h
@@ -46,7 +46,7 @@ static inline pid_t __tracing_get_vcpu_pid(struct kvm_cpu_context *host_ctxt)
 void *tracing_reserve_entry(unsigned long length);
 void tracing_commit_entry(void);
 
-int __tracing_load(unsigned long desc_va, size_t desc_size);
+int __tracing_load(void *desc_va, size_t desc_size);
 void __tracing_unload(void);
 int __tracing_enable(bool enable);
 int __tracing_swap_reader(unsigned int cpu);
@@ -59,7 +59,7 @@ static inline void tracing_commit_entry(void) { }
 #define HYP_EVENT(__name, __proto, __struct, __assign, __printk)      \
 	static inline void trace_##__name(__proto) {}
 
-static inline int __tracing_load(unsigned long desc_va, size_t desc_size) { return -ENODEV; }
+static inline int __tracing_load(void *desc_va, size_t desc_size) { return -ENODEV; }
 static inline void __tracing_unload(void) { }
 static inline int __tracing_enable(bool enable) { return -ENODEV; }
 static inline int __tracing_swap_reader(unsigned int cpu) { return -ENODEV; }
diff --git a/arch/arm64/kvm/hyp/nvhe/hyp-main.c b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
index d3c69de698f48..7537d422deab3 100644
--- a/arch/arm64/kvm/hyp/nvhe/hyp-main.c
+++ b/arch/arm64/kvm/hyp/nvhe/hyp-main.c
@@ -577,8 +577,8 @@ static void handle___pkvm_unreserve_vm(struct kvm_cpu_context *host_ctxt)
 static void handle___pkvm_init_vm(struct kvm_cpu_context *host_ctxt)
 {
 	DECLARE_REG(struct kvm *, host_kvm, host_ctxt, 1);
-	DECLARE_REG(unsigned long, vm_hva, host_ctxt, 2);
-	DECLARE_REG(unsigned long, pgd_hva, host_ctxt, 3);
+	DECLARE_REG(void *, vm_hva, host_ctxt, 2);
+	DECLARE_REG(void *, pgd_hva, host_ctxt, 3);
 
 	host_kvm = kern_hyp_va(host_kvm);
 	cpu_reg(host_ctxt, 1) = __pkvm_init_vm(host_kvm, vm_hva, pgd_hva);
@@ -588,7 +588,7 @@ static void handle___pkvm_init_vcpu(struct kvm_cpu_context *host_ctxt)
 {
 	DECLARE_REG(pkvm_handle_t, handle, host_ctxt, 1);
 	DECLARE_REG(struct kvm_vcpu *, host_vcpu, host_ctxt, 2);
-	DECLARE_REG(unsigned long, vcpu_hva, host_ctxt, 3);
+	DECLARE_REG(void *, vcpu_hva, host_ctxt, 3);
 
 	host_vcpu = kern_hyp_va(host_vcpu);
 	cpu_reg(host_ctxt, 1) = __pkvm_init_vcpu(handle, host_vcpu, vcpu_hva);
@@ -634,7 +634,7 @@ static void handle___pkvm_finalize_teardown_vm(struct kvm_cpu_context *host_ctxt
 
 static void handle___tracing_load(struct kvm_cpu_context *host_ctxt)
 {
-	DECLARE_REG(unsigned long, desc_hva, host_ctxt, 1);
+	DECLARE_REG(void *, desc_hva, host_ctxt, 1);
 	DECLARE_REG(size_t, desc_size, host_ctxt, 2);
 
 	cpu_reg(host_ctxt, 1) = __tracing_load(desc_hva, desc_size);
diff --git a/arch/arm64/kvm/hyp/nvhe/pkvm.c b/arch/arm64/kvm/hyp/nvhe/pkvm.c
index 24d6f164129ac..205c52535c887 100644
--- a/arch/arm64/kvm/hyp/nvhe/pkvm.c
+++ b/arch/arm64/kvm/hyp/nvhe/pkvm.c
@@ -644,9 +644,9 @@ static size_t pkvm_get_hyp_vm_size(unsigned int nr_vcpus)
 		size_mul(sizeof(struct pkvm_hyp_vcpu *), nr_vcpus));
 }
 
-static void *map_donated_memory_noclear(unsigned long host_va, size_t size)
+static void *map_donated_memory_noclear(void *host_va, size_t size)
 {
-	void *va = (void *)kern_hyp_va(host_va);
+	void *va = kern_hyp_va(host_va);
 
 	if (!PAGE_ALIGNED(va))
 		return NULL;
@@ -658,7 +658,7 @@ static void *map_donated_memory_noclear(unsigned long host_va, size_t size)
 	return va;
 }
 
-static void *map_donated_memory(unsigned long host_va, size_t size)
+static void *map_donated_memory(void *host_va, size_t size)
 {
 	void *va = map_donated_memory_noclear(host_va, size);
 
@@ -805,8 +805,7 @@ void teardown_selftest_vm(void)
  *
  * Return 0 success, negative error code on failure.
  */
-int __pkvm_init_vm(struct kvm *host_kvm, unsigned long vm_hva,
-		   unsigned long pgd_hva)
+int __pkvm_init_vm(struct kvm *host_kvm, void *vm_hva, void *pgd_hva)
 {
 	struct pkvm_hyp_vm *hyp_vm = NULL;
 	size_t vm_size, pgd_size;
@@ -897,7 +896,7 @@ static int register_hyp_vcpu(struct pkvm_hyp_vm *hyp_vm,
 }
 
 int __pkvm_init_vcpu(pkvm_handle_t handle, struct kvm_vcpu *host_vcpu,
-		     unsigned long vcpu_hva)
+		     void *vcpu_hva)
 {
 	struct pkvm_hyp_vcpu *hyp_vcpu;
 	struct pkvm_hyp_vm *hyp_vm;
diff --git a/arch/arm64/kvm/hyp/nvhe/trace.c b/arch/arm64/kvm/hyp/nvhe/trace.c
index 177fe3d8fbb13..97203ddd3cf45 100644
--- a/arch/arm64/kvm/hyp/nvhe/trace.c
+++ b/arch/arm64/kvm/hyp/nvhe/trace.c
@@ -206,9 +206,9 @@ static bool hyp_trace_desc_is_valid(struct hyp_trace_desc *desc, size_t desc_siz
 	return true;
 }
 
-int __tracing_load(unsigned long desc_hva, size_t desc_size)
+int __tracing_load(void *desc_hva, size_t desc_size)
 {
-	struct hyp_trace_desc *desc = (struct hyp_trace_desc *)kern_hyp_va(desc_hva);
+	struct hyp_trace_desc *desc = kern_hyp_va(desc_hva);
 	int ret;
 
 	ret = __admit_host_mem(desc, desc_size);
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 08/11] KVM: arm64: Move the host hypercall interface to its own header
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

Move the kvm_call_hyp() dispatch macros and pkvm_handle_t out of
kvm_host.h into a new kvm_hcall.h, giving the host<->hyp hypercall
interface a single home that subsequent patches build on to restore
type-checking across the boundary. The only adjustment to the moved
code is the checkpatch-mandated space in "while (0)".

No functional change intended.

Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_hcall.h | 68 ++++++++++++++++++++++++++++++
 arch/arm64/include/asm/kvm_host.h  | 48 +--------------------
 2 files changed, 69 insertions(+), 47 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_hcall.h

diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
new file mode 100644
index 0000000000000..d925b2c28a3d8
--- /dev/null
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -0,0 +1,68 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * The host<->hyp hypercall interface.
+ *
+ * Copyright (C) 2026 Google LLC
+ * Author: Fuad Tabba <fuad.tabba@linux.dev>
+ */
+
+#ifndef __ARM64_KVM_HCALL_H__
+#define __ARM64_KVM_HCALL_H__
+
+#include <linux/arm-smccc.h>
+#include <linux/bug.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+
+#include <asm/barrier.h>
+#include <asm/kvm_asm.h>
+#include <asm/virt.h>
+
+typedef u16 pkvm_handle_t;
+
+#ifndef __KVM_NVHE_HYPERVISOR__
+#define kvm_call_hyp_nvhe(f, ...)					\
+	({								\
+		struct arm_smccc_res res;				\
+									\
+		arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f),		\
+				  ##__VA_ARGS__, &res);			\
+		if (WARN_ON(res.a0 != SMCCC_RET_SUCCESS))		\
+			res.a1 = -EOPNOTSUPP;				\
+									\
+		res.a1;							\
+	})
+
+/*
+ * The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
+ * where the eret to EL1 acts as a context synchronization event.
+ */
+#define kvm_call_hyp(f, ...)						\
+	do {								\
+		if (has_vhe()) {					\
+			f(__VA_ARGS__);					\
+			isb();						\
+		} else {						\
+			kvm_call_hyp_nvhe(f, ##__VA_ARGS__);		\
+		}							\
+	} while (0)
+
+#define kvm_call_hyp_ret(f, ...)					\
+	({								\
+		typeof(f(__VA_ARGS__)) ret;				\
+									\
+		if (has_vhe()) {					\
+			ret = f(__VA_ARGS__);				\
+		} else {						\
+			ret = kvm_call_hyp_nvhe(f, ##__VA_ARGS__);	\
+		}							\
+									\
+		ret;							\
+	})
+#else /* __KVM_NVHE_HYPERVISOR__ */
+#define kvm_call_hyp(f, ...) f(__VA_ARGS__)
+#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
+#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
+#endif /* __KVM_NVHE_HYPERVISOR__ */
+
+#endif /* __ARM64_KVM_HCALL_H__ */
diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h
index bae2c4f92ef5c..81d359ac7af14 100644
--- a/arch/arm64/include/asm/kvm_host.h
+++ b/arch/arm64/include/asm/kvm_host.h
@@ -27,6 +27,7 @@
 #include <asm/fpsimd.h>
 #include <asm/kvm.h>
 #include <asm/kvm_asm.h>
+#include <asm/kvm_hcall.h>
 #include <asm/vncr_mapping.h>
 
 #define __KVM_HAVE_ARCH_INTC_INITIALIZED
@@ -251,8 +252,6 @@ struct kvm_smccc_features {
 	unsigned long vendor_hyp_bmap_2; /* Function numbers 64-127 */
 };
 
-typedef u16 pkvm_handle_t;
-
 struct kvm_protected_vm {
 	pkvm_handle_t handle;
 	struct kvm_hyp_memcache teardown_mc;
@@ -1252,51 +1251,6 @@ void kvm_arm_resume_guest(struct kvm *kvm);
 
 #define vcpu_has_run_once(vcpu)	(!!READ_ONCE((vcpu)->pid))
 
-#ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...)					\
-	({								\
-		struct arm_smccc_res res;				\
-									\
-		arm_smccc_1_1_hvc(KVM_HOST_SMCCC_FUNC(f),		\
-				  ##__VA_ARGS__, &res);			\
-		if (WARN_ON(res.a0 != SMCCC_RET_SUCCESS))		\
-			res.a1 = -EOPNOTSUPP;				\
-									\
-		res.a1;							\
-	})
-
-/*
- * The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
- * where the eret to EL1 acts as a context synchronization event.
- */
-#define kvm_call_hyp(f, ...)						\
-	do {								\
-		if (has_vhe()) {					\
-			f(__VA_ARGS__);					\
-			isb();						\
-		} else {						\
-			kvm_call_hyp_nvhe(f, ##__VA_ARGS__);		\
-		}							\
-	} while(0)
-
-#define kvm_call_hyp_ret(f, ...)					\
-	({								\
-		typeof(f(__VA_ARGS__)) ret;				\
-									\
-		if (has_vhe()) {					\
-			ret = f(__VA_ARGS__);				\
-		} else {						\
-			ret = kvm_call_hyp_nvhe(f, ##__VA_ARGS__);	\
-		}							\
-									\
-		ret;							\
-	})
-#else /* __KVM_NVHE_HYPERVISOR__ */
-#define kvm_call_hyp(f, ...) f(__VA_ARGS__)
-#define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
-#define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
-#endif /* __KVM_NVHE_HYPERVISOR__ */
-
 int handle_exit(struct kvm_vcpu *vcpu, int exception_index);
 void handle_exit_early(struct kvm_vcpu *vcpu, int exception_index);
 
-- 
2.39.5



^ permalink raw reply related

* [PATCH v1 09/11] KVM: arm64: Type-check hypercall arguments at the caller
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba
In-Reply-To: <20260720161343.1367007-1-fuad.tabba@linux.dev>

kvm_call_hyp_nvhe() reduces its target to an SMCCC function number, so
the compiler never sees a callable: arguments that are wrong in number,
type or order are silently marshalled into registers. The kvm_call_hyp()
wrappers only catch this on the VHE branch, and the pKVM-only hypercalls
have no such branch.

Declare each hypercall's signature once in kvm_hcall.h and generate a
typed stub from it, in the mold of the syscall wrappers. Make
kvm_call_hyp_nvhe() resolve to the stub so every caller is checked
against the declared signature; a stale or mistyped call now fails to
compile. The stubs inline to the same SMCCC call the untyped macro used
to make: the compiled callers are unchanged, apart from hypercall
returns now being tested at their declared width.

The stage-2 protection arguments are declared u64 rather than
enum kvm_pgtable_prot, as kvm_pgtable.h includes linux/kvm_host.h and
the enum cannot be completed here.

Assisted-by: Antigravity:gemini-3.1-pro
Signed-off-by: Fuad Tabba <fuad.tabba@linux.dev>
---
 arch/arm64/include/asm/kvm_hcall.h | 165 ++++++++++++++++++++++++++++-
 arch/arm64/kvm/hyp_trace.c         |   2 +-
 2 files changed, 165 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/include/asm/kvm_hcall.h b/arch/arm64/include/asm/kvm_hcall.h
index d925b2c28a3d8..51bfd14748464 100644
--- a/arch/arm64/include/asm/kvm_hcall.h
+++ b/arch/arm64/include/asm/kvm_hcall.h
@@ -16,12 +16,35 @@
 
 #include <asm/barrier.h>
 #include <asm/kvm_asm.h>
+#include <asm/spectre.h>
 #include <asm/virt.h>
 
 typedef u16 pkvm_handle_t;
 
+struct kvm;
+struct kvm_s2_mmu;
+struct kvm_vcpu;
+struct vgic_v3_cpu_if;
+struct vgic_v5_cpu_if;
+
+/*
+ * Hypercall signatures are declared as (type, name) argument pairs.
+ * __KVM_HCALL_MAP() applies a macro to each pair, in the mold of __MAP()
+ * in <linux/syscalls.h>.
+ */
+#define __KVM_HCALL_MAP1(m, t, a, ...) m(t, a)
+#define __KVM_HCALL_MAP2(m, t, a, ...) m(t, a), __KVM_HCALL_MAP1(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP3(m, t, a, ...) m(t, a), __KVM_HCALL_MAP2(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP4(m, t, a, ...) m(t, a), __KVM_HCALL_MAP3(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP5(m, t, a, ...) m(t, a), __KVM_HCALL_MAP4(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP6(m, t, a, ...) m(t, a), __KVM_HCALL_MAP5(m, __VA_ARGS__)
+#define __KVM_HCALL_MAP(n, ...) __KVM_HCALL_MAP##n(__VA_ARGS__)
+
+#define __KVM_HCALL_DECL(t, a)	t a
+#define __KVM_HCALL_ARGS(t, a)	a
+
 #ifndef __KVM_NVHE_HYPERVISOR__
-#define kvm_call_hyp_nvhe(f, ...)					\
+#define __kvm_call_hyp_nvhe(f, ...)					\
 	({								\
 		struct arm_smccc_res res;				\
 									\
@@ -33,6 +56,43 @@ typedef u16 pkvm_handle_t;
 		res.a1;							\
 	})
 
+/*
+ * Generate a typed stub for each declared hypercall. kvm_call_hyp_nvhe()
+ * resolves to the stub, so a call with the wrong argument count or types
+ * fails to compile instead of being silently truncated to an SMCCC function
+ * number and a pile of registers. The stub inlines to the same SMCCC call
+ * the untyped macro used to make.
+ */
+#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...)			\
+	static __always_inline						\
+	ret nvhe_hvc_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__)) \
+	{								\
+		return (ret)__kvm_call_hyp_nvhe(name,			\
+			__KVM_HCALL_MAP(x, __KVM_HCALL_ARGS, __VA_ARGS__)); \
+	}
+
+#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...)			\
+	static __always_inline						\
+	void nvhe_hvc_##name(__KVM_HCALL_MAP(x, __KVM_HCALL_DECL, __VA_ARGS__)) \
+	{								\
+		__kvm_call_hyp_nvhe(name,				\
+			__KVM_HCALL_MAP(x, __KVM_HCALL_ARGS, __VA_ARGS__)); \
+	}
+
+#define DECLARE_KVM_HOST_HCALL0(ret, name)				\
+	static __always_inline ret nvhe_hvc_##name(void)		\
+	{								\
+		return (ret)__kvm_call_hyp_nvhe(name);			\
+	}
+
+#define DECLARE_KVM_HOST_HCALL0_VOID(name)				\
+	static __always_inline void nvhe_hvc_##name(void)		\
+	{								\
+		__kvm_call_hyp_nvhe(name);				\
+	}
+
+#define kvm_call_hyp_nvhe(f, ...)	nvhe_hvc_##f(__VA_ARGS__)
+
 /*
  * The isb() below is there to guarantee the same behaviour on VHE as on !VHE,
  * where the eret to EL1 acts as a context synchronization event.
@@ -63,6 +123,109 @@ typedef u16 pkvm_handle_t;
 #define kvm_call_hyp(f, ...) f(__VA_ARGS__)
 #define kvm_call_hyp_ret(f, ...) f(__VA_ARGS__)
 #define kvm_call_hyp_nvhe(f, ...) f(__VA_ARGS__)
+
+#define DECLARE_KVM_HOST_HCALL(ret, name, x, ...)
+#define DECLARE_KVM_HOST_HCALL_VOID(name, x, ...)
+#define DECLARE_KVM_HOST_HCALL0(ret, name)
+#define DECLARE_KVM_HOST_HCALL0_VOID(name)
 #endif /* __KVM_NVHE_HYPERVISOR__ */
 
+/* Hypercalls that are unavailable once pKVM has finalised. */
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init, 4,
+	phys_addr_t, phys, unsigned long, size,
+	unsigned long *, per_cpu_base, u32, hyp_va_bits)
+DECLARE_KVM_HOST_HCALL(unsigned long, __pkvm_create_private_mapping, 3,
+	phys_addr_t, phys, size_t, size, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_cpu_set_vector, 1,
+	enum arm64_hyp_spectre_vector, slot)
+DECLARE_KVM_HOST_HCALL0_VOID(__kvm_enable_ssbs)
+DECLARE_KVM_HOST_HCALL0_VOID(__vgic_v3_init_lrs)
+DECLARE_KVM_HOST_HCALL0(u64, __vgic_v3_get_gic_config)
+
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_prot_finalize)
+
+/* Hypercalls that are always available and common to [nh]VHE/pKVM. */
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_adjust_pc, 1,
+	struct kvm_vcpu *, vcpu)
+DECLARE_KVM_HOST_HCALL(int, __kvm_vcpu_run, 1,
+	struct kvm_vcpu *, vcpu)
+DECLARE_KVM_HOST_HCALL0_VOID(__kvm_flush_vm_context)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa, 3,
+	struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_ipa_nsh, 3,
+	struct kvm_s2_mmu *, mmu, phys_addr_t, ipa, int, level)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid, 1,
+	struct kvm_s2_mmu *, mmu)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_tlb_flush_vmid_range, 3,
+	struct kvm_s2_mmu *, mmu, phys_addr_t, start, unsigned long, pages)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_flush_cpu_context, 1,
+	struct kvm_s2_mmu *, mmu)
+DECLARE_KVM_HOST_HCALL_VOID(__kvm_timer_set_cntvoff, 1,
+	u64, cntvoff)
+DECLARE_KVM_HOST_HCALL(int, __tracing_load, 2,
+	void *, desc_hva, size_t, desc_size)
+DECLARE_KVM_HOST_HCALL0_VOID(__tracing_unload)
+DECLARE_KVM_HOST_HCALL(int, __tracing_enable, 1,
+	bool, enable)
+DECLARE_KVM_HOST_HCALL(int, __tracing_swap_reader, 1,
+	unsigned int, cpu)
+DECLARE_KVM_HOST_HCALL_VOID(__tracing_update_clock, 4,
+	u32, mult, u32, shift, u64, epoch_ns, u64, epoch_cyc)
+DECLARE_KVM_HOST_HCALL(int, __tracing_reset, 1,
+	unsigned int, cpu)
+DECLARE_KVM_HOST_HCALL(int, __tracing_enable_event, 2,
+	unsigned short, id, bool, enable)
+DECLARE_KVM_HOST_HCALL_VOID(__tracing_write_event, 1,
+	u64, id)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_save_aprs, 1,
+	struct vgic_v3_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v3_restore_vmcr_aprs, 1,
+	struct vgic_v3_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_save_apr, 1,
+	struct vgic_v5_cpu_if *, cpu_if)
+DECLARE_KVM_HOST_HCALL_VOID(__vgic_v5_restore_vmcr_apr, 1,
+	struct vgic_v5_cpu_if *, cpu_if)
+
+/* Hypercalls that are available only when pKVM has finalised. */
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_share_hyp, 1,
+	u64, pfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_unshare_hyp, 1,
+	u64, pfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_donate_guest, 2,
+	u64, pfn, u64, gfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_share_guest, 4,
+	u64, pfn, u64, gfn, u64, nr_pages, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_unshare_guest, 3,
+	pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_relax_perms_guest, 2,
+	u64, gfn, u64, prot)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_wrprotect_guest, 3,
+	pkvm_handle_t, handle, u64, gfn, u64, nr_pages)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_test_clear_young_guest, 4,
+	pkvm_handle_t, handle, u64, gfn, u64, nr_pages, bool, mkold)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_host_mkyoung_guest, 1,
+	u64, gfn)
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_reserve_vm)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_unreserve_vm, 1,
+	pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vm, 3,
+	struct kvm *, host_kvm, void *, vm_hva, void *, pgd_hva)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_init_vcpu, 3,
+	pkvm_handle_t, handle, struct kvm_vcpu *, host_vcpu,
+	void *, vcpu_hva)
+DECLARE_KVM_HOST_HCALL0(int, __pkvm_vcpu_in_poison_fault)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_force_reclaim_guest_page, 1,
+	phys_addr_t, phys)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_reclaim_dying_guest_page, 2,
+	pkvm_handle_t, handle, u64, gfn)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_start_teardown_vm, 1,
+	pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL(int, __pkvm_finalize_teardown_vm, 1,
+	pkvm_handle_t, handle)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_vcpu_load, 3,
+	pkvm_handle_t, handle, unsigned int, vcpu_idx, u64, hcr_el2)
+DECLARE_KVM_HOST_HCALL0_VOID(__pkvm_vcpu_put)
+DECLARE_KVM_HOST_HCALL_VOID(__pkvm_tlb_flush_vmid, 1,
+	pkvm_handle_t, handle)
+
 #endif /* __ARM64_KVM_HCALL_H__ */
diff --git a/arch/arm64/kvm/hyp_trace.c b/arch/arm64/kvm/hyp_trace.c
index 2411b4c32932c..7fe0e8feb7d7c 100644
--- a/arch/arm64/kvm/hyp_trace.c
+++ b/arch/arm64/kvm/hyp_trace.c
@@ -264,7 +264,7 @@ static struct trace_buffer_desc *hyp_trace_load(unsigned long size, void *priv)
 	if (ret)
 		goto err_free_buffer;
 
-	ret = kvm_call_hyp_nvhe(__tracing_load, (unsigned long)desc, desc_size);
+	ret = kvm_call_hyp_nvhe(__tracing_load, desc, desc_size);
 	if (ret)
 		goto err_unload_pages;
 
-- 
2.39.5



^ permalink raw reply related

* Re: [PATCH v2] dt-bindings: watchdog: snps,dw-wdt: Add RV1106 compatible
From: Guenter Roeck @ 2026-07-20 16:15 UTC (permalink / raw)
  To: Simon Glass
  Cc: Wim Van Sebroeck, Conor Dooley, devicetree, linux-rockchip,
	linux-watchdog, Krzysztof Kozlowski, Rob Herring, Heiko Stuebner,
	Krzysztof Kozlowski, Jamie Iles, linux-arm-kernel, linux-kernel
In-Reply-To: <20260714131856.v2.1.b5339e64b3fe4338b3924ebd9dc0096904699744@changeid>

On Tue, Jul 14, 2026 at 01:18:57PM -0600, Simon Glass wrote:
> Add the compatible for the watchdog of the Rockchip RV1106, which is
> compatible with the Synopsys DesignWare watchdog.
> 
> Signed-off-by: Simon Glass <sjg@chromium.org>
> Acked-by: Krzysztof Kozlowski <krzysztof.kozlowski@oss.qualcomm.com>
> Reviewed-by: Heiko Stuebner <heiko@sntech.de>

Applied.

Thanks,
Guenter


^ permalink raw reply

* [PATCH v1 00/11] KVM: arm64: Restore type-checking across the host/hyp hypercall boundary
From: Fuad Tabba @ 2026-07-20 16:13 UTC (permalink / raw)
  To: maz, oupton, linux-arm-kernel, kvmarm
  Cc: catalin.marinas, will, rostedt, mhiramat, alexandru.elisei,
	vdonnefort, joey.gouly, seiden, suzuki.poulose, yuzenghui,
	qperret, ardb, linux-kernel, linux-trace-kernel, tabba,
	fuad.tabba

Hi folks,

For a change, I thought I'd send a series that's neither a bunch of
Sashiko bug fixes nor pKVM-specific.

The SMCCC conversion of the host/hyp interface reduced every hypercall
to a function number and a pile of registers: kvm_call_hyp_nvhe() never
shows the compiler a callable, so the caller's arguments and the
handler's DECLARE_REG() casts can disagree in type, count or order
without a diagnostic. Reviewing a fix for exactly that class of bug,
Marc wrote [1]:

  "we lost all form of type-checking when everything was hastily
   converted to SMCCC to avoid function pointers. Somehow, I feel that
   the cure was worse than the disease.

   I wish we'd reintroduce some form of compile-time checks, maybe by
   having generated stubs?"

and sketched the shape he preferred [2]: a generated nvhe_hvc_##f()
stub that does the type-checking, driven by "some form of declarative
IDL", with "both the caller and callee stubs ... totally generated".

This series implements that, in plain preprocessor macros rather
than an external generator, in the mold of the syscall wrappers.
Each hypercall's signature is declared once, in kvm_hcall.h:
kvm_call_hyp_nvhe() resolves to a typed nvhe_hvc_##f() stub
generated from the declaration, and the hyp-main.c handlers
unmarshal their arguments through glue that is type-checked
against the same declaration. A mistyped or stale call, or a
handler that drifts from its caller, now fails to compile. On top
of that shared declaration, host-VA parameters gain a __hostva
sparse address space, so dereferencing one at EL2 without
kern_hyp_va_host() translation is flagged by sparse. The address
space is KVM-private and lives with the interface it annotates
rather than in compiler_types.h, like x86's __seg_gs in asm/percpu.h.
The deeper instances of that bug class, host VAs reached through
struct fields after the boundary, are follow-up work.

The declarations do not also generate the function-number enum or the
dispatch table. The enum carries the availability-band markers that
decide when each hypercall becomes reachable, and its base entry is
consumed from assembly, so generating it would hide the banding. The
remaining duplication cannot drift silently: a name mismatch between
declaration, caller and handler fails to compile, and a missing
dispatch-table entry is rejected at run time as
SMCCC_RET_NOT_SUPPORTED.

Along the way it turned out "make C=2" has never checked the nVHE
objects at all: the custom %.nvhe.o rule reuses rule_cc_o_c, which
only hooks the checker for C=1, and that only on a rebuild. Patches
2-5 fix the hook and the handful of pre-existing sparse warnings it
flushes out, so the checker lands clean. The libfdt objects under
arch/arm64/kernel/pi/ have the same gap through the same rule, so
patch 6 gives them the same one-line fix; it touches arm64 core
rather than KVM, so it can go through either tree. Patch 1 is
adjacent: trace_remote_event.h is not self-contained (it uses bool
without including linux/types.h), which the nVHE include order had
been silently working around; it can go through the tracing tree
instead if preferred.

The first six patches do not depend on the type-checking work (the
tracing-header fix, the sparse cleanups, and the two C=2 hook fixes),
so they could be taken on their own, ahead of the rest of the series
if that is easier.

The series is structured as follows:

  01:     Make trace_remote_event.h self-contained.
  02-04:  Fix the pre-existing sparse warnings in the nVHE code.
  05:     Run the source checker on nVHE objects under C=2.
  06:     Same for the libfdt objects under arch/arm64/kernel/pi/.
  07:     Pass the host-VA hypercall arguments as pointers at EL2.
  08:     Move the dispatch macros to a new kvm_hcall.h.
  09:     Declare the hypercall signatures, type-check the callers.
  10:     Generate the handler unmarshalling, type-check the handlers.
  11:     Tag host-VA parameters __hostva for sparse.

The generated code is unchanged, checked by comparing the disassembly
of every KVM object, function by function, against the base: the
callers are identical apart from hypercall returns now being tested at
their declared width and the stage-2 TLB-flush level argument now
being sign-extended as it is loaded (an s8 passed as an int), and the
handlers are instruction-for-instruction identical apart from
flush_hyp_vcpu()/sync_hyp_vcpu() being inlined into their only
caller. The extra argument that prompted the thread, a
mistyped or reordered argument, and a handler that disagrees with its
declaration all now fail to compile. checkpatch complains about the
__KVM_HCALL_MAP() machinery, the (type, name) pair syntax and the
generated signature typedefs, as it does about __MAP() in the syscall
wrappers; the idiom cannot be parenthesized, and the typedef is what
checks the handler against the declaration. Enforcing the
__hostva tag needs sparse v0.6.5-rc1 or later for __typeof_unqual__,
as all sparse checking on current kernels does; no stable sparse
release has it yet, so build from sparse.git (checker-valid.sh skips
the check, with a warning, on anything older).

Based on Linux 7.2-rc4 (1590cf0329716).

Cheers,
/fuad

[1] https://lore.kernel.org/all/86zf7po2n3.wl-maz@kernel.org/
[2] https://lore.kernel.org/all/86wm2tnsd8.wl-maz@kernel.org/

Fuad Tabba (11):
  tracing: Include linux/types.h in trace_remote_event.h
  KVM: arm64: nVHE: Share the stacktrace per-CPU declarations with EL2
  KVM: arm64: nVHE: Declare the hyp event IDs before defining them
  KVM: arm64: nVHE: Use NULL to reset the trace buffer backing pointer
  KVM: arm64: nVHE: Run the source checker under C=2
  arm64: pi: Run the source checker on the libfdt objects under C=2
  KVM: arm64: nVHE: Pass host VA arguments as pointers
  KVM: arm64: Move the host hypercall interface to its own header
  KVM: arm64: Type-check hypercall arguments at the caller
  KVM: arm64: nVHE: Check hypercall handlers against the declared ABI
  KVM: arm64: Tag host-VA hypercall parameters __hostva

 arch/arm64/include/asm/kvm_hcall.h       | 255 +++++++++++++
 arch/arm64/include/asm/kvm_host.h        |  48 +--
 arch/arm64/include/asm/kvm_mmu.h         |  10 +
 arch/arm64/include/asm/stacktrace/nvhe.h |  10 +-
 arch/arm64/kernel/pi/Makefile            |   1 +
 arch/arm64/kvm/hyp/include/nvhe/pkvm.h   |   7 +-
 arch/arm64/kvm/hyp/include/nvhe/trace.h  |   5 +-
 arch/arm64/kvm/hyp/nvhe/Makefile         |   1 +
 arch/arm64/kvm/hyp/nvhe/events.c         |   2 +
 arch/arm64/kvm/hyp/nvhe/hyp-main.c       | 443 +++++++++++------------
 arch/arm64/kvm/hyp/nvhe/pkvm.c           |  12 +-
 arch/arm64/kvm/hyp/nvhe/stacktrace.c     |   3 +-
 arch/arm64/kvm/hyp/nvhe/trace.c          |   6 +-
 arch/arm64/kvm/hyp_trace.c               |   2 +-
 arch/arm64/kvm/stacktrace.c              |   3 -
 include/linux/trace_remote_event.h       |   2 +
 16 files changed, 508 insertions(+), 302 deletions(-)
 create mode 100644 arch/arm64/include/asm/kvm_hcall.h


base-commit: 1590cf0329716306e948a8fc29f1d3ee87d3989f
-- 
2.39.5



^ permalink raw reply

* Re: [PATCH 06/11] dt-bindings: watchdog: apple,wdt: Add t6030 and t6031 compatibles
From: Guenter Roeck @ 2026-07-20 16:17 UTC (permalink / raw)
  To: Janne Grunau
  Cc: Sven Peter, Neal Gompa, Rob Herring, Krzysztof Kozlowski,
	Conor Dooley, Thomas Gleixner, Wim Van Sebroeck, Linus Walleij,
	Mark Kettenis, Andi Shyti, Uwe Kleine-König,
	Sasha Finkelstein, asahi, linux-arm-kernel, devicetree,
	linux-kernel, linux-watchdog, linux-gpio, linux-i2c, linux-pwm
In-Reply-To: <20260709-apple-t603x-initial-devices-v1-6-55b305833123@jannau.net>

On Thu, Jul 09, 2026 at 09:30:52AM +0200, Janne Grunau wrote:
> The watchdog on Apple silicon M3 Pro, Max and Ultra SoCs is compatible
> with the t8103 (M1) one. Add "apple,t6030-wdt" for M3 Pro and
> "apple,t6031-wdt" for M3 Max and Ultra as per-SoC compatibles.
> 
> Signed-off-by: Janne Grunau <j@jannau.net>
> Acked-by: Conor Dooley <conor.dooley@microchip.com>

Applied.

Thanks,
Guenter


^ permalink raw reply

* Re: [PATCH v7 6/7] mm/vmalloc: map contiguous pages in batches for vmap() if possible
From: Wen Jiang @ 2026-07-20 16:20 UTC (permalink / raw)
  To: Dev Jain
  Cc: David Hildenbrand (Arm), akpm, catalin.marinas, linux-mm, urezki,
	will, Xueyuan.chen21, ajd, anshuman.khandual, linux-arm-kernel,
	linux-kernel, rppt, ryan.roberts, baohua, Wen Jiang, Leo Yan
In-Reply-To: <e650604f-316c-48f6-8279-05c162bcdf21@arm.com>

On Mon, 20 Jul 2026 at 15:50, Dev Jain <dev.jain@arm.com> wrote:
>
> [------]
>
> >> +
> >> +    nr_contig = num_pages_contiguous(&pages[idx], max_steps);
> >> +    if (nr_contig < 2)
> >> +            return 0;
> >> +
> >> +    order = ilog2(nr_contig);
> >> +    pfn = page_to_pfn(pages[idx]);
> >> +
> >> +    /* Limit order by pfn alignment */
> >> +    if (pfn > 0)
> >> +            order = min_t(int, order, __ffs(pfn));
> >
> > Wouldn't it make sense to determine that before you call num_pages_contiguous?
> > Because then, you can just scan to that maximum instead of the given nr_pages.
>
> Right!
>
>

Agreed. I will check the PFN alignment limit first before calling
num_pages_contiguous() to avoid unnecessary scanning.

> >> +    unsigned int prev_shift = 0, idx = 0;
> >> +    unsigned long map_addr = addr, batch_end = addr;
> >> +    int err;
> >> +
> >> +    err = kmsan_vmap_pages_range_noflush(addr, end, prot, pages,
> >> +                                         PAGE_SHIFT, GFP_KERNEL);
> >
> > Is the indentation on the second parameter line off?
> >

Will check this, thanks.

> >> +    if (err)
> >> +            goto out;
> >> +
> >> +    for (unsigned int i = 0; i < count; ) {
> >> +            unsigned int shift = PAGE_SHIFT +
> >> +                    get_vmap_batch_order(pages, prot, count - i, i);
> >
> > Having two indices, i and idx, is just confusing.
> >

How about renaming idx to batch_start? I think using i and batch_start
will make the logic much clearer.

> > The whole function is a bit overly complicated. Does it really buy us much to
> > batch over vmap_pages_range_noflush_walk() calling with the same shift?
>
> It will buy us more in the sense that, vmap() speed is sensitive to the number
> of pagetable walks. I think that is reflected by the ioremap(1MB) 1.35x speedup
> mentioned in the cover letter.
>
> In terms of callers, not sure. I would expect a caller to get the highest
> power of 2 from the total needed nr_pages, then get the next highest power
> of 2 from the remaining, and so on.
>
> For the arm64 TRBE usecase, the relevant code is the rb_alloc_aux_page() caller in
> kernel/events/ring_buffer.c. We may get multiple same order requests if can't
> get the first requested higher order.
>
> Since on the cover letter I see Wen and team have tested on boards, I lean
> towards saying it is reasonable to assume a usecase where such order
> fallback can happen.
>

Thanks. The batching is necessary because it significantly reduces
page table walks and effectively handles fallback scenarios (such as
the arm64 TRBE use case).

> But yeah the code for this currently is not so nice I agree.
>
> >
> >> +
> >> +            if (!i)
> >> +                    prev_shift = shift;
> >> +
> >> +            if (shift != prev_shift) {
> >> +                    err = vmap_pages_range_noflush_walk(map_addr, batch_end,
> >> +                                    prot, pages + idx, prev_shift);
> >> +                    if (err)
> >> +                            goto out;
> >> +                    prev_shift = shift;
> >> +                    map_addr = batch_end;
> >> +                    idx = i;
> >> +            }
> >> +
> >> +            /*
> >> +             * Once small pages are encountered, the remaining pages
> >> +             * are likely small as well.
> >
> > "small pages" is odd. Maybe
> >
> > "Once we fail to batch pages, we expect to fail batching for all remaining
> > pages, so just give up."
> >

Will update the comment.

> >> +             */
> >> +            if (shift == PAGE_SHIFT)
> >> +                    break;
> >> +
> >> +            batch_end += 1UL << shift;
> >> +            i += 1U << (shift - PAGE_SHIFT);
> >> +    }
> >> +
> >> +    /* Remaining */
> >> +    if (map_addr < end)
> >> +            err = vmap_pages_range_noflush_walk(map_addr, end,
> >> +                            prot, pages + idx, prev_shift);
> >> +
> >> +out:
> >> +    flush_cache_vmap(addr, end);
> >> +    return err;
> >> +}
> >> +
> >>  /**
> >>   * vmap - map an array of pages into virtually contiguous space
> >>   * @pages: array of page pointers
> >> @@ -3600,8 +3678,8 @@ void *vmap(struct page **pages, unsigned int count,
> >>              return NULL;
> >>
> >>      addr = (unsigned long)area->addr;
> >> -    if (vmap_pages_range(addr, addr + size, pgprot_nx(prot),
> >> -                            pages, PAGE_SHIFT) < 0) {
> >> +    if (vmap_pages_range_batched(addr, addr + size, pgprot_nx(prot),
> >> +                            pages) < 0) {
> >
> > Nit: single line would make that nicer to read.
> >
>

Once you confirm, I will send out a diff to address all the points
mentioned above. Thanks again for the review!

Best regards,
Wen


^ permalink raw reply

* [PATCH v16 0/7] spi: pxa2xx: Fix PM and interrupt issues on Intel LPSS SPI
From: Shih-Yuan Lee @ 2026-07-20 16:21 UTC (permalink / raw)
  To: Mark Brown
  Cc: Andy Shevchenko, Mika Westerberg, Lukas Wunner, Daniel Mack,
	Haojian Zhuang, Robert Jarzmik, linux-arm-kernel, linux-spi,
	linux-kernel, Shih-Yuan Lee

This 7-patch series addresses long-standing power management (PM), runtime autosuspend,
and interrupt synchronization regressions in the spi-pxa2xx host controller driver,
specifically targeting Intel Low Power Subsystem (LPSS) SPI controllers and platforms
such as the Apple MacBook8,1.

Specifically, this series:
  - Prevents system hangs and PCIe Completion Timeouts during S3 suspend/resume by
    restoring Intel LPSS private register context (resets and control registers).
  - Resolves race conditions in the shared interrupt handler (ssp_int()) during PM power
    state transitions (RPM_SUSPENDING) by tracking suspend states and guaranteeing
    active hardware clocks prior to MMIO register access.
  - Locks out runtime PM autosuspend for Intel LPSS SPI controllers in PIO mode to avoid
    unclocked MMIO accesses on subsequent transfers.
  - Applies a PCI glue DMI quirk to force PIO mode for Apple MacBook8,1 to work around
    persistent hardware DMA timeouts.
  - Cleanly refactors clock helper functions, PM callback state alignments, and local
    variable conventions across the driver.

Changes in v16:
  - Addressed feedback from Sashiko review on the v15 patchset:
  - Fixed 'bool suspended' field location in spi-pxa2xx.h (moved from Patch 1 to Patch 2).
  - Updated pxa2xx_spi_clk_disable() to set drv_data->clk_enabled = false BEFORE
    calling clk_disable_unprepare(), eliminating an IRQ handler race window on
    multi-core systems.
  - Updated pxa2xx_spi_suspend() and pxa2xx_spi_runtime_suspend() to explicitly
    set drv_data->suspended = true.
  - Fixed pm_runtime_put_sync() in pxa2xx_spi_remove(), moving the PM reference drop
    to before hardware teardown and using pm_runtime_put_noidle() to prevent
    runtime_suspend calls on unclocked hardware.
  - Fixed PM runtime state alignment in pxa2xx_spi_resume() error path using
    pm_runtime_set_suspended().
  - Resolved merge conflicts and renamed remaining 'status' variables to 'ret'
    in suspend/resume handlers.

Changes in v15:
  - Split the large PIO mode PM and interrupt patch (v14 Patch 2) into 4 distinct,
    single-purpose commits (clock helpers, suspended flag, teardown overhaul,
    and autosuspend lockout).
  - Reordered the commits so that PIO PM and interrupt bug fixes are applied
    before disabling DMA on MacBook8,1, satisfying kernel bisection safety.
  - Replaced raw pxa_ssp_disable() calls in PM suspend/remove with
    pxa2xx_spi_off() to respect the MMP2 platform's SSE-disable quirk.
  - Renamed return variables from 'status' to 'ret' in clock helper functions,
    and added a cleanup commit to rename 'status' to 'ret' in the PM and probe
    callbacks to conform to standard coding conventions.

Changes in v14:
  - Addressed feedback from Sashiko review on the v13 patchset for Patch 2:
  - Updated commit message text for Patch 2 to accurately reflect that ssp_int()
    uses drv_data->suspended and drv_data->clk_enabled instead of pm_runtime_get_if_active().
  - Clarified in commit message that active SPI transfers hold a PM reference via
    spi_controller.auto_runtime_pm (pm_runtime_get_sync()), preventing autosuspend
    from racing while an IRQ handler is reading/writing FIFO registers.
  - Clarified teardown ordering: pxa_ssp_disable() disables hardware interrupt generation
    first, followed by setting drv_data->suspended = true and calling synchronize_irq(),
    ensuring in-flight IRQ handlers drain completely before clock gating.

Changes in v13:
  - Addressed feedback from Sashiko review on the v12 patchset for Patch 2:
  - Removed pm_runtime_get_if_active() check from ssp_int(). During PM state
    transitions (such as RPM_SUSPENDING or RPM_RESUMING), pm_runtime_get_if_active()
    returns 0 because the state is not RPM_ACTIVE. Returning IRQ_NONE during transition
    without clearing a level-triggered interrupt would cause the interrupt controller
    to endlessly re-invoke the handler in a loop.
  - Rely on drv_data->suspended and drv_data->clk_enabled in ssp_int() instead.
    If the clock is enabled (drv_data->clk_enabled == true), MMIO reads are 100% safe
    and will not cause PCIe Completion Timeouts. If the clock is disabled or the device
    is suspended, ssp_int() immediately returns IRQ_NONE to prevent unclocked access.

Changes in v12:
  - Addressed feedback from Sashiko review on the v11 patchset for Patch 2:
  - Preserved the if (!pm_runtime_suspended(dev)) check prior to enabling/disabling
    the clock in pxa2xx_spi_suspend() and pxa2xx_spi_resume(). On non-LPSS platforms,
    if a device was runtime suspended prior to system sleep, unconditionally enabling
    its hardware clock during system resume forced the clock ON while the PM core
    retained RPM_SUSPENDED. Restoring this check prevents PM state desynchronization,
    avoiding power leaks on non-LPSS platforms.

Changes in v11:
  - Addressed feedback from Sashiko review on the v10 patchset for Patch 2:
  - Replaced pm_runtime_put_noidle() with pm_runtime_put_sync() in pxa2xx_spi_remove().
    Using pm_runtime_put_noidle() dropped usage count without executing the runtime_suspend
    callback or updating the device runtime status, leaving it stuck in RPM_ACTIVE. This
    permanently leaked an active child count on the parent LPSS power domain, preventing
    the parent from entering low-power runtime suspend. Switching to pm_runtime_put_sync()
    ensures the runtime PM state machine properly transitions to RPM_SUSPENDED upon driver
    unbind.

Changes in v10:
  - Addressed feedback from Sashiko review on the v9 patchset:
  - Fixed ssp_int() by explicitly returning IRQ_NONE when pm_runtime_get_if_active()
    returns 0 (device inactive or suspending). This prevents reading SSSR and MMIO
    registers when the hardware is powered down or in power transition.
  - Resolved PM usage counter leak and double-increment for PIO mode devices. Removed
    the redundant/unconditional pm_runtime_get_noresume() in pxa2xx_spi_probe() and
    moved the single pm_runtime_get_noresume() call to occur strictly after
    spi_register_controller() succeeds.

Changes in v9:
  - Separated the original "disable DMA and fix runtime PM" patch into two distinct commits:
    1. spi: pxa2xx: disable DMA for Apple MacBook8,1 (PCI glue DMI quirk)
    2. spi: pxa2xx: fix runtime PM and interrupt handling in PIO mode (core driver PM/IRQ fixes)
  - Condensed commit messages for Patches 2 and 3 for clarity and brevity.
  - Fixed checkpatch.pl warning regarding unnecessary braces in pxa2xx_spi_remove().
  - Addressed feedback from Sashiko review on the v8 patchset:
  - Scoped pm_runtime_get_noresume() in pxa2xx_spi_probe() and pm_runtime_put_noidle()
    in remove/error paths using is_lpss_ssp(drv_data). This locks out autosuspend
    for LPSS controllers operating in PIO mode without causing power regressions on
    non-LPSS platforms (e.g. PXA25x, Intel Quark, CE4100) operating in PIO mode.
  - Guarded MMIO accesses in pxa2xx_spi_runtime_suspend() with a drv_data->clk_enabled
    check. If the clock has already been turned off (e.g. in pxa2xx_spi_remove() or
    resume error path), runtime suspend skips hardware writes, avoiding unclocked
    MMIO accesses and PCIe Completion Timeouts if runtime PM triggers after teardown.
  - Cleaned up pxa2xx_spi_pci_can_dma() signature in spi-pxa2xx-pci.c by removing the
    redundant `bool verbose` parameter.

Changes in v8:
  - Addressed feedback from Sashiko review on the v7 patchset:
  - Fixed runtime PM resume interrupt storm in ssp_int() by checking drv_data->clk_enabled
    instead of pm_runtime_get_if_active() == 0.
  - Fixed PM disabled configuration (CONFIG_PM=n) support in ssp_int() by avoiding
    active <= 0 early returns.
  - Reordered suspend and remove sequences to invoke pxa_ssp_disable() before setting
    drv_data->suspended = true and synchronizing the IRQ, closing a race window
    where level-triggered interrupts could cause a storm.
  - Masked hardware interrupt generation in pxa2xx_spi_runtime_suspend() via
    pxa_ssp_disable() to prevent unexpected interrupts during clock enable.
  - Avoided PCIe Completion Timeout system hangs on newer LPSS platforms (SPT, BXT, CNL)
    by introducing pxa2xx_spi_need_lpss_restore() to restrict MMIO save/restore
    loops to LPT, BYT, and BSW platforms (which lack an MFD parent).
  - Fixed compiler error in pxa2xx_spi_probe() due to unused label.

Changes in v7:
  - Addressed feedback from Sashiko review on the v6 patchset:
  - Fixed a race condition during probe by moving the request_irq() call after
    the clock is enabled and the suspended flag is cleared. This prevents an early
    shared interrupt from asserting and triggering an interrupt storm before the clock
    is active to allow clearing it.
  - Rectified the teardown sequence in pxa2xx_spi_remove(): first set drv_data->suspended
    to true and disable SSP hardware-level interrupt generation (pxa_ssp_disable()), then call
    synchronize_irq() to wait for in-flight interrupt handlers to complete, free the
    IRQ, and only then disable the clocks. This eliminates both post-clock-disable MMIO
    accesses and unhandled shared hardware interrupt storms.
  - Clarified that the unconditional MMIO register access in pxa2xx_spi_suspend()
    is safe because pm_runtime_resume_and_get() is invoked at the very beginning of the
    suspend callback, guaranteeing the LPSS device is active and clocked during register
    disabling/saving.
  - Added spi_controller_resume() recovery to the error path of spi_controller_suspend()
    in pxa2xx_spi_suspend() to prevent the controller from remaining permanently disabled
    in the event system suspend is aborted.

Changes in v6:
  - Addressed feedback from Sashiko review on the v5 patchset:
  - Added a synchronize_irq() call to the spi_controller_resume() error path in
    pxa2xx_spi_resume(). This ensures any concurrent shared interrupt handlers
    (which might execute because drv_data->suspended = false was set earlier)
    finish executing before we disable the clock, preventing PCIe timeouts.
  - Checked and confirmed that active == 0 is the correct check in ssp_int(). If
    Runtime PM is disabled, pm_runtime_get_if_active() returns a negative error
    code (like -EINVAL). Changing this check to active <= 0 would cause a
    regression on non-PM configurations because the handler would always return
    IRQ_NONE. Under disabled Runtime PM, the hardware clock is kept constantly
    active, so it is safe to proceed and read registers when active < 0.

Changes in v5:
  - Reverted runtime PM configuration in spi-pxa2xx-pci.c to be unconditional.
    This prevents the usage count from leaking by +1 on unbind for PIO mode,
    while letting pxa2xx_spi_probe()'s pm_runtime_get_noresume() and
    pxa2xx_spi_remove()'s pm_runtime_put_noidle() handle the permanent
    autosuspend lockout for PIO devices symmetrically.
  - Removed the pm_runtime_forbid() call from pxa2xx_spi_remove(). This resolves
    reference leaks for non-PCI platform devices where pm_runtime_allow() was
    never called during probe.
  - Delayed clearing the drv_data->suspended flag on resume until after LPSS reset
    deassertion and private register restoration are complete. This prevents a
    shared interrupt from firing during resume and attempting to read the SSSR
    register while the LPSS block is still held in reset.
  - Set drv_data->suspended = true on spi_controller_resume() failure path in
    pxa2xx_spi_resume(). This ensures that subsequent shared interrupts do not
    attempt register access once the clock is disabled.

Changes in v4:
  - Track clock state using drv_data->clk_enabled via pxa2xx_spi_clk_enable() and
    pxa2xx_spi_clk_disable() helper functions. This guarantees clock enable/disable
    symmetry, preventing clock disable count underflows and framework warnings on S3
    resume or runtime autosuspend error paths.
  - Introduce drv_data->suspended flag to protect MMIO access in ssp_int() during
    system suspend and runtime suspend transition windows.
  - Initialize drv_data->suspended = true early in probe(), clearing it only after
    the clock is successfully enabled. This completely prevents shared interrupt
    handler races during device probe when the clock is still off.
  - Call synchronize_irq() after setting drv_data->suspended = true in suspend and
    runtime_suspend. This ensures any running shared interrupt handlers finish
    executing before the clock is physically turned off.

Changes in v3:
  - Avoid PM reference leaks on probe bind/unbind cycle by keeping probe PM
    configuration symmetric.
  - Prevent userspace (PowerTOP, udev) from overriding runtime PM settings when
    DMA is disabled by holding a PM reference via pm_runtime_get_noresume()
    in pxa2xx_spi_probe() and dropping it in remove/error paths.
  - Check device status in the shared interrupt handler ssp_int() using
    pm_runtime_get_if_active() instead of pm_runtime_suspended(). If the device is
    suspending (RPM_SUSPENDING) or suspended, ssp_int() immediately returns
    IRQ_NONE to avoid reading unclocked MMIO registers during power transition.
  - Adjust the driver teardown order in pxa2xx_spi_remove() and probe error paths:
    always call free_irq() to unregister the handler before calling
    clk_disable_unprepare() to turn off the clock, preventing concurrent
    interrupts from reading registers while the clock is disabled.
  - Avoid duplicate can-DMA pci_info() logging by checking the pre-computed
    enable_dma status in probe and passing a verbose flag to can_dma().

Changes in v2:
  - Addressed feedback from Mark Brown on the original v1 series.
  - Used drv_data->lpss_base together with relative offsets rather than
    hardcoding absolute MMIO offsets that vary between LPSS IP revisions.
  - Moved the register save block in suspend to after the controller is quiesced
    (after spi_controller_suspend() and pxa_ssp_disable()).
  - Store the context array lpss_priv_ctx[6] inside struct driver_data instead of
    struct pxa2xx_spi_controller. This keeps the changes entirely local to the
    core driver, preventing symbol version mismatches (disagrees about version
    of symbol) for other subsystem components (e.g., spi-pxa2xx-platform.ko).
  - Restrict the save/restore loop to the first 6 LPSS private registers
    (offsets 0x00 to 0x14). Offsets beyond 0x14 (except CS control at 0x18, which is
    re-initialised by lpss_ssp_setup()) are reserved/unimplemented on LPT
    platforms (such as MacBook8,1), and writing to them triggers a PCIe
    Completion Timeout causing a system freeze.
  - Added named constants for LPSS_PRIV_RESETS and the de-assert value.
  - Wrapped S3 suspend/resume with pm_runtime_resume_and_get() and
    pm_runtime_put_autosuspend() respectively.

Shih-Yuan Lee (7):
  spi: pxa2xx: introduce clock enable and disable helper functions
  spi: pxa2xx: introduce suspended flag for interrupt synchronization
  spi: pxa2xx: overhaul teardown and suspend sequence using
    pxa2xx_spi_off
  spi: pxa2xx: lock out runtime autosuspend for Intel LPSS SPI in PIO
    mode
  spi: pxa2xx: disable DMA for Apple MacBook8,1
  spi: pxa2xx: restore LPSS private register state on S3 resume
  spi: pxa2xx: rename local status variable to ret

 drivers/spi/spi-pxa2xx-pci.c |  35 ++++-
 drivers/spi/spi-pxa2xx.c     | 256 ++++++++++++++++++++++++++++-------
 drivers/spi/spi-pxa2xx.h     |   4 +
 3 files changed, 246 insertions(+), 49 deletions(-)

-- 
2.39.5


^ permalink raw reply

* [PATCH v16 1/7] spi: pxa2xx: introduce clock enable and disable helper functions
From: Shih-Yuan Lee @ 2026-07-20 16:21 UTC (permalink / raw)
  To: Mark Brown
  Cc: Andy Shevchenko, Mika Westerberg, Lukas Wunner, Daniel Mack,
	Haojian Zhuang, Robert Jarzmik, linux-arm-kernel, linux-spi,
	linux-kernel, Shih-Yuan Lee
In-Reply-To: <20260720162117.32304-1-fourdollars@debian.org>

The driver disables the clock during PM runtime suspend, PM system
suspend, and device unbinding (remove). It also disables the clock
on various error unwinding paths in pxa2xx_spi_probe().

However, if the clock is already disabled (for example, if the device is
already runtime-suspended during driver unbinding), calling the common
clock framework's clk_disable_unprepare() again leads to clock prepare/enable
count underflows, generating kernel warnings.

Introduce pxa2xx_spi_clk_enable() and pxa2xx_spi_clk_disable() helper
functions that track the clock enable state using a new 'clk_enabled'
boolean flag in struct driver_data.

This ensures clk_disable_unprepare() is called only when the clock is
active, preventing clock underflows during suspend transitions and unbind.
It also allows the probe function to safely unwind resource allocations
without triggering clock underflows.

Signed-off-by: Shih-Yuan Lee <fourdollars@debian.org>
---
 drivers/spi/spi-pxa2xx.c | 37 +++++++++++++++++++++++++++++--------
 drivers/spi/spi-pxa2xx.h |  2 ++
 2 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 6291d7c2e06f..d50152aad348 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -713,6 +713,28 @@ static void handle_bad_msg(struct driver_data *drv_data)
 	dev_err(drv_data->ssp->dev, "bad message state in interrupt handler\n");
 }
 
+static int pxa2xx_spi_clk_enable(struct driver_data *drv_data)
+{
+	int ret;
+
+	if (drv_data->clk_enabled)
+		return 0;
+
+	ret = clk_prepare_enable(drv_data->ssp->clk);
+	if (ret == 0)
+		drv_data->clk_enabled = true;
+
+	return ret;
+}
+
+static void pxa2xx_spi_clk_disable(struct driver_data *drv_data)
+{
+	if (drv_data->clk_enabled) {
+		clk_disable_unprepare(drv_data->ssp->clk);
+		drv_data->clk_enabled = false;
+	}
+}
+
 static irqreturn_t ssp_int(int irq, void *dev_id)
 {
 	struct driver_data *drv_data = dev_id;
@@ -1352,7 +1374,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 	}
 
 	/* Enable SOC clock */
-	status = clk_prepare_enable(ssp->clk);
+	status = pxa2xx_spi_clk_enable(drv_data);
 	if (status)
 		goto out_error_dma_irq_alloc;
 
@@ -1449,7 +1471,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 	return status;
 
 out_error_clock_enabled:
-	clk_disable_unprepare(ssp->clk);
+	pxa2xx_spi_clk_disable(drv_data);
 
 out_error_dma_irq_alloc:
 	pxa2xx_spi_dma_release(drv_data);
@@ -1468,7 +1490,7 @@ void pxa2xx_spi_remove(struct device *dev)
 
 	/* Disable the SSP at the peripheral and SOC level */
 	pxa_ssp_disable(ssp);
-	clk_disable_unprepare(ssp->clk);
+	pxa2xx_spi_clk_disable(drv_data);
 
 	/* Release DMA */
 	if (drv_data->controller_info->enable_dma)
@@ -1492,7 +1514,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
 	pxa_ssp_disable(ssp);
 
 	if (!pm_runtime_suspended(dev))
-		clk_disable_unprepare(ssp->clk);
+		pxa2xx_spi_clk_disable(drv_data);
 
 	return 0;
 }
@@ -1500,12 +1522,11 @@ static int pxa2xx_spi_suspend(struct device *dev)
 static int pxa2xx_spi_resume(struct device *dev)
 {
 	struct driver_data *drv_data = dev_get_drvdata(dev);
-	struct ssp_device *ssp = drv_data->ssp;
 	int status;
 
 	/* Enable the SSP clock */
 	if (!pm_runtime_suspended(dev)) {
-		status = clk_prepare_enable(ssp->clk);
+		status = pxa2xx_spi_clk_enable(drv_data);
 		if (status)
 			return status;
 	}
@@ -1518,7 +1539,7 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev)
 {
 	struct driver_data *drv_data = dev_get_drvdata(dev);
 
-	clk_disable_unprepare(drv_data->ssp->clk);
+	pxa2xx_spi_clk_disable(drv_data);
 	return 0;
 }
 
@@ -1526,7 +1547,7 @@ static int pxa2xx_spi_runtime_resume(struct device *dev)
 {
 	struct driver_data *drv_data = dev_get_drvdata(dev);
 
-	return clk_prepare_enable(drv_data->ssp->clk);
+	return pxa2xx_spi_clk_enable(drv_data);
 }
 
 EXPORT_NS_GPL_DEV_PM_OPS(pxa2xx_spi_pm_ops, SPI_PXA2xx) = {
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 447be0369384..820e573a3c60 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -72,6 +72,8 @@ struct driver_data {
 
 	void __iomem *lpss_base;
 
+	bool clk_enabled;
+
 	/* Optional slave FIFO ready signal */
 	struct gpio_desc *gpiod_ready;
 };
-- 
2.39.5



^ permalink raw reply related

* [PATCH v16 2/7] spi: pxa2xx: introduce suspended flag for interrupt synchronization
From: Shih-Yuan Lee @ 2026-07-20 16:21 UTC (permalink / raw)
  To: Mark Brown
  Cc: Andy Shevchenko, Mika Westerberg, Lukas Wunner, Daniel Mack,
	Haojian Zhuang, Robert Jarzmik, linux-arm-kernel, linux-spi,
	linux-kernel, Shih-Yuan Lee
In-Reply-To: <20260720162117.32304-1-fourdollars@debian.org>

When a shared interrupt line is used, the interrupt handler ssp_int()
can be triggered by other devices sharing the line. The handler must
ensure it does not access the SSP controller registers via MMIO when
the device is powered down or when its clock is gated; otherwise, it
will cause PCIe Completion Timeouts and system hangs.

Currently, ssp_int() guards MMIO access using:
    if (pm_runtime_suspended(drv_data->ssp->dev)) return IRQ_NONE;

However, during PM transitions (such as system suspend or runtime PM
autosuspend), device callbacks execute to disable the hardware and gate the
clock, but the PM state machine does not mark the device as RPM_SUSPENDED
until after the suspend callback returns. During this transitional state
(RPM_SUSPENDING), pm_runtime_suspended() returns false. If a shared
interrupt fires after the clock has been gated but before the PM state has
transitioned, ssp_int() will execute, attempt MMIO reads on the unclocked
register space, and hang the system.

Formal verification using Spin/PROMELA confirms that a scheduling window
exists where the interrupt thread accesses MMIO when clk_enabled is false,
violating safety properties.

Introduce a custom 'suspended' boolean flag in struct driver_data to
track the device's suspended state across all PM transitions. Check
both 'drv_data->suspended' and '!drv_data->clk_enabled' in ssp_int()
to return IRQ_NONE immediately before any MMIO access is attempted.

This closes the state transition race condition and mathematically guarantees
deadlock-free, safe shared interrupt handling during power transitions.

Signed-off-by: Shih-Yuan Lee <fourdollars@debian.org>
---
 drivers/spi/spi-pxa2xx.c | 51 ++++++++++++++++++++++++++--------------
 drivers/spi/spi-pxa2xx.h |  1 +
 2 files changed, 35 insertions(+), 17 deletions(-)

diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index d50152aad348..c44349ab2b52 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -730,8 +730,8 @@ static int pxa2xx_spi_clk_enable(struct driver_data *drv_data)
 static void pxa2xx_spi_clk_disable(struct driver_data *drv_data)
 {
 	if (drv_data->clk_enabled) {
-		clk_disable_unprepare(drv_data->ssp->clk);
 		drv_data->clk_enabled = false;
+		clk_disable_unprepare(drv_data->ssp->clk);
 	}
 }
 
@@ -743,12 +743,12 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
 	u32 status;
 
 	/*
-	 * The IRQ might be shared with other peripherals so we must first
-	 * check that are we RPM suspended or not. If we are we assume that
-	 * the IRQ was not for us (we shouldn't be RPM suspended when the
-	 * interrupt is enabled).
+	 * The IRQ might be shared with other peripherals or trigger during
+	 * power state transitions. First check if device is suspended or if
+	 * clock is disabled; if so, return IRQ_NONE immediately to avoid
+	 * unclocked MMIO reads.
 	 */
-	if (pm_runtime_suspended(drv_data->ssp->dev))
+	if (drv_data->suspended || !drv_data->clk_enabled)
 		return IRQ_NONE;
 
 	/*
@@ -1310,6 +1310,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 	drv_data->controller = controller;
 	drv_data->controller_info = platform_info;
 	drv_data->ssp = ssp;
+	drv_data->suspended = true;
 
 	/* The spi->mode bits understood by this driver: */
 	controller->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LOOP;
@@ -1352,11 +1353,6 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 						| SSSR_ROR | SSSR_TUR;
 	}
 
-	status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
-			drv_data);
-	if (status < 0)
-		return dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq);
-
 	/* Setup DMA if requested */
 	if (platform_info->enable_dma) {
 		status = pxa2xx_spi_dma_setup(drv_data);
@@ -1376,7 +1372,16 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 	/* Enable SOC clock */
 	status = pxa2xx_spi_clk_enable(drv_data);
 	if (status)
-		goto out_error_dma_irq_alloc;
+		goto out_error_dma_alloc;
+
+	drv_data->suspended = false;
+
+	status = request_irq(ssp->irq, ssp_int, IRQF_SHARED, dev_name(dev),
+			drv_data);
+	if (status < 0) {
+		status = dev_err_probe(dev, status, "cannot get IRQ %d\n", ssp->irq);
+		goto out_error_clock_enabled;
+	}
 
 	controller->max_speed_hz = clk_get_rate(ssp->clk);
 	/*
@@ -1456,7 +1461,7 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 						"ready", GPIOD_OUT_LOW);
 		if (IS_ERR(drv_data->gpiod_ready)) {
 			status = PTR_ERR(drv_data->gpiod_ready);
-			goto out_error_clock_enabled;
+			goto out_error_irq_alloc;
 		}
 	}
 
@@ -1465,17 +1470,19 @@ int pxa2xx_spi_probe(struct device *dev, struct ssp_device *ssp,
 	status = spi_register_controller(controller);
 	if (status) {
 		dev_err_probe(dev, status, "problem registering SPI controller\n");
-		goto out_error_clock_enabled;
+		goto out_error_irq_alloc;
 	}
 
 	return status;
 
+out_error_irq_alloc:
+	free_irq(ssp->irq, drv_data);
+
 out_error_clock_enabled:
 	pxa2xx_spi_clk_disable(drv_data);
 
-out_error_dma_irq_alloc:
+out_error_dma_alloc:
 	pxa2xx_spi_dma_release(drv_data);
-	free_irq(ssp->irq, drv_data);
 
 	return status;
 }
@@ -1511,6 +1518,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
 	if (status)
 		return status;
 
+	drv_data->suspended = true;
 	pxa_ssp_disable(ssp);
 
 	if (!pm_runtime_suspended(dev))
@@ -1531,6 +1539,8 @@ static int pxa2xx_spi_resume(struct device *dev)
 			return status;
 	}
 
+	drv_data->suspended = false;
+
 	/* Start the queue running */
 	return spi_controller_resume(drv_data->controller);
 }
@@ -1539,6 +1549,7 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev)
 {
 	struct driver_data *drv_data = dev_get_drvdata(dev);
 
+	drv_data->suspended = true;
 	pxa2xx_spi_clk_disable(drv_data);
 	return 0;
 }
@@ -1546,8 +1557,14 @@ static int pxa2xx_spi_runtime_suspend(struct device *dev)
 static int pxa2xx_spi_runtime_resume(struct device *dev)
 {
 	struct driver_data *drv_data = dev_get_drvdata(dev);
+	int ret;
 
-	return pxa2xx_spi_clk_enable(drv_data);
+	ret = pxa2xx_spi_clk_enable(drv_data);
+	if (ret)
+		return ret;
+
+	drv_data->suspended = false;
+	return 0;
 }
 
 EXPORT_NS_GPL_DEV_PM_OPS(pxa2xx_spi_pm_ops, SPI_PXA2xx) = {
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 820e573a3c60..44f37bf9c519 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -72,6 +72,7 @@ struct driver_data {
 
 	void __iomem *lpss_base;
 
+	bool suspended;
 	bool clk_enabled;
 
 	/* Optional slave FIFO ready signal */
-- 
2.39.5



^ permalink raw reply related


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