aboutsummaryrefslogtreecommitdiffstats
path: root/arch/metag
diff options
context:
space:
mode:
authorJames Hogan <james.hogan@imgtec.com>2013-03-15 06:21:56 -0400
committerJames Hogan <james.hogan@imgtec.com>2013-03-15 09:21:05 -0400
commit00e6c92304ce38ff48029471c929d31a25e5cf10 (patch)
tree24610804573b95fbf29ed5ff7f7cf190bf532888 /arch/metag
parentf27086f5dcb0c7e9622f724d5279e4dfe4e844a2 (diff)
metag: OProfile support
Add OProfile support for metag, using the perf backend, and falling back to generic timer based sampling if perf counter interrupt support is disabled. The oprofile code prepends "metag/" to the perf pmu name to give "metag/meta2" which is more consistent with other oprofile arch names. The backtrace code makes use of <asm/stacktrace.h> for kernel backtracing, and a simple frame pointer walk for userland backtracing. Signed-off-by: James Hogan <james.hogan@imgtec.com> Cc: Robert Richter <rric@kernel.org> Cc: oprofile-list@lists.sf.net
Diffstat (limited to 'arch/metag')
-rw-r--r--arch/metag/Kconfig4
-rw-r--r--arch/metag/Makefile2
-rw-r--r--arch/metag/oprofile/Makefile17
-rw-r--r--arch/metag/oprofile/backtrace.c63
-rw-r--r--arch/metag/oprofile/backtrace.h6
-rw-r--r--arch/metag/oprofile/common.c66
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
213config HW_PERF_EVENTS
214 def_bool METAG_PERFCOUNTER_IRQS && PERF_EVENTS
215
212config METAG_DA 216config 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/
49libs-y += arch/metag/lib/ 49libs-y += arch/metag/lib/
50libs-y += arch/metag/tbx/ 50libs-y += arch/metag/tbx/
51 51
52drivers-$(CONFIG_OPROFILE) += arch/metag/oprofile/
53
52boot := arch/metag/boot 54boot := arch/metag/boot
53 55
54boot_targets += uImage 56boot_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 @@
1obj-$(CONFIG_OPROFILE) += oprofile.o
2
3oprofile-core-y += buffer_sync.o
4oprofile-core-y += cpu_buffer.o
5oprofile-core-y += event_buffer.o
6oprofile-core-y += oprof.o
7oprofile-core-y += oprofile_files.o
8oprofile-core-y += oprofile_stats.o
9oprofile-core-y += oprofilefs.o
10oprofile-core-y += timer_int.o
11oprofile-core-$(CONFIG_HW_PERF_EVENTS) += oprofile_perf.o
12
13oprofile-y += backtrace.o
14oprofile-y += common.o
15oprofile-y += $(addprefix ../../../drivers/oprofile/,$(oprofile-core-y))
16
17ccflags-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
16static 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
36static 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
50void 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
4void 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 */
31static char *metag_pmu_op_name;
32
33char *op_name_from_perf_id(void)
34{
35 return metag_pmu_op_name;
36}
37
38int __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
53void oprofile_arch_exit(void)
54{
55 oprofile_perf_exit();
56 kfree(metag_pmu_op_name);
57}
58#else
59int __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}
65void oprofile_arch_exit(void) {}
66#endif /* CONFIG_HW_PERF_EVENTS */