aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/oprofile/common.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/oprofile/common.c')
-rw-r--r--arch/powerpc/oprofile/common.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/arch/powerpc/oprofile/common.c b/arch/powerpc/oprofile/common.c
new file mode 100644
index 000000000000..af2c05d20ba5
--- /dev/null
+++ b/arch/powerpc/oprofile/common.c
@@ -0,0 +1,195 @@
1/*
2 * PPC 64 oprofile support:
3 * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, IBM
4 * PPC 32 oprofile support: (based on PPC 64 support)
5 * Copyright (C) Freescale Semiconductor, Inc 2004
6 * Author: Andy Fleming
7 *
8 * Based on alpha version.
9 *
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version
13 * 2 of the License, or (at your option) any later version.
14 */
15
16#include <linux/oprofile.h>
17#ifndef __powerpc64__
18#include <linux/slab.h>
19#endif /* ! __powerpc64__ */
20#include <linux/init.h>
21#include <linux/smp.h>
22#include <linux/errno.h>
23#include <asm/ptrace.h>
24#include <asm/system.h>
25#include <asm/pmc.h>
26#include <asm/cputable.h>
27#include <asm/oprofile_impl.h>
28
29static struct op_powerpc_model *model;
30
31static struct op_counter_config ctr[OP_MAX_COUNTER];
32static struct op_system_config sys;
33
34#ifndef __powerpc64__
35static char *cpu_type;
36#endif /* ! __powerpc64__ */
37
38static void op_handle_interrupt(struct pt_regs *regs)
39{
40 model->handle_interrupt(regs, ctr);
41}
42
43static int op_powerpc_setup(void)
44{
45 int err;
46
47 /* Grab the hardware */
48 err = reserve_pmc_hardware(op_handle_interrupt);
49 if (err)
50 return err;
51
52 /* Pre-compute the values to stuff in the hardware registers. */
53 model->reg_setup(ctr, &sys, model->num_counters);
54
55 /* Configure the registers on all cpus. */
56#ifdef __powerpc64__
57 on_each_cpu(model->cpu_setup, NULL, 0, 1);
58#else /* __powerpc64__ */
59#if 0
60 /* FIXME: Make multi-cpu work */
61 on_each_cpu(model->reg_setup, NULL, 0, 1);
62#endif
63#endif /* __powerpc64__ */
64
65 return 0;
66}
67
68static void op_powerpc_shutdown(void)
69{
70 release_pmc_hardware();
71}
72
73static void op_powerpc_cpu_start(void *dummy)
74{
75 model->start(ctr);
76}
77
78static int op_powerpc_start(void)
79{
80 on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
81 return 0;
82}
83
84static inline void op_powerpc_cpu_stop(void *dummy)
85{
86 model->stop();
87}
88
89static void op_powerpc_stop(void)
90{
91 on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1);
92}
93
94static int op_powerpc_create_files(struct super_block *sb, struct dentry *root)
95{
96 int i;
97
98#ifdef __powerpc64__
99 /*
100 * There is one mmcr0, mmcr1 and mmcra for setting the events for
101 * all of the counters.
102 */
103 oprofilefs_create_ulong(sb, root, "mmcr0", &sys.mmcr0);
104 oprofilefs_create_ulong(sb, root, "mmcr1", &sys.mmcr1);
105 oprofilefs_create_ulong(sb, root, "mmcra", &sys.mmcra);
106#endif /* __powerpc64__ */
107
108 for (i = 0; i < model->num_counters; ++i) {
109 struct dentry *dir;
110 char buf[3];
111
112 snprintf(buf, sizeof buf, "%d", i);
113 dir = oprofilefs_mkdir(sb, root, buf);
114
115 oprofilefs_create_ulong(sb, dir, "enabled", &ctr[i].enabled);
116 oprofilefs_create_ulong(sb, dir, "event", &ctr[i].event);
117 oprofilefs_create_ulong(sb, dir, "count", &ctr[i].count);
118#ifdef __powerpc64__
119 /*
120 * We dont support per counter user/kernel selection, but
121 * we leave the entries because userspace expects them
122 */
123#endif /* __powerpc64__ */
124 oprofilefs_create_ulong(sb, dir, "kernel", &ctr[i].kernel);
125 oprofilefs_create_ulong(sb, dir, "user", &ctr[i].user);
126
127#ifndef __powerpc64__
128 /* FIXME: Not sure if this is used */
129#endif /* ! __powerpc64__ */
130 oprofilefs_create_ulong(sb, dir, "unit_mask", &ctr[i].unit_mask);
131 }
132
133 oprofilefs_create_ulong(sb, root, "enable_kernel", &sys.enable_kernel);
134 oprofilefs_create_ulong(sb, root, "enable_user", &sys.enable_user);
135#ifdef __powerpc64__
136 oprofilefs_create_ulong(sb, root, "backtrace_spinlocks",
137 &sys.backtrace_spinlocks);
138#endif /* __powerpc64__ */
139
140 /* Default to tracing both kernel and user */
141 sys.enable_kernel = 1;
142 sys.enable_user = 1;
143#ifdef __powerpc64__
144 /* Turn on backtracing through spinlocks by default */
145 sys.backtrace_spinlocks = 1;
146#endif /* __powerpc64__ */
147
148 return 0;
149}
150
151int __init oprofile_arch_init(struct oprofile_operations *ops)
152{
153#ifndef __powerpc64__
154#ifdef CONFIG_FSL_BOOKE
155 model = &op_model_fsl_booke;
156#else
157 return -ENODEV;
158#endif
159
160 cpu_type = kmalloc(32, GFP_KERNEL);
161 if (NULL == cpu_type)
162 return -ENOMEM;
163
164 sprintf(cpu_type, "ppc/%s", cur_cpu_spec->cpu_name);
165
166 model->num_counters = cur_cpu_spec->num_pmcs;
167
168 ops->cpu_type = cpu_type;
169#else /* __powerpc64__ */
170 if (!cur_cpu_spec->oprofile_model || !cur_cpu_spec->oprofile_cpu_type)
171 return -ENODEV;
172 model = cur_cpu_spec->oprofile_model;
173 model->num_counters = cur_cpu_spec->num_pmcs;
174
175 ops->cpu_type = cur_cpu_spec->oprofile_cpu_type;
176#endif /* __powerpc64__ */
177 ops->create_files = op_powerpc_create_files;
178 ops->setup = op_powerpc_setup;
179 ops->shutdown = op_powerpc_shutdown;
180 ops->start = op_powerpc_start;
181 ops->stop = op_powerpc_stop;
182
183 printk(KERN_INFO "oprofile: using %s performance monitoring.\n",
184 ops->cpu_type);
185
186 return 0;
187}
188
189void oprofile_arch_exit(void)
190{
191#ifndef __powerpc64__
192 kfree(cpu_type);
193 cpu_type = NULL;
194#endif /* ! __powerpc64__ */
195}