]>
Commit | Line | Data |
---|---|---|
14f70012 DCZ |
1 | /* |
2 | * Linux performance counter support for MIPS. | |
3 | * | |
4 | * Copyright (C) 2010 MIPS Technologies, Inc. | |
5 | * Author: Deng-Cheng Zhu | |
6 | * | |
7 | * This code is based on the implementation for ARM, which is in turn | |
8 | * based on the sparc64 perf event code and the x86 code. Performance | |
7e788d96 DCZ |
9 | * counter access is based on the MIPS Oprofile code. And the callchain |
10 | * support references the code of MIPS stacktrace.c. | |
14f70012 DCZ |
11 | * |
12 | * This program is free software; you can redistribute it and/or modify | |
13 | * it under the terms of the GNU General Public License version 2 as | |
14 | * published by the Free Software Foundation. | |
15 | */ | |
16 | ||
14f70012 | 17 | #include <linux/perf_event.h> |
68db0cf1 | 18 | #include <linux/sched/task_stack.h> |
14f70012 | 19 | |
14f70012 | 20 | #include <asm/stacktrace.h> |
3a9ab99e | 21 | |
7e788d96 | 22 | /* Callchain handling code. */ |
7e788d96 DCZ |
23 | |
24 | /* | |
25 | * Leave userspace callchain empty for now. When we find a way to trace | |
e5dcb58a | 26 | * the user stack callchains, we will add it here. |
7e788d96 | 27 | */ |
7e788d96 | 28 | |
cfbcf468 ACM |
29 | static void save_raw_perf_callchain(struct perf_callchain_entry_ctx *entry, |
30 | unsigned long reg29) | |
7e788d96 DCZ |
31 | { |
32 | unsigned long *sp = (unsigned long *)reg29; | |
33 | unsigned long addr; | |
34 | ||
35 | while (!kstack_end(sp)) { | |
36 | addr = *sp++; | |
37 | if (__kernel_text_address(addr)) { | |
98f92f2f | 38 | perf_callchain_store(entry, addr); |
3b1fff08 | 39 | if (entry->nr >= entry->max_stack) |
7e788d96 DCZ |
40 | break; |
41 | } | |
42 | } | |
43 | } | |
44 | ||
cfbcf468 ACM |
45 | void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, |
46 | struct pt_regs *regs) | |
7e788d96 DCZ |
47 | { |
48 | unsigned long sp = regs->regs[29]; | |
49 | #ifdef CONFIG_KALLSYMS | |
50 | unsigned long ra = regs->regs[31]; | |
51 | unsigned long pc = regs->cp0_epc; | |
52 | ||
7e788d96 DCZ |
53 | if (raw_show_trace || !__kernel_text_address(pc)) { |
54 | unsigned long stack_page = | |
55 | (unsigned long)task_stack_page(current); | |
56 | if (stack_page && sp >= stack_page && | |
57 | sp <= stack_page + THREAD_SIZE - 32) | |
58 | save_raw_perf_callchain(entry, sp); | |
59 | return; | |
60 | } | |
61 | do { | |
98f92f2f | 62 | perf_callchain_store(entry, pc); |
3b1fff08 | 63 | if (entry->nr >= entry->max_stack) |
7e788d96 DCZ |
64 | break; |
65 | pc = unwind_stack(current, &sp, pc, &ra); | |
66 | } while (pc); | |
67 | #else | |
7e788d96 DCZ |
68 | save_raw_perf_callchain(entry, sp); |
69 | #endif | |
70 | } |