aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Rogan <bcr6@cornell.edu>2006-03-26 19:57:01 -0500
committerPaul Mackerras <paulus@samba.org>2006-03-28 21:44:16 -0500
commit6c6bd754bf43d59756f094de144ecac239629dda (patch)
treeb6cf2a7a3f133d24d22c63ba7bb8f9ebb02a8bab
parentb848e0a07dd5a874821bb587bb724fac4aa45bad (diff)
[PATCH] powerpc: Add oprofile calltrace support
Add oprofile calltrace support to powerpc. Disable spinlock backtracing now we can use calltrace info. (Updated to work on both 32bit and 64bit by me). Signed-off-by: Anton Blanchard <anton@samba.org> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/oprofile/Makefile2
-rw-r--r--arch/powerpc/oprofile/backtrace.c126
-rw-r--r--arch/powerpc/oprofile/common.c4
-rw-r--r--arch/powerpc/oprofile/op_model_power4.c2
-rw-r--r--include/asm-powerpc/oprofile_impl.h2
5 files changed, 132 insertions, 4 deletions
diff --git a/arch/powerpc/oprofile/Makefile b/arch/powerpc/oprofile/Makefile
index 554cd7c75321..f5f9859a8338 100644
--- a/arch/powerpc/oprofile/Makefile
+++ b/arch/powerpc/oprofile/Makefile
@@ -6,7 +6,7 @@ DRIVER_OBJS := $(addprefix ../../../drivers/oprofile/, \
6 oprofilefs.o oprofile_stats.o \ 6 oprofilefs.o oprofile_stats.o \
7 timer_int.o ) 7 timer_int.o )
8 8
9oprofile-y := $(DRIVER_OBJS) common.o 9oprofile-y := $(DRIVER_OBJS) common.o backtrace.o
10oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o 10oprofile-$(CONFIG_PPC64) += op_model_rs64.o op_model_power4.o
11oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o 11oprofile-$(CONFIG_FSL_BOOKE) += op_model_fsl_booke.o
12oprofile-$(CONFIG_PPC32) += op_model_7450.o 12oprofile-$(CONFIG_PPC32) += op_model_7450.o
diff --git a/arch/powerpc/oprofile/backtrace.c b/arch/powerpc/oprofile/backtrace.c
new file mode 100644
index 000000000000..75f57bc96b40
--- /dev/null
+++ b/arch/powerpc/oprofile/backtrace.c
@@ -0,0 +1,126 @@
1/**
2 * Copyright (C) 2005 Brian Rogan <bcr6@cornell.edu>, IBM
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; either version
7 * 2 of the License, or (at your option) any later version.
8**/
9
10#include <linux/oprofile.h>
11#include <linux/sched.h>
12#include <asm/processor.h>
13#include <asm/uaccess.h>
14
15#define STACK_SP(STACK) *(STACK)
16
17#define STACK_LR64(STACK) *((unsigned long *)(STACK) + 2)
18#define STACK_LR32(STACK) *((unsigned int *)(STACK) + 1)
19
20#ifdef CONFIG_PPC64
21#define STACK_LR(STACK) STACK_LR64(STACK)
22#else
23#define STACK_LR(STACK) STACK_LR32(STACK)
24#endif
25
26static unsigned int user_getsp32(unsigned int sp, int is_first)
27{
28 unsigned int stack_frame[2];
29
30 if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
31 return 0;
32
33 /*
34 * The most likely reason for this is that we returned -EFAULT,
35 * which means that we've done all that we can do from
36 * interrupt context.
37 */
38 if (__copy_from_user_inatomic(stack_frame, (void *)(long)sp,
39 sizeof(stack_frame)))
40 return 0;
41
42 if (!is_first)
43 oprofile_add_trace(STACK_LR32(stack_frame));
44
45 /*
46 * We do not enforce increasing stack addresses here because
47 * we may transition to a different stack, eg a signal handler.
48 */
49 return STACK_SP(stack_frame);
50}
51
52#ifdef CONFIG_PPC64
53static unsigned long user_getsp64(unsigned long sp, int is_first)
54{
55 unsigned long stack_frame[3];
56
57 if (!access_ok(VERIFY_READ, sp, sizeof(stack_frame)))
58 return 0;
59
60 if (__copy_from_user_inatomic(stack_frame, (void *)sp,
61 sizeof(stack_frame)))
62 return 0;
63
64 if (!is_first)
65 oprofile_add_trace(STACK_LR64(stack_frame));
66
67 return STACK_SP(stack_frame);
68}
69#endif
70
71static unsigned long kernel_getsp(unsigned long sp, int is_first)
72{
73 unsigned long *stack_frame = (unsigned long *)sp;
74
75 if (!validate_sp(sp, current, STACK_FRAME_OVERHEAD))
76 return 0;
77
78 if (!is_first)
79 oprofile_add_trace(STACK_LR(stack_frame));
80
81 /*
82 * We do not enforce increasing stack addresses here because
83 * we might be transitioning from an interrupt stack to a kernel
84 * stack. validate_sp() is designed to understand this, so just
85 * use it.
86 */
87 return STACK_SP(stack_frame);
88}
89
90void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth)
91{
92 unsigned long sp = regs->gpr[1];
93 int first_frame = 1;
94
95 /* We ditch the top stackframe so need to loop through an extra time */
96 depth += 1;
97
98 if (!user_mode(regs)) {
99 while (depth--) {
100 sp = kernel_getsp(sp, first_frame);
101 if (!sp)
102 break;
103 first_frame = 0;
104 }
105 } else {
106#ifdef CONFIG_PPC64
107 if (!test_thread_flag(TIF_32BIT)) {
108 while (depth--) {
109 sp = user_getsp64(sp, first_frame);
110 if (!sp)
111 break;
112 first_frame = 0;
113 }
114
115 return;
116 }
117#endif
118
119 while (depth--) {
120 sp = user_getsp32(sp, first_frame);
121 if (!sp)
122 break;
123 first_frame = 0;
124 }
125 }
126}
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
index cc2535be3a73..2b9143b0f6ba 100644
--- a/arch/powerpc/oprofile/common.c
+++ b/arch/powerpc/oprofile/common.c
@@ -126,8 +126,7 @@ static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
126 sys.enable_kernel = 1; 126 sys.enable_kernel = 1;
127 sys.enable_user = 1; 127 sys.enable_user = 1;
128#ifdef CONFIG_PPC64 128#ifdef CONFIG_PPC64
129 /* Turn on backtracing through spinlocks by default */ 129 sys.backtrace_spinlocks = 0;
130 sys.backtrace_spinlocks = 1;
131#endif 130#endif
132 131
133 return 0; 132 return 0;
@@ -168,6 +167,7 @@ int __init oprofile_arch_init(struct oprofile_operations *ops)
168 ops->shutdown = op_powerpc_shutdown; 167 ops->shutdown = op_powerpc_shutdown;
169 ops->start = op_powerpc_start; 168 ops->start = op_powerpc_start;
170 ops->stop = op_powerpc_stop; 169 ops->stop = op_powerpc_stop;
170 ops->backtrace = op_powerpc_backtrace;
171 171
172 printk(KERN_INFO "oprofile: using %s performance monitoring.\n", 172 printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
173 ops->cpu_type); 173 ops->cpu_type);
diff --git a/arch/powerpc/oprofile/op_model_power4.c b/arch/powerpc/oprofile/op_model_power4.c
index 4b06e53eb9b4..38db2efef3bc 100644
--- a/arch/powerpc/oprofile/op_model_power4.c
+++ b/arch/powerpc/oprofile/op_model_power4.c
@@ -293,7 +293,7 @@ static void power4_handle_interrupt(struct pt_regs *regs,
293 val = ctr_read(i); 293 val = ctr_read(i);
294 if (val < 0) { 294 if (val < 0) {
295 if (oprofile_running && ctr[i].enabled) { 295 if (oprofile_running && ctr[i].enabled) {
296 oprofile_add_pc(pc, is_kernel, i); 296 oprofile_add_ext_sample(pc, regs, i, is_kernel);
297 ctr_write(i, reset_value[i]); 297 ctr_write(i, reset_value[i]);
298 } else { 298 } else {
299 ctr_write(i, 0); 299 ctr_write(i, 0);
diff --git a/include/asm-powerpc/oprofile_impl.h b/include/asm-powerpc/oprofile_impl.h
index df4defc6321c..aa180e907a67 100644
--- a/include/asm-powerpc/oprofile_impl.h
+++ b/include/asm-powerpc/oprofile_impl.h
@@ -126,5 +126,7 @@ static inline void ctr_write(unsigned int i, unsigned int val)
126} 126}
127#endif /* !CONFIG_FSL_BOOKE */ 127#endif /* !CONFIG_FSL_BOOKE */
128 128
129extern void op_powerpc_backtrace(struct pt_regs * const regs, unsigned int depth);
130
129#endif /* __KERNEL__ */ 131#endif /* __KERNEL__ */
130#endif /* _ASM_POWERPC_OPROFILE_IMPL_H */ 132#endif /* _ASM_POWERPC_OPROFILE_IMPL_H */