diff options
Diffstat (limited to 'arch/parisc/kernel')
| -rw-r--r-- | arch/parisc/kernel/Makefile | 1 | ||||
| -rw-r--r-- | arch/parisc/kernel/drivers.c | 6 | ||||
| -rw-r--r-- | arch/parisc/kernel/firmware.c | 3 | ||||
| -rw-r--r-- | arch/parisc/kernel/perf_event.c | 27 | ||||
| -rw-r--r-- | arch/parisc/kernel/perf_regs.c | 61 | ||||
| -rw-r--r-- | arch/parisc/kernel/traps.c | 2 | ||||
| -rw-r--r-- | arch/parisc/kernel/unaligned.c | 2 | 
7 files changed, 101 insertions, 1 deletions
diff --git a/arch/parisc/kernel/Makefile b/arch/parisc/kernel/Makefile index d5055ba33722..9157bc8bdf41 100644 --- a/arch/parisc/kernel/Makefile +++ b/arch/parisc/kernel/Makefile @@ -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/drivers.c b/arch/parisc/kernel/drivers.c index 1e793f770f71..1f8936fc2292 100644 --- a/arch/parisc/kernel/drivers.c +++ b/arch/parisc/kernel/drivers.c @@ -995,6 +995,7 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)  	struct pdc_system_map_mod_info pdc_mod_info;  	struct pdc_module_path mod_path; +	memset(&iodc_data, 0, sizeof(iodc_data));  	status = pdc_iodc_read(&count, hpa, 0,  		&iodc_data, sizeof(iodc_data));  	if (status != PDC_OK) { @@ -1012,6 +1013,11 @@ static __init int qemu_print_iodc_data(struct device *lin_dev, void *data)  	mod_index = 0;  	do { +		/* initialize device path for old machines */ +		memset(&mod_path, 0xff, sizeof(mod_path)); +		get_node_path(dev->dev.parent, &mod_path.path); +		mod_path.path.mod = dev->hw_path; +		memset(&pdc_mod_info, 0, sizeof(pdc_mod_info));  		status = pdc_system_map_find_mods(&pdc_mod_info,  				&mod_path, mod_index++);  	} while (status == PDC_OK && pdc_mod_info.mod_addr != hpa); diff --git a/arch/parisc/kernel/firmware.c b/arch/parisc/kernel/firmware.c index c69f6d5946e9..042343492a28 100644 --- a/arch/parisc/kernel/firmware.c +++ b/arch/parisc/kernel/firmware.c @@ -464,7 +464,8 @@ int pdc_system_map_find_mods(struct pdc_system_map_mod_info *pdc_mod_info,  	unsigned long flags;  	spin_lock_irqsave(&pdc_lock, flags); -	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),  +	memcpy(pdc_result2, mod_path, sizeof(*mod_path)); +	retval = mem_pdc_call(PDC_SYSTEM_MAP, PDC_FIND_MODULE, __pa(pdc_result),  			      __pa(pdc_result2), mod_index);  	convert_to_wide(pdc_result);  	memcpy(pdc_mod_info, pdc_result, sizeof(*pdc_mod_info)); diff --git a/arch/parisc/kernel/perf_event.c b/arch/parisc/kernel/perf_event.c new file mode 100644 index 000000000000..f90b83886ab4 --- /dev/null +++ b/arch/parisc/kernel/perf_event.c @@ -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 index 000000000000..68458e2f6197 --- /dev/null +++ b/arch/parisc/kernel/perf_regs.c @@ -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); +} diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index b9b3d527bc90..4c7c5df80bd0 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c @@ -31,6 +31,7 @@  #include <linux/uaccess.h>  #include <linux/kdebug.h>  #include <linux/kfence.h> +#include <linux/perf_event.h>  #include <asm/assembly.h>  #include <asm/io.h> @@ -633,6 +634,7 @@ void notrace handle_interruption(int code, struct pt_regs *regs)  		/* Assist Exception Trap, i.e. floating point exception. */  		die_if_kernel("Floating point exception", regs, 0); /* quiet */  		__inc_irq_stat(irq_fpassist_count); +		perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);  		handle_fpe(regs);  		return; diff --git a/arch/parisc/kernel/unaligned.c b/arch/parisc/kernel/unaligned.c index 00e97204783e..fb64d9ce0b17 100644 --- a/arch/parisc/kernel/unaligned.c +++ b/arch/parisc/kernel/unaligned.c @@ -13,6 +13,7 @@  #include <linux/uaccess.h>  #include <linux/sysctl.h>  #include <linux/unaligned.h> +#include <linux/perf_event.h>  #include <asm/hardirq.h>  #include <asm/traps.h>  #include "unaligned.h" @@ -378,6 +379,7 @@ void handle_unaligned(struct pt_regs *regs)  	int ret = ERR_NOTHANDLED;  	__inc_irq_stat(irq_unaligned_count); +	perf_sw_event(PERF_COUNT_SW_ALIGNMENT_FAULTS, 1, regs, regs->ior);  	/* log a message with pacing */  	if (user_mode(regs)) {  | 
