Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

parisc: Add initial kernel-side perf_event support

Signed-off-by: Helge Deller <deller@gmx.de>

+162 -1
+3
arch/parisc/Kconfig
··· 31 31 select HAVE_KERNEL_UNCOMPRESSED 32 32 select HAVE_PCI 33 33 select HAVE_PERF_EVENTS 34 + select HAVE_PERF_REGS 35 + select HAVE_PERF_USER_STACK_DUMP 36 + select PERF_USE_VMALLOC 34 37 select HAVE_KERNEL_BZIP2 35 38 select HAVE_KERNEL_GZIP 36 39 select HAVE_KERNEL_LZ4
+7 -1
arch/parisc/include/asm/perf_event.h
··· 1 1 #ifndef __ASM_PARISC_PERF_EVENT_H 2 2 #define __ASM_PARISC_PERF_EVENT_H 3 3 4 - /* Empty, just to avoid compiling error */ 4 + #include <asm/psw.h> 5 + 6 + #define perf_arch_fetch_caller_regs(regs, __ip) { \ 7 + (regs)->gr[0] = KERNEL_PSW; \ 8 + (regs)->iaoq[0] = (__ip); \ 9 + asm volatile("copy %%sp, %0\n":"=r"((regs)->gr[30])); \ 10 + } 5 11 6 12 #endif /* __ASM_PARISC_PERF_EVENT_H */
+63
arch/parisc/include/uapi/asm/perf_regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + #ifndef _UAPI_ASM_PARISC_PERF_REGS_H 3 + #define _UAPI_ASM_PARISC_PERF_REGS_H 4 + 5 + /* see struct user_regs_struct */ 6 + enum perf_event_parisc_regs { 7 + PERF_REG_PARISC_R0, /* PSW is in gr[0] */ 8 + PERF_REG_PARISC_R1, 9 + PERF_REG_PARISC_R2, 10 + PERF_REG_PARISC_R3, 11 + PERF_REG_PARISC_R4, 12 + PERF_REG_PARISC_R5, 13 + PERF_REG_PARISC_R6, 14 + PERF_REG_PARISC_R7, 15 + PERF_REG_PARISC_R8, 16 + PERF_REG_PARISC_R9, 17 + PERF_REG_PARISC_R10, 18 + PERF_REG_PARISC_R11, 19 + PERF_REG_PARISC_R12, 20 + PERF_REG_PARISC_R13, 21 + PERF_REG_PARISC_R14, 22 + PERF_REG_PARISC_R15, 23 + PERF_REG_PARISC_R16, 24 + PERF_REG_PARISC_R17, 25 + PERF_REG_PARISC_R18, 26 + PERF_REG_PARISC_R19, 27 + PERF_REG_PARISC_R20, 28 + PERF_REG_PARISC_R21, 29 + PERF_REG_PARISC_R22, 30 + PERF_REG_PARISC_R23, 31 + PERF_REG_PARISC_R24, 32 + PERF_REG_PARISC_R25, 33 + PERF_REG_PARISC_R26, 34 + PERF_REG_PARISC_R27, 35 + PERF_REG_PARISC_R28, 36 + PERF_REG_PARISC_R29, 37 + PERF_REG_PARISC_R30, 38 + PERF_REG_PARISC_R31, 39 + 40 + PERF_REG_PARISC_SR0, 41 + PERF_REG_PARISC_SR1, 42 + PERF_REG_PARISC_SR2, 43 + PERF_REG_PARISC_SR3, 44 + PERF_REG_PARISC_SR4, 45 + PERF_REG_PARISC_SR5, 46 + PERF_REG_PARISC_SR6, 47 + PERF_REG_PARISC_SR7, 48 + 49 + PERF_REG_PARISC_IAOQ0, 50 + PERF_REG_PARISC_IAOQ1, 51 + PERF_REG_PARISC_IASQ0, 52 + PERF_REG_PARISC_IASQ1, 53 + 54 + PERF_REG_PARISC_SAR, /* CR11 */ 55 + PERF_REG_PARISC_IIR, /* CR19 */ 56 + PERF_REG_PARISC_ISR, /* CR20 */ 57 + PERF_REG_PARISC_IOR, /* CR21 */ 58 + PERF_REG_PARISC_IPSW, /* CR22 */ 59 + 60 + PERF_REG_PARISC_MAX 61 + }; 62 + 63 + #endif /* _UAPI_ASM_PARISC_PERF_REGS_H */
+1
arch/parisc/kernel/Makefile
··· 38 38 obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o 39 39 obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o 40 40 obj-$(CONFIG_JUMP_LABEL) += jump_label.o 41 + obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o 41 42 obj-$(CONFIG_KGDB) += kgdb.o 42 43 obj-$(CONFIG_KPROBES) += kprobes.o 43 44 obj-$(CONFIG_KEXEC_CORE) += kexec.o relocate_kernel.o
+27
arch/parisc/kernel/perf_event.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Performance event support for parisc 4 + * 5 + * Copyright (C) 2025 by Helge Deller <deller@gmx.de> 6 + */ 7 + 8 + #include <linux/kernel.h> 9 + #include <linux/perf_event.h> 10 + #include <asm/unwind.h> 11 + 12 + void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, 13 + struct pt_regs *regs) 14 + { 15 + 16 + struct unwind_frame_info info; 17 + 18 + unwind_frame_init_task(&info, current, NULL); 19 + while (1) { 20 + if (unwind_once(&info) < 0 || info.ip == 0) 21 + break; 22 + 23 + if (!__kernel_text_address(info.ip) || 24 + perf_callchain_store(entry, info.ip)) 25 + return; 26 + } 27 + }
+61
arch/parisc/kernel/perf_regs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Copyright (C) 2025 by Helge Deller <deller@gmx.de> */ 4 + 5 + #include <linux/perf_event.h> 6 + #include <linux/perf_regs.h> 7 + #include <asm/ptrace.h> 8 + 9 + u64 perf_reg_value(struct pt_regs *regs, int idx) 10 + { 11 + switch (idx) { 12 + case PERF_REG_PARISC_R0 ... PERF_REG_PARISC_R31: 13 + return regs->gr[idx - PERF_REG_PARISC_R0]; 14 + case PERF_REG_PARISC_SR0 ... PERF_REG_PARISC_SR7: 15 + return regs->sr[idx - PERF_REG_PARISC_SR0]; 16 + case PERF_REG_PARISC_IASQ0 ... PERF_REG_PARISC_IASQ1: 17 + return regs->iasq[idx - PERF_REG_PARISC_IASQ0]; 18 + case PERF_REG_PARISC_IAOQ0 ... PERF_REG_PARISC_IAOQ1: 19 + return regs->iasq[idx - PERF_REG_PARISC_IAOQ0]; 20 + case PERF_REG_PARISC_SAR: /* CR11 */ 21 + return regs->sar; 22 + case PERF_REG_PARISC_IIR: /* CR19 */ 23 + return regs->iir; 24 + case PERF_REG_PARISC_ISR: /* CR20 */ 25 + return regs->isr; 26 + case PERF_REG_PARISC_IOR: /* CR21 */ 27 + return regs->ior; 28 + case PERF_REG_PARISC_IPSW: /* CR22 */ 29 + return regs->ipsw; 30 + }; 31 + WARN_ON_ONCE((u32)idx >= PERF_REG_PARISC_MAX); 32 + return 0; 33 + } 34 + 35 + #define REG_RESERVED (~((1ULL << PERF_REG_PARISC_MAX) - 1)) 36 + 37 + int perf_reg_validate(u64 mask) 38 + { 39 + if (!mask || mask & REG_RESERVED) 40 + return -EINVAL; 41 + 42 + return 0; 43 + } 44 + 45 + u64 perf_reg_abi(struct task_struct *task) 46 + { 47 + if (!IS_ENABLED(CONFIG_64BIT)) 48 + return PERF_SAMPLE_REGS_ABI_32; 49 + 50 + if (test_tsk_thread_flag(task, TIF_32BIT)) 51 + return PERF_SAMPLE_REGS_ABI_32; 52 + 53 + return PERF_SAMPLE_REGS_ABI_64; 54 + } 55 + 56 + void perf_get_regs_user(struct perf_regs *regs_user, 57 + struct pt_regs *regs) 58 + { 59 + regs_user->regs = task_pt_regs(current); 60 + regs_user->abi = perf_reg_abi(current); 61 + }