diff options
-rw-r--r-- | arch/metag/Kconfig | 4 | ||||
-rw-r--r-- | arch/metag/Makefile | 2 | ||||
-rw-r--r-- | arch/metag/oprofile/Makefile | 17 | ||||
-rw-r--r-- | arch/metag/oprofile/backtrace.c | 63 | ||||
-rw-r--r-- | arch/metag/oprofile/backtrace.h | 6 | ||||
-rw-r--r-- | arch/metag/oprofile/common.c | 66 |
6 files changed, 158 insertions, 0 deletions
diff --git a/arch/metag/Kconfig b/arch/metag/Kconfig index afc8973d1488..b06b41861aac 100644 --- a/arch/metag/Kconfig +++ b/arch/metag/Kconfig | |||
@@ -25,6 +25,7 @@ config METAG | |||
25 | select HAVE_MEMBLOCK | 25 | select HAVE_MEMBLOCK |
26 | select HAVE_MEMBLOCK_NODE_MAP | 26 | select HAVE_MEMBLOCK_NODE_MAP |
27 | select HAVE_MOD_ARCH_SPECIFIC | 27 | select HAVE_MOD_ARCH_SPECIFIC |
28 | select HAVE_OPROFILE | ||
28 | select HAVE_PERF_EVENTS | 29 | select HAVE_PERF_EVENTS |
29 | select HAVE_SYSCALL_TRACEPOINTS | 30 | select HAVE_SYSCALL_TRACEPOINTS |
30 | select IRQ_DOMAIN | 31 | select IRQ_DOMAIN |
@@ -209,6 +210,9 @@ config METAG_PERFCOUNTER_IRQS | |||
209 | When disabled, Performance Counters information will be collected | 210 | When disabled, Performance Counters information will be collected |
210 | based on Timer Interrupt. | 211 | based on Timer Interrupt. |
211 | 212 | ||
213 | config HW_PERF_EVENTS | ||
214 | def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS | ||
215 | |||
212 | config METAG_DA | 216 | config METAG_DA |
213 | bool "DA support" | 217 | bool "DA support" |
214 | help | 218 | help |
diff --git a/arch/metag/Makefile b/arch/metag/Makefile index 81bd6a1c7483..b566116b171b 100644 --- a/arch/metag/Makefile +++ b/arch/metag/Makefile | |||
@@ -49,6 +49,8 @@ core-y += arch/metag/mm/ | |||
49 | libs-y += arch/metag/lib/ | 49 | libs-y += arch/metag/lib/ |
50 | libs-y += arch/metag/tbx/ | 50 | libs-y += arch/metag/tbx/ |
51 | 51 | ||
52 | drivers-$(CONFIG_OPROFILE) += arch/metag/oprofile/ | ||
53 | |||
52 | boot := arch/metag/boot | 54 | boot := arch/metag/boot |
53 | 55 | ||
54 | boot_targets += uImage | 56 | boot_targets += uImage |
diff --git a/arch/metag/oprofile/Makefile b/arch/metag/oprofile/Makefile new file mode 100644 index 000000000000..c9639d4734d6 --- /dev/null +++ b/arch/metag/oprofile/Makefile | |||
@@ -0,0 +1,17 @@ | |||
1 | obj-$(CONFIG_OPROFILE) += oprofile.o | ||
2 | |||
3 | oprofile-core-y += buffer_sync.o | ||
4 | oprofile-core-y += cpu_buffer.o | ||
5 | oprofile-core-y += event_buffer.o | ||
6 | oprofile-core-y += oprof.o | ||
7 | oprofile-core-y += oprofile_files.o | ||
8 | oprofile-core-y += oprofile_stats.o | ||
9 | oprofile-core-y += oprofilefs.o | ||
10 | oprofile-core-y += timer_int.o | ||
11 | oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o | ||
12 | |||
13 | oprofile-y += backtrace.o | ||
14 | oprofile-y += common.o | ||
15 | oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y)) | ||
16 | |||
17 | ccflags-y += -Werror | ||
diff --git a/arch/metag/oprofile/backtrace.c b/arch/metag/oprofile/backtrace.c new file mode 100644 index 000000000000..7cc3f37cb40e --- /dev/null +++ b/arch/metag/oprofile/backtrace.c | |||
@@ -0,0 +1,63 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2010-2013 Imagination Technologies Ltd. | ||
3 | * | ||
4 | * This file is subject to the terms and conditions of the GNU General Public | ||
5 | * License. See the file "COPYING" in the main directory of this archive | ||
6 | * for more details. | ||
7 | */ | ||
8 | |||
9 | #include <linux/oprofile.h> | ||
10 | #include <linux/uaccess.h> | ||
11 | #include <asm/processor.h> | ||
12 | #include <asm/stacktrace.h> | ||
13 | |||
14 | #include "backtrace.h" | ||
15 | |||
16 | static void user_backtrace_fp(unsigned long __user *fp, unsigned int depth) | ||
17 | { | ||
18 | while (depth-- && access_ok(VERIFY_READ, fp, 8)) { | ||
19 | unsigned long addr; | ||
20 | unsigned long __user *fpnew; | ||
21 | if (__copy_from_user_inatomic(&addr, fp + 1, sizeof(addr))) | ||
22 | break; | ||
23 | addr -= 4; | ||
24 | |||
25 | oprofile_add_trace(addr); | ||
26 | |||
27 | /* stack grows up, so frame pointers must decrease */ | ||
28 | if (__copy_from_user_inatomic(&fpnew, fp + 0, sizeof(fpnew))) | ||
29 | break; | ||
30 | if (fpnew >= fp) | ||
31 | break; | ||
32 | fp = fpnew; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | static int kernel_backtrace_frame(struct stackframe *frame, void *data) | ||
37 | { | ||
38 | unsigned int *depth = data; | ||
39 | |||
40 | oprofile_add_trace(frame->pc); | ||
41 | |||
42 | /* decrement depth and stop if we reach 0 */ | ||
43 | if ((*depth)-- == 0) | ||
44 | return 1; | ||
45 | |||
46 | /* otherwise onto the next frame */ | ||
47 | return 0; | ||
48 | } | ||
49 | |||
50 | void metag_backtrace(struct pt_regs * const regs, unsigned int depth) | ||
51 | { | ||
52 | if (user_mode(regs)) { | ||
53 | unsigned long *fp = (unsigned long *)regs->ctx.AX[1].U0; | ||
54 | user_backtrace_fp((unsigned long __user __force *)fp, depth); | ||
55 | } else { | ||
56 | struct stackframe frame; | ||
57 | frame.fp = regs->ctx.AX[1].U0; /* A0FrP */ | ||
58 | frame.sp = user_stack_pointer(regs); /* A0StP */ | ||
59 | frame.lr = 0; /* from stack */ | ||
60 | frame.pc = regs->ctx.CurrPC; /* PC */ | ||
61 | walk_stackframe(&frame, &kernel_backtrace_frame, &depth); | ||
62 | } | ||
63 | } | ||
diff --git a/arch/metag/oprofile/backtrace.h b/arch/metag/oprofile/backtrace.h new file mode 100644 index 000000000000..c0fcc4265abb --- /dev/null +++ b/arch/metag/oprofile/backtrace.h | |||
@@ -0,0 +1,6 @@ | |||
1 | #ifndef _METAG_OPROFILE_BACKTRACE_H | ||
2 | #define _METAG_OPROFILE_BACKTRACE_H | ||
3 | |||
4 | void metag_backtrace(struct pt_regs * const regs, unsigned int depth); | ||
5 | |||
6 | #endif | ||
diff --git a/arch/metag/oprofile/common.c b/arch/metag/oprofile/common.c new file mode 100644 index 000000000000..ba26152b3c00 --- /dev/null +++ b/arch/metag/oprofile/common.c | |||
@@ -0,0 +1,66 @@ | |||
1 | /* | ||
2 | * arch/metag/oprofile/common.c | ||
3 | * | ||
4 | * Copyright (C) 2013 Imagination Technologies Ltd. | ||
5 | * | ||
6 | * Based on arch/sh/oprofile/common.c: | ||
7 | * | ||
8 | * Copyright (C) 2003 - 2010 Paul Mundt | ||
9 | * | ||
10 | * Based on arch/mips/oprofile/common.c: | ||
11 | * | ||
12 | * Copyright (C) 2004, 2005 Ralf Baechle | ||
13 | * Copyright (C) 2005 MIPS Technologies, Inc. | ||
14 | * | ||
15 | * This file is subject to the terms and conditions of the GNU General Public | ||
16 | * License. See the file "COPYING" in the main directory of this archive | ||
17 | * for more details. | ||
18 | */ | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/oprofile.h> | ||
22 | #include <linux/perf_event.h> | ||
23 | #include <linux/slab.h> | ||
24 | |||
25 | #include "backtrace.h" | ||
26 | |||
27 | #ifdef CONFIG_HW_PERF_EVENTS | ||
28 | /* | ||
29 | * This will need to be reworked when multiple PMUs are supported. | ||
30 | */ | ||
31 | static char *metag_pmu_op_name; | ||
32 | |||
33 | char *op_name_from_perf_id(void) | ||
34 | { | ||
35 | return metag_pmu_op_name; | ||
36 | } | ||
37 | |||
38 | int __init oprofile_arch_init(struct oprofile_operations *ops) | ||
39 | { | ||
40 | ops->backtrace = metag_backtrace; | ||
41 | |||
42 | if (perf_num_counters() == 0) | ||
43 | return -ENODEV; | ||
44 | |||
45 | metag_pmu_op_name = kasprintf(GFP_KERNEL, "metag/%s", | ||
46 | perf_pmu_name()); | ||
47 | if (unlikely(!metag_pmu_op_name)) | ||
48 | return -ENOMEM; | ||
49 | |||
50 | return oprofile_perf_init(ops); | ||
51 | } | ||
52 | |||
53 | void oprofile_arch_exit(void) | ||
54 | { | ||
55 | oprofile_perf_exit(); | ||
56 | kfree(metag_pmu_op_name); | ||
57 | } | ||
58 | #else | ||
59 | int __init oprofile_arch_init(struct oprofile_operations *ops) | ||
60 | { | ||
61 | ops->backtrace = metag_backtrace; | ||
62 | /* fall back to timer interrupt PC sampling */ | ||
63 | return -ENODEV; | ||
64 | } | ||
65 | void oprofile_arch_exit(void) {} | ||
66 | #endif /* CONFIG_HW_PERF_EVENTS */ | ||