]> www.infradead.org Git - users/hch/misc.git/commitdiff
parisc: Add initial kernel-side perf_event support
authorHelge Deller <deller@gmx.de>
Tue, 7 Oct 2025 15:08:16 +0000 (17:08 +0200)
committerHelge Deller <deller@gmx.de>
Tue, 7 Oct 2025 17:35:51 +0000 (19:35 +0200)
Signed-off-by: Helge Deller <deller@gmx.de>
arch/parisc/Kconfig
arch/parisc/include/asm/perf_event.h
arch/parisc/include/uapi/asm/perf_regs.h [new file with mode: 0644]
arch/parisc/kernel/Makefile
arch/parisc/kernel/perf_event.c [new file with mode: 0644]
arch/parisc/kernel/perf_regs.c [new file with mode: 0644]

index 2efa4b08b7b841aa75cbfb1045d3bc47778a4cd4..7abc5f16c280b8e64b8053d44d16a2e909cd29da 100644 (file)
@@ -31,6 +31,9 @@ config PARISC
        select HAVE_KERNEL_UNCOMPRESSED
        select HAVE_PCI
        select HAVE_PERF_EVENTS
+       select HAVE_PERF_REGS
+       select HAVE_PERF_USER_STACK_DUMP
+       select PERF_USE_VMALLOC
        select HAVE_KERNEL_BZIP2
        select HAVE_KERNEL_GZIP
        select HAVE_KERNEL_LZ4
index 1e0fd8ba6c033e5f277afc02075fc7de57b1adc6..8a2925029d157d5e92064a3301c3e4d09ca3d22e 100644 (file)
@@ -1,6 +1,12 @@
 #ifndef __ASM_PARISC_PERF_EVENT_H
 #define __ASM_PARISC_PERF_EVENT_H
 
-/* Empty, just to avoid compiling error */
+#include <asm/psw.h>
+
+#define perf_arch_fetch_caller_regs(regs, __ip) { \
+       (regs)->gr[0] = KERNEL_PSW; \
+       (regs)->iaoq[0] = (__ip); \
+       asm volatile("copy %%sp, %0\n":"=r"((regs)->gr[30])); \
+}
 
 #endif /* __ASM_PARISC_PERF_EVENT_H */
diff --git a/arch/parisc/include/uapi/asm/perf_regs.h b/arch/parisc/include/uapi/asm/perf_regs.h
new file mode 100644 (file)
index 0000000..1ae687b
--- /dev/null
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+#ifndef _UAPI_ASM_PARISC_PERF_REGS_H
+#define _UAPI_ASM_PARISC_PERF_REGS_H
+
+/* see struct user_regs_struct */
+enum perf_event_parisc_regs {
+       PERF_REG_PARISC_R0,     /* PSW is in gr[0] */
+       PERF_REG_PARISC_R1,
+       PERF_REG_PARISC_R2,
+       PERF_REG_PARISC_R3,
+       PERF_REG_PARISC_R4,
+       PERF_REG_PARISC_R5,
+       PERF_REG_PARISC_R6,
+       PERF_REG_PARISC_R7,
+       PERF_REG_PARISC_R8,
+       PERF_REG_PARISC_R9,
+       PERF_REG_PARISC_R10,
+       PERF_REG_PARISC_R11,
+       PERF_REG_PARISC_R12,
+       PERF_REG_PARISC_R13,
+       PERF_REG_PARISC_R14,
+       PERF_REG_PARISC_R15,
+       PERF_REG_PARISC_R16,
+       PERF_REG_PARISC_R17,
+       PERF_REG_PARISC_R18,
+       PERF_REG_PARISC_R19,
+       PERF_REG_PARISC_R20,
+       PERF_REG_PARISC_R21,
+       PERF_REG_PARISC_R22,
+       PERF_REG_PARISC_R23,
+       PERF_REG_PARISC_R24,
+       PERF_REG_PARISC_R25,
+       PERF_REG_PARISC_R26,
+       PERF_REG_PARISC_R27,
+       PERF_REG_PARISC_R28,
+       PERF_REG_PARISC_R29,
+       PERF_REG_PARISC_R30,
+       PERF_REG_PARISC_R31,
+
+       PERF_REG_PARISC_SR0,
+       PERF_REG_PARISC_SR1,
+       PERF_REG_PARISC_SR2,
+       PERF_REG_PARISC_SR3,
+       PERF_REG_PARISC_SR4,
+       PERF_REG_PARISC_SR5,
+       PERF_REG_PARISC_SR6,
+       PERF_REG_PARISC_SR7,
+
+       PERF_REG_PARISC_IAOQ0,
+       PERF_REG_PARISC_IAOQ1,
+       PERF_REG_PARISC_IASQ0,
+       PERF_REG_PARISC_IASQ1,
+
+       PERF_REG_PARISC_SAR,    /* CR11 */
+       PERF_REG_PARISC_IIR,    /* CR19 */
+       PERF_REG_PARISC_ISR,    /* CR20 */
+       PERF_REG_PARISC_IOR,    /* CR21 */
+       PERF_REG_PARISC_IPSW,   /* CR22 */
+
+       PERF_REG_PARISC_MAX
+};
+
+#endif /* _UAPI_ASM_PARISC_PERF_REGS_H */
index d5055ba33722883d4f9ba7e5276144a22b47c30d..9157bc8bdf41cbf41a33b09646199743c1e376ab 100644 (file)
@@ -38,6 +38,7 @@ obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY)   += topology.o
 obj-$(CONFIG_FUNCTION_TRACER)          += ftrace.o
 obj-$(CONFIG_FUNCTION_GRAPH_TRACER)    += ftrace.o
 obj-$(CONFIG_JUMP_LABEL)               += jump_label.o
+obj-$(CONFIG_PERF_EVENTS)              += perf_event.o perf_regs.o
 obj-$(CONFIG_KGDB)                     += kgdb.o
 obj-$(CONFIG_KPROBES)                  += kprobes.o
 obj-$(CONFIG_KEXEC_CORE)               += kexec.o relocate_kernel.o
diff --git a/arch/parisc/kernel/perf_event.c b/arch/parisc/kernel/perf_event.c
new file mode 100644 (file)
index 0000000..f90b838
--- /dev/null
@@ -0,0 +1,27 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Performance event support for parisc
+ *
+ * Copyright (C) 2025 by Helge Deller <deller@gmx.de>
+ */
+
+#include <linux/kernel.h>
+#include <linux/perf_event.h>
+#include <asm/unwind.h>
+
+void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
+                          struct pt_regs *regs)
+{
+
+       struct unwind_frame_info info;
+
+       unwind_frame_init_task(&info, current, NULL);
+       while (1) {
+               if (unwind_once(&info) < 0 || info.ip == 0)
+                       break;
+
+               if (!__kernel_text_address(info.ip) ||
+                       perf_callchain_store(entry, info.ip))
+                               return;
+       }
+}
diff --git a/arch/parisc/kernel/perf_regs.c b/arch/parisc/kernel/perf_regs.c
new file mode 100644 (file)
index 0000000..68458e2
--- /dev/null
@@ -0,0 +1,61 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/* Copyright (C) 2025 by Helge Deller <deller@gmx.de> */
+
+#include <linux/perf_event.h>
+#include <linux/perf_regs.h>
+#include <asm/ptrace.h>
+
+u64 perf_reg_value(struct pt_regs *regs, int idx)
+{
+       switch (idx) {
+       case PERF_REG_PARISC_R0 ... PERF_REG_PARISC_R31:
+               return regs->gr[idx - PERF_REG_PARISC_R0];
+       case PERF_REG_PARISC_SR0 ... PERF_REG_PARISC_SR7:
+               return regs->sr[idx - PERF_REG_PARISC_SR0];
+       case PERF_REG_PARISC_IASQ0 ... PERF_REG_PARISC_IASQ1:
+               return regs->iasq[idx - PERF_REG_PARISC_IASQ0];
+       case PERF_REG_PARISC_IAOQ0 ... PERF_REG_PARISC_IAOQ1:
+               return regs->iasq[idx - PERF_REG_PARISC_IAOQ0];
+       case PERF_REG_PARISC_SAR:       /* CR11 */
+               return regs->sar;
+       case PERF_REG_PARISC_IIR:       /* CR19 */
+               return regs->iir;
+       case PERF_REG_PARISC_ISR:       /* CR20 */
+               return regs->isr;
+       case PERF_REG_PARISC_IOR:       /* CR21 */
+               return regs->ior;
+       case PERF_REG_PARISC_IPSW:      /* CR22 */
+               return regs->ipsw;
+       };
+       WARN_ON_ONCE((u32)idx >= PERF_REG_PARISC_MAX);
+       return 0;
+}
+
+#define REG_RESERVED (~((1ULL << PERF_REG_PARISC_MAX) - 1))
+
+int perf_reg_validate(u64 mask)
+{
+       if (!mask || mask & REG_RESERVED)
+               return -EINVAL;
+
+       return 0;
+}
+
+u64 perf_reg_abi(struct task_struct *task)
+{
+       if (!IS_ENABLED(CONFIG_64BIT))
+               return PERF_SAMPLE_REGS_ABI_32;
+
+       if (test_tsk_thread_flag(task, TIF_32BIT))
+               return PERF_SAMPLE_REGS_ABI_32;
+
+       return PERF_SAMPLE_REGS_ABI_64;
+}
+
+void perf_get_regs_user(struct perf_regs *regs_user,
+                       struct pt_regs *regs)
+{
+       regs_user->regs = task_pt_regs(current);
+       regs_user->abi = perf_reg_abi(current);
+}