1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
214f70012SDeng-Cheng Zhu /*
314f70012SDeng-Cheng Zhu * Linux performance counter support for MIPS.
414f70012SDeng-Cheng Zhu *
514f70012SDeng-Cheng Zhu * Copyright (C) 2010 MIPS Technologies, Inc.
614f70012SDeng-Cheng Zhu * Author: Deng-Cheng Zhu
714f70012SDeng-Cheng Zhu *
814f70012SDeng-Cheng Zhu * This code is based on the implementation for ARM, which is in turn
914f70012SDeng-Cheng Zhu * based on the sparc64 perf event code and the x86 code. Performance
107e788d96SDeng-Cheng Zhu * counter access is based on the MIPS Oprofile code. And the callchain
117e788d96SDeng-Cheng Zhu * support references the code of MIPS stacktrace.c.
1214f70012SDeng-Cheng Zhu */
1314f70012SDeng-Cheng Zhu
1414f70012SDeng-Cheng Zhu #include <linux/perf_event.h>
1568db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
1614f70012SDeng-Cheng Zhu
1714f70012SDeng-Cheng Zhu #include <asm/stacktrace.h>
183a9ab99eSDeng-Cheng Zhu
197e788d96SDeng-Cheng Zhu /* Callchain handling code. */
207e788d96SDeng-Cheng Zhu
217e788d96SDeng-Cheng Zhu /*
227e788d96SDeng-Cheng Zhu * Leave userspace callchain empty for now. When we find a way to trace
23e5dcb58aSDavid Daney * the user stack callchains, we will add it here.
247e788d96SDeng-Cheng Zhu */
257e788d96SDeng-Cheng Zhu
save_raw_perf_callchain(struct perf_callchain_entry_ctx * entry,unsigned long reg29)26cfbcf468SArnaldo Carvalho de Melo static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry,
277e788d96SDeng-Cheng Zhu unsigned long reg29)
287e788d96SDeng-Cheng Zhu {
297e788d96SDeng-Cheng Zhu unsigned long *sp = (unsigned long *)reg29;
307e788d96SDeng-Cheng Zhu unsigned long addr;
317e788d96SDeng-Cheng Zhu
327e788d96SDeng-Cheng Zhu while (!kstack_end(sp)) {
337e788d96SDeng-Cheng Zhu addr = *sp++;
347e788d96SDeng-Cheng Zhu if (__kernel_text_address(addr)) {
3598f92f2fSDeng-Cheng Zhu perf_callchain_store(entry, addr);
363b1fff08SArnaldo Carvalho de Melo if (entry->nr >= entry->max_stack)
377e788d96SDeng-Cheng Zhu break;
387e788d96SDeng-Cheng Zhu }
397e788d96SDeng-Cheng Zhu }
407e788d96SDeng-Cheng Zhu }
417e788d96SDeng-Cheng Zhu
perf_callchain_kernel(struct perf_callchain_entry_ctx * entry,struct pt_regs * regs)42cfbcf468SArnaldo Carvalho de Melo void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
4398f92f2fSDeng-Cheng Zhu struct pt_regs *regs)
447e788d96SDeng-Cheng Zhu {
457e788d96SDeng-Cheng Zhu unsigned long sp = regs->regs[29];
467e788d96SDeng-Cheng Zhu #ifdef CONFIG_KALLSYMS
477e788d96SDeng-Cheng Zhu unsigned long ra = regs->regs[31];
487e788d96SDeng-Cheng Zhu unsigned long pc = regs->cp0_epc;
497e788d96SDeng-Cheng Zhu
507e788d96SDeng-Cheng Zhu if (raw_show_trace || !__kernel_text_address(pc)) {
517e788d96SDeng-Cheng Zhu unsigned long stack_page =
527e788d96SDeng-Cheng Zhu (unsigned long)task_stack_page(current);
537e788d96SDeng-Cheng Zhu if (stack_page && sp >= stack_page &&
547e788d96SDeng-Cheng Zhu sp <= stack_page + THREAD_SIZE - 32)
557e788d96SDeng-Cheng Zhu save_raw_perf_callchain(entry, sp);
567e788d96SDeng-Cheng Zhu return;
577e788d96SDeng-Cheng Zhu }
587e788d96SDeng-Cheng Zhu do {
5998f92f2fSDeng-Cheng Zhu perf_callchain_store(entry, pc);
603b1fff08SArnaldo Carvalho de Melo if (entry->nr >= entry->max_stack)
617e788d96SDeng-Cheng Zhu break;
627e788d96SDeng-Cheng Zhu pc = unwind_stack(current, &sp, pc, &ra);
637e788d96SDeng-Cheng Zhu } while (pc);
647e788d96SDeng-Cheng Zhu #else
657e788d96SDeng-Cheng Zhu save_raw_perf_callchain(entry, sp);
667e788d96SDeng-Cheng Zhu #endif
677e788d96SDeng-Cheng Zhu }
68