* [PATCH v6 8/9] sframe: Initialize debug info for kernel sections
From: Dylan Hatch @ 2026-05-19 6:49 UTC (permalink / raw)
To: Roman Gushchin, Weinan Liu, Will Deacon, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Steven Rostedt, Catalin Marinas,
Jiri Kosina, Mark Rutland, Jens Remus
Cc: Dylan Hatch, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel, Randy Dunlap, Mostafa Saleh, Herbert Xu,
David S. Miller
In-Reply-To: <20260519064950.493949-1-dylanbhatch@google.com>
Setup the optional unwinder debug information for kernel .sframe
sections. Modules are indicated by the format "(<module-name>)".
Suggested-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
---
kernel/unwind/sframe.c | 4 ++++
kernel/unwind/sframe_debug.h | 13 +++++++++++++
2 files changed, 17 insertions(+)
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index e8ede0343cb2..d256e72620fe 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -1036,6 +1036,8 @@ void __init init_sframe_table(void)
kernel_sfsec.text_start = (unsigned long)_stext;
kernel_sfsec.text_end = (unsigned long)_etext;
+ dbg_init(&kernel_sfsec);
+
if (WARN_ON(sframe_read_header(&kernel_sfsec)))
return;
if (WARN_ON(sframe_validate_section(&kernel_sfsec)))
@@ -1099,6 +1101,8 @@ void sframe_module_init(struct module *mod, void *sframe, size_t sframe_size,
sec->text_start = (unsigned long)text;
sec->text_end = (unsigned long)text + text_size;
+ dbg_init(sec);
+
if (WARN_ON(sframe_read_header(sec)))
return;
if (WARN_ON(sframe_sort_fdes(sec)))
diff --git a/kernel/unwind/sframe_debug.h b/kernel/unwind/sframe_debug.h
index e568be4172b1..6c7ab3aa7c9e 100644
--- a/kernel/unwind/sframe_debug.h
+++ b/kernel/unwind/sframe_debug.h
@@ -32,6 +32,19 @@ static inline void dbg_init(struct sframe_section *sec)
struct mm_struct *mm = current->mm;
struct vm_area_struct *vma;
+ if (sec->sec_type == SFRAME_KERNEL) {
+ if (sec == &kernel_sfsec) {
+ sec->filename = kstrdup("(vmlinux)", GFP_KERNEL);
+ } else {
+ struct module *mod = container_of(sec, struct module,
+ arch.sframe_sec);
+ sec->filename = kasprintf(GFP_KERNEL, "(%s)",
+ mod->name);
+ }
+
+ return;
+ }
+
guard(mmap_read_lock)(mm);
vma = vma_lookup(mm, sec->sframe_start);
if (!vma)
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v6 1/9] sframe: Allow kernelspace sframe sections
From: Dylan Hatch @ 2026-05-19 6:49 UTC (permalink / raw)
To: Roman Gushchin, Weinan Liu, Will Deacon, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Steven Rostedt, Catalin Marinas,
Jiri Kosina, Mark Rutland, Jens Remus
Cc: Dylan Hatch, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel, Randy Dunlap, Mostafa Saleh, Herbert Xu,
David S. Miller
In-Reply-To: <20260519064950.493949-1-dylanbhatch@google.com>
Generalize the sframe lookup code to support kernelspace sections. This
is done by defining a SFRAME_LOOKUP option that can be activated
separate from HAVE_UNWIND_USER_SFRAME, as there will be other client to
this library than just userspace unwind.
Sframe section location is now tracked in a separate sec_type field to
determine whether user-access functions are necessary to read the sframe
data. Relevant type delarations are moved and renamed to reflect the
non-user sframe support.
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
---
MAINTAINERS | 2 +-
arch/Kconfig | 4 +
.../{unwind_user_sframe.h => unwind_sframe.h} | 6 +-
arch/x86/include/asm/unwind_user.h | 12 +-
include/linux/sframe.h | 48 ++--
include/linux/unwind_types.h | 46 +++
include/linux/unwind_user_types.h | 41 ---
kernel/unwind/Makefile | 2 +-
kernel/unwind/sframe.c | 270 ++++++++++++------
kernel/unwind/user.c | 45 +--
10 files changed, 295 insertions(+), 181 deletions(-)
rename arch/x86/include/asm/{unwind_user_sframe.h => unwind_sframe.h} (50%)
create mode 100644 include/linux/unwind_types.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 6812f581d44b..54613c683fdb 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27858,7 +27858,7 @@ F: Documentation/driver-api/uio-howto.rst
F: drivers/uio/
F: include/linux/uio_driver.h
-USERSPACE STACK UNWINDING
+STACK UNWINDING
M: Josh Poimboeuf <jpoimboe@kernel.org>
M: Steven Rostedt <rostedt@goodmis.org>
S: Maintained
diff --git a/arch/Kconfig b/arch/Kconfig
index 78dad97bf2a4..6eeafd86347b 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -486,6 +486,9 @@ config AS_SFRAME3
def_bool $(as-instr,.cfi_startproc\n.cfi_endproc,-Wa$(comma)--gsframe-3)
select AS_SFRAME
+config UNWIND_SFRAME_LOOKUP
+ bool
+
config UNWIND_USER
bool
@@ -496,6 +499,7 @@ config HAVE_UNWIND_USER_FP
config HAVE_UNWIND_USER_SFRAME
bool
select UNWIND_USER
+ select UNWIND_SFRAME_LOOKUP
config SFRAME_VALIDATION
bool "Enable .sframe section debugging"
diff --git a/arch/x86/include/asm/unwind_user_sframe.h b/arch/x86/include/asm/unwind_sframe.h
similarity index 50%
rename from arch/x86/include/asm/unwind_user_sframe.h
rename to arch/x86/include/asm/unwind_sframe.h
index d828ae1a4aac..44d42e6ffde4 100644
--- a/arch/x86/include/asm/unwind_user_sframe.h
+++ b/arch/x86/include/asm/unwind_sframe.h
@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0 */
-#ifndef _ASM_X86_UNWIND_USER_SFRAME_H
-#define _ASM_X86_UNWIND_USER_SFRAME_H
+#ifndef _ASM_X86_UNWIND_SFRAME_H
+#define _ASM_X86_UNWIND_SFRAME_H
#ifdef CONFIG_X86_64
@@ -9,4 +9,4 @@
#endif
-#endif /* _ASM_X86_UNWIND_USER_SFRAME_H */
+#endif /* _ASM_X86_UNWIND_SFRAME_H */
diff --git a/arch/x86/include/asm/unwind_user.h b/arch/x86/include/asm/unwind_user.h
index b80f0ec0f7a7..1c7e31ca5d8e 100644
--- a/arch/x86/include/asm/unwind_user.h
+++ b/arch/x86/include/asm/unwind_user.h
@@ -54,30 +54,30 @@ static inline int unwind_user_get_reg(unsigned long *val, unsigned int regnum)
#define ARCH_INIT_USER_FP_FRAME(ws) \
.cfa = { \
- .rule = UNWIND_USER_CFA_RULE_FP_OFFSET,\
+ .rule = UNWIND_CFA_RULE_FP_OFFSET,\
.offset = 2*(ws), \
}, \
.ra = { \
- .rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF,\
+ .rule = UNWIND_RULE_CFA_OFFSET_DEREF,\
.offset = -1*(ws), \
}, \
.fp = { \
- .rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF,\
+ .rule = UNWIND_RULE_CFA_OFFSET_DEREF,\
.offset = -2*(ws), \
}, \
.outermost = false,
#define ARCH_INIT_USER_FP_ENTRY_FRAME(ws) \
.cfa = { \
- .rule = UNWIND_USER_CFA_RULE_SP_OFFSET,\
+ .rule = UNWIND_CFA_RULE_SP_OFFSET,\
.offset = 1*(ws), \
}, \
.ra = { \
- .rule = UNWIND_USER_RULE_CFA_OFFSET_DEREF,\
+ .rule = UNWIND_RULE_CFA_OFFSET_DEREF,\
.offset = -1*(ws), \
}, \
.fp = { \
- .rule = UNWIND_USER_RULE_RETAIN,\
+ .rule = UNWIND_RULE_RETAIN,\
}, \
.outermost = false,
diff --git a/include/linux/sframe.h b/include/linux/sframe.h
index b79c5ec09229..0cb2924367bc 100644
--- a/include/linux/sframe.h
+++ b/include/linux/sframe.h
@@ -3,37 +3,46 @@
#define _LINUX_SFRAME_H
#include <linux/mm_types.h>
+#include <linux/unwind_types.h>
#include <linux/srcu.h>
-#include <linux/unwind_user_types.h>
-#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+#ifdef CONFIG_UNWIND_SFRAME_LOOKUP
+
+enum sframe_sec_type {
+ SFRAME_KERNEL,
+ SFRAME_USER,
+};
struct sframe_section {
- struct rcu_head rcu;
+ struct rcu_head rcu;
#ifdef CONFIG_DYNAMIC_DEBUG
- const char *filename;
+ const char *filename;
#endif
- unsigned long sframe_start;
- unsigned long sframe_end;
- unsigned long text_start;
- unsigned long text_end;
-
- unsigned long fdes_start;
- unsigned long fres_start;
- unsigned long fres_end;
- unsigned int num_fdes;
-
- signed char ra_off;
- signed char fp_off;
+ enum sframe_sec_type sec_type;
+ unsigned long sframe_start;
+ unsigned long sframe_end;
+ unsigned long text_start;
+ unsigned long text_end;
+
+ unsigned long fdes_start;
+ unsigned long fres_start;
+ unsigned long fres_end;
+ unsigned int num_fdes;
+
+ signed char ra_off;
+ signed char fp_off;
};
+#endif /* CONFIG_UNWIND_SFRAME_LOOKUP */
+
+#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+
#define INIT_MM_SFRAME .sframe_mt = MTREE_INIT(sframe_mt, 0),
extern void sframe_free_mm(struct mm_struct *mm);
extern int sframe_add_section(unsigned long sframe_start, unsigned long sframe_end,
unsigned long text_start, unsigned long text_end);
extern int sframe_remove_section(unsigned long sframe_addr);
-extern int sframe_find(unsigned long ip, struct unwind_user_frame *frame);
static inline bool current_has_sframe(void)
{
@@ -42,6 +51,8 @@ static inline bool current_has_sframe(void)
return mm && !mtree_empty(&mm->sframe_mt);
}
+extern int sframe_find_user(unsigned long ip, struct unwind_frame *frame);
+
#else /* !CONFIG_HAVE_UNWIND_USER_SFRAME */
#define INIT_MM_SFRAME
@@ -52,9 +63,10 @@ static inline int sframe_add_section(unsigned long sframe_start, unsigned long s
return -ENOSYS;
}
static inline int sframe_remove_section(unsigned long sframe_addr) { return -ENOSYS; }
-static inline int sframe_find(unsigned long ip, struct unwind_user_frame *frame) { return -ENOSYS; }
static inline bool current_has_sframe(void) { return false; }
+static inline int sframe_find_user(unsigned long ip, struct unwind_frame *frame) { return -ENOSYS; }
+
#endif /* CONFIG_HAVE_UNWIND_USER_SFRAME */
#endif /* _LINUX_SFRAME_H */
diff --git a/include/linux/unwind_types.h b/include/linux/unwind_types.h
new file mode 100644
index 000000000000..08bcb0aa04aa
--- /dev/null
+++ b/include/linux/unwind_types.h
@@ -0,0 +1,46 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _LINUX_UNWIND_TYPES_H
+#define _LINUX_UNWIND_TYPES_H
+
+#define UNWIND_RULE_DEREF BIT(31)
+
+enum unwind_cfa_rule {
+ UNWIND_CFA_RULE_SP_OFFSET, /* CFA = SP + offset */
+ UNWIND_CFA_RULE_FP_OFFSET, /* CFA = FP + offset */
+ UNWIND_CFA_RULE_REG_OFFSET, /* CFA = reg + offset */
+ /* DEREF variants */
+ UNWIND_CFA_RULE_REG_OFFSET_DEREF = /* CFA = *(reg + offset) */
+ UNWIND_CFA_RULE_REG_OFFSET | UNWIND_RULE_DEREF,
+};
+
+struct unwind_cfa_rule_data {
+ enum unwind_cfa_rule rule;
+ s32 offset;
+ unsigned int regnum;
+};
+
+enum unwind_rule {
+ UNWIND_RULE_RETAIN, /* entity = entity */
+ UNWIND_RULE_CFA_OFFSET, /* entity = CFA + offset */
+ UNWIND_RULE_REG_OFFSET, /* entity = register + offset */
+ /* DEREF variants */
+ UNWIND_RULE_CFA_OFFSET_DEREF = /* entity = *(CFA + offset) */
+ UNWIND_RULE_CFA_OFFSET | UNWIND_RULE_DEREF,
+ UNWIND_RULE_REG_OFFSET_DEREF = /* entity = *(register + offset) */
+ UNWIND_RULE_REG_OFFSET | UNWIND_RULE_DEREF,
+};
+
+struct unwind_rule_data {
+ enum unwind_rule rule;
+ s32 offset;
+ unsigned int regnum;
+};
+
+struct unwind_frame {
+ struct unwind_cfa_rule_data cfa;
+ struct unwind_rule_data ra;
+ struct unwind_rule_data fp;
+ bool outermost;
+};
+
+#endif /* _LINUX_UNWIND_TYPES_H */
diff --git a/include/linux/unwind_user_types.h b/include/linux/unwind_user_types.h
index 059e5c76f2f3..646e5fb774db 100644
--- a/include/linux/unwind_user_types.h
+++ b/include/linux/unwind_user_types.h
@@ -27,47 +27,6 @@ struct unwind_stacktrace {
unsigned long *entries;
};
-#define UNWIND_USER_RULE_DEREF BIT(31)
-
-enum unwind_user_cfa_rule {
- UNWIND_USER_CFA_RULE_SP_OFFSET, /* CFA = SP + offset */
- UNWIND_USER_CFA_RULE_FP_OFFSET, /* CFA = FP + offset */
- UNWIND_USER_CFA_RULE_REG_OFFSET, /* CFA = reg + offset */
- /* DEREF variants */
- UNWIND_USER_CFA_RULE_REG_OFFSET_DEREF = /* CFA = *(reg + offset) */
- UNWIND_USER_CFA_RULE_REG_OFFSET | UNWIND_USER_RULE_DEREF,
-};
-
-struct unwind_user_cfa_rule_data {
- enum unwind_user_cfa_rule rule;
- s32 offset;
- unsigned int regnum;
-};
-
-enum unwind_user_rule {
- UNWIND_USER_RULE_RETAIN, /* entity = entity */
- UNWIND_USER_RULE_CFA_OFFSET, /* entity = CFA + offset */
- UNWIND_USER_RULE_REG_OFFSET, /* entity = register + offset */
- /* DEREF variants */
- UNWIND_USER_RULE_CFA_OFFSET_DEREF = /* entity = *(CFA + offset) */
- UNWIND_USER_RULE_CFA_OFFSET | UNWIND_USER_RULE_DEREF,
- UNWIND_USER_RULE_REG_OFFSET_DEREF = /* entity = *(register + offset) */
- UNWIND_USER_RULE_REG_OFFSET | UNWIND_USER_RULE_DEREF,
-};
-
-struct unwind_user_rule_data {
- enum unwind_user_rule rule;
- s32 offset;
- unsigned int regnum;
-};
-
-struct unwind_user_frame {
- struct unwind_user_cfa_rule_data cfa;
- struct unwind_user_rule_data ra;
- struct unwind_user_rule_data fp;
- bool outermost;
-};
-
struct unwind_user_state {
unsigned long ip;
unsigned long sp;
diff --git a/kernel/unwind/Makefile b/kernel/unwind/Makefile
index 146038165865..c5f9f8124564 100644
--- a/kernel/unwind/Makefile
+++ b/kernel/unwind/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_UNWIND_USER) += user.o deferred.o
- obj-$(CONFIG_HAVE_UNWIND_USER_SFRAME) += sframe.o
+ obj-$(CONFIG_UNWIND_SFRAME_LOOKUP) += sframe.o
diff --git a/kernel/unwind/sframe.c b/kernel/unwind/sframe.c
index 5400f481b05d..a2ab9a3e07b4 100644
--- a/kernel/unwind/sframe.c
+++ b/kernel/unwind/sframe.c
@@ -13,8 +13,8 @@
#include <linux/string_helpers.h>
#include <linux/sframe.h>
#include <linux/syscalls.h>
-#include <asm/unwind_user_sframe.h>
-#include <linux/unwind_user_types.h>
+#include <linux/unwind_types.h>
+#include <asm/unwind_sframe.h>
#include <uapi/linux/stacktrace.h>
#include "sframe.h"
@@ -46,8 +46,6 @@ struct sframe_fre_internal {
unsigned char dw_size;
};
-DEFINE_STATIC_SRCU(sframe_srcu);
-
static __always_inline unsigned char fre_type_to_size(unsigned char fre_type)
{
if (fre_type > 2)
@@ -62,6 +60,77 @@ static __always_inline unsigned char dataword_size_enum_to_size(unsigned char da
return 1 << dataword_size;
}
+#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+
+DEFINE_STATIC_SRCU(sframe_srcu);
+
+#define UNSAFE_USER_COPY(to, from, size, label) \
+ unsafe_copy_from_user(to, (void __user *)from, size, label)
+
+#define UNSAFE_USER_GET(to, from, type, label) \
+ unsafe_get_user(to, (type __user *)from, label)
+
+#else /* !CONFIG_HAVE_UNWIND_USER_SFRAME */
+
+#define UNSAFE_USER_COPY(to, from, size, label) do { \
+ (void)to; (void)from; (void)size; \
+ goto label; \
+} while (0)
+
+#define UNSAFE_USER_GET(to, from, type, label) do { \
+ (void)to; (void)from; \
+ goto label; \
+} while (0)
+
+#endif /* !CONFIG_HAVE_UNWIND_USER_SFRAME */
+
+#ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
+
+#define KERNEL_COPY(to, from, size, label) memcpy(to, (void *)from, size)
+#define KERNEL_GET(to, from, type, label) ({ (to) = *(type *)(from); })
+
+#else /* !CONFIG_HAVE_UNWIND_KERNEL_SFRAME */
+
+#define KERNEL_COPY(to, from, size, label) do { \
+ (void)(to); (void)(from); (void)size; \
+ goto label; \
+} while (0)
+
+#define KERNEL_GET(to, from, type, label) do { \
+ (void)(to); (void)(from); \
+ goto label; \
+} while (0)
+
+#endif /* !CONFIG_HAVE_UNWIND_KERNEL_SFRAME */
+
+#define DATA_COPY(sec, to, from, size, label) \
+({ \
+ switch (sec->sec_type) { \
+ case SFRAME_KERNEL: \
+ KERNEL_COPY(to, from, size, label); \
+ break; \
+ case SFRAME_USER: \
+ UNSAFE_USER_COPY(to, from, size, label); \
+ break; \
+ default: \
+ goto label; \
+ } \
+})
+
+#define DATA_GET(sec, to, from, type, label) \
+({ \
+ switch (sec->sec_type) { \
+ case SFRAME_KERNEL: \
+ KERNEL_GET(to, from, type, label); \
+ break; \
+ case SFRAME_USER: \
+ UNSAFE_USER_GET(to, from, type, label); \
+ break; \
+ default: \
+ goto label; \
+ } \
+})
+
static __always_inline int __read_fde(struct sframe_section *sec,
unsigned int fde_num,
struct sframe_fde_internal *fde)
@@ -71,8 +140,8 @@ static __always_inline int __read_fde(struct sframe_section *sec,
struct sframe_fda_v3 _fda;
fde_addr = sec->fdes_start + (fde_num * sizeof(struct sframe_fde_v3));
- unsafe_copy_from_user(&_fde, (void __user *)fde_addr,
- sizeof(struct sframe_fde_v3), Efault);
+ DATA_COPY(sec, &_fde, fde_addr,
+ sizeof(struct sframe_fde_v3), Efault);
func_addr = fde_addr + _fde.func_start_off;
if (func_addr < sec->text_start || func_addr >= sec->text_end)
@@ -81,8 +150,8 @@ static __always_inline int __read_fde(struct sframe_section *sec,
fda_addr = sec->fres_start + _fde.fres_off;
if (fda_addr + sizeof(struct sframe_fda_v3) > sec->fres_end)
return -EINVAL;
- unsafe_copy_from_user(&_fda, (void __user *)fda_addr,
- sizeof(struct sframe_fda_v3), Efault);
+ DATA_COPY(sec, &_fda, fda_addr,
+ sizeof(struct sframe_fda_v3), Efault);
fde->func_addr = func_addr;
fde->func_size = _fde.func_size;
@@ -104,21 +173,21 @@ static __always_inline int __find_fde(struct sframe_section *sec,
struct sframe_fde_internal *fde)
{
unsigned long func_addr_low = 0, func_addr_high = ULONG_MAX;
- struct sframe_fde_v3 __user *first, *low, *high, *found = NULL;
+ struct sframe_fde_v3 *first, *low, *high, *found = NULL;
int ret;
- first = (void __user *)sec->fdes_start;
+ first = (void *)sec->fdes_start;
low = first;
high = first + sec->num_fdes - 1;
while (low <= high) {
- struct sframe_fde_v3 __user *mid;
+ struct sframe_fde_v3 *mid;
s64 func_off;
unsigned long func_addr;
mid = low + ((high - low) / 2);
- unsafe_get_user(func_off, (s64 __user *)mid, Efault);
+ DATA_GET(sec, func_off, mid, s64, Efault);
func_addr = (unsigned long)mid + func_off;
if (ip >= func_addr) {
@@ -156,47 +225,47 @@ static __always_inline int __find_fde(struct sframe_section *sec,
return -EFAULT;
}
-#define ____UNSAFE_GET_USER_INC(to, from, type, label) \
+#define ____GET_INC(sec, to, from, type, label) \
({ \
type __to; \
- unsafe_get_user(__to, (type __user *)from, label); \
+ DATA_GET(sec, __to, from, type, label); \
from += sizeof(__to); \
to = __to; \
})
-#define __UNSAFE_GET_USER_INC(to, from, size, label, u_or_s) \
+#define __GET_INC(sec, to, from, size, label, u_or_s) \
({ \
switch (size) { \
case 1: \
- ____UNSAFE_GET_USER_INC(to, from, u_or_s##8, label); \
+ ____GET_INC(sec, to, from, u_or_s##8, label); \
break; \
case 2: \
- ____UNSAFE_GET_USER_INC(to, from, u_or_s##16, label); \
+ ____GET_INC(sec, to, from, u_or_s##16, label); \
break; \
case 4: \
- ____UNSAFE_GET_USER_INC(to, from, u_or_s##32, label); \
+ ____GET_INC(sec, to, from, u_or_s##32, label); \
break; \
default: \
return -EFAULT; \
} \
})
-#define UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label) \
- __UNSAFE_GET_USER_INC(to, from, size, label, u)
+#define GET_UNSIGNED_INC(sec, to, from, size, label) \
+ __GET_INC(sec, to, from, size, label, u)
-#define UNSAFE_GET_USER_SIGNED_INC(to, from, size, label) \
- __UNSAFE_GET_USER_INC(to, from, size, label, s)
+#define GET_SIGNED_INC(sec, to, from, size, label) \
+ __GET_INC(sec, to, from, size, label, s)
-#define UNSAFE_GET_USER_INC(to, from, size, label) \
- _Generic(to, \
- u8 : UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label), \
- u16 : UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label), \
- u32 : UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label), \
- u64 : UNSAFE_GET_USER_UNSIGNED_INC(to, from, size, label), \
- s8 : UNSAFE_GET_USER_SIGNED_INC(to, from, size, label), \
- s16 : UNSAFE_GET_USER_SIGNED_INC(to, from, size, label), \
- s32 : UNSAFE_GET_USER_SIGNED_INC(to, from, size, label), \
- s64 : UNSAFE_GET_USER_SIGNED_INC(to, from, size, label))
+#define GET_INC(sec, to, from, size, label) \
+ _Generic(to, \
+ u8 : GET_UNSIGNED_INC(sec, to, from, size, label), \
+ u16 : GET_UNSIGNED_INC(sec, to, from, size, label), \
+ u32 : GET_UNSIGNED_INC(sec, to, from, size, label), \
+ u64 : GET_UNSIGNED_INC(sec, to, from, size, label), \
+ s8 : GET_SIGNED_INC(sec, to, from, size, label), \
+ s16 : GET_SIGNED_INC(sec, to, from, size, label), \
+ s32 : GET_SIGNED_INC(sec, to, from, size, label), \
+ s64 : GET_SIGNED_INC(sec, to, from, size, label))
static __always_inline int
__read_default_fre_datawords(struct sframe_section *sec,
@@ -209,19 +278,19 @@ __read_default_fre_datawords(struct sframe_section *sec,
s32 cfa_off, ra_off, fp_off;
unsigned int cfa_regnum;
- UNSAFE_GET_USER_INC(cfa_off, cur, dataword_size, Efault);
+ GET_INC(sec, cfa_off, cur, dataword_size, Efault);
dataword_count--;
ra_off = sec->ra_off;
if (!ra_off && dataword_count) {
dataword_count--;
- UNSAFE_GET_USER_INC(ra_off, cur, dataword_size, Efault);
+ GET_INC(sec, ra_off, cur, dataword_size, Efault);
}
fp_off = sec->fp_off;
if (!fp_off && dataword_count) {
dataword_count--;
- UNSAFE_GET_USER_INC(fp_off, cur, dataword_size, Efault);
+ GET_INC(sec, fp_off, cur, dataword_size, Efault);
}
if (dataword_count)
@@ -257,17 +326,17 @@ __read_flex_fde_fre_datawords(struct sframe_section *sec,
if (dataword_count < 2)
return -EFAULT;
- UNSAFE_GET_USER_INC(cfa_ctl, cur, dataword_size, Efault);
- UNSAFE_GET_USER_INC(cfa_off, cur, dataword_size, Efault);
+ GET_INC(sec, cfa_ctl, cur, dataword_size, Efault);
+ GET_INC(sec, cfa_off, cur, dataword_size, Efault);
dataword_count -= 2;
ra_off = sec->ra_off;
ra_ctl = ra_off ? 2 : 0; /* regnum=0, deref_p=(ra_off != 0), reg_p=0 */
if (dataword_count >= 2) {
- UNSAFE_GET_USER_INC(ra_ctl, cur, dataword_size, Efault);
+ GET_INC(sec, ra_ctl, cur, dataword_size, Efault);
dataword_count--;
if (ra_ctl) {
- UNSAFE_GET_USER_INC(ra_off, cur, dataword_size, Efault);
+ GET_INC(sec, ra_off, cur, dataword_size, Efault);
dataword_count--;
} else {
/* Padding RA location info */
@@ -278,10 +347,10 @@ __read_flex_fde_fre_datawords(struct sframe_section *sec,
fp_off = sec->fp_off;
fp_ctl = fp_off ? 2 : 0; /* regnum=0, deref_p=(fp_off != 0), reg_p=0 */
if (dataword_count >= 2) {
- UNSAFE_GET_USER_INC(fp_ctl, cur, dataword_size, Efault);
+ GET_INC(sec, fp_ctl, cur, dataword_size, Efault);
dataword_count--;
if (fp_ctl) {
- UNSAFE_GET_USER_INC(fp_off, cur, dataword_size, Efault);
+ GET_INC(sec, fp_off, cur, dataword_size, Efault);
dataword_count--;
} else {
/* Padding FP location info */
@@ -355,11 +424,11 @@ static __always_inline int __read_fre(struct sframe_section *sec,
if (fre_addr + addr_size + 1 > sec->fres_end)
return -EFAULT;
- UNSAFE_GET_USER_INC(ip_off, cur, addr_size, Efault);
+ GET_INC(sec, ip_off, cur, addr_size, Efault);
if (fde_pctype == SFRAME_FDE_PCTYPE_INC && ip_off > fde->func_size)
return -EFAULT;
- UNSAFE_GET_USER_INC(info, cur, 1, Efault);
+ GET_INC(sec, info, cur, 1, Efault);
dataword_count = SFRAME_V3_FRE_DATAWORD_COUNT(info);
dataword_size = dataword_size_enum_to_size(SFRAME_V3_FRE_DATAWORD_SIZE(info));
if (!dataword_size)
@@ -382,7 +451,7 @@ static __always_inline int __read_fre(struct sframe_section *sec,
}
static __always_inline int
-sframe_init_cfa_rule_data(struct unwind_user_cfa_rule_data *cfa_rule_data,
+sframe_init_cfa_rule_data(struct unwind_cfa_rule_data *cfa_rule_data,
u32 ctlword, s32 offset)
{
bool deref_p = SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P(ctlword);
@@ -393,13 +462,13 @@ sframe_init_cfa_rule_data(struct unwind_user_cfa_rule_data *cfa_rule_data,
switch (regnum) {
case SFRAME_REG_SP:
- cfa_rule_data->rule = UNWIND_USER_CFA_RULE_SP_OFFSET;
+ cfa_rule_data->rule = UNWIND_CFA_RULE_SP_OFFSET;
break;
case SFRAME_REG_FP:
- cfa_rule_data->rule = UNWIND_USER_CFA_RULE_FP_OFFSET;
+ cfa_rule_data->rule = UNWIND_CFA_RULE_FP_OFFSET;
break;
default:
- cfa_rule_data->rule = UNWIND_USER_CFA_RULE_REG_OFFSET;
+ cfa_rule_data->rule = UNWIND_CFA_RULE_REG_OFFSET;
cfa_rule_data->regnum = regnum;
}
} else {
@@ -407,7 +476,7 @@ sframe_init_cfa_rule_data(struct unwind_user_cfa_rule_data *cfa_rule_data,
}
if (deref_p)
- cfa_rule_data->rule |= UNWIND_USER_RULE_DEREF;
+ cfa_rule_data->rule |= UNWIND_RULE_DEREF;
cfa_rule_data->offset = offset;
@@ -415,27 +484,27 @@ sframe_init_cfa_rule_data(struct unwind_user_cfa_rule_data *cfa_rule_data,
}
static __always_inline void
-sframe_init_rule_data(struct unwind_user_rule_data *rule_data,
+sframe_init_rule_data(struct unwind_rule_data *rule_data,
u32 ctlword, s32 offset)
{
bool deref_p = SFRAME_V3_FLEX_FDE_CTRLWORD_DEREF_P(ctlword);
bool reg_p = SFRAME_V3_FLEX_FDE_CTRLWORD_REG_P(ctlword);
if (!ctlword && !offset) {
- rule_data->rule = UNWIND_USER_RULE_RETAIN;
+ rule_data->rule = UNWIND_RULE_RETAIN;
return;
}
if (reg_p) {
unsigned int regnum = SFRAME_V3_FLEX_FDE_CTRLWORD_REGNUM(ctlword);
- rule_data->rule = UNWIND_USER_RULE_REG_OFFSET;
+ rule_data->rule = UNWIND_RULE_REG_OFFSET;
rule_data->regnum = regnum;
} else {
- rule_data->rule = UNWIND_USER_RULE_CFA_OFFSET;
+ rule_data->rule = UNWIND_RULE_CFA_OFFSET;
}
if (deref_p)
- rule_data->rule |= UNWIND_USER_RULE_DEREF;
+ rule_data->rule |= UNWIND_RULE_DEREF;
rule_data->offset = offset;
}
@@ -443,7 +512,7 @@ sframe_init_rule_data(struct unwind_user_rule_data *rule_data,
static __always_inline int __find_fre(struct sframe_section *sec,
struct sframe_fde_internal *fde,
unsigned long ip,
- struct unwind_user_frame *frame)
+ struct unwind_frame *frame)
{
unsigned char fde_pctype = SFRAME_V3_FDE_PCTYPE(fde->info);
struct sframe_fre_internal *fre, *prev_fre = NULL;
@@ -503,40 +572,18 @@ static __always_inline int __find_fre(struct sframe_section *sec,
return 0;
}
-int sframe_find(unsigned long ip, struct unwind_user_frame *frame)
+static __always_inline int __sframe_find(struct sframe_section *sec,
+ unsigned long ip,
+ struct unwind_frame *frame)
{
- struct mm_struct *mm = current->mm;
- struct sframe_section *sec;
struct sframe_fde_internal fde;
int ret;
- if (!mm)
- return -EINVAL;
-
- guard(srcu)(&sframe_srcu);
-
- sec = mtree_load(&mm->sframe_mt, ip);
- if (!sec)
- return -EINVAL;
-
- if (!user_read_access_begin((void __user *)sec->sframe_start,
- sec->sframe_end - sec->sframe_start))
- return -EFAULT;
-
ret = __find_fde(sec, ip, &fde);
if (ret)
- goto end;
-
- ret = __find_fre(sec, &fde, ip, frame);
-end:
- user_read_access_end();
-
- if (ret == -EFAULT) {
- dbg_sec("removing bad .sframe section\n");
- WARN_ON_ONCE(sframe_remove_section(sec->sframe_start));
- }
+ return ret;
- return ret;
+ return __find_fre(sec, &fde, ip, frame);
}
#ifdef CONFIG_SFRAME_VALIDATION
@@ -661,20 +708,23 @@ static int sframe_validate_section(struct sframe_section *sec) { return 0; }
#endif /* !CONFIG_SFRAME_VALIDATION */
-static void free_section(struct sframe_section *sec)
-{
- dbg_free(sec);
- kfree(sec);
-}
-
static int sframe_read_header(struct sframe_section *sec)
{
unsigned long header_end, fdes_start, fdes_end, fres_start, fres_end;
struct sframe_header shdr;
unsigned int num_fdes;
- if (copy_from_user(&shdr, (void __user *)sec->sframe_start, sizeof(shdr))) {
- dbg_sec("header usercopy failed\n");
+ switch (sec->sec_type) {
+ case SFRAME_USER:
+ if (copy_from_user(&shdr, (void __user *)sec->sframe_start, sizeof(shdr))) {
+ dbg_sec("header usercopy failed\n");
+ return -EFAULT;
+ }
+ break;
+ case SFRAME_KERNEL:
+ shdr = *(struct sframe_header *)sec->sframe_start;
+ break;
+ default:
return -EFAULT;
}
@@ -721,6 +771,45 @@ static int sframe_read_header(struct sframe_section *sec)
return 0;
}
+#ifdef CONFIG_HAVE_UNWIND_USER_SFRAME
+
+int sframe_find_user(unsigned long ip, struct unwind_frame *frame)
+{
+ struct mm_struct *mm = current->mm;
+ struct sframe_section *sec;
+ int ret;
+
+ if (!mm)
+ return -EINVAL;
+
+ guard(srcu)(&sframe_srcu);
+
+ sec = mtree_load(&mm->sframe_mt, ip);
+ if (!sec)
+ return -EINVAL;
+
+ if (!user_read_access_begin((void __user *)sec->sframe_start,
+ sec->sframe_end - sec->sframe_start))
+ return -EFAULT;
+
+ ret = __sframe_find(sec, ip, frame);
+
+ user_read_access_end();
+
+ if (ret == -EFAULT) {
+ dbg_sec("removing bad .sframe section\n");
+ WARN_ON_ONCE(sframe_remove_section(sec->sframe_start));
+ }
+
+ return ret;
+}
+
+static void free_section(struct sframe_section *sec)
+{
+ dbg_free(sec);
+ kfree(sec);
+}
+
int sframe_add_section(unsigned long sframe_start, unsigned long sframe_end,
unsigned long text_start, unsigned long text_end)
{
@@ -757,6 +846,7 @@ int sframe_add_section(unsigned long sframe_start, unsigned long sframe_end,
if (!sec)
return -ENOMEM;
+ sec->sec_type = SFRAME_USER;
sec->sframe_start = sframe_start;
sec->sframe_end = sframe_end;
sec->text_start = text_start;
@@ -877,3 +967,5 @@ SYSCALL_DEFINE5(stacktrace_setup, int, op, unsigned long, addr_start,
}
return -EINVAL;
}
+
+#endif /* CONFIG_HAVE_UNWIND_USER_SFRAME */
diff --git a/kernel/unwind/user.c b/kernel/unwind/user.c
index 3d596da588d0..5670579e3990 100644
--- a/kernel/unwind/user.c
+++ b/kernel/unwind/user.c
@@ -8,6 +8,7 @@
#include <linux/unwind_user.h>
#include <linux/uaccess.h>
#include <linux/sframe.h>
+#include <linux/unwind_types.h>
#define for_each_user_frame(state) \
for (unwind_user_start(state); !(state)->done; unwind_user_next(state))
@@ -28,7 +29,7 @@ get_user_word(unsigned long *word, unsigned long base, int off, unsigned int ws)
}
static int unwind_user_next_common(struct unwind_user_state *state,
- const struct unwind_user_frame *frame)
+ const struct unwind_frame *frame)
{
unsigned long cfa, fp, ra;
@@ -40,16 +41,16 @@ static int unwind_user_next_common(struct unwind_user_state *state,
/* Get the Canonical Frame Address (CFA) */
switch (frame->cfa.rule) {
- case UNWIND_USER_CFA_RULE_SP_OFFSET:
+ case UNWIND_CFA_RULE_SP_OFFSET:
cfa = state->sp;
break;
- case UNWIND_USER_CFA_RULE_FP_OFFSET:
+ case UNWIND_CFA_RULE_FP_OFFSET:
if (state->fp < state->sp)
return -EINVAL;
cfa = state->fp;
break;
- case UNWIND_USER_CFA_RULE_REG_OFFSET:
- case UNWIND_USER_CFA_RULE_REG_OFFSET_DEREF:
+ case UNWIND_CFA_RULE_REG_OFFSET:
+ case UNWIND_CFA_RULE_REG_OFFSET_DEREF:
if (!state->topmost || unwind_user_get_reg(&cfa, frame->cfa.regnum))
return -EINVAL;
break;
@@ -58,7 +59,7 @@ static int unwind_user_next_common(struct unwind_user_state *state,
return -EINVAL;
}
cfa += frame->cfa.offset;
- if (frame->cfa.rule & UNWIND_USER_RULE_DEREF &&
+ if (frame->cfa.rule & UNWIND_RULE_DEREF &&
get_user_word(&cfa, cfa, 0, state->ws))
return -EINVAL;
@@ -76,19 +77,19 @@ static int unwind_user_next_common(struct unwind_user_state *state,
/* Get the Return Address (RA) */
switch (frame->ra.rule) {
- case UNWIND_USER_RULE_RETAIN:
+ case UNWIND_RULE_RETAIN:
if (!state->topmost || unwind_user_get_ra_reg(&ra))
return -EINVAL;
break;
/*
- * UNWIND_USER_RULE_CFA_OFFSET doesn't make sense for RA.
+ * UNWIND_RULE_CFA_OFFSET doesn't make sense for RA.
* A return address cannot legitimately be a stack address.
*/
- case UNWIND_USER_RULE_CFA_OFFSET_DEREF:
+ case UNWIND_RULE_CFA_OFFSET_DEREF:
ra = cfa + frame->ra.offset;
break;
- case UNWIND_USER_RULE_REG_OFFSET:
- case UNWIND_USER_RULE_REG_OFFSET_DEREF:
+ case UNWIND_RULE_REG_OFFSET:
+ case UNWIND_RULE_REG_OFFSET_DEREF:
if (!state->topmost || unwind_user_get_reg(&ra, frame->ra.regnum))
return -EINVAL;
ra += frame->ra.offset;
@@ -97,24 +98,24 @@ static int unwind_user_next_common(struct unwind_user_state *state,
WARN_ON_ONCE(1);
return -EINVAL;
}
- if (frame->ra.rule & UNWIND_USER_RULE_DEREF &&
+ if (frame->ra.rule & UNWIND_RULE_DEREF &&
get_user_word(&ra, ra, 0, state->ws))
return -EINVAL;
/* Get the Frame Pointer (FP) */
switch (frame->fp.rule) {
- case UNWIND_USER_RULE_RETAIN:
+ case UNWIND_RULE_RETAIN:
fp = state->fp;
break;
/*
- * UNWIND_USER_RULE_CFA_OFFSET is currently not used for FP
+ * UNWIND_RULE_CFA_OFFSET is currently not used for FP
* (e.g. SFrame cannot represent this rule).
*/
- case UNWIND_USER_RULE_CFA_OFFSET_DEREF:
+ case UNWIND_RULE_CFA_OFFSET_DEREF:
fp = cfa + frame->fp.offset;
break;
- case UNWIND_USER_RULE_REG_OFFSET:
- case UNWIND_USER_RULE_REG_OFFSET_DEREF:
+ case UNWIND_RULE_REG_OFFSET:
+ case UNWIND_RULE_REG_OFFSET_DEREF:
if (!state->topmost || unwind_user_get_reg(&fp, frame->fp.regnum))
return -EINVAL;
fp += frame->fp.offset;
@@ -123,7 +124,7 @@ static int unwind_user_next_common(struct unwind_user_state *state,
WARN_ON_ONCE(1);
return -EINVAL;
}
- if (frame->fp.rule & UNWIND_USER_RULE_DEREF &&
+ if (frame->fp.rule & UNWIND_RULE_DEREF &&
get_user_word(&fp, fp, 0, state->ws))
return -EINVAL;
@@ -139,13 +140,13 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
struct pt_regs *regs = task_pt_regs(current);
if (state->topmost && unwind_user_at_function_start(regs)) {
- const struct unwind_user_frame fp_entry_frame = {
+ const struct unwind_frame fp_entry_frame = {
ARCH_INIT_USER_FP_ENTRY_FRAME(state->ws)
};
return unwind_user_next_common(state, &fp_entry_frame);
}
- const struct unwind_user_frame fp_frame = {
+ const struct unwind_frame fp_frame = {
ARCH_INIT_USER_FP_FRAME(state->ws)
};
return unwind_user_next_common(state, &fp_frame);
@@ -153,10 +154,10 @@ static int unwind_user_next_fp(struct unwind_user_state *state)
static int unwind_user_next_sframe(struct unwind_user_state *state)
{
- struct unwind_user_frame frame;
+ struct unwind_frame frame;
/* sframe expects the frame to be local storage */
- if (sframe_find(state->ip, &frame))
+ if (sframe_find_user(state->ip, &frame))
return -ENOENT;
return unwind_user_next_common(state, &frame);
}
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v6 3/9] arm64: entry: add unwind info for call_on_irq_stack()
From: Dylan Hatch @ 2026-05-19 6:49 UTC (permalink / raw)
To: Roman Gushchin, Weinan Liu, Will Deacon, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Steven Rostedt, Catalin Marinas,
Jiri Kosina, Mark Rutland, Jens Remus
Cc: Dylan Hatch, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel, Randy Dunlap, Mostafa Saleh, Herbert Xu,
David S. Miller
In-Reply-To: <20260519064950.493949-1-dylanbhatch@google.com>
From: Weinan Liu <wnliu@google.com>
DWARF CFI (Call Frame Information) specifies how to recover the return
address and callee-saved registers at each PC in a given function.
Compilers are able to generate the CFI annotations when they compile
the code to assembly language. For handcrafted assembly, we need to
annotate them by hand.
Frame pointers alone are usually sufficient to recover stack frames
(without CFI), except at the exception boundary, where more information
is needed to determine if the LR is live.
Since an exception can be taken from call_on_irq_stack(), annotate it
with CFI. The actual entry assembly functions are left untouched, since
they are not expected to take exceptions themselves.
Signed-off-by: Weinan Liu <wnliu@google.com>
Suggested-by: Jens Remus <jremus@linux.ibm.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
---
arch/arm64/kernel/entry.S | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index e0db14e9c843..5f4172ba4274 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -30,6 +30,12 @@
#include <asm/asm-uaccess.h>
#include <asm/unistd.h>
+/*
+ * Do not generate .eh_frame. Only generate .debug_frame and optionally
+ * .sframe (via assembler option --gsframe[-N]).
+ */
+ .cfi_sections .debug_frame
+
.macro clear_gp_regs
.irp n,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29
mov x\n, xzr
@@ -870,6 +876,7 @@ NOKPROBE(ret_from_fork)
* Calls func(regs) using this CPU's irq stack and shadow irq stack.
*/
SYM_FUNC_START(call_on_irq_stack)
+ .cfi_startproc
save_and_disable_daif x9
#ifdef CONFIG_SHADOW_CALL_STACK
get_current_task x16
@@ -880,6 +887,9 @@ SYM_FUNC_START(call_on_irq_stack)
/* Create a frame record to save our LR and SP (implicit in FP) */
stp x29, x30, [sp, #-16]!
mov x29, sp
+ .cfi_def_cfa 29, 16
+ .cfi_offset 29, -16
+ .cfi_offset 30, -8
ldr_this_cpu x16, irq_stack_ptr, x17
@@ -895,9 +905,13 @@ SYM_FUNC_START(call_on_irq_stack)
*/
mov sp, x29
ldp x29, x30, [sp], #16
+ .cfi_restore 29
+ .cfi_restore 30
+ .cfi_def_cfa 31, 0
scs_load_current
restore_irq x9
ret
+ .cfi_endproc
SYM_FUNC_END(call_on_irq_stack)
NOKPROBE(call_on_irq_stack)
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* [PATCH v6 2/9] arm64, unwind: build kernel with sframe V3 info
From: Dylan Hatch @ 2026-05-19 6:49 UTC (permalink / raw)
To: Roman Gushchin, Weinan Liu, Will Deacon, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Steven Rostedt, Catalin Marinas,
Jiri Kosina, Mark Rutland, Jens Remus
Cc: Dylan Hatch, Prasanna Kumar T S M, Puranjay Mohan, Song Liu,
joe.lawrence, linux-toolchains, linux-kernel, live-patching,
linux-arm-kernel, Randy Dunlap, Mostafa Saleh, Herbert Xu,
David S. Miller
In-Reply-To: <20260519064950.493949-1-dylanbhatch@google.com>
Build with -Wa,--gsframe-3 flags to generate a .sframe section. This
will be used for in-kernel reliable stacktrace in cases where the frame
pointer alone is insufficient.
Currently, the sframe format only supports arm64, x86_64 and s390x
architectures.
Signed-off-by: Weinan Liu <wnliu@google.com>
Reviewed-by: Prasanna Kumar T S M <ptsm@linux.microsoft.com>
Reviewed-by: Jens Remus <jremus@linux.ibm.com>
Signed-off-by: Dylan Hatch <dylanbhatch@google.com>
---
MAINTAINERS | 2 +-
Makefile | 8 ++++++++
arch/Kconfig | 21 +++++++++++++++++++++
arch/arm64/Kconfig | 1 +
arch/arm64/include/asm/unwind_sframe.h | 8 ++++++++
arch/arm64/kernel/vdso/Makefile | 2 +-
include/asm-generic/sections.h | 4 ++++
include/asm-generic/vmlinux.lds.h | 15 +++++++++++++++
8 files changed, 59 insertions(+), 2 deletions(-)
create mode 100644 arch/arm64/include/asm/unwind_sframe.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 54613c683fdb..046d06dcdb86 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -27862,8 +27862,8 @@ STACK UNWINDING
M: Josh Poimboeuf <jpoimboe@kernel.org>
M: Steven Rostedt <rostedt@goodmis.org>
S: Maintained
+F: arch/*/include/asm/unwind_sframe.h
F: arch/*/include/asm/unwind_user.h
-F: arch/*/include/asm/unwind_user_sframe.h
F: include/asm-generic/unwind_user.h
F: include/linux/sframe.h
F: include/linux/unwind*.h
diff --git a/Makefile b/Makefile
index 9f88dcaae382..227fda16deb1 100644
--- a/Makefile
+++ b/Makefile
@@ -1147,6 +1147,14 @@ endif
# Ensure compilers do not transform certain loops into calls to wcslen()
KBUILD_CFLAGS += -fno-builtin-wcslen
+# build with sframe table
+ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
+CC_FLAGS_SFRAME := -Wa,--gsframe-3
+KBUILD_CFLAGS += $(CC_FLAGS_SFRAME)
+KBUILD_AFLAGS += $(CC_FLAGS_SFRAME)
+export CC_FLAGS_SFRAME
+endif
+
# change __FILE__ to the relative path to the source directory
ifdef building_out_of_srctree
KBUILD_CPPFLAGS += -fmacro-prefix-map=$(srcroot)/=
diff --git a/arch/Kconfig b/arch/Kconfig
index 6eeafd86347b..f931b5848593 100644
--- a/arch/Kconfig
+++ b/arch/Kconfig
@@ -520,6 +520,27 @@ config SFRAME_VALIDATION
If unsure, say N.
+config ARCH_SUPPORTS_UNWIND_KERNEL_SFRAME
+ bool
+ help
+ An architecture can select this if it enables the SFrame (Simple
+ Frame) unwinder for unwinding kernel stack traces. It uses an unwind
+ table that is directly generated by the toolchain based on DWARF CFI
+ information.
+
+config HAVE_UNWIND_KERNEL_SFRAME
+ bool "Sframe unwinder"
+ depends on AS_SFRAME3
+ depends on 64BIT
+ depends on ARCH_SUPPORTS_UNWIND_KERNEL_SFRAME
+ select UNWIND_SFRAME_LOOKUP
+ help
+ This option enables the SFrame (Simple Frame) unwinder for unwinding
+ kernel stack traces. It uses unwind an table that is directly
+ generated by the toolchain based on DWARF CFI information. In
+ practice, this can provide more reliable stacktrace results than
+ unwinding with frame pointers alone.
+
config HAVE_PERF_REGS
bool
help
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index fe60738e5943..c3ef478469e5 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -86,6 +86,7 @@ config ARM64
select ARCH_SUPPORTS_SCHED_SMT
select ARCH_SUPPORTS_SCHED_CLUSTER
select ARCH_SUPPORTS_SCHED_MC
+ select ARCH_SUPPORTS_UNWIND_KERNEL_SFRAME
select ARCH_WANT_BATCHED_UNMAP_TLB_FLUSH
select ARCH_WANT_COMPAT_IPC_PARSE_VERSION if COMPAT
select ARCH_WANT_DEFAULT_BPF_JIT
diff --git a/arch/arm64/include/asm/unwind_sframe.h b/arch/arm64/include/asm/unwind_sframe.h
new file mode 100644
index 000000000000..876412881196
--- /dev/null
+++ b/arch/arm64/include/asm/unwind_sframe.h
@@ -0,0 +1,8 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_ARM64_UNWIND_SFRAME_H
+#define _ASM_ARM64_UNWIND_SFRAME_H
+
+#define SFRAME_REG_SP 31
+#define SFRAME_REG_FP 29
+
+#endif /* _ASM_ARM64_UNWIND_SFRAME_H */
diff --git a/arch/arm64/kernel/vdso/Makefile b/arch/arm64/kernel/vdso/Makefile
index 7dec05dd33b7..c60ef921956f 100644
--- a/arch/arm64/kernel/vdso/Makefile
+++ b/arch/arm64/kernel/vdso/Makefile
@@ -38,7 +38,7 @@ ccflags-y += -DDISABLE_BRANCH_PROFILING -DBUILD_VDSO
CC_FLAGS_REMOVE_VDSO := $(CC_FLAGS_FTRACE) -Os $(CC_FLAGS_SCS) \
$(RANDSTRUCT_CFLAGS) $(KSTACK_ERASE_CFLAGS) \
$(GCC_PLUGINS_CFLAGS) \
- $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) \
+ $(CC_FLAGS_LTO) $(CC_FLAGS_CFI) $(CC_FLAGS_SFRAME) \
-Wmissing-prototypes -Wmissing-declarations
CC_FLAGS_ADD_VDSO := -O2 -mcmodel=tiny -fasynchronous-unwind-tables
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index 0755bc39b0d8..336d27011a58 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -31,6 +31,7 @@
* __irqentry_text_start, __irqentry_text_end
* __softirqentry_text_start, __softirqentry_text_end
* __start_opd, __end_opd
+ * __start_sframe, __end_sframe
*/
extern char _text[], _stext[], _etext[];
extern char _data[], _sdata[], _edata[];
@@ -53,6 +54,9 @@ extern char __ctors_start[], __ctors_end[];
/* Start and end of .opd section - used for function descriptors. */
extern char __start_opd[], __end_opd[];
+/* Start and end of .sframe section - used for stack unwinding. */
+extern char __start_sframe[], __end_sframe[];
+
/* Start and end of instrumentation protected text section */
extern char __noinstr_text_start[], __noinstr_text_end[];
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 60c8c22fd3e4..6aeed39097dd 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -491,6 +491,8 @@
*(.rodata1) \
} \
\
+ SFRAME \
+ \
/* PCI quirks */ \
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
BOUNDED_SECTION_PRE_LABEL(.pci_fixup_early, _pci_fixups_early, __start, __end) \
@@ -904,6 +906,19 @@
#define TRACEDATA
#endif
+#ifdef CONFIG_HAVE_UNWIND_KERNEL_SFRAME
+#define SFRAME \
+ /* sframe */ \
+ .sframe : AT(ADDR(.sframe) - LOAD_OFFSET) { \
+ __start_sframe = .; \
+ KEEP(*(.sframe)) \
+ KEEP(*(.init.sframe)) \
+ __end_sframe = .; \
+ }
+#else
+#define SFRAME
+#endif
+
#ifdef CONFIG_PRINTK_INDEX
#define PRINTK_INDEX \
.printk_index : AT(ADDR(.printk_index) - LOAD_OFFSET) { \
--
2.54.0.563.g4f69b47b94-goog
^ permalink raw reply related
* Arm32: correct string.h functions for "int" -> "unsigned char" conversion
From: Jan Beulich @ 2026-05-19 6:44 UTC (permalink / raw)
To: linux-arm-kernel@lists.infradead.org; +Cc: Russell King
While Arm64 does so uniformly, for Arm32 only strchr() currently handles
this properly. Add the necessary conversion also to strrchr(), memchr(),
and memset().
As to the placement in memset(): Putting the new insn at the beginning
of the function could perhaps be deemed more "obvious", but the code
reachable without ever making it to the "1" label only ever does byte
stores.
Signed-off-by: Jan Beulich <jbeulich@suse.com>
--- a/arch/arm/lib/memchr.S
+++ b/arch/arm/lib/memchr.S
@@ -12,6 +12,7 @@
.text
.align 5
ENTRY(memchr)
+ and r1, r1, #0xff
1: subs r2, r2, #1
bmi 2f
ldrb r3, [r0], #1
--- a/arch/arm/lib/memset.S
+++ b/arch/arm/lib/memset.S
@@ -24,7 +24,8 @@ UNWIND( .fnstart )
/*
* we know that the pointer in ip is aligned to a word boundary.
*/
-1: orr r1, r1, r1, lsl #8
+1: and r1, r1, #0xff
+ orr r1, r1, r1, lsl #8
orr r1, r1, r1, lsl #16
mov r3, r1
7: cmp r2, #16
--- a/arch/arm/lib/strrchr.S
+++ b/arch/arm/lib/strrchr.S
@@ -12,6 +12,7 @@
.text
.align 5
ENTRY(strrchr)
+ and r1, r1, #0xff
mov r3, #0
1: ldrb r2, [r0], #1
teq r2, r1
^ permalink raw reply
* Re: [PATCH 06/13] drm/meson: encoder_hdmi: Use bridge connector CEC notifier
From: Hans Verkuil @ 2026-05-19 6:38 UTC (permalink / raw)
To: Jonas Karlman, Neil Armstrong, Kevin Hilman, Heiko Stuebner,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jerome Brunet, Martin Blumenstingl
Cc: dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel,
linux-rockchip
In-Reply-To: <20260518194744.2483580-7-jonas@kwiboo.se>
On 18/05/2026 21:47, Jonas Karlman wrote:
> The dw-hdmi bridge detect() func now updates EDID and CEC phys addr for
> the connector and any registered generic CEC notifier.
>
> Replace the open-coded CEC notifier handling with use of the bridge CEC
> notifier op.
>
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> drivers/gpu/drm/meson/Kconfig | 1 +
> drivers/gpu/drm/meson/meson_encoder_hdmi.c | 85 +++++-----------------
> 2 files changed, 19 insertions(+), 67 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/Kconfig b/drivers/gpu/drm/meson/Kconfig
> index 417f79829cf8..0dc5ca21e4fc 100644
> --- a/drivers/gpu/drm/meson/Kconfig
> +++ b/drivers/gpu/drm/meson/Kconfig
> @@ -13,6 +13,7 @@ config DRM_MESON
> select REGMAP_MMIO
> select MESON_CANVAS
> select CEC_CORE if CEC_NOTIFIER
> + select DRM_DISPLAY_HDMI_CEC_NOTIFIER_HELPER if CEC_NOTIFIER
>
> config DRM_MESON_DW_HDMI
> tristate "HDMI Synopsys Controller support for Amlogic Meson Display"
> diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> index 1b9a1d9ed3d3..45104ef35344 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> @@ -16,8 +16,6 @@
> #include <linux/regulator/consumer.h>
> #include <linux/reset.h>
>
> -#include <media/cec-notifier.h>
> -
> #include <drm/drm_atomic_helper.h>
> #include <drm/drm_bridge.h>
> #include <drm/drm_bridge_connector.h>
> @@ -41,7 +39,6 @@ struct meson_encoder_hdmi {
> struct drm_connector *connector;
> struct meson_drm *priv;
> unsigned long output_bus_fmt;
> - struct cec_notifier *cec_notifier;
> };
>
> #define bridge_to_meson_encoder_hdmi(x) \
> @@ -57,14 +54,6 @@ static int meson_encoder_hdmi_attach(struct drm_bridge *bridge,
> &encoder_hdmi->bridge, flags);
> }
>
> -static void meson_encoder_hdmi_detach(struct drm_bridge *bridge)
> -{
> - struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
> -
> - cec_notifier_conn_unregister(encoder_hdmi->cec_notifier);
> - encoder_hdmi->cec_notifier = NULL;
> -}
> -
> static void meson_encoder_hdmi_set_vclk(struct meson_encoder_hdmi *encoder_hdmi,
> const struct drm_display_mode *mode)
> {
> @@ -321,27 +310,9 @@ static int meson_encoder_hdmi_atomic_check(struct drm_bridge *bridge,
> return 0;
> }
>
> -static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
> - struct drm_connector *connector,
> - enum drm_connector_status status)
> -{
> - struct meson_encoder_hdmi *encoder_hdmi = bridge_to_meson_encoder_hdmi(bridge);
> -
> - if (!encoder_hdmi->cec_notifier)
> - return;
> -
> - if (status == connector_status_connected)
> - cec_notifier_set_phys_addr(encoder_hdmi->cec_notifier,
> - connector->display_info.source_physical_address);
> - else
> - cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier);
> -}
> -
> static const struct drm_bridge_funcs meson_encoder_hdmi_bridge_funcs = {
> .attach = meson_encoder_hdmi_attach,
> - .detach = meson_encoder_hdmi_detach,
> .mode_valid = meson_encoder_hdmi_mode_valid,
> - .hpd_notify = meson_encoder_hdmi_hpd_notify,
> .atomic_enable = meson_encoder_hdmi_atomic_enable,
> .atomic_disable = meson_encoder_hdmi_atomic_disable,
> .atomic_get_input_bus_fmts = meson_encoder_hdmi_get_inp_bus_fmts,
> @@ -374,9 +345,9 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
>
> meson_encoder_hdmi->bridge.next_bridge = of_drm_find_and_get_bridge(remote);
> if (!meson_encoder_hdmi->bridge.next_bridge) {
> - ret = dev_err_probe(priv->dev, -EPROBE_DEFER,
> - "Failed to find HDMI transceiver bridge\n");
> - goto err_put_node;
> + of_node_put(remote);
> + return dev_err_probe(priv->dev, -EPROBE_DEFER,
> + "Failed to find HDMI transceiver bridge\n");
> }
>
> /* HDMI Encoder Bridge */
> @@ -384,6 +355,13 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
> meson_encoder_hdmi->bridge.type = DRM_MODE_CONNECTOR_HDMIA;
> meson_encoder_hdmi->bridge.interlace_allowed = true;
>
> + pdev = of_find_device_by_node(remote);
> + of_node_put(remote);
> + if (pdev) {
> + meson_encoder_hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER;
> + meson_encoder_hdmi->bridge.hdmi_cec_dev = &pdev->dev;
> + }
> +
> drm_bridge_add(&meson_encoder_hdmi->bridge);
>
> meson_encoder_hdmi->priv = priv;
> @@ -391,30 +369,24 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
> /* Encoder */
> ret = drm_simple_encoder_init(priv->drm, &meson_encoder_hdmi->encoder,
> DRM_MODE_ENCODER_TMDS);
> - if (ret) {
> - dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n");
> - goto err_put_node;
> - }
> + if (ret)
> + return dev_err_probe(priv->dev, ret, "Failed to init HDMI encoder\n");
>
> meson_encoder_hdmi->encoder.possible_crtcs = BIT(0);
>
> /* Attach HDMI Encoder Bridge to Encoder */
> ret = drm_bridge_attach(&meson_encoder_hdmi->encoder, &meson_encoder_hdmi->bridge, NULL,
> DRM_BRIDGE_ATTACH_NO_CONNECTOR);
> - if (ret) {
> - dev_err_probe(priv->dev, ret, "Failed to attach bridge\n");
> - goto err_put_node;
> - }
> + if (ret)
> + return dev_err_probe(priv->dev, ret, "Failed to attach bridge\n");
>
> /* Initialize & attach Bridge Connector */
> meson_encoder_hdmi->connector = drm_bridge_connector_init(priv->drm,
> &meson_encoder_hdmi->encoder);
> - if (IS_ERR(meson_encoder_hdmi->connector)) {
> - ret = dev_err_probe(priv->dev,
> - PTR_ERR(meson_encoder_hdmi->connector),
> - "Unable to create HDMI bridge connector\n");
> - goto err_put_node;
> - }
> + if (IS_ERR(meson_encoder_hdmi->connector))
> + return dev_err_probe(priv->dev,
> + PTR_ERR(meson_encoder_hdmi->connector),
> + "Unable to create HDMI bridge connector\n");
>
> /*
> * We should have now in place:
> @@ -437,32 +409,11 @@ int meson_encoder_hdmi_probe(struct meson_drm *priv)
> /* Handle this here until handled by drm_bridge_connector_init() */
> meson_encoder_hdmi->connector->ycbcr_420_allowed = true;
>
> - pdev = of_find_device_by_node(remote);
> - of_node_put(remote);
> - if (pdev) {
> - struct cec_connector_info conn_info;
> - struct cec_notifier *notifier;
> -
> - cec_fill_conn_info_from_drm(&conn_info, meson_encoder_hdmi->connector);
> -
> - notifier = cec_notifier_conn_register(&pdev->dev, NULL, &conn_info);
> - if (!notifier) {
> - put_device(&pdev->dev);
> - return -ENOMEM;
> - }
> -
> - meson_encoder_hdmi->cec_notifier = notifier;
> - }
> -
> priv->encoders[MESON_ENC_HDMI] = meson_encoder_hdmi;
>
> dev_dbg(priv->dev, "HDMI encoder initialized\n");
>
> return 0;
> -
> -err_put_node:
> - of_node_put(remote);
> - return ret;
> }
>
> void meson_encoder_hdmi_remove(struct meson_drm *priv)
^ permalink raw reply
* Re: [PATCH 05/13] drm/meson: encoder_hdmi: Use CEC phys addr from display_info
From: Hans Verkuil @ 2026-05-19 6:36 UTC (permalink / raw)
To: Jonas Karlman, Neil Armstrong, Kevin Hilman, Heiko Stuebner,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Jerome Brunet, Martin Blumenstingl
Cc: dri-devel, linux-amlogic, linux-arm-kernel, linux-kernel,
linux-rockchip
In-Reply-To: <20260518194744.2483580-6-jonas@kwiboo.se>
On 18/05/2026 21:47, Jonas Karlman wrote:
> The dw-hdmi bridge detect() func now updates EDID for the connector.
> Something that ensures that display_info.source_physical_address has an
> updated CEC phys addr when the hpd_notify() func is called.
>
> Change to use display_info source_physical_address directly instead of
> re-reading EDID to set the CEC phys addr at HPD interrupt.
>
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> drivers/gpu/drm/meson/meson_encoder_hdmi.c | 26 ++++------------------
> 1 file changed, 4 insertions(+), 22 deletions(-)
>
> diff --git a/drivers/gpu/drm/meson/meson_encoder_hdmi.c b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> index 55c0601df3c6..1b9a1d9ed3d3 100644
> --- a/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> +++ b/drivers/gpu/drm/meson/meson_encoder_hdmi.c
> @@ -330,28 +330,10 @@ static void meson_encoder_hdmi_hpd_notify(struct drm_bridge *bridge,
> if (!encoder_hdmi->cec_notifier)
> return;
>
> - if (status == connector_status_connected) {
> - const struct drm_edid *drm_edid;
> - const struct edid *edid;
> -
> - drm_edid = drm_bridge_edid_read(encoder_hdmi->bridge.next_bridge,
> - encoder_hdmi->connector);
> - if (!drm_edid)
> - return;
> -
> - /*
> - * FIXME: The CEC physical address should be set using
> - * cec_notifier_set_phys_addr(encoder_hdmi->cec_notifier,
> - * connector->display_info.source_physical_address) from a path
> - * that has read the EDID and called
> - * drm_edid_connector_update().
> - */
> - edid = drm_edid_raw(drm_edid);
> -
> - cec_notifier_set_phys_addr_from_edid(encoder_hdmi->cec_notifier, edid);
> -
> - drm_edid_free(drm_edid);
> - } else
> + if (status == connector_status_connected)
> + cec_notifier_set_phys_addr(encoder_hdmi->cec_notifier,
> + connector->display_info.source_physical_address);
> + else
> cec_notifier_phys_addr_invalidate(encoder_hdmi->cec_notifier);
> }
>
^ permalink raw reply
* Re: [PATCH v7 17/23] drm: bridge: dw_hdmi: Declare bridge CEC notifier support
From: Hans Verkuil @ 2026-05-19 6:35 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-18-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> EDID and CEC phys addr is now being updated in bridge detect() func,
> making it possible to have CEC notifier support using the bridge
> connector.
>
> Add the CEC notifier bridge op to instruct the bridge connector to make
> use of the generic CEC notifier helpers.
>
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: Only declare CEC notifier support when CEC device register succeeds
> v6: New patch
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 4 ++++
> 1 file changed, 4 insertions(+)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 0c4388e7aa5e..5dacb8a99715 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -3515,6 +3515,10 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
> pdevinfo.dma_mask = 0;
>
> hdmi->cec = platform_device_register_full(&pdevinfo);
> + if (!IS_ERR(hdmi->cec)) {
> + hdmi->bridge.ops |= DRM_BRIDGE_OP_HDMI_CEC_NOTIFIER;
> + hdmi->bridge.hdmi_cec_dev = hdmi->dev;
> + }
> }
>
> drm_bridge_add(&hdmi->bridge);
^ permalink raw reply
* Re: [PATCH v7 15/23] drm: bridge: dw_hdmi: Use generic CEC notifier helpers
From: Hans Verkuil @ 2026-05-19 6:32 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-16-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> The commit 8b1a8f8b2002 ("drm/display: add CEC helpers code") added
> generic CEC helpers to be used by HDMI drivers.
>
> Replace the open-coded CEC notifier handling with use of the generic CEC
> notifier helpers. Ensure DRM_DISPLAY_HDMI_CEC_NOTIFIER_HELPER is also
> selected when DRM_DW_HDMI_CEC is enabled so that the CEC helpers is
> available.
>
> The drmm release action for the generic CEC notifier should run just
> before dw_hdmi_connector_destroy(), closely matching the lifetime of
> the replaced CEC notifier and the connector.
>
> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: No change
> v6: Update commit message,
> Collect t-b tag
> v5: Collect r-b tag
> v4: New patch
> ---
> drivers/gpu/drm/bridge/synopsys/Kconfig | 1 +
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 26 +++++------------------
> 2 files changed, 6 insertions(+), 21 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/Kconfig b/drivers/gpu/drm/bridge/synopsys/Kconfig
> index a46df7583bcf..e6723af03b43 100644
> --- a/drivers/gpu/drm/bridge/synopsys/Kconfig
> +++ b/drivers/gpu/drm/bridge/synopsys/Kconfig
> @@ -49,6 +49,7 @@ config DRM_DW_HDMI_CEC
> depends on DRM_DW_HDMI
> select CEC_CORE
> select CEC_NOTIFIER
> + select DRM_DISPLAY_HDMI_CEC_NOTIFIER_HELPER
> help
> Support the CE interface which is part of the Synopsys
> Designware HDMI block.
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 0e84dff72470..37406555af7b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -23,12 +23,11 @@
> #include <linux/dma-mapping.h>
> #include <linux/spinlock.h>
>
> -#include <media/cec-notifier.h>
> -
> #include <linux/media-bus-format.h>
> #include <linux/videodev2.h>
>
> #include <drm/bridge/dw_hdmi.h>
> +#include <drm/display/drm_hdmi_cec_helper.h>
> #include <drm/display/drm_hdmi_helper.h>
> #include <drm/display/drm_scdc_helper.h>
> #include <drm/drm_atomic.h>
> @@ -183,8 +182,6 @@ struct dw_hdmi {
> void (*enable_audio)(struct dw_hdmi *hdmi);
> void (*disable_audio)(struct dw_hdmi *hdmi);
>
> - struct cec_notifier *cec_notifier;
> -
> hdmi_codec_plugged_cb plugged_cb;
> struct device *codec_dev;
> enum drm_connector_status last_connector_result;
> @@ -2453,7 +2450,7 @@ dw_hdmi_connector_status_update(struct dw_hdmi *hdmi,
>
> if (status == connector_status_disconnected) {
> drm_edid_connector_update(connector, NULL);
> - cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> + drm_connector_cec_phys_addr_invalidate(connector);
> return;
> }
>
> @@ -2462,8 +2459,7 @@ dw_hdmi_connector_status_update(struct dw_hdmi *hdmi,
> drm_edid_free(drm_edid);
>
> if (status == connector_status_connected)
> - cec_notifier_set_phys_addr(hdmi->cec_notifier,
> - connector->display_info.source_physical_address);
> + drm_connector_cec_phys_addr_set(connector);
> }
>
> static enum drm_connector_status
> @@ -2525,9 +2521,6 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector);
>
> - cec_notifier_conn_unregister(hdmi->cec_notifier);
> - hdmi->cec_notifier = NULL;
> -
> drm_connector_cleanup(connector);
> drm_bridge_put(&hdmi->bridge);
> }
> @@ -2550,8 +2543,6 @@ static const struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs =
> static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
> {
> struct drm_connector *connector = &hdmi->connector;
> - struct cec_connector_info conn_info;
> - struct cec_notifier *notifier;
> int ret;
>
> if (hdmi->version >= 0x200a)
> @@ -2587,15 +2578,8 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
>
> drm_connector_attach_encoder(connector, hdmi->bridge.encoder);
>
> - cec_fill_conn_info_from_drm(&conn_info, connector);
> -
> - notifier = cec_notifier_conn_register(hdmi->dev, NULL, &conn_info);
> - if (!notifier)
> - return -ENOMEM;
> -
> - hdmi->cec_notifier = notifier;
> -
> - return 0;
> + return drmm_connector_hdmi_cec_notifier_register(connector, NULL,
> + hdmi->dev);
> }
>
> /* -----------------------------------------------------------------------------
^ permalink raw reply
* Re: [PATCH v14 14/44] arm64: RMI: Basic infrastructure for creating a realm.
From: Aneesh Kumar K.V @ 2026-05-19 6:31 UTC (permalink / raw)
To: Steven Price, kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Emi Kisanuki,
Vishal Annapurve, WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <20260513131757.116630-15-steven.price@arm.com>
Steven Price <steven.price@arm.com> writes:
> @@ -1114,7 +1119,10 @@ void kvm_free_stage2_pgd(struct kvm_s2_mmu *mmu)
> write_unlock(&kvm->mmu_lock);
>
> if (pgt) {
> - kvm_stage2_destroy(pgt);
> + if (!kvm_is_realm(kvm))
> + kvm_stage2_destroy(pgt);
> + else
> + kvm_pgtable_stage2_destroy_pgd(pgt);
> kfree(pgt);
> }
> }
Maybe add a comment here explaining the difference.
We now have:
kvm_arch_destroy_vm()
-> kvm_uninit_stage2_mmu()
-> kvm_realm_uninit_stage2()
-> unmap_range(0, max_ipa) // for Realm VMs
-> kvm_free_stage2_pgd()
-> unmap and free PGD // for non-Realm VMs
-> kvm_destroy_realm() // for Realm VMs
-> kvm_free_stage2_pgd()
-> free PGD // for Realm VMs
I wonder whether this can be simplified using different functions names?
(can we call kvm_pgtable_stage2_destroy_pgd() from kvm_destroy_realm()? )
-aneesh
^ permalink raw reply
* Re: [PATCH v5 8/8] unwind: arm64: Use sframe to unwind interrupt frames
From: Dylan Hatch @ 2026-05-19 6:29 UTC (permalink / raw)
To: Mark Rutland
Cc: Roman Gushchin, Weinan Liu, Will Deacon, Josh Poimboeuf,
Indu Bhagat, Peter Zijlstra, Steven Rostedt, Catalin Marinas,
Jiri Kosina, Jens Remus, Prasanna Kumar T S M, Puranjay Mohan,
Song Liu, joe.lawrence, linux-toolchains, linux-kernel,
live-patching, linux-arm-kernel, Randy Dunlap
In-Reply-To: <afTYzAF_x41pyilu@J2N7QTR9R3>
Hi Mark,
I'm sending a v6 shortly that should address all/most of your
feedback, but I wanted to circle back on a question you had:
On Fri, May 1, 2026 at 9:46 AM Mark Rutland <mark.rutland@arm.com> wrote:
> > + /*
> > + * Consume RA and FP from the stack. The frame record puts FP at a lower
> > + * address than RA, so we always read FP first.
> > + */
> > + if (frame.fp.rule & UNWIND_RULE_DEREF &&
> > + !get_word(&state->common, &fp))
> > + return -EINVAL;
>
> Why is this get_word() rather than get_consume_word()?
I use get_word() here because get_consume_word(), in calling
unwind_consume_stack() under the hood, consumes the stack up to the
given address+size such that another unwind step cannot consume it
again. If the subsequent call to get_consume_word() fails, the stack
needs to be in a state such that we can fall back on a frame pointer
unwind. But if we were to use get_consume_word() here, the fallback
call to kunwind_next_frame_record() would not be able to consume the
FP from the stack because it would already have been consumed by the
failed call to unwind_next_frame_sframe().
By only calling get_consume_word() on the RA at the end, we defer
making any changes to the underlying unwind state stack until we are
sure the SFrame unwind step will succeed.
>
> > +
> > + if (frame.ra.rule & UNWIND_RULE_DEREF &&
> > + get_consume_word(&state->common, &ra))
> > + return -EINVAL;
> > +
> > + state->common.pc = ra;
> > + state->common.sp = cfa;
Please let me know if this reasoning seems sound.
Thanks,
Dylan
^ permalink raw reply
* Re: [PATCH v7 13/23] drm: bridge: dw_hdmi: Use dw_hdmi_connector_status_update()
From: Hans Verkuil @ 2026-05-19 6:29 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-14-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> Update connector EDID and CEC phys addr from detect and force funcs to
> ensure that userspace always have access to latest read EDID after a
> sink use a HPD low voltage pulse to indicate that EDID has changed.
>
> With EDID being updated in detect and force funcs, there should no
> longer be a need to re-read EDID in get_modes funcs, so drop it.
>
> This change make the dw-hdmi connector work more closely like the bridge
> connector does with a hdmi bridge.
>
> Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: No change
> v6: Pass struct dw_hdmi as a parameter,
> Collect t-b tag
> v5: No change
> v4: Move last_connector_result assign in force ops to this patch,
> Collect r-b tag
> v3: Reworked 'Update EDID during hotplug processing' patch
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 28 ++++++++++++-----------
> 1 file changed, 15 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index a056e147731b..a4ecf830103d 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2473,36 +2473,36 @@ dw_hdmi_connector_status_update(struct dw_hdmi *hdmi,
> {
> const struct drm_edid *drm_edid;
>
> + if (status == connector_status_disconnected) {
> + drm_edid_connector_update(connector, NULL);
> + cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> + return;
> + }
> +
> drm_edid = dw_hdmi_edid_read(hdmi, connector);
> drm_edid_connector_update(connector, drm_edid);
> drm_edid_free(drm_edid);
>
> - cec_notifier_set_phys_addr(hdmi->cec_notifier,
> - connector->display_info.source_physical_address);
> + if (status == connector_status_connected)
> + cec_notifier_set_phys_addr(hdmi->cec_notifier,
> + connector->display_info.source_physical_address);
> }
>
> static enum drm_connector_status
> dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
> {
> - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> - connector);
> + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector);
> enum drm_connector_status status;
>
> status = dw_hdmi_detect(hdmi);
>
> - if (status == connector_status_disconnected)
> - cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> + dw_hdmi_connector_status_update(hdmi, connector, status);
>
> return status;
> }
>
> static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
> {
> - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> - connector);
> -
> - dw_hdmi_connector_status_update(hdmi, connector, connector->status);
> -
> return drm_edid_connector_add_modes(connector);
> }
>
> @@ -2532,13 +2532,15 @@ static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
>
> static void dw_hdmi_connector_force(struct drm_connector *connector)
> {
> - struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> - connector);
> + struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector);
>
> mutex_lock(&hdmi->mutex);
> hdmi->force = connector->force;
> + hdmi->last_connector_result = connector->status;
> dw_hdmi_update_phy_mask(hdmi);
> mutex_unlock(&hdmi->mutex);
> +
> + dw_hdmi_connector_status_update(hdmi, connector, connector->status);
> }
>
> static void dw_hdmi_connector_destroy(struct drm_connector *connector)
^ permalink raw reply
* Re: [PATCH v7 11/23] drm: bridge: dw_hdmi: Remove cec_notifier_mutex
From: Hans Verkuil @ 2026-05-19 6:28 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-12-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> With CEC phys addr invalidation moved away from the irq handler there is
> no longer a need for cec_notifier_mutex, remove it.
>
> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Nice, I wondered why that mutex was there at all.
Regards,
Hans
> ---
> v7: No change
> v6: Collect t-b tag
> v5: No change, cec_notifier_conn_unregister() call moved
> v4: No change
> v3: No change
> v2: Collect r-b tag
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 11 +----------
> 1 file changed, 1 insertion(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index aae1b890167b..0dd4c823c60a 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -189,7 +189,6 @@ struct dw_hdmi {
> void (*enable_audio)(struct dw_hdmi *hdmi);
> void (*disable_audio)(struct dw_hdmi *hdmi);
>
> - struct mutex cec_notifier_mutex;
> struct cec_notifier *cec_notifier;
>
> hdmi_codec_plugged_cb plugged_cb;
> @@ -2476,11 +2475,8 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
>
> status = dw_hdmi_detect(hdmi);
>
> - if (status == connector_status_disconnected) {
> - mutex_lock(&hdmi->cec_notifier_mutex);
> + if (status == connector_status_disconnected)
> cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> - mutex_unlock(&hdmi->cec_notifier_mutex);
> - }
>
> return status;
> }
> @@ -2542,10 +2538,8 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector);
>
> - mutex_lock(&hdmi->cec_notifier_mutex);
> cec_notifier_conn_unregister(hdmi->cec_notifier);
> hdmi->cec_notifier = NULL;
> - mutex_unlock(&hdmi->cec_notifier_mutex);
>
> drm_connector_cleanup(connector);
> drm_bridge_put(&hdmi->bridge);
> @@ -2612,9 +2606,7 @@ static int dw_hdmi_connector_create(struct dw_hdmi *hdmi)
> if (!notifier)
> return -ENOMEM;
>
> - mutex_lock(&hdmi->cec_notifier_mutex);
> hdmi->cec_notifier = notifier;
> - mutex_unlock(&hdmi->cec_notifier_mutex);
>
> return 0;
> }
> @@ -3323,7 +3315,6 @@ struct dw_hdmi *dw_hdmi_probe(struct platform_device *pdev,
>
> mutex_init(&hdmi->mutex);
> mutex_init(&hdmi->audio_mutex);
> - mutex_init(&hdmi->cec_notifier_mutex);
> spin_lock_init(&hdmi->audio_lock);
>
> ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
^ permalink raw reply
* Re: [PATCH v7 12/23] drm: bridge: dw_hdmi: Extract dw_hdmi_connector_status_update()
From: Hans Verkuil @ 2026-05-19 6:26 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-13-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> Move connector EDID update and CEC phys addr handling to a helper
> function as a preparation before moving EDID refresh from get_modes
> funcs to detect/force funcs.
>
> Reviewed-by: Nicolas Frattaroli <nicolas.frattaroli@collabora.com>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: No change
> v6: Pass struct dw_hdmi as a parameter, to allow calls from bridge funcs,
> Collect t-b tag
> v5: No change
> v4: Collect r-b tag
> v3: New patch
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 27 ++++++++++++++---------
> 1 file changed, 17 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 0dd4c823c60a..a056e147731b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2466,6 +2466,21 @@ static const struct drm_edid *dw_hdmi_edid_read(struct dw_hdmi *hdmi,
> * DRM Connector Operations
> */
>
> +static void
> +dw_hdmi_connector_status_update(struct dw_hdmi *hdmi,
> + struct drm_connector *connector,
> + enum drm_connector_status status)
> +{
> + const struct drm_edid *drm_edid;
> +
> + drm_edid = dw_hdmi_edid_read(hdmi, connector);
> + drm_edid_connector_update(connector, drm_edid);
> + drm_edid_free(drm_edid);
> +
> + cec_notifier_set_phys_addr(hdmi->cec_notifier,
> + connector->display_info.source_physical_address);
> +}
> +
> static enum drm_connector_status
> dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
> {
> @@ -2485,18 +2500,10 @@ static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> connector);
> - const struct drm_edid *drm_edid;
> - int ret;
>
> - drm_edid = dw_hdmi_edid_read(hdmi, connector);
> + dw_hdmi_connector_status_update(hdmi, connector, connector->status);
>
> - drm_edid_connector_update(connector, drm_edid);
> - cec_notifier_set_phys_addr(hdmi->cec_notifier,
> - connector->display_info.source_physical_address);
> - ret = drm_edid_connector_add_modes(connector);
> - drm_edid_free(drm_edid);
> -
> - return ret;
> + return drm_edid_connector_add_modes(connector);
> }
>
> static int dw_hdmi_connector_atomic_check(struct drm_connector *connector,
^ permalink raw reply
* Re: [PATCH v7 10/23] drm: bridge: dw_hdmi: Invalidate CEC phys addr from connector detect
From: Hans Verkuil @ 2026-05-19 6:25 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-11-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> Wait until the connector detect ops is called to invalidate CEC phys
> addr instead of doing it directly from the irq handler.
>
> The CEC notifier is only registered for the dw-hdmi connector so this
> has no impact when the bridge connector is used.
>
> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: Update commit message
> v6: Collect t-b tag
> v5: No change
> v4: No change
> v3: No change
> v2: Collect r-b tag
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 18 +++++++++++-------
> 1 file changed, 11 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index 5fd26ff8f55b..aae1b890167b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2472,7 +2472,17 @@ dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
> connector);
> - return dw_hdmi_detect(hdmi);
> + enum drm_connector_status status;
> +
> + status = dw_hdmi_detect(hdmi);
> +
> + if (status == connector_status_disconnected) {
> + mutex_lock(&hdmi->cec_notifier_mutex);
> + cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> + mutex_unlock(&hdmi->cec_notifier_mutex);
> + }
> +
> + return status;
> }
>
> static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
> @@ -3106,12 +3116,6 @@ static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
> phy_stat & HDMI_PHY_HPD,
> phy_stat & HDMI_PHY_RX_SENSE);
>
> - if ((phy_stat & (HDMI_PHY_RX_SENSE | HDMI_PHY_HPD)) == 0) {
> - mutex_lock(&hdmi->cec_notifier_mutex);
> - cec_notifier_phys_addr_invalidate(hdmi->cec_notifier);
> - mutex_unlock(&hdmi->cec_notifier_mutex);
> - }
> -
> if ((intr_stat & HDMI_IH_PHY_STAT0_HPD) &&
> (phy_stat & HDMI_PHY_HPD))
> status = connector_status_connected;
^ permalink raw reply
* Re: [PATCH v7 09/23] drm: bridge: dw_hdmi: Unregister CEC notifier during connector cleanup
From: Hans Verkuil @ 2026-05-19 6:22 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-10-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> The CEC notifier is being unregistered when the bridge detach,
> something that happens earlier than normal connector cleanup.
>
> Change to unregister the CEC notifier at connector cleanup, in the
> connector .destroy() func, to align the lifetime of the connector and
> the CEC notifier and closer match a drmres handled generic CEC notifier.
>
> Tested-by: Diederik de Haas <diederik@cknow-tech.com> # Rock64, RockPro64, Quartz64-B
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: No change
> v6: Collect t-b tag
> v5: New patch
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 16 +++++-----------
> 1 file changed, 5 insertions(+), 11 deletions(-)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> index cbbd15578042..5fd26ff8f55b 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
> @@ -2532,6 +2532,11 @@ static void dw_hdmi_connector_destroy(struct drm_connector *connector)
> {
> struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi, connector);
>
> + mutex_lock(&hdmi->cec_notifier_mutex);
> + cec_notifier_conn_unregister(hdmi->cec_notifier);
> + hdmi->cec_notifier = NULL;
> + mutex_unlock(&hdmi->cec_notifier_mutex);
> +
> drm_connector_cleanup(connector);
> drm_bridge_put(&hdmi->bridge);
> }
> @@ -2909,16 +2914,6 @@ static int dw_hdmi_bridge_attach(struct drm_bridge *bridge,
> return dw_hdmi_connector_create(hdmi);
> }
>
> -static void dw_hdmi_bridge_detach(struct drm_bridge *bridge)
> -{
> - struct dw_hdmi *hdmi = bridge->driver_private;
> -
> - mutex_lock(&hdmi->cec_notifier_mutex);
> - cec_notifier_conn_unregister(hdmi->cec_notifier);
> - hdmi->cec_notifier = NULL;
> - mutex_unlock(&hdmi->cec_notifier_mutex);
> -}
> -
> static enum drm_mode_status
> dw_hdmi_bridge_mode_valid(struct drm_bridge *bridge,
> const struct drm_display_info *info,
> @@ -2996,7 +2991,6 @@ static const struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
> .atomic_destroy_state = drm_atomic_helper_bridge_destroy_state,
> .atomic_reset = drm_atomic_helper_bridge_reset,
> .attach = dw_hdmi_bridge_attach,
> - .detach = dw_hdmi_bridge_detach,
> .atomic_check = dw_hdmi_bridge_atomic_check,
> .atomic_get_output_bus_fmts = dw_hdmi_bridge_atomic_get_output_bus_fmts,
> .atomic_get_input_bus_fmts = dw_hdmi_bridge_atomic_get_input_bus_fmts,
^ permalink raw reply
* Re: [PATCH v7 03/23] drm: bridge: dw_hdmi: Free IRQ before CEC adapter is unregistered
From: Hans Verkuil @ 2026-05-19 6:21 UTC (permalink / raw)
To: Jonas Karlman, Andrzej Hajda, Neil Armstrong, Robert Foss,
Heiko Stuebner, Laurent Pinchart, Jernej Skrabec, Luca Ceresoli,
Maarten Lankhorst, Maxime Ripard, Thomas Zimmermann, David Airlie,
Simona Vetter, Russell King, Hans Verkuil, Archit Taneja
Cc: Liu Ying, Sandy Huang, Andy Yan, Chen-Yu Tsai, Christian Hewitt,
Diederik de Haas, Nicolas Frattaroli, Dmitry Baryshkov, dri-devel,
linux-arm-kernel, linux-rockchip, linux-amlogic, linux-sunxi, imx,
linux-kernel
In-Reply-To: <20260518180206.2480119-4-jonas@kwiboo.se>
On 18/05/2026 20:01, Jonas Karlman wrote:
> The interrupt allocated with devm_request_threaded_irq() can be
> use-after-free when the devres release action try to free_irq().
>
> KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq during unbind:
>
> Call trace:
> [...]
> dw_hdmi_cec_hardirq+0x4cc/0x560
> free_irq+0x48c/0x7e4
> devm_irq_release+0x54/0x90
> dr_node_release+0x38/0x5c
> release_nodes+0xac/0x130
> devres_release_all+0xf4/0x1b0
> device_unbind_cleanup+0x28/0x1f8
> device_release_driver_internal+0x358/0x470
> device_release_driver+0x18/0x24
> bus_remove_device+0x33c/0x4f0
> device_del+0x2d8/0x790
> platform_device_del+0x34/0x1e0
> platform_device_unregister+0x14/0x3c
> dw_hdmi_remove+0x74/0x180
> [...]
>
> Freed by:
> [...]
> kfree+0x1dc/0x5dc
> cec_delete_adapter+0xd4/0x118
> cec_devnode_release+0xa4/0xe0
> device_release+0xa0/0x200
> kobject_put+0x14c/0x26c
> put_device+0x14/0x30
> cec_unregister_adapter+0x20c/0x280
> dw_hdmi_cec_remove+0x8c/0xd0
> [...]
>
> Explicitly devm_free_irq() before the CEC adapter is unregistered to
> fix this possible use-after-free issue.
>
> Fixes: a616e63c56ef ("drm/bridge: dw-hdmi: add cec driver")
> Signed-off-by: Jonas Karlman <jonas@kwiboo.se>
Acked-by: Hans Verkuil <hverkuil+cisco@kernel.org>
Regards,
Hans
> ---
> v7: New patch
>
> KASAN report a slab-use-after-free in dw_hdmi_cec_hardirq when,
> echo fe0a0000.hdmi > /sys/bus/platform/drivers/dwhdmi-rockchip/unbind
> on a Rockchip RK3566 device prior to this fix.
> ---
> drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> index 9549dabde941..67a2a242d3ca 100644
> --- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> +++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi-cec.c
> @@ -309,6 +309,7 @@ static void dw_hdmi_cec_remove(struct platform_device *pdev)
> struct dw_hdmi_cec *cec = platform_get_drvdata(pdev);
>
> cec_notifier_cec_adap_unregister(cec->notify, cec->adap);
> + devm_free_irq(&pdev->dev, cec->irq, cec->adap);
> cec_unregister_adapter(cec->adap);
> }
>
^ permalink raw reply
* Re: [PATCH v2 2/5] arm64/mm: drop vmemmap_pmd helpers and use generic code
From: Muchun Song @ 2026-05-19 6:15 UTC (permalink / raw)
To: Will Deacon
Cc: Muchun Song, Catalin Marinas, linux-mm, akpm, Ryan Roberts,
David Hildenbrand, Kevin Brodsky, Dev Jain, Lorenzo Stoakes,
Anshuman Khandual, Yang Shi, Chaitanya S Prakash,
linux-arm-kernel, linux-kernel
In-Reply-To: <agsHINLR-D-tRiGd@willie-the-truck>
> On May 18, 2026, at 20:33, Will Deacon <will@kernel.org> wrote:
>
> On Sat, Apr 04, 2026 at 08:20:55PM +0800, Muchun Song wrote:
>> The generic implementations now suffice; remove the arm64 copies.
>>
>> Signed-off-by: Muchun Song <songmuchun@bytedance.com>
>> ---
>> arch/arm64/mm/mmu.c | 14 --------------
>> 1 file changed, 14 deletions(-)
>>
>> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
>> index ec1c6971a561..b87053452641 100644
>> --- a/arch/arm64/mm/mmu.c
>> +++ b/arch/arm64/mm/mmu.c
>> @@ -1745,20 +1745,6 @@ static void free_empty_tables(unsigned long addr, unsigned long end,
>> }
>> #endif
>>
>> -void __meminit vmemmap_set_pmd(pmd_t *pmdp, void *p, int node,
>> - unsigned long addr, unsigned long next)
>> -{
>> - pmd_set_huge(pmdp, __pa(p), __pgprot(PROT_SECT_NORMAL));
>> -}
>> -
>> -int __meminit vmemmap_check_pmd(pmd_t *pmdp, int node,
>> - unsigned long addr, unsigned long next)
>> -{
>> - vmemmap_verify((pte_t *)pmdp, node, addr, next);
>> -
>> - return pmd_sect(READ_ONCE(*pmdp));
>> -}
>
> I think this is fine:
>
> Acked-by: Will Deacon <will@kernel.org>
Thanks.
>
> but note that, since c25c4aa3f79a ("arm64: mm: Add PTE_DIRTY back to
> PAGE_KERNEL* to fix kexec/hibernation"), I think that using PAGE_KERNEL
> (like the generic code does in the first patch of this series) means
> that this change isn't a no-op -- it means that the huge entries will
> now be marked as dirty. That's possibly a bug fix (?)
I think you are right. We should mark kernel mapping as dirty.
Thanks,
Muchun
>
> Will
^ permalink raw reply
* [PATCH] ACPI: Use LIST_HEAD() to initialize on stack list head
From: Jisheng Zhang @ 2026-05-19 5:54 UTC (permalink / raw)
To: Rafael J . Wysocki, Len Brown, Lorenzo Pieralisi, Hanjun Guo,
Sudeep Holla, Catalin Marinas, Will Deacon
Cc: linux-acpi, linux-kernel, linux-arm-kernel
Use LIST_HEAD to initialize on stack list head. No intentional
functional impact.
Change generated with below coccinelle script:
@@
identifier name;
@@
- struct list_head name;
+ LIST_HEAD(name);
... when != name
- INIT_LIST_HEAD(&name);
Signed-off-by: Jisheng Zhang <jszhang@kernel.org>
---
drivers/acpi/acpi_apd.c | 3 +--
drivers/acpi/arm64/amba.c | 3 +--
drivers/acpi/resource.c | 3 +--
drivers/acpi/scan.c | 3 +--
drivers/acpi/x86/lpss.c | 3 +--
5 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
index bed0791c17fc..fa28acc541fe 100644
--- a/drivers/acpi/acpi_apd.c
+++ b/drivers/acpi/acpi_apd.c
@@ -68,14 +68,13 @@ static int fch_misc_setup(struct apd_private_data *pdata)
struct platform_device *clkdev;
struct fch_clk_data *clk_data;
struct resource_entry *rentry;
- struct list_head resource_list;
+ LIST_HEAD(resource_list);
int ret;
clk_data = devm_kzalloc(&adev->dev, sizeof(*clk_data), GFP_KERNEL);
if (!clk_data)
return -ENOMEM;
- INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_memory_resources(adev, &resource_list);
if (ret < 0)
return -ENOENT;
diff --git a/drivers/acpi/arm64/amba.c b/drivers/acpi/arm64/amba.c
index 1350083bce5f..ec342404306b 100644
--- a/drivers/acpi/arm64/amba.c
+++ b/drivers/acpi/arm64/amba.c
@@ -39,7 +39,7 @@ static int amba_handler_attach(struct acpi_device *adev,
struct acpi_device *parent = acpi_dev_parent(adev);
struct amba_device *dev;
struct resource_entry *rentry;
- struct list_head resource_list;
+ LIST_HEAD(resource_list);
bool address_found = false;
int irq_no = 0;
int ret;
@@ -55,7 +55,6 @@ static int amba_handler_attach(struct acpi_device *adev,
return -ENOMEM;
}
- INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (ret < 0)
goto err_free;
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index bc8050d8a6f5..ff78311c136b 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -1118,11 +1118,10 @@ EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
static int acpi_dev_consumes_res(struct acpi_device *adev, struct resource *res)
{
- struct list_head resource_list;
+ LIST_HEAD(resource_list);
struct resource_entry *rentry;
int ret, found = 0;
- INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (ret < 0)
return 0;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 530547cda8b2..bd599d0a9348 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1738,7 +1738,7 @@ static bool acpi_is_indirect_io_slave(struct acpi_device *device)
static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
{
- struct list_head resource_list;
+ LIST_HEAD(resource_list);
bool is_serial_bus_slave = false;
static const struct acpi_device_id ignore_serial_bus_ids[] = {
/*
@@ -1792,7 +1792,6 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
if (!acpi_match_device_ids(device, ignore_serial_bus_ids))
return false;
- INIT_LIST_HEAD(&resource_list);
acpi_dev_get_resources(device, &resource_list,
acpi_check_serial_bus_slave,
&is_serial_bus_slave);
diff --git a/drivers/acpi/x86/lpss.c b/drivers/acpi/x86/lpss.c
index 0171eef00484..d33dc34a2894 100644
--- a/drivers/acpi/x86/lpss.c
+++ b/drivers/acpi/x86/lpss.c
@@ -615,7 +615,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
const struct lpss_device_desc *dev_desc;
struct lpss_private_data *pdata;
struct resource_entry *rentry;
- struct list_head resource_list;
+ LIST_HEAD(resource_list);
struct platform_device *pdev;
int ret;
@@ -627,7 +627,6 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
if (!pdata)
return -ENOMEM;
- INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_memory_resources(adev, &resource_list);
if (ret < 0)
goto err_out;
--
2.53.0
^ permalink raw reply related
* [PATCH next] firmware: imx: fix use after free in init_device_context()
From: Dan Carpenter @ 2026-05-19 6:13 UTC (permalink / raw)
To: Pankaj Gupta
Cc: Frank Li, Sascha Hauer, Pengutronix Kernel Team, Fabio Estevam,
Frieder Schrempf, imx, linux-arm-kernel, linux-kernel,
kernel-janitors
Add a missing return statement on the error path. Otherwise we have a
use after free when it dereferences "dev_ctx" on the next line.
Fixes: 63536a73a3bb ("firmware: drivers: imx: adds miscdev")
Signed-off-by: Dan Carpenter <error27@gmail.com>
---
This was in the original fix but I guess there was a merge problem.
https://lore.kernel.org/all/20260514090457.2186933-1-pankaj.gupta@nxp.com/
drivers/firmware/imx/se_ctrl.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/firmware/imx/se_ctrl.c b/drivers/firmware/imx/se_ctrl.c
index 9327d47e4312..010af8221dfe 100644
--- a/drivers/firmware/imx/se_ctrl.c
+++ b/drivers/firmware/imx/se_ctrl.c
@@ -486,6 +486,7 @@ static int init_device_context(struct se_if_priv *priv, int ch_id,
kfree(dev_ctx->devname);
kfree(dev_ctx);
*new_dev_ctx = NULL;
+ return ret;
}
list_add_tail(&dev_ctx->link, &priv->dev_ctx_list);
--
2.53.0
^ permalink raw reply related
* RE: [PATCH V14 02/12] PCI: host-generic: Add common helpers for parsing Root Port properties
From: Sherry Sun (OSS) @ 2026-05-19 6:07 UTC (permalink / raw)
To: mani@kernel.org
Cc: Bjorn Helgaas, robh@kernel.org, krzk+dt@kernel.org,
conor+dt@kernel.org, Frank Li, s.hauer@pengutronix.de,
kernel@pengutronix.de, festevam@gmail.com, lpieralisi@kernel.org,
kwilczynski@kernel.org, bhelgaas@google.com, Hongxing Zhu,
l.stach@pengutronix.de, imx@lists.linux.dev,
linux-pci@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
In-Reply-To: <xyued2adtz2fs47nnl537aef7rsjuhswivcaieh6lxhlxpohkr@gpxmdcpczik7>
> Subject: Re: [PATCH V14 02/12] PCI: host-generic: Add common helpers for
> parsing Root Port properties
>
> On Mon, May 18, 2026 at 08:42:38AM +0000, Sherry Sun wrote:
> > > Subject: Re: [PATCH V14 02/12] PCI: host-generic: Add common helpers
> > > for parsing Root Port properties
> > >
> > > On Wed, Apr 22, 2026 at 05:35:39PM +0800, Sherry Sun wrote:
> > > > Introduce generic helper functions to parse Root Port device tree
> > > > nodes and extract common properties like reset GPIOs. This allows
> > > > multiple PCI host controller drivers to share the same parsing logic.
> > > >
> > > > Define struct pci_host_port to hold common Root Port properties
> > > > (currently only list of PERST# GPIO descriptors) and add
> > > > pci_host_common_parse_ports() to parse Root Port nodes from device
> > > tree.
> > > >
> > > > Also add the 'ports' list to struct pci_host_bridge for better
> > > > maintain parsed Root Port information.
> > > > ...
> > >
> > > > +static int pci_host_common_parse_port(struct device *dev,
> > > > + struct pci_host_bridge *bridge,
> > > > + struct device_node *node) {
> > > > + struct pci_host_port *port;
> > > > + int ret;
> > > > +
> > > > + port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> > > > + if (!port)
> > > > + return -ENOMEM;
> > > > +
> > > > + INIT_LIST_HEAD(&port->perst);
> > > > +
> > > > + ret = pci_host_common_parse_perst(dev, port, node);
> > > > + if (ret)
> > > > + return ret;
> > > > +
> > > > + /*
> > > > + * 1. PERST# found in RP or its child nodes - list is not empty, continue
> > > > + * 2. PERST# not found in RP/children, but found in RC node -
> > > > +return -
> > > ENODEV
> > > > + * to fallback legacy binding
> > > > + * 3. PERST# not found anywhere - list is empty, continue
> > > > +(optional
> > > PERST#)
> > > > + */
> > > > + if (list_empty(&port->perst)) {
> > > > + if (of_property_present(dev->of_node, "reset-gpios") ||
> > > > + of_property_present(dev->of_node, "reset-gpio"))
> > > > + return -ENODEV;
> > >
> > > This doesn't seem right to me. The parser of per-Root Port
> > > properties should not be responsible for deciding whether legacy
> > > methods are valid, i.e., whether a property is in the Root Complex
> > > node. I think it's up to the caller to decide whether it needs to look
> elsewhere.
> > >
> > > I don't think this even needs to return a "success/failure" value
> > > because there may be more properties in the future, and not all will
> > > be required. This function can't tell which properties a specific
> > > driver requires and which are optional.
> > >
> > > The caller can check whether we found what it needs and fall back to
> > > a legacy method as needed.
> >
> > Hi Bjorn,
> > The code here was suggested by Mani,
> https://lore.ke/
> rnel.org%2Fall%2Flnzprzrdwra7pn7d6m3sbj5pvjy64blwpjl6i3lmlnfbyho63b%4
> 0czpyhpgz5vum%2F&data=05%7C02%7Csherry.sun%40nxp.com%7C4fe904a4
> 5dd242113c0008deb56ad494%7C686ea1d3bc2b4c6fa92cd99c5c301635%7C0
> %7C0%7C639147667610810003%7CUnknown%7CTWFpbGZsb3d8eyJFbXB0e
> U1hcGkiOnRydWUsIlYiOiIwLjAuMDAwMCIsIlAiOiJXaW4zMiIsIkFOIjoiTWFpbCI
> sIldUIjoyfQ%3D%3D%7C0%7C%7C%7C&sdata=jo875iGio19v5xllCJ%2Fxa3xQO
> BRUXA6PLk1llD8%2FP70%3D&reserved=0.
> > I think your suggestion here is reasonable, the per-Root Port parser
> > shouldn't check the RC-level binding. That's a policy decision that belongs to
> the caller.
> >
> > Hi Mani, if you also agree, I'll rework this so that:
> > 1. pci_host_common_parse_port() only parses properties from the Root
> Port
> > (and its children) without checking the RC node.
> > 2. The function won't return failure for "property not found" - it will only
> return
> > errors for real failures (e.g., -ENOMEM, GPIO acquisition errors).
> > 3. The legacy fallback logic will be moved to the caller, which can inspect the
> > parsed result and decide whether to fall back to the legacy binding.
> >
>
> Fine with me. The reason for suggesting fallback within this API itself was to
> avoid duplicating the fallback code as it will be mostly generic. But I do agree
> with Bjorn on the fact that individual host controller drivers might have
> optional properties in the RC node and we can't incorporate all of them here.
>
> But no need to rework this series as it got applied for v7.2. You can send
> rework patches on top of this series.
>
Ok, will do, thanks!
Best Regards
Sherry
^ permalink raw reply
* Re: [PATCH v14 10/44] arm64: RMI: Add support for SRO
From: Aneesh Kumar K.V @ 2026-05-19 6:02 UTC (permalink / raw)
To: Steven Price, kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Emi Kisanuki,
Vishal Annapurve, WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <20260513131757.116630-11-steven.price@arm.com>
Steven Price <steven.price@arm.com> writes:
> +static unsigned long donate_req_to_size(unsigned long donatereq)
> +{
> + unsigned long unit_size = RMI_DONATE_SIZE(donatereq);
> +
> + switch (unit_size) {
> + case 0:
> + return PAGE_SIZE;
> + case 1:
> + return PMD_SIZE;
> + case 2:
> + return PUD_SIZE;
> + case 3:
> + return P4D_SIZE;
> + }
> + unreachable();
> +}
>
> +
> +static void rmi_smccc_invoke(struct arm_smccc_1_2_regs *regs_in,
> + struct arm_smccc_1_2_regs *regs_out)
> +{
> + struct arm_smccc_1_2_regs regs = *regs_in;
> + unsigned long status;
> +
> + do {
> + arm_smccc_1_2_invoke(®s, regs_out);
> + status = RMI_RETURN_STATUS(regs_out->a0);
> + } while (status == RMI_BUSY || status == RMI_BLOCKED);
> +}
> +
> +int free_delegated_page(phys_addr_t phys)
> +{
> + if (WARN_ON(rmi_undelegate_page(phys))) {
> + /* Undelegate failed: leak the page */
> + return -EBUSY;
> + }
> +
> + free_page((unsigned long)phys_to_virt(phys));
> +
> + return 0;
> +}
> +
> +static int rmi_sro_ensure_capacity(struct rmi_sro_state *sro,
> + unsigned long count)
> +{
> + if (WARN_ON_ONCE(sro->addr_count > RMI_MAX_ADDR_LIST))
> + return -EOVERFLOW;
> +
> + if (count > RMI_MAX_ADDR_LIST - sro->addr_count)
> + return -ENOSPC;
> +
> + return 0;
> +}
> +
> +static int rmi_sro_donate_contig(struct rmi_sro_state *sro,
> + unsigned long sro_handle,
> + unsigned long donatereq,
> + struct arm_smccc_1_2_regs *out_regs,
> + gfp_t gfp)
> +{
> + unsigned long unit_size = RMI_DONATE_SIZE(donatereq);
> + unsigned long unit_size_bytes = donate_req_to_size(donatereq);
> + unsigned long count = RMI_DONATE_COUNT(donatereq);
> + unsigned long state = RMI_DONATE_STATE(donatereq);
> + unsigned long size = unit_size_bytes * count;
> + unsigned long addr_range;
>
Looking at above and the related code, I am wondering whether we should
use u64 instead of unsigned long for everything that the specification
defines as 64-bit.
-aneesh
^ permalink raw reply
* Re: [PATCH net-next v2 2/2] net: ti: icssg: Add HSR and LRE PA statistics
From: Luka Gejak @ 2026-05-19 5:55 UTC (permalink / raw)
To: Jakub Kicinski, MD Danish Anwar, Felix Maurer
Cc: David S. Miller, Eric Dumazet, Paolo Abeni, Simon Horman,
Jonathan Corbet, Shuah Khan, Roger Quadros, Andrew Lunn,
Meghana Malladi, Jacob Keller, David Carlier, Vadim Fedorenko,
Kevin Hao, netdev, linux-doc, linux-kernel, linux-arm-kernel,
Vladimir Oltean, luka.gejak
In-Reply-To: <20260518184506.694c584e@kernel.org>
On May 19, 2026 3:45:06 AM GMT+02:00, Jakub Kicinski <kuba@kernel.org> wrote:
>On Thu, 14 May 2026 13:26:05 +0530 MD Danish Anwar wrote:
>> Add new firmware PA statistics counters for HSR and LRE to the ethtool
>> statistics exposed by the ICSSG driver.
>>
>> New statistics added:
>> - FW_HSR_FWD_CHECK_FAIL_DROP: Packets dropped on the HSR forwarding path
>> - FW_HSR_HE_CHECK_FAIL_DROP: Packets dropped on the HSR host egress path
>> - FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES: Frames with duplicate discard
>> skipped
>> - FW_LRE_CNT_UNIQUE/DUPLICATE/MULTIPLE_RX: LRE duplicate detection
>> counters
>> - FW_LRE_CNT_RX/TX: LRE per-port frame counters
>> - FW_LRE_CNT_OWN_RX: Own HSR tagged frames received
>> - FW_LRE_CNT_ERRWRONGLAN: Frames with wrong LAN identifier (PRP)
>>
>> Document the new HSR/LRE statistics in icssg_prueth.rst.
>
>To an untrained eye these stats look like stuff that could
>be standardized across drivers.
>
>Luka, Felix, others on CC, do you think we should expose these
>from HSR over netlink as "standard" offload stats different drivers
>can plug into or not worth it?
Hi Jakub,
I think there is a case for standardizing part of this, but I would
not standardize the whole set as-is.
The LRE counters look generic enough to me, especially:
- unique rx
- duplicate rx
- multiple rx
- rx / tx
- own rx
- wrong LAN, PRP only
Those are protocol/LRE concepts rather than TI firmware details, so
exposing them from the HSR/PRP layer sounds useful. I would expect
both the software implementation and offloaded implementations to be
able to provide at least some of them, with unsupported counters
omitted or reported as not available.
I would not put the firmware check/drop counters in the same standard
bucket, though:
- FW_HSR_FWD_CHECK_FAIL_DROP
- FW_HSR_HE_CHECK_FAIL_DROP
- FW_HSR_SKIP_HOST_DUP_DISCARD_FRAMES
Those sound more like implementation/debug counters for the ICSSG
firmware pipeline. They are still useful in ethtool driver stats, but
I would be hesitant to bake their exact semantics into HSR UAPI.
So my preference would be:
1. Keep driver-private ethtool stats for the full firmware counter set.
2. Add a small HSR/PRP standard stats set separately, limited to
well-defined LRE counters.
3. Make the HSR layer expose them, with offload drivers plugging in via
an optional callback or offload stats op.
4. Define the counters carefully, including whether they are per-HSR
device or per-port A/B, and what PRP-only counters mean for HSR.
I do not think this patch should blindly become the UAPI definition,
but I do think it points at a useful follow-up. If we want to avoid
adding driver-private names first and then standardizing different
names later, then it may be worth asking Danish to split the
protocol-level LRE counters out and route those through a common HSR
stats interface.
Best regards,
Luka Gejak
^ permalink raw reply
* Re: [PATCH v14 08/44] arm64: RMI: Ensure that the RMM has GPT entries for memory
From: Aneesh Kumar K.V @ 2026-05-19 5:55 UTC (permalink / raw)
To: Steven Price, kvm, kvmarm
Cc: Steven Price, Catalin Marinas, Marc Zyngier, Will Deacon,
James Morse, Oliver Upton, Suzuki K Poulose, Zenghui Yu,
linux-arm-kernel, linux-kernel, Joey Gouly, Alexandru Elisei,
Christoffer Dall, Fuad Tabba, linux-coco, Ganapatrao Kulkarni,
Gavin Shan, Shanker Donthineni, Alper Gun, Emi Kisanuki,
Vishal Annapurve, WeiLin.Chang, Lorenzo.Pieralisi2
In-Reply-To: <20260513131757.116630-9-steven.price@arm.com>
> +
> +bool rmi_is_available(void)
> +{
> + return arm64_rmi_is_available;
> +}
> +
Can we rename to is_rmi_available(void) ?
-aneesh
^ permalink raw reply
* [PATCH] arm64: dts: imx943-evk: Fix PCIe EP vpcie-supply
From: Sherry Sun (OSS) @ 2026-05-19 5:54 UTC (permalink / raw)
To: Frank.Li, s.hauer, kernel, festevam, robh, krzk+dt, conor+dt,
hongxing.zhu
Cc: imx, linux-arm-kernel, devicetree, linux-kernel
From: Sherry Sun <sherry.sun@nxp.com>
The vpcie-supply property should reference the regulator that controls
the actual M.2 power supply, not the W_DISABLE1# signal.
On imx943-evk:
- reg_m2_wlan controls M.2 W_DISABLE1# signal
- reg_m2_pwr controls the actual M.2 power supply
Fix the vpcie-supply to use reg_m2_pwr for proper power control in
PCIe endpoint mode.
Fixes: 1962c596d51c ("arm64: dts: imx943-evk: Add pcie[0,1] and pcie-ep[0,1] support")
Signed-off-by: Sherry Sun <sherry.sun@nxp.com>
---
arch/arm64/boot/dts/freescale/imx943-evk.dts | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/arm64/boot/dts/freescale/imx943-evk.dts b/arch/arm64/boot/dts/freescale/imx943-evk.dts
index 1346a6a56883..7cfd42468950 100644
--- a/arch/arm64/boot/dts/freescale/imx943-evk.dts
+++ b/arch/arm64/boot/dts/freescale/imx943-evk.dts
@@ -1043,7 +1043,7 @@ &pcie0 {
&pcie0_ep {
pinctrl-0 = <&pinctrl_pcie0>;
pinctrl-names = "default";
- vpcie-supply = <®_m2_wlan>;
+ vpcie-supply = <®_m2_pwr>;
status = "disabled";
};
base-commit: 5f9e9f83aee0fa8f2124c6f192505de2cdf7c5dc
--
2.37.1
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox