* [PATCH v4 4/8] perf build: Be more programmatic when setting up libunwind variables
From: Ian Rogers @ 2026-04-13 2:48 UTC (permalink / raw)
To: acme
Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, irogers, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260413024805.1316480-1-irogers@google.com>
Iterate LIBUNWIND_ARCHS when setting up CONFIG_ and HAVE_ definitions
rather than treating each architecture individually. This sets up the
libunwind build variables and C definitions beyond x86 and
arm/aarch64. The existing naming convention is followed for
compatibility.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/Makefile.config | 215 +++++++++++++++----------------------
1 file changed, 89 insertions(+), 126 deletions(-)
diff --git a/tools/perf/Makefile.config b/tools/perf/Makefile.config
index 333ddd0e4bd8..9d31d0f6f52a 100644
--- a/tools/perf/Makefile.config
+++ b/tools/perf/Makefile.config
@@ -65,95 +65,83 @@ $(call detected_var,SRCARCH)
CFLAGS += -I$(OUTPUT)arch/$(SRCARCH)/include/generated
-# Additional ARCH settings for ppc
-ifeq ($(SRCARCH),powerpc)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
- endif
-endif
-
# Additional ARCH settings for x86
ifeq ($(SRCARCH),x86)
$(call detected,CONFIG_X86)
ifeq (${IS_64_BIT}, 1)
CFLAGS += -DHAVE_ARCH_X86_64_SUPPORT
ARCH_INCLUDE = ../../arch/x86/lib/memcpy_64.S ../../arch/x86/lib/memset_64.S
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
- endif
$(call detected,CONFIG_X86_64)
- else
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind-x86 -llzma -lunwind
- endif
endif
endif
-ifeq ($(SRCARCH),arm)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind -lunwind-arm
- endif
+ifeq ($(ARCH),s390)
+ CFLAGS += -fPIC
endif
-ifeq ($(SRCARCH),arm64)
- ifndef NO_LIBUNWIND
- LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
- endif
+ifneq ($(LIBUNWIND),1)
+ NO_LIBUNWIND := 1
endif
-ifeq ($(SRCARCH),loongarch)
- ifndef NO_LIBUNWIND
+ifndef NO_LIBUNWIND
+ ifeq ($(SRCARCH),arm)
+ LIBUNWIND_LIBS = -lunwind -lunwind-arm
+ endif
+ ifeq ($(SRCARCH),arm64)
+ LIBUNWIND_LIBS = -lunwind -lunwind-aarch64
+ endif
+ ifeq ($(SRCARCH),loongarch)
LIBUNWIND_LIBS = -lunwind -lunwind-loongarch64
endif
-endif
-
-ifeq ($(ARCH),s390)
- CFLAGS += -fPIC
-endif
-
-ifeq ($(ARCH),mips)
- ifndef NO_LIBUNWIND
+ ifeq ($(ARCH),mips)
LIBUNWIND_LIBS = -lunwind -lunwind-mips
endif
+ ifeq ($(SRCARCH),powerpc)
+ LIBUNWIND_LIBS := -lunwind -lunwind-ppc64
+ endif
+ ifeq ($(SRCARCH),riscv)
+ LIBUNWIND_LIBS := -lunwind -lunwind-riscv
+ endif
+ ifeq ($(SRCARCH),s390)
+ LIBUNWIND_LIBS := -lunwind -lunwind-s390x
+ endif
+ ifeq ($(SRCARCH),x86)
+ ifeq (${IS_64_BIT}, 1)
+ LIBUNWIND_LIBS = -lunwind-x86_64 -lunwind -llzma
+ else
+ LIBUNWIND_LIBS = -lunwind-x86 -lunwind -llzma
+ endif
+ endif
+ ifeq ($(LIBUNWIND_LIBS),)
+ NO_LIBUNWIND := 1
+ endif
endif
-ifneq ($(LIBUNWIND),1)
- NO_LIBUNWIND := 1
-endif
-
-ifeq ($(LIBUNWIND_LIBS),)
- NO_LIBUNWIND := 1
-endif
#
# For linking with debug library, run like:
#
# make DEBUG=1 LIBUNWIND_DIR=/opt/libunwind/
#
-
-libunwind_arch_set_flags = $(eval $(libunwind_arch_set_flags_code))
-define libunwind_arch_set_flags_code
- FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include
- FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
-endef
-
-ifdef LIBUNWIND_DIR
- LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
- LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
- LIBUNWIND_ARCHS = x86 x86_64 arm aarch64 debug-frame-arm debug-frame-aarch64 loongarch
- $(foreach libunwind_arch,$(LIBUNWIND_ARCHS),$(call libunwind_arch_set_flags,$(libunwind_arch)))
-endif
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
ifndef NO_LIBUNWIND
- # Set per-feature check compilation flags
FEATURE_CHECK_CFLAGS-libunwind = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
FEATURE_CHECK_CFLAGS-libunwind-debug-frame = $(LIBUNWIND_CFLAGS)
FEATURE_CHECK_LDFLAGS-libunwind-debug-frame = $(LIBUNWIND_LDFLAGS) $(LIBUNWIND_LIBS)
-
- FEATURE_CHECK_LDFLAGS-libunwind-arm += -lunwind -lunwind-arm
- FEATURE_CHECK_LDFLAGS-libunwind-aarch64 += -lunwind -lunwind-aarch64
- FEATURE_CHECK_LDFLAGS-libunwind-x86 += -lunwind -llzma -lunwind-x86
- FEATURE_CHECK_LDFLAGS-libunwind-x86_64 += -lunwind -llzma -lunwind-x86_64
+
+ ifdef LIBUNWIND_DIR
+ LIBUNWIND_CFLAGS = -I$(LIBUNWIND_DIR)/include
+ LIBUNWIND_LDFLAGS = -L$(LIBUNWIND_DIR)/lib
+
+ define libunwind_arch_set_flags
+ FEATURE_CHECK_CFLAGS-libunwind-$(1) = -I$(LIBUNWIND_DIR)/include
+ FEATURE_CHECK_LDFLAGS-libunwind-$(1) = -L$(LIBUNWIND_DIR)/lib
+ endef
+ $(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call libunwind_arch_set_flags,$(arch))) \
+ )
+ endif
endif
ifdef CSINCLUDES
@@ -638,49 +626,6 @@ ifeq ($(SRCARCH),powerpc)
endif
endif
-ifndef NO_LIBUNWIND
- have_libunwind :=
-
- $(call feature_check,libunwind)
-
- $(call feature_check,libunwind-x86)
- ifeq ($(feature-libunwind-x86), 1)
- $(call detected,CONFIG_LIBUNWIND_X86)
- CFLAGS += -DHAVE_LIBUNWIND_X86_SUPPORT
- LDFLAGS += -lunwind-x86
- EXTLIBS_LIBUNWIND += -lunwind-x86
- have_libunwind = 1
- endif
-
- $(call feature_check,libunwind-aarch64)
- ifeq ($(feature-libunwind-aarch64), 1)
- $(call detected,CONFIG_LIBUNWIND_AARCH64)
- CFLAGS += -DHAVE_LIBUNWIND_AARCH64_SUPPORT
- LDFLAGS += -lunwind-aarch64
- EXTLIBS_LIBUNWIND += -lunwind-aarch64
- have_libunwind = 1
- $(call feature_check,libunwind-debug-frame-aarch64)
- ifneq ($(feature-libunwind-debug-frame-aarch64), 1)
- $(warning No debug_frame support found in libunwind-aarch64)
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_AARCH64
- endif
- endif
-
- ifneq ($(feature-libunwind), 1)
- $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR and set LIBUNWIND=1 in the make command line as it is opt-in now)
- NO_LOCAL_LIBUNWIND := 1
- else
- have_libunwind := 1
- $(call detected,CONFIG_LOCAL_LIBUNWIND)
- endif
-
- ifneq ($(have_libunwind), 1)
- NO_LIBUNWIND := 1
- endif
-else
- NO_LOCAL_LIBUNWIND := 1
-endif
-
ifndef NO_LIBBPF
ifneq ($(feature-bpf), 1)
$(warning BPF API too old. Please install recent kernel headers. BPF support in 'perf record' is disabled.)
@@ -739,6 +684,49 @@ ifndef GEN_VMLINUX_H
VMLINUX_H=$(src-perf)/util/bpf_skel/vmlinux/vmlinux.h
endif
+ifndef NO_LIBUNWIND
+ have_libunwind :=
+
+ $(call feature_check,libunwind)
+ ifneq ($(feature-libunwind), 1)
+ $(warning No libunwind found. Please install libunwind-dev[el] >= 1.1 and/or set LIBUNWIND_DIR and set LIBUNWIND=1 in the make command line as it is opt-in now)
+ NO_LOCAL_LIBUNWIND := 1
+ else
+ have_libunwind := 1
+ $(call detected,CONFIG_LOCAL_LIBUNWIND)
+ CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
+ CFLAGS += $(LIBUNWIND_CFLAGS)
+ LDFLAGS += $(LIBUNWIND_LDFLAGS)
+ EXTLIBS += $(EXTLIBS_LIBUNWIND)
+ $(call feature_check,libunwind-debug-frame)
+ ifneq ($(feature-libunwind-debug-frame), 1)
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
+ endif
+ endif
+
+ define PROCESS_REMOTE_LIBUNWIND_ARCH
+ $(call feature_check,libunwind-$(1))
+
+ ifeq ($$(feature-libunwind-$(1)), 1)
+ upper_arch := $$(shell echo $(1) | tr '[:lower:]' '[:upper:]')
+ $$(call detected,CONFIG_LIBUNWIND_$$(upper_arch))
+
+ CFLAGS += -DHAVE_LIBUNWIND_$$(upper_arch)_SUPPORT
+ LDFLAGS += -lunwind-$(1)
+ EXTLIBS_LIBUNWIND += -lunwind-$(1)
+ have_libunwind := 1
+
+ $$(call feature_check,libunwind-debug-frame-$(1))
+ ifneq ($$(feature-libunwind-debug-frame-$(1)), 1)
+ CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME_$$(upper_arch)
+ endif
+ endif
+ endef
+ $(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call PROCESS_REMOTE_LIBUNWIND_ARCH,$(arch))) \
+ )
+endif
+
dwarf-post-unwind := 1
dwarf-post-unwind-text := BUG
@@ -761,31 +749,6 @@ ifeq ($(dwarf-post-unwind),1)
$(call detected,CONFIG_DWARF_UNWIND)
endif
-ifndef NO_LIBUNWIND
- ifndef NO_LOCAL_LIBUNWIND
- ifeq ($(SRCARCH),$(filter $(SRCARCH),arm arm64))
- $(call feature_check,libunwind-debug-frame)
- ifneq ($(feature-libunwind-debug-frame), 1)
- $(warning No debug_frame support found in libunwind)
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- else
- # non-ARM has no dwarf_find_debug_frame() function:
- CFLAGS += -DNO_LIBUNWIND_DEBUG_FRAME
- endif
- EXTLIBS += $(LIBUNWIND_LIBS)
- LDFLAGS += $(LIBUNWIND_LIBS)
- endif
- ifeq ($(findstring -static,${LDFLAGS}),-static)
- # gcc -static links libgcc_eh which contans piece of libunwind
- LIBUNWIND_LDFLAGS += -Wl,--allow-multiple-definition
- endif
- CFLAGS += -DHAVE_LIBUNWIND_SUPPORT
- CFLAGS += $(LIBUNWIND_CFLAGS)
- LDFLAGS += $(LIBUNWIND_LDFLAGS)
- EXTLIBS += $(EXTLIBS_LIBUNWIND)
-endif
-
ifneq ($(NO_LIBTRACEEVENT),1)
$(call detected,CONFIG_TRACE)
endif
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v4 3/8] tools build: Deduplicate test-libunwind for different architectures
From: Ian Rogers @ 2026-04-13 2:48 UTC (permalink / raw)
To: acme
Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, irogers, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260413024805.1316480-1-irogers@google.com>
The separate test files only exist to pass a different #include,
instead have a single source file and pass -include to $(CC) to
include the relevant header file for the architecture being
tested. Generate the rules using a foreach loop. Include tests for all
current libunwind architectures.
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/build/feature/Makefile | 38 +++++++++----------
tools/build/feature/test-libunwind-aarch64.c | 27 -------------
tools/build/feature/test-libunwind-arm.c | 28 --------------
.../test-libunwind-debug-frame-aarch64.c | 17 ---------
.../feature/test-libunwind-debug-frame-arm.c | 17 ---------
.../feature/test-libunwind-debug-frame.c | 1 -
tools/build/feature/test-libunwind-x86.c | 28 --------------
tools/build/feature/test-libunwind-x86_64.c | 28 --------------
tools/build/feature/test-libunwind.c | 1 -
9 files changed, 19 insertions(+), 166 deletions(-)
delete mode 100644 tools/build/feature/test-libunwind-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-arm.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
delete mode 100644 tools/build/feature/test-libunwind-x86.c
delete mode 100644 tools/build/feature/test-libunwind-x86_64.c
diff --git a/tools/build/feature/Makefile b/tools/build/feature/Makefile
index f163a245837a..bda8ef868e44 100644
--- a/tools/build/feature/Makefile
+++ b/tools/build/feature/Makefile
@@ -210,27 +210,27 @@ $(OUTPUT)test-numa_num_possible_cpus.bin:
$(BUILD) -lnuma
$(OUTPUT)test-libunwind.bin:
- $(BUILD) -lelf -llzma
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
$(OUTPUT)test-libunwind-debug-frame.bin:
- $(BUILD) -lelf -llzma
-$(OUTPUT)test-libunwind-x86.bin:
- $(BUILD) -lelf -llzma -lunwind-x86
-
-$(OUTPUT)test-libunwind-x86_64.bin:
- $(BUILD) -lelf -llzma -lunwind-x86_64
-
-$(OUTPUT)test-libunwind-arm.bin:
- $(BUILD) -lelf -llzma -lunwind-arm
-
-$(OUTPUT)test-libunwind-aarch64.bin:
- $(BUILD) -lelf -llzma -lunwind-aarch64
-
-$(OUTPUT)test-libunwind-debug-frame-arm.bin:
- $(BUILD) -lelf -llzma -lunwind-arm
-
-$(OUTPUT)test-libunwind-debug-frame-aarch64.bin:
- $(BUILD) -lelf -llzma -lunwind-aarch64
+ $(BUILD) -include libunwind.h -lelf -llzma -lunwind
+
+LIBUNWIND_ARCHS:=aarch64 arm loongarch64 mips ppc32 ppc64 riscv s390x x86 x86_64
+define LIBUNWIND_RULE
+$$(OUTPUT)test-libunwind-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+$$(OUTPUT)test-libunwind-debug-frame-$(1).bin:
+ $$(CC) $$(CFLAGS) -MD -Wall -Werror -include libunwind-$(1).h -o $$@ \
+ test-libunwind-debug-frame.c $$(LDFLAGS) -lelf -llzma -lunwind-$(1) \
+ > $$(@:.bin=.make.output) 2>&1
+
+endef
+$(foreach arch,$(LIBUNWIND_ARCHS), \
+ $(eval $(call LIBUNWIND_RULE,$(arch))) \
+)
$(OUTPUT)test-libslang.bin:
$(BUILD) -lslang
diff --git a/tools/build/feature/test-libunwind-aarch64.c b/tools/build/feature/test-libunwind-aarch64.c
deleted file mode 100644
index 323803f49212..000000000000
--- a/tools/build/feature/test-libunwind-aarch64.c
+++ /dev/null
@@ -1,27 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-aarch64.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-arm.c b/tools/build/feature/test-libunwind-arm.c
deleted file mode 100644
index cb378b7d6866..000000000000
--- a/tools/build/feature/test-libunwind-arm.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-arm.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame-aarch64.c b/tools/build/feature/test-libunwind-debug-frame-aarch64.c
deleted file mode 100644
index 36d6646c185e..000000000000
--- a/tools/build/feature/test-libunwind-debug-frame-aarch64.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-aarch64.h>
-#include <stdlib.h>
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
- unw_word_t ip, unw_word_t segbase,
- const char *obj_name, unw_word_t start,
- unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-int main(void)
-{
- dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame-arm.c b/tools/build/feature/test-libunwind-debug-frame-arm.c
deleted file mode 100644
index 8696e48e1268..000000000000
--- a/tools/build/feature/test-libunwind-debug-frame-arm.c
+++ /dev/null
@@ -1,17 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-arm.h>
-#include <stdlib.h>
-
-extern int
-UNW_OBJ(dwarf_find_debug_frame) (int found, unw_dyn_info_t *di_debug,
- unw_word_t ip, unw_word_t segbase,
- const char *obj_name, unw_word_t start,
- unw_word_t end);
-
-#define dwarf_find_debug_frame UNW_OBJ(dwarf_find_debug_frame)
-
-int main(void)
-{
- dwarf_find_debug_frame(0, NULL, 0, 0, NULL, 0, 0);
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-debug-frame.c b/tools/build/feature/test-libunwind-debug-frame.c
index efb55cdd8d01..4c57e37004b3 100644
--- a/tools/build/feature/test-libunwind-debug-frame.c
+++ b/tools/build/feature/test-libunwind-debug-frame.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
-#include <libunwind.h>
#include <stdlib.h>
extern int
diff --git a/tools/build/feature/test-libunwind-x86.c b/tools/build/feature/test-libunwind-x86.c
deleted file mode 100644
index e5e0f6c89637..000000000000
--- a/tools/build/feature/test-libunwind-x86.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-x86.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind-x86_64.c b/tools/build/feature/test-libunwind-x86_64.c
deleted file mode 100644
index 62ae4db597dc..000000000000
--- a/tools/build/feature/test-libunwind-x86_64.c
+++ /dev/null
@@ -1,28 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-#include <libunwind-x86_64.h>
-#include <stdlib.h>
-
-extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
- unw_word_t ip,
- unw_dyn_info_t *di,
- unw_proc_info_t *pi,
- int need_unwind_info, void *arg);
-
-
-#define dwarf_search_unwind_table UNW_OBJ(dwarf_search_unwind_table)
-
-static unw_accessors_t accessors;
-
-int main(void)
-{
- unw_addr_space_t addr_space;
-
- addr_space = unw_create_addr_space(&accessors, 0);
- if (addr_space)
- return 0;
-
- unw_init_remote(NULL, addr_space, NULL);
- dwarf_search_unwind_table(addr_space, 0, NULL, NULL, 0, NULL);
-
- return 0;
-}
diff --git a/tools/build/feature/test-libunwind.c b/tools/build/feature/test-libunwind.c
index 53fd26614ff0..5af5dc3a73d4 100644
--- a/tools/build/feature/test-libunwind.c
+++ b/tools/build/feature/test-libunwind.c
@@ -1,5 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
-#include <libunwind.h>
#include <stdlib.h>
extern int UNW_OBJ(dwarf_search_unwind_table) (unw_addr_space_t as,
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v4 1/8] perf unwind: Refactor get_entries to allow dynamic libdw/libunwind selection
From: Ian Rogers @ 2026-04-13 2:47 UTC (permalink / raw)
To: acme
Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, irogers, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <20260413024805.1316480-1-irogers@google.com>
Currently, both libdw and libunwind define 'unwind__get_entries'. This
causes a duplicate symbol build failure when both are compiled into
perf.
This commit refactors the DWARF unwind post-processing to be
configurable at runtime via the .perfconfig file option
'unwind.style', or using the argument '--unwind-style' in the commands
'perf report', 'perf script' and 'perf inject', in a similar manner to
the addr2line or the disassembler style.
The file 'tools/perf/util/unwind.c' adds the top-level dispatch
function 'unwind__get_entries'. The backend implementations are
renamed to 'libdw__get_entries' and 'libunwind__get_entries'. Both are
attempted as fallbacks if not configured, or if the primary backend
fails.
Fixes: 2e9191573a69 ("perf build: Remove NO_LIBDW_DWARF_UNWIND option")
Signed-off-by: Ian Rogers <irogers@google.com>
---
tools/perf/builtin-inject.c | 4 ++
tools/perf/builtin-report.c | 4 ++
tools/perf/builtin-script.c | 4 ++
tools/perf/util/Build | 1 +
tools/perf/util/symbol_conf.h | 10 +++
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind.c | 2 +-
tools/perf/util/unwind.c | 98 ++++++++++++++++++++++++++++++
tools/perf/util/unwind.h | 63 ++++++++++++-------
9 files changed, 163 insertions(+), 25 deletions(-)
create mode 100644 tools/perf/util/unwind.c
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index f174bc69cec4..60f0c7dab31b 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -26,6 +26,7 @@
#include "util/synthetic-events.h"
#include "util/thread.h"
#include "util/namespaces.h"
+#include "util/unwind.h"
#include "util/util.h"
#include "util/tsc.h"
@@ -2562,6 +2563,9 @@ int cmd_inject(int argc, const char **argv)
OPT_STRING(0, "guestmount", &symbol_conf.guestmount, "directory",
"guest mount directory under which every guest os"
" instance has a subdir"),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_BOOLEAN(0, "convert-callchain", &inject.convert_callchain,
"Generate callchains using DWARF and drop register/stack data"),
OPT_END()
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 95c0bdba6b11..0b0966d94128 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -48,6 +48,7 @@
#include "util/time-utils.h"
#include "util/auxtrace.h"
#include "util/units.h"
+#include "util/unwind.h"
#include "util/util.h" // perf_tip()
#include "ui/ui.h"
#include "ui/progress.h"
@@ -1449,6 +1450,9 @@ int cmd_report(int argc, const char **argv)
OPT_CALLBACK(0, "addr2line-style", NULL, "addr2line style",
"addr2line styles (libdw,llvm,libbfd,addr2line)",
report_parse_addr2line_config),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
"Symbol demangling. Enabled by default, use --no-demangle to disable."),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index c8ac9f01a36b..fd0b4609516b 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -63,6 +63,7 @@
#include <linux/err.h>
#include "util/dlfilter.h"
#include "util/record.h"
+#include "util/unwind.h"
#include "util/util.h"
#include "util/cgroup.h"
#include "util/annotate.h"
@@ -4159,6 +4160,9 @@ int cmd_script(int argc, const char **argv)
"Enable symbol demangling"),
OPT_BOOLEAN(0, "demangle-kernel", &symbol_conf.demangle_kernel,
"Enable kernel symbol demangling"),
+ OPT_CALLBACK(0, "unwind-style", NULL, "unwind style",
+ "unwind styles (libdw,libunwind)",
+ unwind__option),
OPT_STRING(0, "addr2line", &symbol_conf.addr2line_path, "path",
"addr2line binary to use for line numbers"),
OPT_STRING(0, "time", &script.time_str, "str",
diff --git a/tools/perf/util/Build b/tools/perf/util/Build
index 70cc91d00804..01edfccebb88 100644
--- a/tools/perf/util/Build
+++ b/tools/perf/util/Build
@@ -216,6 +216,7 @@ ifndef CONFIG_SETNS
perf-util-y += setns.o
endif
+perf-util-y += unwind.o
perf-util-$(CONFIG_LIBDW) += probe-finder.o
perf-util-$(CONFIG_LIBDW) += dwarf-aux.o
perf-util-$(CONFIG_LIBDW) += dwarf-regs.o
diff --git a/tools/perf/util/symbol_conf.h b/tools/perf/util/symbol_conf.h
index 6cd454d7c98e..0dee5aa6a534 100644
--- a/tools/perf/util/symbol_conf.h
+++ b/tools/perf/util/symbol_conf.h
@@ -9,6 +9,15 @@
struct strlist;
struct intlist;
+enum unwind_style {
+ UNWIND_STYLE_UNKNOWN = 0,
+ UNWIND_STYLE_LIBDW,
+ UNWIND_STYLE_LIBUNWIND,
+};
+
+#define MAX_UNWIND_STYLE (UNWIND_STYLE_LIBUNWIND + 1)
+
+
enum a2l_style {
A2L_STYLE_UNKNOWN = 0,
A2L_STYLE_LIBDW,
@@ -81,6 +90,7 @@ struct symbol_conf {
const char *addr2line_path;
enum a2l_style addr2line_style[MAX_A2L_STYLE];
int addr2line_timeout_ms;
+ enum unwind_style unwind_style[MAX_UNWIND_STYLE];
unsigned long time_quantum;
struct strlist *dso_list,
*comm_list,
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 05e8e68bd49c..d8a5b7d54192 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -339,7 +339,7 @@ frame_callback(Dwfl_Frame *state, void *arg)
DWARF_CB_ABORT : DWARF_CB_OK;
}
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data,
int max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index cb8be6acfb6f..a0016b897dae 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -79,7 +79,7 @@ void unwind__finish_access(struct maps *maps)
ops->finish_access(maps);
}
-int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort)
diff --git a/tools/perf/util/unwind.c b/tools/perf/util/unwind.c
new file mode 100644
index 000000000000..86c2d1692d08
--- /dev/null
+++ b/tools/perf/util/unwind.c
@@ -0,0 +1,98 @@
+// SPDX-License-Identifier: GPL-2.0
+#include "debug.h"
+#include "symbol_conf.h"
+#include "unwind.h"
+#include <linux/string.h>
+#include <string.h>
+#include <stdlib.h>
+
+int unwind__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
+{
+ int ret = 0;
+
+#if defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
+ if (symbol_conf.unwind_style[0] == UNWIND_STYLE_UNKNOWN) {
+ int i = 0;
+#ifdef HAVE_LIBDW_SUPPORT
+ symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBDW;
+#endif
+#ifdef HAVE_LIBUNWIND_SUPPORT
+ symbol_conf.unwind_style[i++] = UNWIND_STYLE_LIBUNWIND;
+#endif
+ }
+#endif //defined(HAVE_LIBDW_SUPPORT) || defined(HAVE_LIBUNWIND_SUPPORT)
+
+ for (size_t i = 0; i < ARRAY_SIZE(symbol_conf.unwind_style); i++) {
+ switch (symbol_conf.unwind_style[i]) {
+ case UNWIND_STYLE_LIBDW:
+ ret = libdw__get_entries(cb, arg, thread, data, max_stack, best_effort);
+ break;
+ case UNWIND_STYLE_LIBUNWIND:
+ ret = libunwind__get_entries(cb, arg, thread, data, max_stack, best_effort);
+ break;
+ case UNWIND_STYLE_UNKNOWN:
+ default:
+#if !defined(HAVE_LIBDW_SUPPORT) && !defined(HAVE_LIBUNWIND_SUPPORT)
+ pr_warning_once(
+ "Error: dwarf unwinding not supported, build perf with libdw or libunwind.\n");
+#endif
+ ret = -1;
+ break;
+ }
+ if (ret == 0)
+ break;
+ }
+ return ret;
+}
+
+int unwind__configure(const char *var, const char *value, void *cb __maybe_unused)
+{
+ static const char * const unwind_style_names[] = {
+ [UNWIND_STYLE_LIBDW] = "libdw",
+ [UNWIND_STYLE_LIBUNWIND] = "libunwind",
+ NULL
+ };
+ char *s, *p, *saveptr;
+ size_t i = 0;
+
+ if (strcmp(var, "unwind.style"))
+ return 0;
+
+ if (!value)
+ return -1;
+
+ s = strdup(value);
+ if (!s)
+ return -1;
+
+ p = strtok_r(s, ",", &saveptr);
+ while (p && i < ARRAY_SIZE(symbol_conf.unwind_style)) {
+ bool found = false;
+ char *q = strim(p);
+
+ for (size_t j = UNWIND_STYLE_LIBDW; j < MAX_UNWIND_STYLE; j++) {
+ if (!strcasecmp(q, unwind_style_names[j])) {
+ symbol_conf.unwind_style[i++] = j;
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ pr_warning("Unknown unwind style: %s\n", q);
+ p = strtok_r(NULL, ",", &saveptr);
+ }
+
+ free(s);
+ return 0;
+}
+
+int unwind__option(const struct option *opt __maybe_unused,
+ const char *arg,
+ int unset __maybe_unused)
+{
+ return unwind__configure("unwind.style", arg, NULL);
+}
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index 9f7164c6d9aa..ac0776e39f84 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -4,9 +4,10 @@
#include <linux/compiler.h>
#include <linux/types.h>
-#include "util/map_symbol.h"
+#include "map_symbol.h"
struct maps;
+struct option;
struct perf_sample;
struct thread;
@@ -26,7 +27,9 @@ struct unwind_libunwind_ops {
struct perf_sample *data, int max_stack, bool best_effort);
};
-#ifdef HAVE_DWARF_UNWIND_SUPPORT
+int unwind__configure(const char *var, const char *value, void *cb);
+int unwind__option(const struct option *opt, const char *arg, int unset);
+
/*
* When best_effort is set, don't report errors and fail silently. This could
* be expanded in the future to be more permissive about things other than
@@ -36,8 +39,31 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
struct thread *thread,
struct perf_sample *data, int max_stack,
bool best_effort);
-/* libunwind specific */
+
+#ifdef HAVE_LIBDW_SUPPORT
+int libdw__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct thread *thread,
+ struct perf_sample *data, int max_stack,
+ bool best_effort);
+#else
+#include "debug.h"
+static inline int libdw__get_entries(unwind_entry_cb_t cb __maybe_unused, void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
+{
+ pr_err("Error: libdw dwarf unwinding not built into perf\n");
+ return -1;
+}
+#endif
+
#ifdef HAVE_LIBUNWIND_SUPPORT
+/* libunwind specific */
+int libunwind__get_entries(unwind_entry_cb_t cb, void *arg,
+ struct thread *thread,
+ struct perf_sample *data, int max_stack,
+ bool best_effort);
#ifndef LIBUNWIND__ARCH_REG_ID
#define LIBUNWIND__ARCH_REG_ID(regnum) libunwind__arch_reg_id(regnum)
#endif
@@ -47,26 +73,16 @@ int unwind__prepare_access(struct maps *maps, struct map *map, bool *initialized
void unwind__flush_access(struct maps *maps);
void unwind__finish_access(struct maps *maps);
#else
-static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
- struct map *map __maybe_unused,
- bool *initialized __maybe_unused)
-{
- return 0;
-}
-
-static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
-static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif
-#else
-static inline int
-unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
- void *arg __maybe_unused,
- struct thread *thread __maybe_unused,
- struct perf_sample *data __maybe_unused,
- int max_stack __maybe_unused,
- bool best_effort __maybe_unused)
+#include "debug.h"
+static inline int libunwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
+ void *arg __maybe_unused,
+ struct thread *thread __maybe_unused,
+ struct perf_sample *data __maybe_unused,
+ int max_stack __maybe_unused,
+ bool best_effort __maybe_unused)
{
- return 0;
+ pr_err("Error: libunwind dwarf unwinding not built into perf\n");
+ return -1;
}
static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
@@ -78,5 +94,6 @@ static inline int unwind__prepare_access(struct maps *maps __maybe_unused,
static inline void unwind__flush_access(struct maps *maps __maybe_unused) {}
static inline void unwind__finish_access(struct maps *maps __maybe_unused) {}
-#endif /* HAVE_DWARF_UNWIND_SUPPORT */
+#endif
+
#endif /* __UNWIND_H */
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply related
* [PATCH v4 0/8] perf libunwind multiple remote support
From: Ian Rogers @ 2026-04-13 2:47 UTC (permalink / raw)
To: acme
Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, irogers, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <advv6twWCEVBo_Hc@x1>
Fix the libunwind build for when libdw and libunwind are feature
detected, currently failing with a duplicate symbol.
Refactor the libunwind support so that whenever a remote target is
available, perf functions using the ELF machine can use that remote
target regardless of what the host/local machine is. Migrate existing
libunwind supported architectures like powerpc, arm64 and loongarch so
that they can work in a cross-architecture way. Add support for
RISC-V. Make the code more regular in function names, etc. and avoid
including a C-file. This increases the lines of code. It is similar in
style to the unwind-libdw implementation. It is hoped that the more
uniform nature of the code with help with refactoring the perf
registers for SIMD/APX support.
Aside from local host testing these patches are under tested, in part
as I'm failing to see how to build libunwind with support for multiple
remote targets. Please could I get help in testing.
v4: Rebase, in particular the zalloc->calloc change conflicted.
v3: Minor whitespace clean up and warn when a dynamic choice of libdw
or libunwind is selected for unwinding and support is missing (Arnaldo).
https://lore.kernel.org/lkml/20260404054032.1538095-1-irogers@google.com/
v2: Move two fixes patches to position 1 and 2 in the series. Fix
struct naming inconsistency, Andrew Jones
<andrew.jones@oss.qualcomm.com>. Fix other inconsistencies and
potential non-x86 build issues.
https://lore.kernel.org/lkml/20260305221927.3237145-1-irogers@google.com/
v1: https://lore.kernel.org/lkml/20260224142938.26088-1-irogers@google.com/
Ian Rogers (8):
perf unwind: Refactor get_entries to allow dynamic libdw/libunwind
selection
perf build loongarch: Remove reference to missing file
tools build: Deduplicate test-libunwind for different architectures
perf build: Be more programmatic when setting up libunwind variables
perf unwind-libunwind: Make libunwind register reading cross platform
perf unwind-libunwind: Move flush/finish access out of local
perf unwind-libunwind: Remove libunwind-local
perf unwind-libunwind: Add RISC-V libunwind support
tools/build/feature/Makefile | 38 +-
tools/build/feature/test-libunwind-aarch64.c | 27 -
tools/build/feature/test-libunwind-arm.c | 28 -
.../test-libunwind-debug-frame-aarch64.c | 17 -
.../feature/test-libunwind-debug-frame-arm.c | 17 -
.../feature/test-libunwind-debug-frame.c | 1 -
tools/build/feature/test-libunwind-x86.c | 28 -
tools/build/feature/test-libunwind-x86_64.c | 28 -
tools/build/feature/test-libunwind.c | 1 -
tools/perf/Makefile.config | 215 ++---
tools/perf/arch/arm/util/Build | 2 -
tools/perf/arch/arm/util/unwind-libunwind.c | 50 --
tools/perf/arch/arm64/util/Build | 1 -
tools/perf/arch/arm64/util/unwind-libunwind.c | 17 -
tools/perf/arch/loongarch/util/Build | 3 -
.../arch/loongarch/util/unwind-libunwind.c | 82 --
tools/perf/arch/mips/Build | 1 -
tools/perf/arch/mips/util/Build | 1 -
tools/perf/arch/mips/util/unwind-libunwind.c | 22 -
tools/perf/arch/powerpc/util/Build | 1 -
.../perf/arch/powerpc/util/unwind-libunwind.c | 92 --
tools/perf/arch/x86/util/Build | 3 -
tools/perf/arch/x86/util/unwind-libunwind.c | 115 ---
tools/perf/builtin-inject.c | 4 +
tools/perf/builtin-report.c | 4 +
tools/perf/builtin-script.c | 4 +
tools/perf/util/Build | 5 +-
tools/perf/util/libunwind-arch/Build | 11 +
.../perf/util/libunwind-arch/libunwind-arch.c | 319 +++++++
.../perf/util/libunwind-arch/libunwind-arch.h | 296 +++++++
.../perf/util/libunwind-arch/libunwind-arm.c | 290 ++++++
.../util/libunwind-arch/libunwind-arm64.c | 289 ++++++
.../perf/util/libunwind-arch/libunwind-i386.c | 312 +++++++
.../util/libunwind-arch/libunwind-loongarch.c | 297 +++++++
.../perf/util/libunwind-arch/libunwind-mips.c | 299 +++++++
.../util/libunwind-arch/libunwind-ppc32.c | 301 +++++++
.../util/libunwind-arch/libunwind-ppc64.c | 303 +++++++
.../util/libunwind-arch/libunwind-riscv.c | 297 +++++++
.../perf/util/libunwind-arch/libunwind-s390.c | 299 +++++++
.../util/libunwind-arch/libunwind-x86_64.c | 320 +++++++
tools/perf/util/libunwind/arm64.c | 40 -
tools/perf/util/libunwind/x86_32.c | 41 -
tools/perf/util/maps.c | 29 +-
tools/perf/util/maps.h | 4 +-
tools/perf/util/symbol_conf.h | 10 +
tools/perf/util/thread.c | 29 +-
tools/perf/util/unwind-libdw.c | 2 +-
tools/perf/util/unwind-libunwind-local.c | 831 ------------------
tools/perf/util/unwind-libunwind.c | 679 ++++++++++++--
tools/perf/util/unwind.c | 98 +++
tools/perf/util/unwind.h | 77 +-
51 files changed, 4549 insertions(+), 1731 deletions(-)
delete mode 100644 tools/build/feature/test-libunwind-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-arm.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-aarch64.c
delete mode 100644 tools/build/feature/test-libunwind-debug-frame-arm.c
delete mode 100644 tools/build/feature/test-libunwind-x86.c
delete mode 100644 tools/build/feature/test-libunwind-x86_64.c
delete mode 100644 tools/perf/arch/arm/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/arm64/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/loongarch/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/mips/Build
delete mode 100644 tools/perf/arch/mips/util/Build
delete mode 100644 tools/perf/arch/mips/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/powerpc/util/unwind-libunwind.c
delete mode 100644 tools/perf/arch/x86/util/unwind-libunwind.c
create mode 100644 tools/perf/util/libunwind-arch/Build
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arch.h
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-arm64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-i386.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-loongarch.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-mips.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc32.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-ppc64.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-riscv.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-s390.c
create mode 100644 tools/perf/util/libunwind-arch/libunwind-x86_64.c
delete mode 100644 tools/perf/util/libunwind/arm64.c
delete mode 100644 tools/perf/util/libunwind/x86_32.c
delete mode 100644 tools/perf/util/unwind-libunwind-local.c
create mode 100644 tools/perf/util/unwind.c
--
2.53.0.1213.gd9a14994de-goog
^ permalink raw reply
* Re: [PATCH v3 3/5] coresight: etm4x: fix inconsistencies with sysfs configration
From: Jie Gan @ 2026-04-13 2:37 UTC (permalink / raw)
To: Yeoreum Yun, coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan
In-Reply-To: <20260412175506.412301-4-yeoreum.yun@arm.com>
Hi Yeoreum,
On 4/13/2026 1:55 AM, Yeoreum Yun wrote:
> The current ETM4x configuration via sysfs can lead to the following
> inconsistencies:
>
> - If a configuration is modified via sysfs while a perf session is
> active, the running configuration may differ between before
> a sched-out and after a subsequent sched-in.
>
> - If a perf session and sysfs session tries to enable concurrently,
> configuration from configfs could be corrupted.
>
> - There is chance to corrupt drvdata->config if perf session tries
> to enabled among handling cscfg_csdev_disable_active_config()
> in etm4_disable_sysfs().
>
> To resolve these inconsistencies, the configuration should be separated into:
>
> - active_config, which is applied configuration for the current session
> - config, which stores the settings configured via sysfs.
>
> and apply configuration from configfs after taking a mode.
typo in subject:
s/configration/configuration
>
> Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> .../hwtracing/coresight/coresight-etm4x-cfg.c | 2 +-
> .../coresight/coresight-etm4x-core.c | 74 ++++++++++++-------
> drivers/hwtracing/coresight/coresight-etm4x.h | 2 +
> 3 files changed, 49 insertions(+), 29 deletions(-)
>
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> index d14d7c8a23e5..0553771d04e7 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> +++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
> @@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
> struct cscfg_regval_csdev *reg_csdev, u32 offset)
> {
> int err = -EINVAL, idx;
> - struct etmv4_config *drvcfg = &drvdata->config;
> + struct etmv4_config *drvcfg = &drvdata->active_config;
> u32 off_mask;
<...>
> struct device *etm_dev = &csdev->dev;
> struct csdev_access *csa = &csdev->access;
> @@ -616,19 +621,36 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
> static void etm4_enable_sysfs_smp_call(void *info)
> {
> struct etm4_enable_arg *arg = info;
> + struct etmv4_drvdata *drvdata;
> struct coresight_device *csdev;
>
> if (WARN_ON(!arg))
> return;
>
> - csdev = arg->drvdata->csdev;
> + drvdata = arg->drvdata;
> + csdev = drvdata->csdev;
> if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
> /* Someone is already using the tracer */
> arg->rc = -EBUSY;
> return;
> }
>
> - arg->rc = etm4_enable_hw(arg->drvdata);
> + drvdata->active_config = drvdata->config;
> +
> + if (arg->cfg_hash) {
> + arg->rc = cscfg_csdev_enable_active_config(csdev,
> + arg->cfg_hash,
> + arg->preset);
> + if (arg->rc)
we need reset the mode once enable failed before return.
coresight_set_mode(csdev, CS_MODE_DISABLED);
Thanks,
Jie
> + return;
> + }
> +
> + drvdata->trcid = arg->trace_id;
> +
> + /* Tracer will never be paused in sysfs mode */
> + drvdata->paused = false;
> +
> + arg->rc = etm4_enable_hw(drvdata);
>
> /* The tracer didn't start */
> if (arg->rc)
> @@ -670,7 +692,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
> int ctridx;
> int rselector;
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
>
> /* No point in trying if we don't have at least one counter */
> if (!caps->nr_cntr)
> @@ -754,7 +776,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
> int ret = 0;
> struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct perf_event_attr max_timestamp = {
> .ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
> };
> @@ -916,24 +938,18 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
>
> /* enable any config activated by configfs */
> cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
> - if (cfg_hash) {
> - ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
> - if (ret)
> - return ret;
> - }
>
> raw_spin_lock(&drvdata->spinlock);
>
> - drvdata->trcid = path->trace_id;
> -
> - /* Tracer will never be paused in sysfs mode */
> - drvdata->paused = false;
> -
> /*
> * Executing etm4_enable_hw on the cpu whose ETM is being enabled
> * ensures that register writes occur when cpu is powered.
> */
> arg.drvdata = drvdata;
> + arg.cfg_hash = cfg_hash;
> + arg.preset = preset;
> + arg.trace_id = path->trace_id;
> +
> ret = smp_call_function_single(drvdata->cpu,
> etm4_enable_sysfs_smp_call, &arg, 1);
> if (!ret)
> @@ -1034,7 +1050,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
> {
> u32 control;
> const struct etmv4_caps *caps = &drvdata->caps;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct coresight_device *csdev = drvdata->csdev;
> struct csdev_access *csa = &csdev->access;
> int i;
> @@ -1070,6 +1086,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
>
> etm4_disable_hw(drvdata);
>
> + cscfg_csdev_disable_active_config(drvdata->csdev);
> +
> coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
> }
>
> @@ -1130,9 +1148,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
> drvdata, 1);
>
> raw_spin_unlock(&drvdata->spinlock);
> -
> - cscfg_csdev_disable_active_config(csdev);
> -
> cpus_read_unlock();
>
> /*
> @@ -1375,6 +1390,7 @@ static void etm4_init_arch_data(void *info)
> struct etm4_init_arg *init_arg = info;
> struct etmv4_drvdata *drvdata;
> struct etmv4_caps *caps;
> + struct etmv4_config *config;
> struct csdev_access *csa;
> struct device *dev = init_arg->dev;
> int i;
> @@ -1382,6 +1398,7 @@ static void etm4_init_arch_data(void *info)
> drvdata = dev_get_drvdata(init_arg->dev);
> caps = &drvdata->caps;
> csa = init_arg->csa;
> + config = &drvdata->active_config;
>
> /*
> * If we are unable to detect the access mechanism,
> @@ -1442,7 +1459,7 @@ static void etm4_init_arch_data(void *info)
>
> /* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
> caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
> - drvdata->config.s_ex_level = caps->s_ex_level;
> + config->s_ex_level = caps->s_ex_level;
> /* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
> caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
> /*
> @@ -1687,7 +1704,7 @@ static void etm4_set_default(struct etmv4_config *config)
> static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
> {
> int nr_comparator, index = 0;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
>
> /*
> * nr_addr_cmp holds the number of comparator _pair_, so time 2
> @@ -1728,7 +1745,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
> {
> int i, comparator, ret = 0;
> u64 address;
> - struct etmv4_config *config = &drvdata->config;
> + struct etmv4_config *config = &drvdata->active_config;
> struct etm_filters *filters = event->hw.addr_filters;
>
> if (!filters)
> @@ -2250,7 +2267,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
> if (!desc.name)
> return -ENOMEM;
>
> - etm4_set_default(&drvdata->config);
> + etm4_set_default(&drvdata->active_config);
> + drvdata->config = drvdata->active_config;
>
> pdata = coresight_get_platform_data(dev);
> if (IS_ERR(pdata))
> diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
> index 3cc1ca76c933..b943c28c9c71 100644
> --- a/drivers/hwtracing/coresight/coresight-etm4x.h
> +++ b/drivers/hwtracing/coresight/coresight-etm4x.h
> @@ -1069,6 +1069,7 @@ struct etmv4_save_state {
> * allows tracing at all ELs. We don't want to compute this
> * at runtime, due to the additional setting of TRFCR_CX when
> * in EL2. Otherwise, 0.
> + * @active_config: structure holding current applied configuration parameters.
> * @config: structure holding configuration parameters.
> * @save_state: State to be preserved across power loss
> * @paused: Indicates if the trace unit is paused.
> @@ -1089,6 +1090,7 @@ struct etmv4_drvdata {
> bool os_unlock : 1;
> bool paused : 1;
> u64 trfcr;
> + struct etmv4_config active_config;
> struct etmv4_config config;
> struct etmv4_save_state *save_state;
> DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
^ permalink raw reply
* [PATCH net,v2 1/1] net: stmmac: Update default_an_inband before passing value to phylink_config
From: KhaiWenTan @ 2026-04-13 2:03 UTC (permalink / raw)
To: andrew+netdev, davem, edumazet, kuba, pabeni, mcoquelin.stm32,
alexandre.torgue, rmk+kernel, maxime.chevallier, ovidiu.panait.rb,
vladimir.oltean
Cc: netdev, linux-stm32, linux-arm-kernel, linux-kernel,
yoong.siang.song, hong.aun.looi, khai.wen.tan, KhaiWenTan
get_interfaces() will update both the plat->phy_interfaces and
mdio_bus_data->default_an_inband based on reading a SERDES register. As
get_interfaces() will be called after default_an_inband had already been
read, dwmac-intel regressed as a result with incorrect default_an_inband
value in phylink_config.
Therefore, we moved the priv->plat->get_interfaces() to be executed first
before assigning mdio_bus_data->default_an_inband to
config->default_an_inband to ensure default_an_inband is in correct value.
Fixes: d3836052fe09 ("net: stmmac: intel: convert speed_mode_2500() to get_interfaces()")
Signed-off-by: KhaiWenTan <khai.wen.tan@linux.intel.com>
---
v2:
- update commit message for better understanding (Russell King)
- corrected the blamed commit (Russell King)
v1: https://patchwork.kernel.org/project/netdevbpf/patch/20260410020735.327590-1-khai.wen.tan@linux.intel.com/
---
drivers/net/ethernet/stmicro/stmmac/stmmac_main.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index 13d3cac056be..c92054648a7e 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1345,10 +1345,6 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
priv->tx_lpi_clk_stop = priv->plat->flags &
STMMAC_FLAG_EN_TX_LPI_CLOCKGATING;
- mdio_bus_data = priv->plat->mdio_bus_data;
- if (mdio_bus_data)
- config->default_an_inband = mdio_bus_data->default_an_inband;
-
/* Get the PHY interface modes (at the PHY end of the link) that
* are supported by the platform.
*/
@@ -1356,6 +1352,10 @@ static int stmmac_phylink_setup(struct stmmac_priv *priv)
priv->plat->get_interfaces(priv, priv->plat->bsp_priv,
config->supported_interfaces);
+ mdio_bus_data = priv->plat->mdio_bus_data;
+ if (mdio_bus_data)
+ config->default_an_inband = mdio_bus_data->default_an_inband;
+
/* Set the platform/firmware specified interface mode if the
* supported interfaces have not already been provided using
* phy_interface as a last resort.
--
2.43.0
^ permalink raw reply related
* RE: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add global-regs and enable-dma properties
From: Ryan Chen @ 2026-04-13 1:57 UTC (permalink / raw)
To: Ryan Chen, Jeremy Kerr, Krzysztof Kozlowski
Cc: andriy.shevchenko@linux.intel.com, Andi Shyti, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Joel Stanley, Andrew Jeffery,
Benjamin Herrenschmidt, Philipp Zabel, linux-i2c@vger.kernel.org,
devicetree@vger.kernel.org, linux-arm-kernel@lists.infradead.org,
linux-aspeed@lists.ozlabs.org, linux-kernel@vger.kernel.org,
openbmc@lists.ozlabs.org
In-Reply-To: <TY2PPF5CB9A1BE64B7988CD85A7189164E1F253A@TY2PPF5CB9A1BE6.apcprd06.prod.outlook.com>
> > Subject: Re: [PATCH v28 2/4] dt-bindings: i2c: ast2600-i2c.yaml: Add
> > global-regs and enable-dma properties
> >
> > Hi Ryan,
> >
> > > > Sounds reasonable, but before you do so, how are you planning to
> > > > manage the allocation of DMA channels across multiple i2c peripherals?
> > > >
> > > The AST2600 I2C hardware has only one can use DMA at a time.
> > > To avoid the complexity of managing DMA channel contention, I plan
> > > to use buffer mode by default for all controllers, which still
> > > provides better performance than byte mode without requiring DMA
> > > channel
> > allocation.
> >
> > OK, but your wording there ("by default") implies that DMA is still
> > selectable for one controller peripheral. In which case: you still
> > have the problem of managing DMA channel contention, but now it's at
> runtime instead.
> >
> > So my question still stands: how are you planning to enforce that DMA
> > is only enabled for one controller?
> >
> > Or are you planning to disable I2C DMA entirely on AST2600?
> Yes, This is my intent to do.
> Disable I2C DMA entirely on AST2600.
> If I remove DMA, should can I keep byte and buffer for sysfs?
Hello Rob,
On the AST2600, we have a single-channel constraint, which makes DMA
support across all controllers difficult to implement without some kind of
predefined configuration. That would be a bit of a misuse of a DT property.
For future platforms such as the AST2700, DMA support should be much
more straightforward. DMA capability can be inferred from the compatible
string.
Unless there are any objections, I will rework this series to use buffer mode
only on the AST2600, and add AST2700 DMA support separately.
Ryan
^ permalink raw reply
* Re: [PATCH] mailbox: prefix new constants with MBOX_
From: Jassi Brar @ 2026-04-13 1:42 UTC (permalink / raw)
To: Wolfram Sang
Cc: linux-renesas-soc, Peter Chen, Fugang Duan,
CIX Linux Kernel Upstream Group, Frank Li, Sascha Hauer,
Pengutronix Kernel Team, Fabio Estevam, Matthias Brugger,
AngeloGioacchino Del Regno, Thierry Reding, Jonathan Hunter,
linux-arm-kernel, imx, linux-mediatek, linux-tegra
In-Reply-To: <20260410125105.39340-2-wsa+renesas@sang-engineering.com>
On Fri, Apr 10, 2026 at 7:51 AM Wolfram Sang
<wsa+renesas@sang-engineering.com> wrote:
>
> Commit 89e5d7d61600 ("mailbox: remove superfluous internal header")
> moved some constants to a public header but forgot to add a mailbox
> specific prefix. Add this now to prevent future collisions on a too
> generic naming.
>
> Link: https://sashiko.dev/#/patchset/20260327151112.5202-2-wsa%2Brenesas%40sang-engineering.com
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
> ---
>
> This patch improves the above mentioned commit which already sits in
> -next. It is not really a fix but it probably is still a good idea to
> apply it before rc1 to avoid confusion.
>
> drivers/mailbox/cix-mailbox.c | 2 +-
> drivers/mailbox/imx-mailbox.c | 2 +-
> drivers/mailbox/mailbox.c | 22 +++++++++++-----------
> drivers/mailbox/mtk-cmdq-mailbox.c | 2 +-
> drivers/mailbox/omap-mailbox.c | 2 +-
> drivers/mailbox/tegra-hsp.c | 2 +-
> include/linux/mailbox_controller.h | 6 +++---
> 7 files changed, 19 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/mailbox/cix-mailbox.c b/drivers/mailbox/cix-mailbox.c
> index 8cfaa91b75bd..43c76cdab24a 100644
> --- a/drivers/mailbox/cix-mailbox.c
> +++ b/drivers/mailbox/cix-mailbox.c
> @@ -413,7 +413,7 @@ static int cix_mbox_startup(struct mbox_chan *chan)
> switch (cp->type) {
> case CIX_MBOX_TYPE_DB:
> /* Overwrite txdone_method for DB channel */
> - chan->txdone_method = TXDONE_BY_ACK;
> + chan->txdone_method = MBOX_TXDONE_BY_ACK;
> fallthrough;
> case CIX_MBOX_TYPE_REG:
> if (priv->dir == CIX_MBOX_TX) {
> diff --git a/drivers/mailbox/imx-mailbox.c b/drivers/mailbox/imx-mailbox.c
> index 22331b579489..246a9a9e3952 100644
> --- a/drivers/mailbox/imx-mailbox.c
> +++ b/drivers/mailbox/imx-mailbox.c
> @@ -732,7 +732,7 @@ static struct mbox_chan * imx_mu_xlate(struct mbox_controller *mbox,
> p_chan = &mbox->chans[chan];
>
> if (type == IMX_MU_TYPE_TXDB_V2)
> - p_chan->txdone_method = TXDONE_BY_ACK;
> + p_chan->txdone_method = MBOX_TXDONE_BY_ACK;
>
> return p_chan;
> }
> diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
> index 138ffbcd4fde..30eafdf3a91e 100644
> --- a/drivers/mailbox/mailbox.c
> +++ b/drivers/mailbox/mailbox.c
> @@ -72,7 +72,7 @@ static void msg_submit(struct mbox_chan *chan)
> }
> }
>
> - if (!err && (chan->txdone_method & TXDONE_BY_POLL)) {
> + if (!err && (chan->txdone_method & MBOX_TXDONE_BY_POLL)) {
> /* kick start the timer immediately to avoid delays */
> scoped_guard(spinlock_irqsave, &chan->mbox->poll_hrt_lock)
> hrtimer_start(&chan->mbox->poll_hrt, 0, HRTIMER_MODE_REL);
> @@ -162,7 +162,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_received_data);
> */
> void mbox_chan_txdone(struct mbox_chan *chan, int r)
> {
> - if (unlikely(!(chan->txdone_method & TXDONE_BY_IRQ))) {
> + if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_IRQ))) {
> dev_err(chan->mbox->dev,
> "Controller can't run the TX ticker\n");
> return;
> @@ -183,7 +183,7 @@ EXPORT_SYMBOL_GPL(mbox_chan_txdone);
> */
> void mbox_client_txdone(struct mbox_chan *chan, int r)
> {
> - if (unlikely(!(chan->txdone_method & TXDONE_BY_ACK))) {
> + if (unlikely(!(chan->txdone_method & MBOX_TXDONE_BY_ACK))) {
> dev_err(chan->mbox->dev, "Client can't run the TX ticker\n");
> return;
> }
> @@ -344,8 +344,8 @@ static int __mbox_bind_client(struct mbox_chan *chan, struct mbox_client *cl)
> chan->cl = cl;
> init_completion(&chan->tx_complete);
>
> - if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
> - chan->txdone_method = TXDONE_BY_ACK;
> + if (chan->txdone_method == MBOX_TXDONE_BY_POLL && cl->knows_txdone)
> + chan->txdone_method = MBOX_TXDONE_BY_ACK;
> }
>
> if (chan->mbox->ops->startup) {
> @@ -499,8 +499,8 @@ void mbox_free_channel(struct mbox_chan *chan)
> scoped_guard(spinlock_irqsave, &chan->lock) {
> chan->cl = NULL;
> chan->active_req = MBOX_NO_MSG;
> - if (chan->txdone_method == TXDONE_BY_ACK)
> - chan->txdone_method = TXDONE_BY_POLL;
> + if (chan->txdone_method == MBOX_TXDONE_BY_ACK)
> + chan->txdone_method = MBOX_TXDONE_BY_POLL;
> }
>
> module_put(chan->mbox->dev->driver->owner);
> @@ -531,13 +531,13 @@ int mbox_controller_register(struct mbox_controller *mbox)
> return -EINVAL;
>
> if (mbox->txdone_irq)
> - txdone = TXDONE_BY_IRQ;
> + txdone = MBOX_TXDONE_BY_IRQ;
> else if (mbox->txdone_poll)
> - txdone = TXDONE_BY_POLL;
> + txdone = MBOX_TXDONE_BY_POLL;
> else /* It has to be ACK then */
> - txdone = TXDONE_BY_ACK;
> + txdone = MBOX_TXDONE_BY_ACK;
>
> - if (txdone == TXDONE_BY_POLL) {
> + if (txdone == MBOX_TXDONE_BY_POLL) {
>
> if (!mbox->ops->last_tx_done) {
> dev_err(mbox->dev, "last_tx_done method is absent\n");
> diff --git a/drivers/mailbox/mtk-cmdq-mailbox.c b/drivers/mailbox/mtk-cmdq-mailbox.c
> index 547a10a8fad3..e523c84b4808 100644
> --- a/drivers/mailbox/mtk-cmdq-mailbox.c
> +++ b/drivers/mailbox/mtk-cmdq-mailbox.c
> @@ -728,7 +728,7 @@ static int cmdq_probe(struct platform_device *pdev)
> cmdq->mbox.ops = &cmdq_mbox_chan_ops;
> cmdq->mbox.of_xlate = cmdq_xlate;
>
> - /* make use of TXDONE_BY_ACK */
> + /* make use of MBOX_TXDONE_BY_ACK */
> cmdq->mbox.txdone_irq = false;
> cmdq->mbox.txdone_poll = false;
>
> diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
> index 5772c6b9886a..535ca8020877 100644
> --- a/drivers/mailbox/omap-mailbox.c
> +++ b/drivers/mailbox/omap-mailbox.c
> @@ -238,7 +238,7 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
> }
>
> if (mbox->send_no_irq)
> - mbox->chan->txdone_method = TXDONE_BY_ACK;
> + mbox->chan->txdone_method = MBOX_TXDONE_BY_ACK;
>
> omap_mbox_enable_irq(mbox, IRQ_RX);
>
> diff --git a/drivers/mailbox/tegra-hsp.c b/drivers/mailbox/tegra-hsp.c
> index 7b1e1b83ea29..500fa77c7d53 100644
> --- a/drivers/mailbox/tegra-hsp.c
> +++ b/drivers/mailbox/tegra-hsp.c
> @@ -514,7 +514,7 @@ static int tegra_hsp_mailbox_startup(struct mbox_chan *chan)
> struct tegra_hsp *hsp = mb->channel.hsp;
> unsigned long flags;
>
> - chan->txdone_method = TXDONE_BY_IRQ;
> + chan->txdone_method = MBOX_TXDONE_BY_IRQ;
>
> /*
> * Shared mailboxes start out as consumers by default. FULL and EMPTY
> diff --git a/include/linux/mailbox_controller.h b/include/linux/mailbox_controller.h
> index e3896b08f22e..a49ee687d4cf 100644
> --- a/include/linux/mailbox_controller.h
> +++ b/include/linux/mailbox_controller.h
> @@ -15,9 +15,9 @@ struct mbox_chan;
> /* Sentinel value distinguishing "no active request" from "NULL message data" */
> #define MBOX_NO_MSG ((void *)-1)
>
> -#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
> -#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
> -#define TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */
> +#define MBOX_TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
> +#define MBOX_TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
> +#define MBOX_TXDONE_BY_ACK BIT(2) /* S/W ACK received by Client ticks the TX */
>
> /**
> * struct mbox_chan_ops - methods to control mailbox channels
> --
> 2.51.0
>
Applied to mailbox/for-next
Thanks
Jassi
^ permalink raw reply
* Re: [PATCH net-next] net: stmmac: enable RPS and RBU interrupts
From: Sam Edwards @ 2026-04-13 1:42 UTC (permalink / raw)
To: Russell King (Oracle)
Cc: Maxime Chevallier, Andrew Lunn, Alexandre Torgue, Andrew Lunn,
David S. Miller, Eric Dumazet, Jakub Kicinski, linux-arm-kernel,
linux-stm32, netdev, Paolo Abeni
In-Reply-To: <aduq7Lvkfrz971Rb@shell.armlinux.org.uk>
On Sun, Apr 12, 2026 at 7:23 AM Russell King (Oracle)
<linux@armlinux.org.uk> wrote:
> As the dwmac 5.0 core receive path seems to lock up after the first
> RBU, I never see more than one of those at a time.
>
> Right now, I consider this pretty much unsolvable - I've spent quite
> some time looking at it and trying various approaches, nothing seems
> to fix it. However, adding dma_rmb() in the descriptor cleanup/refill
> paths does seem to improve the situation a little with the 480Mbps
> case, because I think it means that we're reading the descriptors in
> a more timely manner after the hardware has updated them.
Hey Russell,
I'd like to repro this but I currently can't boot net-next. My issue
is the same as [1], and the patch to fix it [2] isn't yet committed
anywhere apparently.
This prevents my Jetson Xavier NX from starting at all (and after
enough attempts, corrupts eMMC); I'm surprised you're not suffering
the same effects. But because this bug lives in the IOMMU subsystem
(and it has somewhat inconsistent effects), perhaps this is just a
different way it manifests? Could you confirm whether your dwmac hang
happens with IOMMU disabled, and/or with [1] reverted or [2] applied?
I'm using a defconfig build and a fairly minimal cmdline (just
console=, root=, and rootwait).
Cheers,
Sam
[1] https://lore.kernel.org/all/8800a38b-8515-4bbe-af15-0dae81274bf7@nvidia.com/
[2] https://lore.kernel.org/all/0-v1-664d3acaabb9+78b-iommu_gather_always_jgg@nvidia.com/
^ permalink raw reply
* Re: [PATCH v2 3/4] KVM: arm64: sefltests: Add basic NV selftest
From: Itaru Kitayama @ 2026-04-12 23:19 UTC (permalink / raw)
To: Wei-Lin Chang
Cc: linux-arm-kernel, kvmarm, kvm, linux-kselftest, linux-kernel,
Marc Zyngier, Oliver Upton, Joey Gouly, Suzuki K Poulose,
Zenghui Yu, Catalin Marinas, Will Deacon, Paolo Bonzini,
Shuah Khan
In-Reply-To: <20260412142216.3806482-4-weilin.chang@arm.com>
On Sun, Apr 12, 2026 at 03:22:15PM +0100, Wei-Lin Chang wrote:
> This selftest simply starts an L1, which starts its own guest (L2). L2
> runs without stage-1 and 2 translations, it calls an HVC to jump back
> to L1.
How do you disable both the nested guest (L2)'s MMU and stage 2
translations?
Itaru.
>
> Signed-off-by: Wei-Lin Chang <weilin.chang@arm.com>
> ---
> tools/testing/selftests/kvm/Makefile.kvm | 1 +
> .../selftests/kvm/arm64/hello_nested.c | 103 ++++++++++++++++++
> 2 files changed, 104 insertions(+)
> create mode 100644 tools/testing/selftests/kvm/arm64/hello_nested.c
>
> diff --git a/tools/testing/selftests/kvm/Makefile.kvm b/tools/testing/selftests/kvm/Makefile.kvm
> index 3dc3e39f7025..e8c108e0c487 100644
> --- a/tools/testing/selftests/kvm/Makefile.kvm
> +++ b/tools/testing/selftests/kvm/Makefile.kvm
> @@ -168,6 +168,7 @@ TEST_GEN_PROGS_arm64 += arm64/arch_timer_edge_cases
> TEST_GEN_PROGS_arm64 += arm64/at
> TEST_GEN_PROGS_arm64 += arm64/debug-exceptions
> TEST_GEN_PROGS_arm64 += arm64/hello_el2
> +TEST_GEN_PROGS_arm64 += arm64/hello_nested
> TEST_GEN_PROGS_arm64 += arm64/host_sve
> TEST_GEN_PROGS_arm64 += arm64/hypercalls
> TEST_GEN_PROGS_arm64 += arm64/external_aborts
> diff --git a/tools/testing/selftests/kvm/arm64/hello_nested.c b/tools/testing/selftests/kvm/arm64/hello_nested.c
> new file mode 100644
> index 000000000000..97387e4697b3
> --- /dev/null
> +++ b/tools/testing/selftests/kvm/arm64/hello_nested.c
> @@ -0,0 +1,103 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * hello_nested - Go from vEL2 to EL1 then back
> + */
> +
> +#include "nested.h"
> +#include "processor.h"
> +#include "test_util.h"
> +#include "ucall.h"
> +
> +#define XLATE2GPA (0xABCD)
> +#define L2STACKSZ (0x100)
> +
> +/*
> + * TPIDR_EL2 is used to store vcpu id, so save and restore it.
> + */
> +static vm_paddr_t ucall_translate_to_gpa(void *gva)
> +{
> + vm_paddr_t gpa;
> + u64 vcpu_id = read_sysreg(tpidr_el2);
> +
> + GUEST_SYNC2(XLATE2GPA, gva);
> +
> + /* get the result from userspace */
> + gpa = read_sysreg(tpidr_el2);
> +
> + write_sysreg(vcpu_id, tpidr_el2);
> +
> + return gpa;
> +}
> +
> +static void l2_guest_code(void)
> +{
> + do_hvc();
> +}
> +
> +static void guest_code(void)
> +{
> + struct vcpu vcpu;
> + struct hyp_data hyp_data;
> + int ret;
> + vm_paddr_t l2_pc, l2_stack_top;
> + /* force 16-byte alignment for the stack pointer */
> + u8 l2_stack[L2STACKSZ] __attribute__((aligned(16)));
> +
> + GUEST_ASSERT_EQ(get_current_el(), 2);
> + GUEST_PRINTF("vEL2 entry\n");
> +
> + l2_pc = ucall_translate_to_gpa(l2_guest_code);
> + l2_stack_top = ucall_translate_to_gpa(&l2_stack[L2STACKSZ]);
> +
> + init_vcpu(&vcpu, l2_pc, l2_stack_top);
> + prepare_hyp();
> +
> + ret = run_l2(&vcpu, &hyp_data);
> + GUEST_ASSERT_EQ(ret, ARM_EXCEPTION_TRAP);
> + GUEST_DONE();
> +}
> +
> +int main(void)
> +{
> + struct kvm_vcpu_init init;
> + struct kvm_vcpu *vcpu;
> + struct kvm_vm *vm;
> + struct ucall uc;
> + vm_paddr_t gpa;
> +
> + TEST_REQUIRE(kvm_check_cap(KVM_CAP_ARM_EL2));
> + vm = vm_create(1);
> +
> + kvm_get_default_vcpu_target(vm, &init);
> + init.features[0] |= BIT(KVM_ARM_VCPU_HAS_EL2);
> + vcpu = aarch64_vcpu_add(vm, 0, &init, guest_code);
> + kvm_arch_vm_finalize_vcpus(vm);
> +
> + while (true) {
> + vcpu_run(vcpu);
> +
> + switch (get_ucall(vcpu, &uc)) {
> + case UCALL_SYNC:
> + if (uc.args[0] == XLATE2GPA) {
> + gpa = addr_gva2gpa(vm, (vm_vaddr_t)uc.args[1]);
> + vcpu_set_reg(vcpu, KVM_ARM64_SYS_REG(SYS_TPIDR_EL2), gpa);
> + }
> + break;
> + case UCALL_PRINTF:
> + pr_info("%s", uc.buffer);
> + break;
> + case UCALL_DONE:
> + pr_info("DONE!\n");
> + goto end;
> + case UCALL_ABORT:
> + REPORT_GUEST_ASSERT(uc);
> + fallthrough;
> + default:
> + TEST_FAIL("Unhandled ucall: %ld\n", uc.cmd);
> + }
> + }
> +
> +end:
> + kvm_vm_free(vm);
> + return 0;
> +}
> --
> 2.43.0
>
^ permalink raw reply
* Re: [PATCH net v2] net: ethernet: mtk_eth_soc: initialize PPE per-tag-layer MTU registers
From: patchwork-bot+netdevbpf @ 2026-04-12 22:30 UTC (permalink / raw)
To: Daniel Golle
Cc: nbd, lorenzo, andrew+netdev, davem, edumazet, kuba, pabeni,
matthias.bgg, angelogioacchino.delregno, pablo, netdev,
linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <ec995ab8ce8be423267a1cc093147a74d2eb9d82.1775789829.git.daniel@makrotopia.org>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Fri, 10 Apr 2026 03:57:52 +0100 you wrote:
> The PPE enforces output frame size limits via per-tag-layer VLAN_MTU
> registers that the driver never initializes. The hardware defaults do
> not account for PPPoE overhead, causing the PPE to punt encapsulated
> frames back to the CPU instead of forwarding them.
>
> Initialize the registers at PPE start and on MTU changes using the
> maximum GMAC MTU. This is a conservative approximation -- the actual
> per-PPE requirement depends on egress path, but using the global
> maximum ensures the limits are never too small.
>
> [...]
Here is the summary with links:
- [net,v2] net: ethernet: mtk_eth_soc: initialize PPE per-tag-layer MTU registers
https://git.kernel.org/netdev/net/c/2dddb34dd0d0
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2 0/3] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
From: patchwork-bot+netdevbpf @ 2026-04-12 21:00 UTC (permalink / raw)
To: Josua Mayer
Cc: robh, krzk+dt, conor+dt, shawnguo, Frank.Li, s.hauer, kernel,
festevam, andrew, olteanv, davem, edumazet, kuba, pabeni,
yazan.shhady, mikhail.anikin, ada, devicetree, linux-kernel, imx,
linux-arm-kernel, vladimir.oltean, conor.dooley, krzk, netdev,
krzysztof.kozlowski
In-Reply-To: <20260409-imx8dxl-sr-som-v2-0-83ff20629ba0@solid-run.com>
Hello:
This series was applied to netdev/net-next.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Thu, 09 Apr 2026 14:34:32 +0200 you wrote:
> Add bindings and description for SolidRUn i.MX8DXL based SoM and
> HummingBoard Telematics.
>
> Modify SJA1110 Ethernet Switch bindings to allow SPI Mode 0.
>
> This patch-set is based on v7.0-rc2, because rc1 was experiencing
> deadlocks with imx8qxp clock driver.
>
> [...]
Here is the summary with links:
- [v2,1/3] dt-bindings: net: dsa: nxp,sja1105: make spi-cpol optional for sja1110
https://git.kernel.org/netdev/net-next/c/600f01dc4bd0
- [v2,2/3] dt-bindings: arm: fsl: Add SolidRun i.MX8DXL SoM and HummingBoard
(no matching commit)
- [v2,3/3] arm64: dts: imx8dxl: Add SolidRun SoM and HummingBoard
(no matching commit)
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [RFC net-next v5 0/3] Add RSS and LRO support
From: Frank Wunderlich @ 2026-04-12 19:24 UTC (permalink / raw)
To: Jakub Kicinski, Frank Wunderlich
Cc: linux, nbd, sean.wang, lorenzo, andrew+netdev, davem, edumazet,
pabeni, matthias.bgg, angelogioacchino.delregno, linux, daniel,
netdev, linux-kernel, linux-arm-kernel, linux-mediatek
In-Reply-To: <20260412075402.2eda04d3@kernel.org>
Am 12. April 2026 um 16:54 schrieb "Jakub Kicinski" <kuba@kernel.org>:
>
> On Sun, 12 Apr 2026 11:57:47 +0000 Frank Wunderlich wrote:
>
> >
> > some time has passed without a single comment, so i just send a friendly reminder ;)
> >
> You have a lot of people in the To:
> Could you clarify who you expect to action these patches?
> Patches are an RFC and I suppose ain't nobody got much comments?
Hi,
imho 11 people are in "To" is not much, but i was told that no comments can mean
"OK so far" so i will send v6 soon rebased on current net-next.
regards Frank
^ permalink raw reply
* Re: [PATCH v3 0/8] perf libunwind multiple remote support
From: Arnaldo Carvalho de Melo @ 2026-04-12 19:18 UTC (permalink / raw)
To: Ian Rogers
Cc: 9erthalion6, adrian.hunter, alex, alexander.shishkin,
andrew.jones, aou, atrajeev, blakejones, ctshao, dapeng1.mi,
howardchu95, james.clark, john.g.garry, jolsa, leo.yan,
libunwind-devel, linux-arm-kernel, linux-kernel, linux-perf-users,
linux-riscv, mingo, namhyung, palmer, peterz, pjw, shimin.guo,
tglozar, tmricht, will, yuzhuo
In-Reply-To: <CAP-5=fUz60Guq_gVV6wb_FfwhPs-fUN+PAbB3rQn3pycXbF3DA@mail.gmail.com>
On Fri, Apr 10, 2026 at 06:04:57PM -0700, Ian Rogers wrote:
> On Fri, Apr 3, 2026 at 10:40 PM Ian Rogers <irogers@google.com> wrote:
> >
> > Fix the libunwind build for when libdw and libunwind are feature
> > detected, currently failing with a duplicate symbol.
> >
> > Refactor the libunwind support so that whenever a remote target is
> > available, perf functions using the ELF machine can use that remote
> > target regardless of what the host/local machine is. Migrate existing
> > libunwind supported architectures like powerpc, arm64 and loongarch so
> > that they can work in a cross-architecture way. Add support for
> > RISC-V. Make the code more regular in function names, etc. and avoid
> > including a C-file. This increases the lines of code. It is similar in
> > style to the unwind-libdw implementation. It is hoped that the more
> > uniform nature of the code with help with refactoring the perf
> > registers for SIMD/APX support.
> >
> > Aside from local host testing these patches are under tested, in part
> > as I'm failing to see how to build libunwind with support for multiple
> > remote targets. Please could I get help in testing.
> >
> > v3: Minor whitespace clean up and warn when a dynamic choice of libdw
> > or libunwind is selected for unwinding and support is missing (Arnaldo).
>
> Hi Arnaldo,
>
> anything else outstanding from this series?
It is not applying, I did an attempt to refresh it but stomped at 7/8
⬢ [acme@toolbx perf-tools-next]$ patch -p1 < ./v3_20260403_irogers_perf_libunwind_multiple_remote_support.mbx
patching file tools/perf/util/Build
patching file tools/perf/util/libunwind-arch/libunwind-arch.c
patching file tools/perf/util/libunwind-arch/libunwind-arch.h
patching file tools/perf/util/libunwind-arch/libunwind-arm.c
patching file tools/perf/util/libunwind-arch/libunwind-arm64.c
patching file tools/perf/util/libunwind-arch/libunwind-i386.c
patching file tools/perf/util/libunwind-arch/libunwind-loongarch.c
patching file tools/perf/util/libunwind-arch/libunwind-mips.c
patching file tools/perf/util/libunwind-arch/libunwind-ppc32.c
patching file tools/perf/util/libunwind-arch/libunwind-ppc64.c
patching file tools/perf/util/libunwind-arch/libunwind-s390.c
patching file tools/perf/util/libunwind-arch/libunwind-x86_64.c
patching file tools/perf/util/libunwind/arm64.c
patching file tools/perf/util/libunwind/x86_32.c
patching file tools/perf/util/maps.c
patching file tools/perf/util/maps.h
patching file tools/perf/util/unwind-libunwind-local.c
Reversed (or previously applied) patch detected! Assume -R? [n] ^C
⬢ [acme@toolbx perf-tools-next]$
Can you please take a look and maybe resubmit it so that Sashiko can
have a look at it?
Two other patches had to be refreshed before 7/8.
- Arnaldo
^ permalink raw reply
* Re: [PATCH v6 0/4] perf arm_spe: Extend SIMD operations
From: Namhyung Kim @ 2026-04-12 19:11 UTC (permalink / raw)
To: Arnaldo Carvalho de Melo, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Mark Rutland, Leo Yan
Cc: Arnaldo Carvalho de Melo, linux-perf-users, linux-arm-kernel
In-Reply-To: <20260410-perf_support_arm_spev1-3-v6-0-3c6f2dfe2cd3@arm.com>
On Fri, 10 Apr 2026 08:36:57 +0100, Leo Yan wrote:
> This series extends SIMD flag for Arm SPE and updated the document.
>
> This version is rebased onto the latest perf-tools-next branch.
>
>
Applied to perf-tools-next, thanks!
Best regards,
Namhyung
^ permalink raw reply
* Re: [PATCH 0/3] firmware: arm_scmi: Miscellaneous improvements
From: Cristian Marussi @ 2026-04-12 18:44 UTC (permalink / raw)
To: Geert Uytterhoeven
Cc: Sudeep Holla, Cristian Marussi, Marek Vasut, arm-scmi,
linux-arm-kernel, linux-renesas-soc
In-Reply-To: <cover.1775205358.git.geert+renesas@glider.be>
On Fri, Apr 03, 2026 at 10:41:28AM +0200, Geert Uytterhoeven wrote:
> Hi all,
Hi Geert,
thanks for this, first of all.
I was a bit off the keyboard so the delay in my answer.
I will get back at this SCMI/Clocks/Quirks matters in the next few weeks
targeting next rc1-ish...
In a nutshell I was thinking to proceed roughly as follows:
- respinning a V3 of my original Clock Rates series WITH the addtion
of your previous fixes series on top (or merged into) BUT DROPPING
from my original series the patch that triggered a lot of FW panics
in the wild due to out of spec FWs. (Harden Clock protocol initialization)
- spinning another NEW series on top of this 'Miscellaneous improvement'
series of yours, since I want to add, on top of this rework of yours, the
capability for the Quirk framework to match the same quirk definition
(static key) against multiple vendors/subvendors/impl....since, as you may
have noticed :P, I broke a number of boards recently with just one fix
kernel side BUT all of these issues can be really quirked using some
common identical quirk snippet to match against all the needed vendors
(rockchip/nxp/renesas as of now)
...I have some ugly working hack with which I am experimenting on this
quirk matching evolution...
On top of all of this I would then reapply the FW-breaking fix AND all
the quirks we determine as needed (possibly N matching M vendoes) and
test as much as possible pushing into for-next...
Then we'll see what Sudeep thinks about all of this, of course.
Thoughts ? Any feedback welcome.
Thanks,
Cristian
^ permalink raw reply
* Re: [PATCH net] net: airoha: Add missing RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue()
From: patchwork-bot+netdevbpf @ 2026-04-12 18:40 UTC (permalink / raw)
To: Lorenzo Bianconi
Cc: andrew+netdev, davem, edumazet, kuba, pabeni, linux-arm-kernel,
linux-mediatek, netdev
In-Reply-To: <20260408-airoha-cpu-idx-airoha_qdma_cleanup_rx_queue-v1-1-8efa64844308@kernel.org>
Hello:
This patch was applied to netdev/net.git (main)
by Jakub Kicinski <kuba@kernel.org>:
On Wed, 08 Apr 2026 20:26:56 +0200 you wrote:
> When the descriptor index written in REG_RX_CPU_IDX() is equal to the one
> stored in REG_RX_DMA_IDX(), the hw will stop since the QDMA RX ring is
> empty.
> Add missing REG_RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue
> routine during QDMA RX ring cleanup.
>
> Fixes: 514aac359987 ("net: airoha: Add missing cleanup bits in airoha_qdma_cleanup_rx_queue()")
> Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
>
> [...]
Here is the summary with links:
- [net] net: airoha: Add missing RX_CPU_IDX() configuration in airoha_qdma_cleanup_rx_queue()
https://git.kernel.org/netdev/net/c/656121b15503
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
^ permalink raw reply
* Re: [PATCH v2] ASoC: dt-bindings: rockchip: convert rk3399-gru-sound to DT Schema
From: Mark Brown @ 2026-04-12 16:24 UTC (permalink / raw)
To: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Heiko Stuebner, Anushka Badhe
Cc: linux-sound, devicetree, linux-arm-kernel, linux-rockchip,
linux-kernel
In-Reply-To: <20260410055532.60868-1-anushkabadhe@gmail.com>
On Fri, 10 Apr 2026 11:25:32 +0530, Anushka Badhe wrote:
> ASoC: dt-bindings: rockchip: convert rk3399-gru-sound to DT Schema
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-7.1
Thanks!
[1/1] ASoC: dt-bindings: rockchip: convert rk3399-gru-sound to DT Schema
https://git.kernel.org/broonie/sound/c/115e7d764dad
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
^ permalink raw reply
* [PATCH v3 5/5] coresight: etm3x: fix inconsistencies with sysfs configration
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
In-Reply-To: <20260412175506.412301-1-yeoreum.yun@arm.com>
The current ETM3x configuration via sysfs can lead to the following
inconsistencies:
- If a configuration is modified via sysfs while a perf session is
active, the running configuration may differ between before
a sched-out and after a subsequent sched-in.
To resolve these inconsistencies, the configuration should be separated into:
- active_config, which is applied configuration for the current session
- config, which stores the settings configured via sysfs.
and apply configuration after taking a mode.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm.h | 2 ++
.../coresight/coresight-etm3x-core.c | 20 ++++++++++++-------
2 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 2ffe477c0c12..85ede334c9d0 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -243,6 +243,7 @@ struct etm_config {
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
* @traceid: value of the current ID for this component.
+ * @active_config: structure holding current running configuration parameters.
* @config: structure holding configuration parameters.
*/
struct etm_drvdata {
@@ -258,6 +259,7 @@ struct etm_drvdata {
bool boot_enable;
bool os_unlock;
u32 traceid;
+ struct etm_config active_config;
struct etm_config config;
};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index f669eeeef538..efed6b8a7d72 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -309,7 +309,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
struct perf_event *event)
{
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct perf_event_attr *attr = &event->attr;
u8 ts_level;
@@ -368,7 +368,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
int i, rc;
u32 etmcr;
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
CS_UNLOCK(drvdata->csa.base);
@@ -442,24 +442,30 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
struct etm_enable_arg {
struct etm_drvdata *drvdata;
+ u32 traceid;
int rc;
};
static void etm_enable_sysfs_smp_call(void *info)
{
struct etm_enable_arg *arg = info;
+ struct etm_drvdata *drvdata;
struct coresight_device *csdev;
if (WARN_ON(!arg))
return;
- csdev = arg->drvdata->csdev;
+ drvdata = arg->drvdata;
+ csdev = drvdata->csdev;
if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
/* Someone is already using the tracer */
arg->rc = -EBUSY;
return;
}
+ drvdata->active_config = drvdata->config;
+ drvdata->traceid = arg->traceid;
+
arg->rc = etm_enable_hw(arg->drvdata);
/* The tracer didn't start */
@@ -514,14 +520,13 @@ static int etm_enable_sysfs(struct coresight_device *csdev, struct coresight_pat
spin_lock(&drvdata->spinlock);
- drvdata->traceid = path->trace_id;
-
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place on the local CPU during bring up.
*/
if (cpu_online(drvdata->cpu)) {
arg.drvdata = drvdata;
+ arg.traceid = path->trace_id;
ret = smp_call_function_single(drvdata->cpu,
etm_enable_sysfs_smp_call, &arg, 1);
if (!ret)
@@ -565,7 +570,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
{
int i;
const struct etm_caps *caps = &drvdata->caps;
- struct etm_config *config = &drvdata->config;
+ struct etm_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
CS_UNLOCK(drvdata->csa.base);
@@ -884,7 +889,8 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
if (etm_arch_supported(drvdata->arch) == false)
return -EINVAL;
- etm_set_default(&drvdata->config);
+ etm_set_default(&drvdata->active_config);
+ drvdata->config = drvdata->active_config;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH v3 3/5] coresight: etm4x: fix inconsistencies with sysfs configration
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
In-Reply-To: <20260412175506.412301-1-yeoreum.yun@arm.com>
The current ETM4x configuration via sysfs can lead to the following
inconsistencies:
- If a configuration is modified via sysfs while a perf session is
active, the running configuration may differ between before
a sched-out and after a subsequent sched-in.
- If a perf session and sysfs session tries to enable concurrently,
configuration from configfs could be corrupted.
- There is chance to corrupt drvdata->config if perf session tries
to enabled among handling cscfg_csdev_disable_active_config()
in etm4_disable_sysfs().
To resolve these inconsistencies, the configuration should be separated into:
- active_config, which is applied configuration for the current session
- config, which stores the settings configured via sysfs.
and apply configuration from configfs after taking a mode.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../hwtracing/coresight/coresight-etm4x-cfg.c | 2 +-
.../coresight/coresight-etm4x-core.c | 74 ++++++++++++-------
drivers/hwtracing/coresight/coresight-etm4x.h | 2 +
3 files changed, 49 insertions(+), 29 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index d14d7c8a23e5..0553771d04e7 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -47,7 +47,7 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
struct cscfg_regval_csdev *reg_csdev, u32 offset)
{
int err = -EINVAL, idx;
- struct etmv4_config *drvcfg = &drvdata->config;
+ struct etmv4_config *drvcfg = &drvdata->active_config;
u32 off_mask;
if (((offset >= TRCEVENTCTL0R) && (offset <= TRCVIPCSSCTLR)) ||
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 8ebfd3924143..ba1935decff1 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -245,6 +245,9 @@ void etm4_release_trace_id(struct etmv4_drvdata *drvdata)
struct etm4_enable_arg {
struct etmv4_drvdata *drvdata;
+ unsigned long cfg_hash;
+ int preset;
+ u8 trace_id;
int rc;
};
@@ -270,10 +273,11 @@ static void etm4x_prohibit_trace(struct etmv4_drvdata *drvdata)
static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
{
u64 trfcr = drvdata->trfcr;
+ struct etmv4_config *config = &drvdata->active_config;
- if (drvdata->config.mode & ETM_MODE_EXCL_KERN)
+ if (config->mode & ETM_MODE_EXCL_KERN)
trfcr &= ~TRFCR_EL1_ExTRE;
- if (drvdata->config.mode & ETM_MODE_EXCL_USER)
+ if (config->mode & ETM_MODE_EXCL_USER)
trfcr &= ~TRFCR_EL1_E0TRE;
return trfcr;
@@ -281,7 +285,7 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
/*
* etm4x_allow_trace - Allow CPU tracing in the respective ELs,
- * as configured by the drvdata->config.mode for the current
+ * as configured by the drvdata->active_config.mode for the current
* session. Even though we have TRCVICTLR bits to filter the
* trace in the ELs, it doesn't prevent the ETM from generating
* a packet (e.g, TraceInfo) that might contain the addresses from
@@ -292,12 +296,13 @@ static u64 etm4x_get_kern_user_filter(struct etmv4_drvdata *drvdata)
static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
{
u64 trfcr, guest_trfcr;
+ struct etmv4_config *config = &drvdata->active_config;
/* If the CPU doesn't support FEAT_TRF, nothing to do */
if (!drvdata->trfcr)
return;
- if (drvdata->config.mode & ETM_MODE_EXCL_HOST)
+ if (config->mode & ETM_MODE_EXCL_HOST)
trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
else
trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -305,7 +310,7 @@ static void etm4x_allow_trace(struct etmv4_drvdata *drvdata)
write_trfcr(trfcr);
/* Set filters for guests and pass to KVM */
- if (drvdata->config.mode & ETM_MODE_EXCL_GUEST)
+ if (config->mode & ETM_MODE_EXCL_GUEST)
guest_trfcr = drvdata->trfcr & ~(TRFCR_EL1_ExTRE | TRFCR_EL1_E0TRE);
else
guest_trfcr = etm4x_get_kern_user_filter(drvdata);
@@ -499,7 +504,7 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
struct device *etm_dev = &csdev->dev;
struct csdev_access *csa = &csdev->access;
@@ -616,19 +621,36 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
static void etm4_enable_sysfs_smp_call(void *info)
{
struct etm4_enable_arg *arg = info;
+ struct etmv4_drvdata *drvdata;
struct coresight_device *csdev;
if (WARN_ON(!arg))
return;
- csdev = arg->drvdata->csdev;
+ drvdata = arg->drvdata;
+ csdev = drvdata->csdev;
if (!coresight_take_mode(csdev, CS_MODE_SYSFS)) {
/* Someone is already using the tracer */
arg->rc = -EBUSY;
return;
}
- arg->rc = etm4_enable_hw(arg->drvdata);
+ drvdata->active_config = drvdata->config;
+
+ if (arg->cfg_hash) {
+ arg->rc = cscfg_csdev_enable_active_config(csdev,
+ arg->cfg_hash,
+ arg->preset);
+ if (arg->rc)
+ return;
+ }
+
+ drvdata->trcid = arg->trace_id;
+
+ /* Tracer will never be paused in sysfs mode */
+ drvdata->paused = false;
+
+ arg->rc = etm4_enable_hw(drvdata);
/* The tracer didn't start */
if (arg->rc)
@@ -670,7 +692,7 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
int ctridx;
int rselector;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
/* No point in trying if we don't have at least one counter */
if (!caps->nr_cntr)
@@ -754,7 +776,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct perf_event_attr max_timestamp = {
.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
};
@@ -916,24 +938,18 @@ static int etm4_enable_sysfs(struct coresight_device *csdev, struct coresight_pa
/* enable any config activated by configfs */
cscfg_config_sysfs_get_active_cfg(&cfg_hash, &preset);
- if (cfg_hash) {
- ret = cscfg_csdev_enable_active_config(csdev, cfg_hash, preset);
- if (ret)
- return ret;
- }
raw_spin_lock(&drvdata->spinlock);
- drvdata->trcid = path->trace_id;
-
- /* Tracer will never be paused in sysfs mode */
- drvdata->paused = false;
-
/*
* Executing etm4_enable_hw on the cpu whose ETM is being enabled
* ensures that register writes occur when cpu is powered.
*/
arg.drvdata = drvdata;
+ arg.cfg_hash = cfg_hash;
+ arg.preset = preset;
+ arg.trace_id = path->trace_id;
+
ret = smp_call_function_single(drvdata->cpu,
etm4_enable_sysfs_smp_call, &arg, 1);
if (!ret)
@@ -1034,7 +1050,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
{
u32 control;
const struct etmv4_caps *caps = &drvdata->caps;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa = &csdev->access;
int i;
@@ -1070,6 +1086,8 @@ static void etm4_disable_sysfs_smp_call(void *info)
etm4_disable_hw(drvdata);
+ cscfg_csdev_disable_active_config(drvdata->csdev);
+
coresight_set_mode(drvdata->csdev, CS_MODE_DISABLED);
}
@@ -1130,9 +1148,6 @@ static void etm4_disable_sysfs(struct coresight_device *csdev)
drvdata, 1);
raw_spin_unlock(&drvdata->spinlock);
-
- cscfg_csdev_disable_active_config(csdev);
-
cpus_read_unlock();
/*
@@ -1375,6 +1390,7 @@ static void etm4_init_arch_data(void *info)
struct etm4_init_arg *init_arg = info;
struct etmv4_drvdata *drvdata;
struct etmv4_caps *caps;
+ struct etmv4_config *config;
struct csdev_access *csa;
struct device *dev = init_arg->dev;
int i;
@@ -1382,6 +1398,7 @@ static void etm4_init_arch_data(void *info)
drvdata = dev_get_drvdata(init_arg->dev);
caps = &drvdata->caps;
csa = init_arg->csa;
+ config = &drvdata->active_config;
/*
* If we are unable to detect the access mechanism,
@@ -1442,7 +1459,7 @@ static void etm4_init_arch_data(void *info)
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
- drvdata->config.s_ex_level = caps->s_ex_level;
+ config->s_ex_level = caps->s_ex_level;
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
/*
@@ -1687,7 +1704,7 @@ static void etm4_set_default(struct etmv4_config *config)
static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
{
int nr_comparator, index = 0;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
/*
* nr_addr_cmp holds the number of comparator _pair_, so time 2
@@ -1728,7 +1745,7 @@ static int etm4_set_event_filters(struct etmv4_drvdata *drvdata,
{
int i, comparator, ret = 0;
u64 address;
- struct etmv4_config *config = &drvdata->config;
+ struct etmv4_config *config = &drvdata->active_config;
struct etm_filters *filters = event->hw.addr_filters;
if (!filters)
@@ -2250,7 +2267,8 @@ static int etm4_add_coresight_dev(struct etm4_init_arg *init_arg)
if (!desc.name)
return -ENOMEM;
- etm4_set_default(&drvdata->config);
+ etm4_set_default(&drvdata->active_config);
+ drvdata->config = drvdata->active_config;
pdata = coresight_get_platform_data(dev);
if (IS_ERR(pdata))
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 3cc1ca76c933..b943c28c9c71 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -1069,6 +1069,7 @@ struct etmv4_save_state {
* allows tracing at all ELs. We don't want to compute this
* at runtime, due to the additional setting of TRFCR_CX when
* in EL2. Otherwise, 0.
+ * @active_config: structure holding current applied configuration parameters.
* @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
* @paused: Indicates if the trace unit is paused.
@@ -1089,6 +1090,7 @@ struct etmv4_drvdata {
bool os_unlock : 1;
bool paused : 1;
u64 trfcr;
+ struct etmv4_config active_config;
struct etmv4_config config;
struct etmv4_save_state *save_state;
DECLARE_BITMAP(arch_features, ETM4_IMPDEF_FEATURE_MAX);
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH v3 4/5] coresight: etm3x: introduce struct etm_caps
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
In-Reply-To: <20260412175506.412301-1-yeoreum.yun@arm.com>
Introduce struct etm_caps to describe ETMv3 capabilities
and move capabilities information into it.
Since drvdata->etmccr and drvdata->etmccer are used to check
whether it supports fifofull logic and timestamping,
remove etmccr and etmccer field from drvdata and add relevant fields
in etm_caps structure.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
drivers/hwtracing/coresight/coresight-etm.h | 42 ++++++++++++-------
.../coresight/coresight-etm3x-core.c | 39 ++++++++++-------
.../coresight/coresight-etm3x-sysfs.c | 29 ++++++++-----
3 files changed, 67 insertions(+), 43 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm.h b/drivers/hwtracing/coresight/coresight-etm.h
index 1d753cca2943..2ffe477c0c12 100644
--- a/drivers/hwtracing/coresight/coresight-etm.h
+++ b/drivers/hwtracing/coresight/coresight-etm.h
@@ -140,6 +140,30 @@
ETM_ADD_COMP_0 | \
ETM_EVENT_NOT_A)
+/**
+ * struct etmv_caps - specifics ETM capabilities
+ * @port_size: port size as reported by ETMCR bit 4-6 and 21.
+ * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
+ * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
+ * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
+ * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
+ * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
+ * @fifofull: FIFOFULL logic is present.
+ * @timestamp: Timestamping is implemented.
+ * @retstacak: Return stack is implemented.
+ */
+struct etm_caps {
+ int port_size;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 nr_ext_out;
+ u8 nr_ctxid_cmp;
+ bool fifofull : 1;
+ bool timestamp : 1;
+ bool retstack : 1;
+};
+
/**
* struct etm_config - configuration information related to an ETM
* @mode: controls various modes supported by this ETM/PTM.
@@ -212,19 +236,12 @@ struct etm_config {
* @csdev: component vitals needed by the framework.
* @spinlock: only one at a time pls.
* @cpu: the cpu this component is affined to.
- * @port_size: port size as reported by ETMCR bit 4-6 and 21.
* @arch: ETM/PTM version number.
+ * @caps: ETM capabilities.
* @use_cpu14: true if management registers need to be accessed via CP14.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:true if we should start tracing at boot time.
* @os_unlock: true if access to management registers is allowed.
- * @nr_addr_cmp:Number of pairs of address comparators as found in ETMCCR.
- * @nr_cntr: Number of counters as found in ETMCCR bit 13-15.
- * @nr_ext_inp: Number of external input as found in ETMCCR bit 17-19.
- * @nr_ext_out: Number of external output as found in ETMCCR bit 20-22.
- * @nr_ctxid_cmp: Number of contextID comparators as found in ETMCCR bit 24-25.
- * @etmccr: value of register ETMCCR.
- * @etmccer: value of register ETMCCER.
* @traceid: value of the current ID for this component.
* @config: structure holding configuration parameters.
*/
@@ -234,19 +251,12 @@ struct etm_drvdata {
struct coresight_device *csdev;
spinlock_t spinlock;
int cpu;
- int port_size;
u8 arch;
+ struct etm_caps caps;
bool use_cp14;
bool sticky_enable;
bool boot_enable;
bool os_unlock;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 nr_ext_out;
- u8 nr_ctxid_cmp;
- u32 etmccr;
- u32 etmccer;
u32 traceid;
struct etm_config config;
};
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-core.c b/drivers/hwtracing/coresight/coresight-etm3x-core.c
index a547a6d2e0bd..f669eeeef538 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-core.c
@@ -308,6 +308,7 @@ void etm_config_trace_mode(struct etm_config *config)
static int etm_parse_event_config(struct etm_drvdata *drvdata,
struct perf_event *event)
{
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct perf_event_attr *attr = &event->attr;
u8 ts_level;
@@ -356,8 +357,7 @@ static int etm_parse_event_config(struct etm_drvdata *drvdata,
* has ret stack) on the same SoC. So only enable when it can be honored
* - trace will still continue normally otherwise.
*/
- if (ATTR_CFG_GET_FLD(attr, retstack) &&
- (drvdata->etmccer & ETMCCER_RETSTACK))
+ if (ATTR_CFG_GET_FLD(attr, retstack) && (caps->retstack))
config->ctrl |= ETMCR_RETURN_STACK;
return 0;
@@ -367,6 +367,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
{
int i, rc;
u32 etmcr;
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
@@ -388,7 +389,7 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etmcr = etm_readl(drvdata, ETMCR);
/* Clear setting from a previous run if need be */
etmcr &= ~ETM3X_SUPPORTED_OPTIONS;
- etmcr |= drvdata->port_size;
+ etmcr |= caps->port_size;
etmcr |= ETMCR_ETM_EN;
etm_writel(drvdata, config->ctrl | etmcr, ETMCR);
etm_writel(drvdata, config->trigger_event, ETMTRIGGER);
@@ -396,11 +397,11 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etm_writel(drvdata, config->enable_event, ETMTEEVR);
etm_writel(drvdata, config->enable_ctrl1, ETMTECR1);
etm_writel(drvdata, config->fifofull_level, ETMFFLR);
- for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+ for (i = 0; i < caps->nr_addr_cmp; i++) {
etm_writel(drvdata, config->addr_val[i], ETMACVRn(i));
etm_writel(drvdata, config->addr_acctype[i], ETMACTRn(i));
}
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm_writel(drvdata, config->cntr_rld_val[i], ETMCNTRLDVRn(i));
etm_writel(drvdata, config->cntr_event[i], ETMCNTENRn(i));
etm_writel(drvdata, config->cntr_rld_event[i],
@@ -414,9 +415,9 @@ static int etm_enable_hw(struct etm_drvdata *drvdata)
etm_writel(drvdata, config->seq_32_event, ETMSQ32EVR);
etm_writel(drvdata, config->seq_13_event, ETMSQ13EVR);
etm_writel(drvdata, config->seq_curr_state, ETMSQR);
- for (i = 0; i < drvdata->nr_ext_out; i++)
+ for (i = 0; i < caps->nr_ext_out; i++)
etm_writel(drvdata, ETM_DEFAULT_EVENT_VAL, ETMEXTOUTEVRn(i));
- for (i = 0; i < drvdata->nr_ctxid_cmp; i++)
+ for (i = 0; i < caps->nr_ctxid_cmp; i++)
etm_writel(drvdata, config->ctxid_pid[i], ETMCIDCVRn(i));
etm_writel(drvdata, config->ctxid_mask, ETMCIDCMR);
etm_writel(drvdata, config->sync_freq, ETMSYNCFR);
@@ -563,6 +564,7 @@ static int etm_enable(struct coresight_device *csdev, struct perf_event *event,
static void etm_disable_hw(struct etm_drvdata *drvdata)
{
int i;
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
@@ -572,7 +574,7 @@ static void etm_disable_hw(struct etm_drvdata *drvdata)
/* Read back sequencer and counters for post trace analysis */
config->seq_curr_state = (etm_readl(drvdata, ETMSQR) & ETM_SQR_MASK);
- for (i = 0; i < drvdata->nr_cntr; i++)
+ for (i = 0; i < caps->nr_cntr; i++)
config->cntr_val[i] = etm_readl(drvdata, ETMCNTVRn(i));
etm_set_pwrdwn(drvdata);
@@ -754,7 +756,9 @@ static void etm_init_arch_data(void *info)
{
u32 etmidr;
u32 etmccr;
+ u32 etmccer;
struct etm_drvdata *drvdata = info;
+ struct etm_caps *caps = &drvdata->caps;
/* Make sure all registers are accessible */
etm_os_unlock(drvdata);
@@ -779,16 +783,19 @@ static void etm_init_arch_data(void *info)
/* Find all capabilities */
etmidr = etm_readl(drvdata, ETMIDR);
drvdata->arch = BMVAL(etmidr, 4, 11);
- drvdata->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+ caps->port_size = etm_readl(drvdata, ETMCR) & PORT_SIZE_MASK;
+
+ etmccer = etm_readl(drvdata, ETMCCER);
+ caps->timestamp = !!(etmccer & ETMCCER_TIMESTAMP);
+ caps->retstack = !!(etmccer & ETMCCER_RETSTACK);
- drvdata->etmccer = etm_readl(drvdata, ETMCCER);
etmccr = etm_readl(drvdata, ETMCCR);
- drvdata->etmccr = etmccr;
- drvdata->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
- drvdata->nr_cntr = BMVAL(etmccr, 13, 15);
- drvdata->nr_ext_inp = BMVAL(etmccr, 17, 19);
- drvdata->nr_ext_out = BMVAL(etmccr, 20, 22);
- drvdata->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
+ caps->fifofull = !!(etmccr & ETMCCR_FIFOFULL);
+ caps->nr_addr_cmp = BMVAL(etmccr, 0, 3) * 2;
+ caps->nr_cntr = BMVAL(etmccr, 13, 15);
+ caps->nr_ext_inp = BMVAL(etmccr, 17, 19);
+ caps->nr_ext_out = BMVAL(etmccr, 20, 22);
+ caps->nr_ctxid_cmp = BMVAL(etmccr, 24, 25);
coresight_clear_self_claim_tag_unlocked(&drvdata->csa);
etm_set_pwrdwn(drvdata);
diff --git a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
index 762109307b86..056210779dd2 100644
--- a/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm3x-sysfs.c
@@ -15,8 +15,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
{
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
- val = drvdata->nr_addr_cmp;
+ val = caps->nr_addr_cmp;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_addr_cmp);
@@ -25,8 +26,9 @@ static ssize_t nr_cntr_show(struct device *dev,
struct device_attribute *attr, char *buf)
{ unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
- val = drvdata->nr_cntr;
+ val = caps->nr_cntr;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_cntr);
@@ -37,7 +39,7 @@ static ssize_t nr_ctxid_cmp_show(struct device *dev,
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
- val = drvdata->nr_ctxid_cmp;
+ val = drvdata->caps.nr_ctxid_cmp;
return sprintf(buf, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ctxid_cmp);
@@ -80,7 +82,7 @@ static ssize_t reset_store(struct device *dev,
memset(config, 0, sizeof(struct etm_config));
config->mode = ETM_MODE_EXCLUDE;
config->trigger_event = ETM_DEFAULT_EVENT_VAL;
- for (i = 0; i < drvdata->nr_addr_cmp; i++) {
+ for (i = 0; i < drvdata->caps.nr_addr_cmp; i++) {
config->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
@@ -111,6 +113,7 @@ static ssize_t mode_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
@@ -131,7 +134,7 @@ static ssize_t mode_store(struct device *dev,
config->ctrl &= ~ETMCR_CYC_ACC;
if (config->mode & ETM_MODE_STALL) {
- if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
+ if (!caps->fifofull) {
dev_warn(dev, "stall mode not supported\n");
ret = -EINVAL;
goto err_unlock;
@@ -141,7 +144,7 @@ static ssize_t mode_store(struct device *dev,
config->ctrl &= ~ETMCR_STALL_MODE;
if (config->mode & ETM_MODE_TIMESTAMP) {
- if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
+ if (!caps->timestamp) {
dev_warn(dev, "timestamp not supported\n");
ret = -EINVAL;
goto err_unlock;
@@ -286,13 +289,14 @@ static ssize_t addr_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_addr_cmp)
+ if (val >= caps->nr_addr_cmp)
return -EINVAL;
/*
@@ -589,13 +593,14 @@ static ssize_t cntr_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_cntr)
+ if (val >= caps->nr_cntr)
return -EINVAL;
/*
* Use spinlock to ensure index doesn't change while it gets
@@ -720,18 +725,19 @@ static ssize_t cntr_val_show(struct device *dev,
int i, ret = 0;
u32 val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
if (!coresight_get_mode(drvdata->csdev)) {
spin_lock(&drvdata->spinlock);
- for (i = 0; i < drvdata->nr_cntr; i++)
+ for (i = 0; i < caps->nr_cntr; i++)
ret += sprintf(buf, "counter %d: %x\n",
i, config->cntr_val[i]);
spin_unlock(&drvdata->spinlock);
return ret;
}
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
val = etm_readl(drvdata, ETMCNTVRn(i));
ret += sprintf(buf, "counter %d: %x\n", i, val);
}
@@ -999,13 +1005,14 @@ static ssize_t ctxid_idx_store(struct device *dev,
int ret;
unsigned long val;
struct etm_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etm_caps *caps = &drvdata->caps;
struct etm_config *config = &drvdata->config;
ret = kstrtoul(buf, 16, &val);
if (ret)
return ret;
- if (val >= drvdata->nr_ctxid_cmp)
+ if (val >= caps->nr_ctxid_cmp)
return -EINVAL;
/*
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH v3 1/5] coresight: etm4x: introduce struct etm4_caps
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
In-Reply-To: <20260412175506.412301-1-yeoreum.yun@arm.com>
introduce struct etm4_caps to describe ETMv4 capabilities
and move capabilities information into it.
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../coresight/coresight-etm4x-core.c | 234 +++++++++---------
.../coresight/coresight-etm4x-sysfs.c | 190 ++++++++------
drivers/hwtracing/coresight/coresight-etm4x.h | 175 ++++++-------
3 files changed, 327 insertions(+), 272 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index d565a73f0042..6443f3717b37 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -88,8 +88,9 @@ static int etm4_probe_cpu(unsigned int cpu);
*/
static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
{
- return (n < drvdata->nr_ss_cmp) &&
- drvdata->nr_pe &&
+ const struct etmv4_caps *caps = &drvdata->caps;
+
+ return (n < caps->nr_ss_cmp) && caps->nr_pe &&
(drvdata->config.ss_status[n] & TRCSSCSRn_PC);
}
@@ -160,17 +161,20 @@ static void ete_sysreg_write(u64 val, u32 offset, bool _relaxed, bool _64bit)
static void etm_detect_os_lock(struct etmv4_drvdata *drvdata,
struct csdev_access *csa)
{
+ struct etmv4_caps *caps = &drvdata->caps;
u32 oslsr = etm4x_relaxed_read32(csa, TRCOSLSR);
- drvdata->os_lock_model = ETM_OSLSR_OSLM(oslsr);
+ caps->os_lock_model = ETM_OSLSR_OSLM(oslsr);
}
static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
struct csdev_access *csa, u32 val)
{
+ const struct etmv4_caps *caps = &drvdata->caps;
+
val = !!val;
- switch (drvdata->os_lock_model) {
+ switch (caps->os_lock_model) {
case ETM_OSLOCK_PRESENT:
etm4x_relaxed_write32(csa, val, TRCOSLAR);
break;
@@ -179,7 +183,7 @@ static void etm_write_os_lock(struct etmv4_drvdata *drvdata,
break;
default:
pr_warn_once("CPU%d: Unsupported Trace OSLock model: %x\n",
- smp_processor_id(), drvdata->os_lock_model);
+ smp_processor_id(), caps->os_lock_model);
fallthrough;
case ETM_OSLOCK_NI:
return;
@@ -494,6 +498,7 @@ static int etm4_enable_trace_unit(struct etmv4_drvdata *drvdata)
static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
{
int i, rc;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
struct device *etm_dev = &csdev->dev;
@@ -525,14 +530,14 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
if (etm4x_wait_status(csa, TRCSTATR_IDLE_BIT, 1))
dev_err(etm_dev,
"timeout while waiting for Idle Trace Status\n");
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
etm4x_relaxed_write32(csa, config->pe_sel, TRCPROCSELR);
etm4x_relaxed_write32(csa, config->cfg, TRCCONFIGR);
/* nothing specific implemented */
etm4x_relaxed_write32(csa, 0x0, TRCAUXCTLR);
etm4x_relaxed_write32(csa, config->eventctrl0, TRCEVENTCTL0R);
etm4x_relaxed_write32(csa, config->eventctrl1, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
etm4x_relaxed_write32(csa, config->stall_ctrl, TRCSTALLCTLR);
etm4x_relaxed_write32(csa, config->ts_ctrl, TRCTSCTLR);
etm4x_relaxed_write32(csa, config->syncfreq, TRCSYNCPR);
@@ -542,17 +547,17 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, config->vinst_ctrl, TRCVICTLR);
etm4x_relaxed_write32(csa, config->viiectlr, TRCVIIECTLR);
etm4x_relaxed_write32(csa, config->vissctlr, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
etm4x_relaxed_write32(csa, config->vipcssctlr, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, config->seq_ctrl[i], TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
etm4x_relaxed_write32(csa, config->seq_rst, TRCSEQRSTEVR);
etm4x_relaxed_write32(csa, config->seq_state, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
etm4x_relaxed_write32(csa, config->ext_inp, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm4x_relaxed_write32(csa, config->cntrldvr[i], TRCCNTRLDVRn(i));
etm4x_relaxed_write32(csa, config->cntr_ctrl[i], TRCCNTCTLRn(i));
etm4x_relaxed_write32(csa, config->cntr_val[i], TRCCNTVRn(i));
@@ -562,10 +567,10 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
* Resource selector pair 0 is always implemented and reserved. As
* such start at 2.
*/
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
/* always clear status bit on restart if using single-shot */
if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
config->ss_status[i] &= ~TRCSSCSRn_STATUS;
@@ -574,23 +579,23 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
etm4x_relaxed_write64(csa, config->addr_val[i], TRCACVRn(i));
etm4x_relaxed_write64(csa, config->addr_acc[i], TRCACATRn(i));
}
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
etm4x_relaxed_write64(csa, config->ctxid_pid[i], TRCCIDCVRn(i));
etm4x_relaxed_write32(csa, config->ctxid_mask0, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
etm4x_relaxed_write32(csa, config->ctxid_mask1, TRCCIDCCTLR1);
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
etm4x_relaxed_write64(csa, config->vmid_val[i], TRCVMIDCVRn(i));
etm4x_relaxed_write32(csa, config->vmid_mask0, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
etm4x_relaxed_write32(csa, config->vmid_mask1, TRCVMIDCCTLR1);
- if (!drvdata->skip_power_up) {
+ if (!caps->skip_power_up) {
u32 trcpdcr = etm4x_relaxed_read32(csa, TRCPDCR);
/*
@@ -666,19 +671,20 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
{
int ctridx;
int rselector;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/* No point in trying if we don't have at least one counter */
- if (!drvdata->nr_cntr)
+ if (!caps->nr_cntr)
return -EINVAL;
/* Find a counter that hasn't been initialised */
- for (ctridx = 0; ctridx < drvdata->nr_cntr; ctridx++)
+ for (ctridx = 0; ctridx < caps->nr_cntr; ctridx++)
if (config->cntr_val[ctridx] == 0)
break;
/* All the counters have been configured already, bail out */
- if (ctridx == drvdata->nr_cntr) {
+ if (ctridx == caps->nr_cntr) {
pr_debug("%s: no available counter found\n", __func__);
return -ENOSPC;
}
@@ -694,11 +700,11 @@ static int etm4_config_timestamp_event(struct etmv4_drvdata *drvdata,
* ETMIDR4 gives the number of resource selector _pairs_, hence multiply
* by 2.
*/
- for (rselector = 2; rselector < drvdata->nr_resource * 2; rselector++)
+ for (rselector = 2; rselector < caps->nr_resource * 2; rselector++)
if (!config->res_ctrl[rselector])
break;
- if (rselector == drvdata->nr_resource * 2) {
+ if (rselector == caps->nr_resource * 2) {
pr_debug("%s: no available resource selector found\n",
__func__);
return -ENOSPC;
@@ -749,6 +755,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
{
int ret = 0;
struct etmv4_drvdata *drvdata = dev_get_drvdata(csdev->dev.parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct perf_event_attr max_timestamp = {
.ATTR_CFG_FLD_timestamp_CFG = U64_MAX,
@@ -788,8 +795,8 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
cc_threshold = ATTR_CFG_GET_FLD(attr, cc_threshold);
if (!cc_threshold)
cc_threshold = ETM_CYC_THRESHOLD_DEFAULT;
- if (cc_threshold < drvdata->ccitmin)
- cc_threshold = drvdata->ccitmin;
+ if (cc_threshold < caps->ccitmin)
+ cc_threshold = caps->ccitmin;
config->ccctlr = cc_threshold;
}
@@ -837,7 +844,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
}
/* return stack - enable if selected and supported */
- if (ATTR_CFG_GET_FLD(attr, retstack) && drvdata->retstack)
+ if (ATTR_CFG_GET_FLD(attr, retstack) && caps->retstack)
/* bit[12], Return stack enable bit */
config->cfg |= TRCCONFIGR_RS;
@@ -853,7 +860,7 @@ static int etm4_parse_event_config(struct coresight_device *csdev,
/* branch broadcast - enable if selected and supported */
if (ATTR_CFG_GET_FLD(attr, branch_broadcast)) {
- if (!drvdata->trcbb) {
+ if (!caps->trcbb) {
/*
* Missing BB support could cause silent decode errors
* so fail to open if it's not supported.
@@ -1028,6 +1035,7 @@ static void etm4_disable_trace_unit(struct etmv4_drvdata *drvdata)
static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
{
u32 control;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa = &csdev->access;
@@ -1036,7 +1044,7 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_cs_unlock(drvdata, csa);
etm4_disable_arch_specific(drvdata);
- if (!drvdata->skip_power_up) {
+ if (!caps->skip_power_up) {
/* power can be removed from the trace unit now */
control = etm4x_relaxed_read32(csa, TRCPDCR);
control &= ~TRCPDCR_PU;
@@ -1046,13 +1054,13 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_disable_trace_unit(drvdata);
/* read the status of the single shot comparators */
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
config->ss_status[i] =
etm4x_relaxed_read32(csa, TRCSSCSRn(i));
}
/* read back the current counter values */
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
config->cntr_val[i] =
etm4x_relaxed_read32(csa, TRCCNTVRn(i));
}
@@ -1350,7 +1358,7 @@ static struct midr_range etm_wrong_ccitmin_cpus[] = {
{},
};
-static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
+static void etm4_fixup_wrong_ccitmin(struct etmv4_caps *caps)
{
/*
* Erratum affected cpus will read 256 as the minimum
@@ -1360,8 +1368,8 @@ static void etm4_fixup_wrong_ccitmin(struct etmv4_drvdata *drvdata)
* this problem.
*/
if (is_midr_in_range_list(etm_wrong_ccitmin_cpus)) {
- if (drvdata->ccitmin == 256)
- drvdata->ccitmin = 4;
+ if (caps->ccitmin == 256)
+ caps->ccitmin = 4;
}
}
@@ -1374,11 +1382,13 @@ static void etm4_init_arch_data(void *info)
u32 etmidr5;
struct etm4_init_arg *init_arg = info;
struct etmv4_drvdata *drvdata;
+ struct etmv4_caps *caps;
struct csdev_access *csa;
struct device *dev = init_arg->dev;
int i;
drvdata = dev_get_drvdata(init_arg->dev);
+ caps = &drvdata->caps;
csa = init_arg->csa;
/*
@@ -1391,7 +1401,7 @@ static void etm4_init_arch_data(void *info)
if (!csa->io_mem ||
fwnode_property_present(dev_fwnode(dev), "qcom,skip-power-up"))
- drvdata->skip_power_up = true;
+ caps->skip_power_up = true;
/* Detect the support for OS Lock before we actually use it */
etm_detect_os_lock(drvdata, csa);
@@ -1406,71 +1416,71 @@ static void etm4_init_arch_data(void *info)
etmidr0 = etm4x_relaxed_read32(csa, TRCIDR0);
/* INSTP0, bits[2:1] P0 tracing support field */
- drvdata->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
+ caps->instrp0 = !!(FIELD_GET(TRCIDR0_INSTP0_MASK, etmidr0) == 0b11);
/* TRCBB, bit[5] Branch broadcast tracing support bit */
- drvdata->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
+ caps->trcbb = !!(etmidr0 & TRCIDR0_TRCBB);
/* TRCCOND, bit[6] Conditional instruction tracing support bit */
- drvdata->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
+ caps->trccond = !!(etmidr0 & TRCIDR0_TRCCOND);
/* TRCCCI, bit[7] Cycle counting instruction bit */
- drvdata->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
+ caps->trccci = !!(etmidr0 & TRCIDR0_TRCCCI);
/* RETSTACK, bit[9] Return stack bit */
- drvdata->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
+ caps->retstack = !!(etmidr0 & TRCIDR0_RETSTACK);
/* NUMEVENT, bits[11:10] Number of events field */
- drvdata->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
+ caps->nr_event = FIELD_GET(TRCIDR0_NUMEVENT_MASK, etmidr0);
/* QSUPP, bits[16:15] Q element support field */
- drvdata->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
- if (drvdata->q_support)
- drvdata->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
+ caps->q_support = FIELD_GET(TRCIDR0_QSUPP_MASK, etmidr0);
+ if (caps->q_support)
+ caps->q_filt = !!(etmidr0 & TRCIDR0_QFILT);
/* TSSIZE, bits[28:24] Global timestamp size field */
- drvdata->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
+ caps->ts_size = FIELD_GET(TRCIDR0_TSSIZE_MASK, etmidr0);
/* maximum size of resources */
etmidr2 = etm4x_relaxed_read32(csa, TRCIDR2);
/* CIDSIZE, bits[9:5] Indicates the Context ID size */
- drvdata->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
+ caps->ctxid_size = FIELD_GET(TRCIDR2_CIDSIZE_MASK, etmidr2);
/* VMIDSIZE, bits[14:10] Indicates the VMID size */
- drvdata->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
+ caps->vmid_size = FIELD_GET(TRCIDR2_VMIDSIZE_MASK, etmidr2);
/* CCSIZE, bits[28:25] size of the cycle counter in bits minus 12 */
- drvdata->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
+ caps->ccsize = FIELD_GET(TRCIDR2_CCSIZE_MASK, etmidr2);
etmidr3 = etm4x_relaxed_read32(csa, TRCIDR3);
/* CCITMIN, bits[11:0] minimum threshold value that can be programmed */
- drvdata->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
- etm4_fixup_wrong_ccitmin(drvdata);
+ caps->ccitmin = FIELD_GET(TRCIDR3_CCITMIN_MASK, etmidr3);
+ etm4_fixup_wrong_ccitmin(caps);
/* EXLEVEL_S, bits[19:16] Secure state instruction tracing */
- drvdata->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
- drvdata->config.s_ex_level = drvdata->s_ex_level;
+ caps->s_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_S_MASK, etmidr3);
+ drvdata->config.s_ex_level = caps->s_ex_level;
/* EXLEVEL_NS, bits[23:20] Non-secure state instruction tracing */
- drvdata->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
+ caps->ns_ex_level = FIELD_GET(TRCIDR3_EXLEVEL_NS_MASK, etmidr3);
/*
* TRCERR, bit[24] whether a trace unit can trace a
* system error exception.
*/
- drvdata->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
+ caps->trc_error = !!(etmidr3 & TRCIDR3_TRCERR);
/* SYNCPR, bit[25] implementation has a fixed synchronization period? */
- drvdata->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
+ caps->syncpr = !!(etmidr3 & TRCIDR3_SYNCPR);
/* STALLCTL, bit[26] is stall control implemented? */
- drvdata->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
+ caps->stallctl = !!(etmidr3 & TRCIDR3_STALLCTL);
/* SYSSTALL, bit[27] implementation can support stall control? */
- drvdata->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
+ caps->sysstall = !!(etmidr3 & TRCIDR3_SYSSTALL);
/*
* NUMPROC - the number of PEs available for tracing, 5bits
* = TRCIDR3.bits[13:12]bits[30:28]
* bits[4:3] = TRCIDR3.bits[13:12] (since etm-v4.2, otherwise RES0)
* bits[3:0] = TRCIDR3.bits[30:28]
*/
- drvdata->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
- FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
+ caps->nr_pe = (FIELD_GET(TRCIDR3_NUMPROC_HI_MASK, etmidr3) << 3) |
+ FIELD_GET(TRCIDR3_NUMPROC_LO_MASK, etmidr3);
/* NOOVERFLOW, bit[31] is trace overflow prevention supported */
- drvdata->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
+ caps->nooverflow = !!(etmidr3 & TRCIDR3_NOOVERFLOW);
/* number of resources trace unit supports */
etmidr4 = etm4x_relaxed_read32(csa, TRCIDR4);
/* NUMACPAIRS, bits[0:3] number of addr comparator pairs for tracing */
- drvdata->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
+ caps->nr_addr_cmp = FIELD_GET(TRCIDR4_NUMACPAIRS_MASK, etmidr4);
/* NUMPC, bits[15:12] number of PE comparator inputs for tracing */
- drvdata->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
+ caps->nr_pe_cmp = FIELD_GET(TRCIDR4_NUMPC_MASK, etmidr4);
/*
* NUMRSPAIR, bits[19:16]
* The number of resource pairs conveyed by the HW starts at 0, i.e a
@@ -1481,41 +1491,41 @@ static void etm4_init_arch_data(void *info)
* the default TRUE and FALSE resource selectors are omitted.
* Otherwise for values 0x1 and above the number is N + 1 as per v4.2.
*/
- drvdata->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
- if ((drvdata->arch < ETM_ARCH_V4_3) || (drvdata->nr_resource > 0))
- drvdata->nr_resource += 1;
+ caps->nr_resource = FIELD_GET(TRCIDR4_NUMRSPAIR_MASK, etmidr4);
+ if ((drvdata->arch < ETM_ARCH_V4_3) || (caps->nr_resource > 0))
+ caps->nr_resource += 1;
/*
* NUMSSCC, bits[23:20] the number of single-shot
* comparator control for tracing. Read any status regs as these
* also contain RO capability data.
*/
- drvdata->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
drvdata->config.ss_status[i] =
etm4x_relaxed_read32(csa, TRCSSCSRn(i));
}
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
- drvdata->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
+ caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
/* NUMVMIDC, bits[31:28] number of VMID comparators for tracing */
- drvdata->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
+ caps->numvmidc = FIELD_GET(TRCIDR4_NUMVMIDC_MASK, etmidr4);
etmidr5 = etm4x_relaxed_read32(csa, TRCIDR5);
/* NUMEXTIN, bits[8:0] number of external inputs implemented */
- drvdata->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
- drvdata->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
+ caps->nr_ext_inp = FIELD_GET(TRCIDR5_NUMEXTIN_MASK, etmidr5);
+ caps->numextinsel = FIELD_GET(TRCIDR5_NUMEXTINSEL_MASK, etmidr5);
/* TRACEIDSIZE, bits[21:16] indicates the trace ID width */
- drvdata->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
+ caps->trcid_size = FIELD_GET(TRCIDR5_TRACEIDSIZE_MASK, etmidr5);
/* ATBTRIG, bit[22] implementation can support ATB triggers? */
- drvdata->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
+ caps->atbtrig = !!(etmidr5 & TRCIDR5_ATBTRIG);
/*
* LPOVERRIDE, bit[23] implementation supports
* low-power state override
*/
- drvdata->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!drvdata->skip_power_up);
+ caps->lpoverride = (etmidr5 & TRCIDR5_LPOVERRIDE) && (!caps->skip_power_up);
/* NUMSEQSTATE, bits[27:25] number of sequencer states implemented */
- drvdata->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
+ caps->nrseqstate = FIELD_GET(TRCIDR5_NUMSEQSTATE_MASK, etmidr5);
/* NUMCNTR, bits[30:28] number of counters available for tracing */
- drvdata->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
+ caps->nr_cntr = FIELD_GET(TRCIDR5_NUMCNTR_MASK, etmidr5);
coresight_clear_self_claim_tag_unlocked(csa);
etm4_cs_lock(drvdata, csa);
@@ -1691,7 +1701,7 @@ static int etm4_get_next_comparator(struct etmv4_drvdata *drvdata, u32 type)
* nr_addr_cmp holds the number of comparator _pair_, so time 2
* for the total number of comparators.
*/
- nr_comparator = drvdata->nr_addr_cmp * 2;
+ nr_comparator = drvdata->caps.nr_addr_cmp * 2;
/* Go through the tally of comparators looking for a free one. */
while (index < nr_comparator) {
@@ -1869,6 +1879,7 @@ static int etm4_dying_cpu(unsigned int cpu)
static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
{
int i, ret = 0;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_save_state *state;
struct coresight_device *csdev = drvdata->csdev;
struct csdev_access *csa;
@@ -1905,57 +1916,57 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
state = drvdata->save_state;
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
state->trcprocselr = etm4x_read32(csa, TRCPROCSELR);
state->trcconfigr = etm4x_read32(csa, TRCCONFIGR);
state->trcauxctlr = etm4x_read32(csa, TRCAUXCTLR);
state->trceventctl0r = etm4x_read32(csa, TRCEVENTCTL0R);
state->trceventctl1r = etm4x_read32(csa, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
state->trcstallctlr = etm4x_read32(csa, TRCSTALLCTLR);
state->trctsctlr = etm4x_read32(csa, TRCTSCTLR);
state->trcsyncpr = etm4x_read32(csa, TRCSYNCPR);
state->trcccctlr = etm4x_read32(csa, TRCCCCTLR);
state->trcbbctlr = etm4x_read32(csa, TRCBBCTLR);
state->trctraceidr = etm4x_read32(csa, TRCTRACEIDR);
- if (drvdata->q_filt)
+ if (caps->q_filt)
state->trcqctlr = etm4x_read32(csa, TRCQCTLR);
state->trcvictlr = etm4x_read32(csa, TRCVICTLR);
state->trcviiectlr = etm4x_read32(csa, TRCVIIECTLR);
state->trcvissctlr = etm4x_read32(csa, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
state->trcvipcssctlr = etm4x_read32(csa, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
state->trcseqevr[i] = etm4x_read32(csa, TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
state->trcseqrstevr = etm4x_read32(csa, TRCSEQRSTEVR);
state->trcseqstr = etm4x_read32(csa, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
state->trcextinselr = etm4x_read32(csa, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
state->trccntrldvr[i] = etm4x_read32(csa, TRCCNTRLDVRn(i));
state->trccntctlr[i] = etm4x_read32(csa, TRCCNTCTLRn(i));
state->trccntvr[i] = etm4x_read32(csa, TRCCNTVRn(i));
}
/* Resource selector pair 0 is reserved */
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
state->trcrsctlr[i] = etm4x_read32(csa, TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
state->trcssccr[i] = etm4x_read32(csa, TRCSSCCRn(i));
state->trcsscsr[i] = etm4x_read32(csa, TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
state->trcsspcicr[i] = etm4x_read32(csa, TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
state->trcacvr[i] = etm4x_read64(csa, TRCACVRn(i));
state->trcacatr[i] = etm4x_read64(csa, TRCACATRn(i));
}
@@ -1967,23 +1978,23 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
* unit") of ARM IHI 0064D.
*/
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
state->trccidcvr[i] = etm4x_read64(csa, TRCCIDCVRn(i));
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
state->trcvmidcvr[i] = etm4x_read64(csa, TRCVMIDCVRn(i));
state->trccidcctlr0 = etm4x_read32(csa, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
state->trccidcctlr1 = etm4x_read32(csa, TRCCIDCCTLR1);
state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
state->trcvmidcctlr0 = etm4x_read32(csa, TRCVMIDCCTLR1);
state->trcclaimset = etm4x_read32(csa, TRCCLAIMCLR);
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
state->trcpdcr = etm4x_read32(csa, TRCPDCR);
/* wait for TRCSTATR.IDLE to go up */
@@ -2000,7 +2011,7 @@ static int __etm4_cpu_save(struct etmv4_drvdata *drvdata)
* potentially save power on systems that respect the TRCPDCR_PU
* despite requesting software to save/restore state.
*/
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
etm4x_relaxed_write32(csa, (state->trcpdcr & ~TRCPDCR_PU),
TRCPDCR);
out:
@@ -2027,6 +2038,7 @@ static int etm4_cpu_save(struct etmv4_drvdata *drvdata)
static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
{
int i;
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_save_state *state = drvdata->save_state;
struct csdev_access *csa = &drvdata->csdev->access;
@@ -2036,77 +2048,77 @@ static void __etm4_cpu_restore(struct etmv4_drvdata *drvdata)
etm4_cs_unlock(drvdata, csa);
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
- if (drvdata->nr_pe)
+ if (caps->nr_pe)
etm4x_relaxed_write32(csa, state->trcprocselr, TRCPROCSELR);
etm4x_relaxed_write32(csa, state->trcconfigr, TRCCONFIGR);
etm4x_relaxed_write32(csa, state->trcauxctlr, TRCAUXCTLR);
etm4x_relaxed_write32(csa, state->trceventctl0r, TRCEVENTCTL0R);
etm4x_relaxed_write32(csa, state->trceventctl1r, TRCEVENTCTL1R);
- if (drvdata->stallctl)
+ if (caps->stallctl)
etm4x_relaxed_write32(csa, state->trcstallctlr, TRCSTALLCTLR);
etm4x_relaxed_write32(csa, state->trctsctlr, TRCTSCTLR);
etm4x_relaxed_write32(csa, state->trcsyncpr, TRCSYNCPR);
etm4x_relaxed_write32(csa, state->trcccctlr, TRCCCCTLR);
etm4x_relaxed_write32(csa, state->trcbbctlr, TRCBBCTLR);
etm4x_relaxed_write32(csa, state->trctraceidr, TRCTRACEIDR);
- if (drvdata->q_filt)
+ if (caps->q_filt)
etm4x_relaxed_write32(csa, state->trcqctlr, TRCQCTLR);
etm4x_relaxed_write32(csa, state->trcvictlr, TRCVICTLR);
etm4x_relaxed_write32(csa, state->trcviiectlr, TRCVIIECTLR);
etm4x_relaxed_write32(csa, state->trcvissctlr, TRCVISSCTLR);
- if (drvdata->nr_pe_cmp)
+ if (caps->nr_pe_cmp)
etm4x_relaxed_write32(csa, state->trcvipcssctlr, TRCVIPCSSCTLR);
- for (i = 0; i < drvdata->nrseqstate - 1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
etm4x_relaxed_write32(csa, state->trcseqevr[i], TRCSEQEVRn(i));
- if (drvdata->nrseqstate) {
+ if (caps->nrseqstate) {
etm4x_relaxed_write32(csa, state->trcseqrstevr, TRCSEQRSTEVR);
etm4x_relaxed_write32(csa, state->trcseqstr, TRCSEQSTR);
}
- if (drvdata->numextinsel)
+ if (caps->numextinsel)
etm4x_relaxed_write32(csa, state->trcextinselr, TRCEXTINSELR);
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
etm4x_relaxed_write32(csa, state->trccntrldvr[i], TRCCNTRLDVRn(i));
etm4x_relaxed_write32(csa, state->trccntctlr[i], TRCCNTCTLRn(i));
etm4x_relaxed_write32(csa, state->trccntvr[i], TRCCNTVRn(i));
}
/* Resource selector pair 0 is reserved */
- for (i = 2; i < drvdata->nr_resource * 2; i++)
+ for (i = 2; i < caps->nr_resource * 2; i++)
etm4x_relaxed_write32(csa, state->trcrsctlr[i], TRCRSCTLRn(i));
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
etm4x_relaxed_write32(csa, state->trcssccr[i], TRCSSCCRn(i));
etm4x_relaxed_write32(csa, state->trcsscsr[i], TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, state->trcsspcicr[i], TRCSSPCICRn(i));
}
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
etm4x_relaxed_write64(csa, state->trcacvr[i], TRCACVRn(i));
etm4x_relaxed_write64(csa, state->trcacatr[i], TRCACATRn(i));
}
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
etm4x_relaxed_write64(csa, state->trccidcvr[i], TRCCIDCVRn(i));
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
etm4x_relaxed_write64(csa, state->trcvmidcvr[i], TRCVMIDCVRn(i));
etm4x_relaxed_write32(csa, state->trccidcctlr0, TRCCIDCCTLR0);
- if (drvdata->numcidc > 4)
+ if (caps->numcidc > 4)
etm4x_relaxed_write32(csa, state->trccidcctlr1, TRCCIDCCTLR1);
etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR0);
- if (drvdata->numvmidc > 4)
+ if (caps->numvmidc > 4)
etm4x_relaxed_write32(csa, state->trcvmidcctlr0, TRCVMIDCCTLR1);
etm4x_relaxed_write32(csa, state->trcclaimset, TRCCLAIMSET);
- if (!drvdata->skip_power_up)
+ if (!caps->skip_power_up)
etm4x_relaxed_write32(csa, state->trcpdcr, TRCPDCR);
/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index e9eeea6240d5..50408215d1ac 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -62,8 +62,9 @@ static ssize_t nr_pe_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_pe_cmp;
+ val = caps->nr_pe_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_pe_cmp);
@@ -74,8 +75,9 @@ static ssize_t nr_addr_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_addr_cmp;
+ val = caps->nr_addr_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_addr_cmp);
@@ -86,8 +88,9 @@ static ssize_t nr_cntr_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_cntr;
+ val = caps->nr_cntr;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_cntr);
@@ -98,8 +101,9 @@ static ssize_t nr_ext_inp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_ext_inp;
+ val = caps->nr_ext_inp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ext_inp);
@@ -110,8 +114,9 @@ static ssize_t numcidc_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->numcidc;
+ val = caps->numcidc;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(numcidc);
@@ -122,8 +127,9 @@ static ssize_t numvmidc_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->numvmidc;
+ val = caps->numvmidc;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(numvmidc);
@@ -134,8 +140,9 @@ static ssize_t nrseqstate_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nrseqstate;
+ val = caps->nrseqstate;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nrseqstate);
@@ -146,8 +153,9 @@ static ssize_t nr_resource_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_resource;
+ val = caps->nr_resource;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_resource);
@@ -158,8 +166,9 @@ static ssize_t nr_ss_cmp_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
- val = drvdata->nr_ss_cmp;
+ val = caps->nr_ss_cmp;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
static DEVICE_ATTR_RO(nr_ss_cmp);
@@ -171,6 +180,7 @@ static ssize_t reset_store(struct device *dev,
int i;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -200,7 +210,7 @@ static ssize_t reset_store(struct device *dev,
config->stall_ctrl = 0x0;
/* Reset trace synchronization period to 2^8 = 256 bytes*/
- if (drvdata->syncpr == false)
+ if (!caps->syncpr)
config->syncfreq = 0x8;
/*
@@ -209,7 +219,7 @@ static ssize_t reset_store(struct device *dev,
* each trace run.
*/
config->vinst_ctrl = FIELD_PREP(TRCVICTLR_EVENT_MASK, 0x01);
- if (drvdata->nr_addr_cmp > 0) {
+ if (caps->nr_addr_cmp > 0) {
config->mode |= ETM_MODE_VIEWINST_STARTSTOP;
/* SSSTATUS, bit[9] */
config->vinst_ctrl |= TRCVICTLR_SSSTATUS;
@@ -223,7 +233,7 @@ static ssize_t reset_store(struct device *dev,
config->vipcssctlr = 0x0;
/* Disable seq events */
- for (i = 0; i < drvdata->nrseqstate-1; i++)
+ for (i = 0; i < caps->nrseqstate - 1; i++)
config->seq_ctrl[i] = 0x0;
config->seq_rst = 0x0;
config->seq_state = 0x0;
@@ -232,38 +242,38 @@ static ssize_t reset_store(struct device *dev,
config->ext_inp = 0x0;
config->cntr_idx = 0x0;
- for (i = 0; i < drvdata->nr_cntr; i++) {
+ for (i = 0; i < caps->nr_cntr; i++) {
config->cntrldvr[i] = 0x0;
config->cntr_ctrl[i] = 0x0;
config->cntr_val[i] = 0x0;
}
config->res_idx = 0x0;
- for (i = 2; i < 2 * drvdata->nr_resource; i++)
+ for (i = 2; i < 2 * caps->nr_resource; i++)
config->res_ctrl[i] = 0x0;
config->ss_idx = 0x0;
- for (i = 0; i < drvdata->nr_ss_cmp; i++) {
+ for (i = 0; i < caps->nr_ss_cmp; i++) {
config->ss_ctrl[i] = 0x0;
config->ss_pe_cmp[i] = 0x0;
}
config->addr_idx = 0x0;
- for (i = 0; i < drvdata->nr_addr_cmp * 2; i++) {
+ for (i = 0; i < caps->nr_addr_cmp * 2; i++) {
config->addr_val[i] = 0x0;
config->addr_acc[i] = 0x0;
config->addr_type[i] = ETM_ADDR_TYPE_NONE;
}
config->ctxid_idx = 0x0;
- for (i = 0; i < drvdata->numcidc; i++)
+ for (i = 0; i < caps->numcidc; i++)
config->ctxid_pid[i] = 0x0;
config->ctxid_mask0 = 0x0;
config->ctxid_mask1 = 0x0;
config->vmid_idx = 0x0;
- for (i = 0; i < drvdata->numvmidc; i++)
+ for (i = 0; i < caps->numvmidc; i++)
config->vmid_val[i] = 0x0;
config->vmid_mask0 = 0x0;
config->vmid_mask1 = 0x0;
@@ -297,6 +307,7 @@ static ssize_t mode_store(struct device *dev,
{
unsigned long val, mode;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -305,7 +316,7 @@ static ssize_t mode_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
config->mode = val & ETMv4_MODE_ALL;
- if (drvdata->instrp0 == true) {
+ if (caps->instrp0) {
/* start by clearing instruction P0 field */
config->cfg &= ~TRCCONFIGR_INSTP0_LOAD_STORE;
if (config->mode & ETM_MODE_LOAD)
@@ -323,45 +334,44 @@ static ssize_t mode_store(struct device *dev,
}
/* bit[3], Branch broadcast mode */
- if ((config->mode & ETM_MODE_BB) && (drvdata->trcbb == true))
+ if ((config->mode & ETM_MODE_BB) && (caps->trcbb))
config->cfg |= TRCCONFIGR_BB;
else
config->cfg &= ~TRCCONFIGR_BB;
/* bit[4], Cycle counting instruction trace bit */
if ((config->mode & ETMv4_MODE_CYCACC) &&
- (drvdata->trccci == true))
+ (caps->trccci == true))
config->cfg |= TRCCONFIGR_CCI;
else
config->cfg &= ~TRCCONFIGR_CCI;
/* bit[6], Context ID tracing bit */
- if ((config->mode & ETMv4_MODE_CTXID) && (drvdata->ctxid_size))
+ if ((config->mode & ETMv4_MODE_CTXID) && (caps->ctxid_size))
config->cfg |= TRCCONFIGR_CID;
else
config->cfg &= ~TRCCONFIGR_CID;
- if ((config->mode & ETM_MODE_VMID) && (drvdata->vmid_size))
+ if ((config->mode & ETM_MODE_VMID) && (caps->vmid_size))
config->cfg |= TRCCONFIGR_VMID;
else
config->cfg &= ~TRCCONFIGR_VMID;
/* bits[10:8], Conditional instruction tracing bit */
mode = ETM_MODE_COND(config->mode);
- if (drvdata->trccond == true) {
+ if (caps->trccond) {
config->cfg &= ~TRCCONFIGR_COND_MASK;
config->cfg |= mode << __bf_shf(TRCCONFIGR_COND_MASK);
}
/* bit[11], Global timestamp tracing bit */
- if ((config->mode & ETMv4_MODE_TIMESTAMP) && (drvdata->ts_size))
+ if ((config->mode & ETMv4_MODE_TIMESTAMP) && (caps->ts_size))
config->cfg |= TRCCONFIGR_TS;
else
config->cfg &= ~TRCCONFIGR_TS;
/* bit[12], Return stack enable bit */
- if ((config->mode & ETM_MODE_RETURNSTACK) &&
- (drvdata->retstack == true))
+ if ((config->mode & ETM_MODE_RETURNSTACK) && (caps->retstack))
config->cfg |= TRCCONFIGR_RS;
else
config->cfg &= ~TRCCONFIGR_RS;
@@ -375,31 +385,29 @@ static ssize_t mode_store(struct device *dev,
* Always set the low bit for any requested mode. Valid combos are
* 0b00, 0b01 and 0b11.
*/
- if (mode && drvdata->q_support)
+ if (mode && caps->q_support)
config->cfg |= TRCCONFIGR_QE_W_COUNTS;
/*
* if supported, Q elements with and without instruction
* counts are enabled
*/
- if ((mode & BIT(1)) && (drvdata->q_support & BIT(1)))
+ if ((mode & BIT(1)) && (caps->q_support & BIT(1)))
config->cfg |= TRCCONFIGR_QE_WO_COUNTS;
/* bit[11], AMBA Trace Bus (ATB) trigger enable bit */
- if ((config->mode & ETM_MODE_ATB_TRIGGER) &&
- (drvdata->atbtrig == true))
+ if ((config->mode & ETM_MODE_ATB_TRIGGER) && (caps->atbtrig))
config->eventctrl1 |= TRCEVENTCTL1R_ATB;
else
config->eventctrl1 &= ~TRCEVENTCTL1R_ATB;
/* bit[12], Low-power state behavior override bit */
- if ((config->mode & ETM_MODE_LPOVERRIDE) &&
- (drvdata->lpoverride == true))
+ if ((config->mode & ETM_MODE_LPOVERRIDE) && (caps->lpoverride))
config->eventctrl1 |= TRCEVENTCTL1R_LPOVERRIDE;
else
config->eventctrl1 &= ~TRCEVENTCTL1R_LPOVERRIDE;
/* bit[8], Instruction stall bit */
- if ((config->mode & ETM_MODE_ISTALL_EN) && (drvdata->stallctl == true))
+ if ((config->mode & ETM_MODE_ISTALL_EN) && (caps->stallctl))
config->stall_ctrl |= TRCSTALLCTLR_ISTALL;
else
config->stall_ctrl &= ~TRCSTALLCTLR_ISTALL;
@@ -411,8 +419,7 @@ static ssize_t mode_store(struct device *dev,
config->stall_ctrl &= ~TRCSTALLCTLR_INSTPRIORITY;
/* bit[13], Trace overflow prevention bit */
- if ((config->mode & ETM_MODE_NOOVERFLOW) &&
- (drvdata->nooverflow == true))
+ if ((config->mode & ETM_MODE_NOOVERFLOW) && (caps->nooverflow))
config->stall_ctrl |= TRCSTALLCTLR_NOOVERFLOW;
else
config->stall_ctrl &= ~TRCSTALLCTLR_NOOVERFLOW;
@@ -430,8 +437,7 @@ static ssize_t mode_store(struct device *dev,
config->vinst_ctrl &= ~TRCVICTLR_TRCRESET;
/* bit[11], Whether a trace unit must trace a system error exception */
- if ((config->mode & ETM_MODE_TRACE_ERR) &&
- (drvdata->trc_error == true))
+ if ((config->mode & ETM_MODE_TRACE_ERR) && (caps->trc_error))
config->vinst_ctrl |= TRCVICTLR_TRCERR;
else
config->vinst_ctrl &= ~TRCVICTLR_TRCERR;
@@ -463,13 +469,14 @@ static ssize_t pe_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
- if (val > drvdata->nr_pe) {
+ if (val > caps->nr_pe) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -498,13 +505,14 @@ static ssize_t event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
- switch (drvdata->nr_event) {
+ switch (caps->nr_event) {
case 0x0:
/* EVENT0, bits[7:0] */
config->eventctrl0 = val & 0xFF;
@@ -547,6 +555,7 @@ static ssize_t event_instren_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -555,7 +564,7 @@ static ssize_t event_instren_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
/* start by clearing all instruction event enable bits */
config->eventctrl1 &= ~TRCEVENTCTL1R_INSTEN_MASK;
- switch (drvdata->nr_event) {
+ switch (caps->nr_event) {
case 0x0:
/* generate Event element for event 1 */
config->eventctrl1 |= val & TRCEVENTCTL1R_INSTEN_1;
@@ -603,11 +612,12 @@ static ssize_t event_ts_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!drvdata->ts_size)
+ if (!caps->ts_size)
return -EINVAL;
config->ts_ctrl = val & ETMv4_EVENT_MASK;
@@ -633,11 +643,12 @@ static ssize_t syncfreq_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (drvdata->syncpr == true)
+ if (caps->syncpr)
return -EINVAL;
config->syncfreq = val & ETMv4_SYNC_MASK;
@@ -663,6 +674,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -670,7 +682,7 @@ static ssize_t cyc_threshold_store(struct device *dev,
/* mask off max threshold before checking min value */
val &= ETM_CYC_THRESHOLD_MASK;
- if (val < drvdata->ccitmin)
+ if (val < caps->ccitmin)
return -EINVAL;
config->ccctlr = val;
@@ -696,13 +708,14 @@ static ssize_t bb_ctrl_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (drvdata->trcbb == false)
+ if (!caps->trcbb)
return -EINVAL;
- if (!drvdata->nr_addr_cmp)
+ if (!caps->nr_addr_cmp)
return -EINVAL;
/*
@@ -768,6 +781,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -777,7 +791,7 @@ static ssize_t s_exlevel_vinst_store(struct device *dev,
/* clear all EXLEVEL_S bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_S_MASK;
/* enable instruction tracing for corresponding exception level */
- val &= drvdata->s_ex_level;
+ val &= caps->s_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_S_MASK);
raw_spin_unlock(&drvdata->spinlock);
return size;
@@ -803,6 +817,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -812,7 +827,7 @@ static ssize_t ns_exlevel_vinst_store(struct device *dev,
/* clear EXLEVEL_NS bits */
config->vinst_ctrl &= ~TRCVICTLR_EXLEVEL_NS_MASK;
/* enable instruction tracing for corresponding exception level */
- val &= drvdata->ns_ex_level;
+ val &= caps->ns_ex_level;
config->vinst_ctrl |= val << __bf_shf(TRCVICTLR_EXLEVEL_NS_MASK);
raw_spin_unlock(&drvdata->spinlock);
return size;
@@ -837,11 +852,12 @@ static ssize_t addr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_addr_cmp * 2)
+ if (val >= caps->nr_addr_cmp * 2)
return -EINVAL;
/*
@@ -1060,6 +1076,7 @@ static ssize_t addr_start_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1067,7 +1084,7 @@ static ssize_t addr_start_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
- if (!drvdata->nr_addr_cmp) {
+ if (!caps->nr_addr_cmp) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -1115,6 +1132,7 @@ static ssize_t addr_stop_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1122,7 +1140,7 @@ static ssize_t addr_stop_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->addr_idx;
- if (!drvdata->nr_addr_cmp) {
+ if (!caps->nr_addr_cmp) {
raw_spin_unlock(&drvdata->spinlock);
return -EINVAL;
}
@@ -1167,6 +1185,7 @@ static ssize_t addr_ctxtype_store(struct device *dev,
u8 idx;
char str[10] = "";
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (strlen(buf) >= 10)
@@ -1181,13 +1200,13 @@ static ssize_t addr_ctxtype_store(struct device *dev,
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_MASK;
else if (!strcmp(str, "ctxid")) {
/* 0b01 The trace unit performs a Context ID */
- if (drvdata->numcidc) {
+ if (caps->numcidc) {
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_VMID;
}
} else if (!strcmp(str, "vmid")) {
/* 0b10 The trace unit performs a VMID */
- if (drvdata->numvmidc) {
+ if (caps->numvmidc) {
config->addr_acc[idx] &= ~TRCACATRn_CONTEXTTYPE_CTXID;
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
}
@@ -1196,9 +1215,9 @@ static ssize_t addr_ctxtype_store(struct device *dev,
* 0b11 The trace unit performs a Context ID
* comparison and a VMID
*/
- if (drvdata->numcidc)
+ if (caps->numcidc)
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_CTXID;
- if (drvdata->numvmidc)
+ if (caps->numvmidc)
config->addr_acc[idx] |= TRCACATRn_CONTEXTTYPE_VMID;
}
raw_spin_unlock(&drvdata->spinlock);
@@ -1230,14 +1249,15 @@ static ssize_t addr_context_store(struct device *dev,
u8 idx;
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if ((drvdata->numcidc <= 1) && (drvdata->numvmidc <= 1))
+ if ((caps->numcidc <= 1) && (caps->numvmidc <= 1))
return -EINVAL;
- if (val >= (drvdata->numcidc >= drvdata->numvmidc ?
- drvdata->numcidc : drvdata->numvmidc))
+ if (val >= (caps->numcidc >= caps->numvmidc ?
+ caps->numcidc : caps->numvmidc))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1348,9 +1368,10 @@ static ssize_t vinst_pe_cmp_start_stop_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
- if (!drvdata->nr_pe_cmp)
+ if (!caps->nr_pe_cmp)
return -EINVAL;
val = config->vipcssctlr;
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
@@ -1361,11 +1382,12 @@ static ssize_t vinst_pe_cmp_start_stop_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!drvdata->nr_pe_cmp)
+ if (!caps->nr_pe_cmp)
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1393,11 +1415,12 @@ static ssize_t seq_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nrseqstate - 1)
+ if (val >= caps->nrseqstate - 1)
return -EINVAL;
/*
@@ -1429,11 +1452,12 @@ static ssize_t seq_state_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nrseqstate)
+ if (val >= caps->nrseqstate)
return -EINVAL;
config->seq_state = val;
@@ -1496,11 +1520,12 @@ static ssize_t seq_reset_event_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (!(drvdata->nrseqstate))
+ if (!(caps->nrseqstate))
return -EINVAL;
config->seq_rst = val & ETMv4_EVENT_MASK;
@@ -1526,11 +1551,12 @@ static ssize_t cntr_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_cntr)
+ if (val >= caps->nr_cntr)
return -EINVAL;
/*
@@ -1674,6 +1700,7 @@ static ssize_t res_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
@@ -1682,7 +1709,7 @@ static ssize_t res_idx_store(struct device *dev,
* Resource selector pair 0 is always implemented and reserved,
* namely an idx with 0 and 1 is illegal.
*/
- if ((val < 2) || (val >= 2 * drvdata->nr_resource))
+ if ((val < 2) || (val >= 2 * caps->nr_resource))
return -EINVAL;
/*
@@ -1756,11 +1783,12 @@ static ssize_t sshot_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->nr_ss_cmp)
+ if (val >= caps->nr_ss_cmp)
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -1874,11 +1902,12 @@ static ssize_t ctxid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->numcidc)
+ if (val >= caps->numcidc)
return -EINVAL;
/*
@@ -1922,6 +1951,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
u8 idx;
unsigned long pid;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/*
@@ -1941,7 +1971,7 @@ static ssize_t ctxid_pid_store(struct device *dev,
* ctxid comparator is implemented and ctxid is greater than 0 bits
* in length
*/
- if (!drvdata->ctxid_size || !drvdata->numcidc)
+ if (!caps->ctxid_size || !caps->numcidc)
return -EINVAL;
if (kstrtoul(buf, 16, &pid))
return -EINVAL;
@@ -1983,6 +2013,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
int nr_inputs;
@@ -1998,11 +2029,11 @@ static ssize_t ctxid_masks_store(struct device *dev,
* ctxid comparator is implemented and ctxid is greater than 0 bits
* in length
*/
- if (!drvdata->ctxid_size || !drvdata->numcidc)
+ if (!caps->ctxid_size || !caps->numcidc)
return -EINVAL;
/* one mask if <= 4 comparators, two for up to 8 */
nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
- if ((drvdata->numcidc > 4) && (nr_inputs != 2))
+ if ((caps->numcidc > 4) && (nr_inputs != 2))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -2010,7 +2041,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
* each byte[0..3] controls mask value applied to ctxid
* comparator[0..3]
*/
- switch (drvdata->numcidc) {
+ switch (caps->numcidc) {
case 0x1:
/* COMP0, bits[7:0] */
config->ctxid_mask0 = val1 & 0xFF;
@@ -2057,7 +2088,7 @@ static ssize_t ctxid_masks_store(struct device *dev,
* of ctxid comparator0 value (corresponding to byte 0) register.
*/
mask = config->ctxid_mask0;
- for (i = 0; i < drvdata->numcidc; i++) {
+ for (i = 0; i < caps->numcidc; i++) {
/* mask value of corresponding ctxid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
/*
@@ -2100,11 +2131,12 @@ static ssize_t vmid_idx_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
- if (val >= drvdata->numvmidc)
+ if (val >= caps->numvmidc)
return -EINVAL;
/*
@@ -2145,6 +2177,7 @@ static ssize_t vmid_val_store(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
/*
@@ -2158,7 +2191,7 @@ static ssize_t vmid_val_store(struct device *dev,
* only implemented when vmid tracing is enabled, i.e. at least one
* vmid comparator is implemented and at least 8 bit vmid size
*/
- if (!drvdata->vmid_size || !drvdata->numvmidc)
+ if (!caps->vmid_size || !caps->numvmidc)
return -EINVAL;
if (kstrtoul(buf, 16, &val))
return -EINVAL;
@@ -2198,6 +2231,7 @@ static ssize_t vmid_masks_store(struct device *dev,
u8 i, j, maskbyte;
unsigned long val1, val2, mask;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
int nr_inputs;
@@ -2212,11 +2246,11 @@ static ssize_t vmid_masks_store(struct device *dev,
* only implemented when vmid tracing is enabled, i.e. at least one
* vmid comparator is implemented and at least 8 bit vmid size
*/
- if (!drvdata->vmid_size || !drvdata->numvmidc)
+ if (!caps->vmid_size || !caps->numvmidc)
return -EINVAL;
/* one mask if <= 4 comparators, two for up to 8 */
nr_inputs = sscanf(buf, "%lx %lx", &val1, &val2);
- if ((drvdata->numvmidc > 4) && (nr_inputs != 2))
+ if ((caps->numvmidc > 4) && (nr_inputs != 2))
return -EINVAL;
raw_spin_lock(&drvdata->spinlock);
@@ -2225,7 +2259,7 @@ static ssize_t vmid_masks_store(struct device *dev,
* each byte[0..3] controls mask value applied to vmid
* comparator[0..3]
*/
- switch (drvdata->numvmidc) {
+ switch (caps->numvmidc) {
case 0x1:
/* COMP0, bits[7:0] */
config->vmid_mask0 = val1 & 0xFF;
@@ -2273,7 +2307,7 @@ static ssize_t vmid_masks_store(struct device *dev,
* of vmid comparator0 value (corresponding to byte 0) register.
*/
mask = config->vmid_mask0;
- for (i = 0; i < drvdata->numvmidc; i++) {
+ for (i = 0; i < caps->numvmidc; i++) {
/* mask value of corresponding vmid comparator */
maskbyte = mask & ETMv4_EVENT_MASK;
/*
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 89d81ce4e04e..8eebb83fcaeb 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -812,6 +812,94 @@ enum etm_impdef_type {
ETM4_IMPDEF_FEATURE_MAX,
};
+/**
+ * struct etmv4_caps - specifics ETM capabilities
+ * @nr_pe: The number of processing entity available for tracing.
+ * @nr_pe_cmp: The number of processing entity comparator inputs that are
+ * available for tracing.
+ * @nr_addr_cmp:Number of pairs of address comparators available
+ * as found in ETMIDR4 0-3.
+ * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
+ * @nr_ext_inp: Number of external input.
+ * @numcidc: Number of contextID comparators.
+ * @numvmidc: Number of VMID comparators.
+ * @nrseqstate: The number of sequencer states that are implemented.
+ * @nr_event: Indicates how many events the trace unit support.
+ * @nr_resource:The number of resource selection pairs available for tracing.
+ * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * @trcid_size: Indicates the trace ID width.
+ * @ts_size: Global timestamp size field.
+ * @ctxid_size: Size of the context ID field to consider.
+ * @vmid_size: Size of the VM ID comparator to consider.
+ * @ccsize: Indicates the size of the cycle counter in bits.
+ * @ccitmin: minimum value that can be programmed in
+ * @s_ex_level: In secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
+ * supported for the corresponding Exception level.
+ * @q_support: Q element support characteristics.
+ * @os_lock_model: OSLock model.
+ * @instrp0: Tracing of load and store instructions
+ * as P0 elements is supported.
+ * @q_filt: Q element filtering support, if Q elements are supported.
+ * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
+ * @trccond: If the trace unit supports conditional
+ * instruction tracing.
+ * @retstack: Indicates if the implementation supports a return stack.
+ * @trccci: Indicates if the trace unit supports cycle counting
+ * for instruction.
+ * @trc_error: Whether a trace unit can trace a system
+ * error exception.
+ * @syncpr: Indicates if an implementation has a fixed
+ * synchronization period.
+ * @stallctl: If functionality that prevents trace unit buffer overflows
+ * is available.
+ * @sysstall: Does the system support stall control of the PE?
+ * @nooverflow: Indicate if overflow prevention is supported.
+ * @atbtrig: If the implementation can support ATB triggers
+ * @lpoverride: If the implementation can support low-power state over.
+ * @skip_power_up: Indicates if an implementation can skip powering up
+ * the trace unit.
+ */
+struct etmv4_caps {
+ u8 nr_pe;
+ u8 nr_pe_cmp;
+ u8 nr_addr_cmp;
+ u8 nr_cntr;
+ u8 nr_ext_inp;
+ u8 numcidc;
+ u8 numextinsel;
+ u8 numvmidc;
+ u8 nrseqstate;
+ u8 nr_event;
+ u8 nr_resource;
+ u8 nr_ss_cmp;
+ u8 trcid_size;
+ u8 ts_size;
+ u8 ctxid_size;
+ u8 vmid_size;
+ u8 ccsize;
+ u16 ccitmin;
+ u8 s_ex_level;
+ u8 ns_ex_level;
+ u8 q_support;
+ u8 os_lock_model;
+ bool instrp0 : 1;
+ bool q_filt : 1;
+ bool trcbb : 1;
+ bool trccond : 1;
+ bool retstack : 1;
+ bool trccci : 1;
+ bool trc_error : 1;
+ bool syncpr : 1;
+ bool stallctl : 1;
+ bool sysstall : 1;
+ bool nooverflow : 1;
+ bool atbtrig : 1;
+ bool lpoverride : 1;
+ bool skip_power_up : 1;
+};
+
/**
* struct etmv4_config - configuration information related to an ETMv4
* @mode: Controls various modes supported by this ETM.
@@ -819,8 +907,8 @@ enum etm_impdef_type {
* @cfg: Controls the tracing options.
* @eventctrl0: Controls the tracing of arbitrary events.
* @eventctrl1: Controls the behavior of the events that @event_ctrl0 selects.
- * @stallctl: If functionality that prevents trace unit buffer overflows
- * is available.
+ * @stall_ctrl: Enables trace unit functionality that prevents trace
+ * unit buffer overflows.
* @ts_ctrl: Controls the insertion of global timestamps in the
* trace streams.
* @syncfreq: Controls how often trace synchronization requests occur.
@@ -971,61 +1059,17 @@ struct etmv4_save_state {
* @mode: This tracer's mode, i.e sysFS, Perf or disabled.
* @cpu: The cpu this component is affined to.
* @arch: ETM architecture version.
- * @nr_pe: The number of processing entity available for tracing.
- * @nr_pe_cmp: The number of processing entity comparator inputs that are
- * available for tracing.
- * @nr_addr_cmp:Number of pairs of address comparators available
- * as found in ETMIDR4 0-3.
- * @nr_cntr: Number of counters as found in ETMIDR5 bit 28-30.
- * @nr_ext_inp: Number of external input.
- * @numcidc: Number of contextID comparators.
- * @numvmidc: Number of VMID comparators.
- * @nrseqstate: The number of sequencer states that are implemented.
- * @nr_event: Indicates how many events the trace unit support.
- * @nr_resource:The number of resource selection pairs available for tracing.
- * @nr_ss_cmp: Number of single-shot comparator controls that are available.
+ * @caps: ETM capabilities.
* @trcid: value of the current ID for this component.
- * @trcid_size: Indicates the trace ID width.
- * @ts_size: Global timestamp size field.
- * @ctxid_size: Size of the context ID field to consider.
- * @vmid_size: Size of the VM ID comparator to consider.
- * @ccsize: Indicates the size of the cycle counter in bits.
- * @ccitmin: minimum value that can be programmed in
- * @s_ex_level: In secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
- * @ns_ex_level:In non-secure state, indicates whether instruction tracing is
- * supported for the corresponding Exception level.
* @sticky_enable: true if ETM base configuration has been done.
* @boot_enable:True if we should start tracing at boot time.
* @os_unlock: True if access to management registers is allowed.
- * @instrp0: Tracing of load and store instructions
- * as P0 elements is supported.
- * @q_filt: Q element filtering support, if Q elements are supported.
- * @trcbb: Indicates if the trace unit supports branch broadcast tracing.
- * @trccond: If the trace unit supports conditional
- * instruction tracing.
- * @retstack: Indicates if the implementation supports a return stack.
- * @trccci: Indicates if the trace unit supports cycle counting
- * for instruction.
- * @q_support: Q element support characteristics.
- * @trc_error: Whether a trace unit can trace a system
- * error exception.
- * @syncpr: Indicates if an implementation has a fixed
- * synchronization period.
- * @stall_ctrl: Enables trace unit functionality that prevents trace
- * unit buffer overflows.
- * @sysstall: Does the system support stall control of the PE?
- * @nooverflow: Indicate if overflow prevention is supported.
- * @atbtrig: If the implementation can support ATB triggers
- * @lpoverride: If the implementation can support low-power state over.
* @trfcr: If the CPU supports FEAT_TRF, value of the TRFCR_ELx that
* allows tracing at all ELs. We don't want to compute this
* at runtime, due to the additional setting of TRFCR_CX when
* in EL2. Otherwise, 0.
* @config: structure holding configuration parameters.
* @save_state: State to be preserved across power loss
- * @skip_power_up: Indicates if an implementation can skip powering up
- * the trace unit.
* @paused: Indicates if the trace unit is paused.
* @arch_features: Bitmap of arch features of etmv4 devices.
*/
@@ -1037,46 +1081,11 @@ struct etmv4_drvdata {
raw_spinlock_t spinlock;
int cpu;
u8 arch;
- u8 nr_pe;
- u8 nr_pe_cmp;
- u8 nr_addr_cmp;
- u8 nr_cntr;
- u8 nr_ext_inp;
- u8 numcidc;
- u8 numextinsel;
- u8 numvmidc;
- u8 nrseqstate;
- u8 nr_event;
- u8 nr_resource;
- u8 nr_ss_cmp;
+ struct etmv4_caps caps;
u8 trcid;
- u8 trcid_size;
- u8 ts_size;
- u8 ctxid_size;
- u8 vmid_size;
- u8 ccsize;
- u16 ccitmin;
- u8 s_ex_level;
- u8 ns_ex_level;
- u8 q_support;
- u8 os_lock_model;
bool sticky_enable : 1;
bool boot_enable : 1;
bool os_unlock : 1;
- bool instrp0 : 1;
- bool q_filt : 1;
- bool trcbb : 1;
- bool trccond : 1;
- bool retstack : 1;
- bool trccci : 1;
- bool trc_error : 1;
- bool syncpr : 1;
- bool stallctl : 1;
- bool sysstall : 1;
- bool nooverflow : 1;
- bool atbtrig : 1;
- bool lpoverride : 1;
- bool skip_power_up : 1;
bool paused : 1;
u64 trfcr;
struct etmv4_config config;
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH v3 2/5] coresight: etm4x: exclude ss_status from drvdata->config
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
In-Reply-To: <20260412175506.412301-1-yeoreum.yun@arm.com>
The purpose of TRCSSCSRn register is to show status of
the corresponding Single-shot Comparator Control and input supports.
That means writable field's purpose for reset or restore from idle status
not for configuration.
Therefore, exclude ss_status from drvdata->config, move it to etm4x_caps.
This includes remove TRCSSCRn from configurable item and
remove saving in etm4_disable_hw().
Signed-off-by: Yeoreum Yun <yeoreum.yun@arm.com>
---
.../hwtracing/coresight/coresight-etm4x-cfg.c | 1 -
.../hwtracing/coresight/coresight-etm4x-core.c | 18 +++++-------------
.../coresight/coresight-etm4x-sysfs.c | 7 ++-----
drivers/hwtracing/coresight/coresight-etm4x.h | 3 ++-
4 files changed, 9 insertions(+), 20 deletions(-)
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
index c302072b293a..d14d7c8a23e5 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-cfg.c
@@ -86,7 +86,6 @@ static int etm4_cfg_map_reg_offset(struct etmv4_drvdata *drvdata,
off_mask = (offset & GENMASK(11, 5));
do {
CHECKREGIDX(TRCSSCCRn(0), ss_ctrl, idx, off_mask);
- CHECKREGIDX(TRCSSCSRn(0), ss_status, idx, off_mask);
CHECKREGIDX(TRCSSPCICRn(0), ss_pe_cmp, idx, off_mask);
} while (0);
} else if ((offset >= TRCCIDCVRn(0)) && (offset <= TRCVMIDCVRn(7))) {
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-core.c b/drivers/hwtracing/coresight/coresight-etm4x-core.c
index 6443f3717b37..8ebfd3924143 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-core.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-core.c
@@ -91,7 +91,7 @@ static bool etm4x_sspcicrn_present(struct etmv4_drvdata *drvdata, int n)
const struct etmv4_caps *caps = &drvdata->caps;
return (n < caps->nr_ss_cmp) && caps->nr_pe &&
- (drvdata->config.ss_status[n] & TRCSSCSRn_PC);
+ (caps->ss_status[n] & TRCSSCSRn_PC);
}
u64 etm4x_sysreg_read(u32 offset, bool _relaxed, bool _64bit)
@@ -571,11 +571,9 @@ static int etm4_enable_hw(struct etmv4_drvdata *drvdata)
etm4x_relaxed_write32(csa, config->res_ctrl[i], TRCRSCTLRn(i));
for (i = 0; i < caps->nr_ss_cmp; i++) {
- /* always clear status bit on restart if using single-shot */
- if (config->ss_ctrl[i] || config->ss_pe_cmp[i])
- config->ss_status[i] &= ~TRCSSCSRn_STATUS;
etm4x_relaxed_write32(csa, config->ss_ctrl[i], TRCSSCCRn(i));
- etm4x_relaxed_write32(csa, config->ss_status[i], TRCSSCSRn(i));
+ /* always clear status and pending bits on restart if using single-shot */
+ etm4x_relaxed_write32(csa, caps->ss_status[i], TRCSSCSRn(i));
if (etm4x_sspcicrn_present(drvdata, i))
etm4x_relaxed_write32(csa, config->ss_pe_cmp[i], TRCSSPCICRn(i));
}
@@ -1053,12 +1051,6 @@ static void etm4_disable_hw(struct etmv4_drvdata *drvdata)
etm4_disable_trace_unit(drvdata);
- /* read the status of the single shot comparators */
- for (i = 0; i < caps->nr_ss_cmp; i++) {
- config->ss_status[i] =
- etm4x_relaxed_read32(csa, TRCSSCSRn(i));
- }
-
/* read back the current counter values */
for (i = 0; i < caps->nr_cntr; i++) {
config->cntr_val[i] =
@@ -1501,8 +1493,8 @@ static void etm4_init_arch_data(void *info)
*/
caps->nr_ss_cmp = FIELD_GET(TRCIDR4_NUMSSCC_MASK, etmidr4);
for (i = 0; i < caps->nr_ss_cmp; i++) {
- drvdata->config.ss_status[i] =
- etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+ caps->ss_status[i] = etm4x_relaxed_read32(csa, TRCSSCSRn(i));
+ caps->ss_status[i] &= ~(TRCSSCSRn_STATUS | TRCSSCSRn_PENDING);
}
/* NUMCIDC, bits[27:24] number of Context ID comparators for tracing */
caps->numcidc = FIELD_GET(TRCIDR4_NUMCIDC_MASK, etmidr4);
diff --git a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
index 50408215d1ac..dd62f01674cf 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
+++ b/drivers/hwtracing/coresight/coresight-etm4x-sysfs.c
@@ -1827,8 +1827,6 @@ static ssize_t sshot_ctrl_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_ctrl[idx] = FIELD_PREP(TRCSSCCRn_SAC_ARC_RST_MASK, val);
- /* must clear bit 31 in related status register on programming */
- config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
raw_spin_unlock(&drvdata->spinlock);
return size;
}
@@ -1839,10 +1837,11 @@ static ssize_t sshot_status_show(struct device *dev,
{
unsigned long val;
struct etmv4_drvdata *drvdata = dev_get_drvdata(dev->parent);
+ const struct etmv4_caps *caps = &drvdata->caps;
struct etmv4_config *config = &drvdata->config;
raw_spin_lock(&drvdata->spinlock);
- val = config->ss_status[config->ss_idx];
+ val = caps->ss_status[config->ss_idx];
raw_spin_unlock(&drvdata->spinlock);
return scnprintf(buf, PAGE_SIZE, "%#lx\n", val);
}
@@ -1877,8 +1876,6 @@ static ssize_t sshot_pe_ctrl_store(struct device *dev,
raw_spin_lock(&drvdata->spinlock);
idx = config->ss_idx;
config->ss_pe_cmp[idx] = FIELD_PREP(TRCSSPCICRn_PC_MASK, val);
- /* must clear bit 31 in related status register on programming */
- config->ss_status[idx] &= ~TRCSSCSRn_STATUS;
raw_spin_unlock(&drvdata->spinlock);
return size;
}
diff --git a/drivers/hwtracing/coresight/coresight-etm4x.h b/drivers/hwtracing/coresight/coresight-etm4x.h
index 8eebb83fcaeb..3cc1ca76c933 100644
--- a/drivers/hwtracing/coresight/coresight-etm4x.h
+++ b/drivers/hwtracing/coresight/coresight-etm4x.h
@@ -213,6 +213,7 @@
#define TRCACATRn_EXLEVEL_MASK GENMASK(14, 8)
#define TRCSSCSRn_STATUS BIT(31)
+#define TRCSSCSRn_PENDING BIT(30)
#define TRCSSCCRn_SAC_ARC_RST_MASK GENMASK(24, 0)
#define TRCSSPCICRn_PC_MASK GENMASK(7, 0)
@@ -898,6 +899,7 @@ struct etmv4_caps {
bool atbtrig : 1;
bool lpoverride : 1;
bool skip_power_up : 1;
+ u32 ss_status[ETM_MAX_SS_CMP];
};
/**
@@ -976,7 +978,6 @@ struct etmv4_config {
u32 res_ctrl[ETM_MAX_RES_SEL]; /* TRCRSCTLRn */
u8 ss_idx;
u32 ss_ctrl[ETM_MAX_SS_CMP];
- u32 ss_status[ETM_MAX_SS_CMP];
u32 ss_pe_cmp[ETM_MAX_SS_CMP];
u8 addr_idx;
u64 addr_val[ETM_MAX_SINGLE_ADDR_CMP];
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply related
* [PATCH v3 0/5] fix inconsistencies with sysfs configuration in etmX
From: Yeoreum Yun @ 2026-04-12 17:55 UTC (permalink / raw)
To: coresight, linux-arm-kernel, linux-kernel
Cc: suzuki.poulose, mike.leach, james.clark, alexander.shishkin,
leo.yan, jie.gan, Yeoreum Yun
The current ETMx configuration via sysfs can lead to the following
inconsistencies:
- If a configuration is modified via sysfs while a perf session is
active, the running configuration may differ between before
a sched-out and after a subsequent sched-in.
- If a perf session and sysfs session tries to enable concurrently,
configuration from configfs could be corrupted (etm4).
- There is chance to corrupt drvdata->config if perf session tries
to enabled among handling cscfg_csdev_disable_active_config()
in etm4_disable_sysfs() (etm4).
To resolve these inconsistencies, the configuration should be separated into:
- active_config, which is applied configuration for the current session
- config, which stores the settings configured via sysfs.
and apply configuration from configfs after taking a mode.
This patch based on v7.0-rc7
Patch History
=============
from v2 to v3:
- fix build error for etm3x.
- fix checkpatch warning.
- https://lore.kernel.org/all/20260410074310.2693385-1-yeoreum.yun@arm.com/
from v1 to v2
- rebased to v7.0-rc7.
- introduce etmX_caps structure to save etmX's capabilities.
- remove ss_status from etmv4_config.
- modify active_config after taking a mode (perf/sysfs).
- https://lore.kernel.org/all/20260317181705.2456271-1-yeoreum.yun@arm.com/
Yeoreum Yun (5):
coresight: etm4x: introduce struct etm4_caps
coresight: etm4x: exclude ss_status from drvdata->config
coresight: etm4x: fix inconsistencies with sysfs configration
coresight: etm3x: introduce struct etm_caps
coresight: etm3x: fix inconsistencies with sysfs configration
drivers/hwtracing/coresight/coresight-etm.h | 44 ++-
.../coresight/coresight-etm3x-core.c | 59 ++--
.../coresight/coresight-etm3x-sysfs.c | 29 +-
.../hwtracing/coresight/coresight-etm4x-cfg.c | 3 +-
.../coresight/coresight-etm4x-core.c | 322 ++++++++++--------
.../coresight/coresight-etm4x-sysfs.c | 197 ++++++-----
drivers/hwtracing/coresight/coresight-etm4x.h | 180 +++++-----
7 files changed, 465 insertions(+), 369 deletions(-)
base-commit: 591cd656a1bf5ea94a222af5ef2ee76df029c1d2
--
LEVI:{C3F47F37-75D8-414A-A8BA-3980EC8A46D7}
^ permalink raw reply
* [PATCH] arm: dts: allwinner: t113s mangopi: enable watchdog for reboot
From: Michal Piekos @ 2026-04-12 17:42 UTC (permalink / raw)
To: Rob Herring, Krzysztof Kozlowski, Conor Dooley, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland
Cc: devicetree, linux-arm-kernel, linux-sunxi, linux-kernel,
Michal Piekos
Reboot hangs on MangoPi MQ-R T113s because no restart handler is
available.
Enable the SoC watchdog whose driver registers a restart handler.
Tested on MangoPi MQ-R T113s.
Signed-off-by: Michal Piekos <michal.piekos@mmpsystems.pl>
---
arch/arm/boot/dts/allwinner/sun8i-t113s-mangopi-mq-r-t113.dts | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/arch/arm/boot/dts/allwinner/sun8i-t113s-mangopi-mq-r-t113.dts b/arch/arm/boot/dts/allwinner/sun8i-t113s-mangopi-mq-r-t113.dts
index 8b3a75383816..f0232a5e903b 100644
--- a/arch/arm/boot/dts/allwinner/sun8i-t113s-mangopi-mq-r-t113.dts
+++ b/arch/arm/boot/dts/allwinner/sun8i-t113s-mangopi-mq-r-t113.dts
@@ -33,3 +33,7 @@ rtl8189ftv: wifi@1 {
interrupt-names = "host-wake";
};
};
+
+&wdt {
+ status = "okay";
+};
---
base-commit: f5459048c38a00fc583658d6dcd0f894aff6df8f
change-id: 20260412-t113-mangopi-reboot-hang-c9a9def82e2b
Best regards,
--
Michal Piekos <michal.piekos@mmpsystems.pl>
^ 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