Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik...
[linux-2.6-microblaze.git] / arch / powerpc / oprofile / common.c
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
29 static struct op_powerpc_model *model;
30
31 static struct op_counter_config ctr[OP_MAX_COUNTER];
32 static struct op_system_config sys;
33
34 #ifndef __powerpc64__
35 static char *cpu_type;
36 #endif /* ! __powerpc64__ */
37
38 static void op_handle_interrupt(struct pt_regs *regs)
39 {
40         model->handle_interrupt(regs, ctr);
41 }
42
43 static 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
68 static void op_powerpc_shutdown(void)
69 {
70         release_pmc_hardware();
71 }
72
73 static void op_powerpc_cpu_start(void *dummy)
74 {
75         model->start(ctr);
76 }
77
78 static int op_powerpc_start(void)
79 {
80         on_each_cpu(op_powerpc_cpu_start, NULL, 0, 1);
81         return 0;
82 }
83
84 static inline void op_powerpc_cpu_stop(void *dummy)
85 {
86         model->stop();
87 }
88
89 static void op_powerpc_stop(void)
90 {
91         on_each_cpu(op_powerpc_cpu_stop, NULL, 0, 1);
92 }
93
94 static 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
151 int __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
189 void oprofile_arch_exit(void)
190 {
191 #ifndef __powerpc64__
192         kfree(cpu_type);
193         cpu_type = NULL;
194 #endif /* ! __powerpc64__ */
195 }