ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / arch / ppc64 / oprofile / op_model_power4.c
1 /*
2  * Copyright (C) 2004 Anton Blanchard <anton@au.ibm.com>, 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/init.h>
12 #include <linux/smp.h>
13 #include <asm/ptrace.h>
14 #include <asm/system.h>
15 #include <asm/processor.h>
16 #include <asm/cputable.h>
17 #include <asm/systemcfg.h>
18 #include <asm/rtas.h>
19
20 #define dbg(args...) printk(args)
21
22 #include "op_impl.h"
23
24 static unsigned long reset_value[OP_MAX_COUNTER];
25
26 static int num_counters;
27
28 static void power4_reg_setup(struct op_counter_config *ctr,
29                              struct op_system_config *sys,
30                              int num_ctrs)
31 {
32         int i;
33
34         num_counters = num_ctrs;
35
36         for (i = 0; i < num_counters; ++i)
37                 reset_value[i] = 0x80000000UL - ctr[i].count;
38
39         /* XXX setup user and kernel profiling */
40 }
41
42 extern void ppc64_enable_pmcs(void);
43
44 static void power4_cpu_setup(void *unused)
45 {
46         unsigned int mmcr0 = mfspr(SPRN_MMCR0);
47         unsigned long mmcra = mfspr(SPRN_MMCRA);
48
49         ppc64_enable_pmcs();
50
51         /* set the freeze bit */
52         mmcr0 |= MMCR0_FC;
53         mtspr(SPRN_MMCR0, mmcr0);
54
55         mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
56         mmcr0 |= MMCR0_PMC1INTCONTROL|MMCR0_PMCNINTCONTROL;
57         mtspr(SPRN_MMCR0, mmcr0);
58
59         mmcra |= MMCRA_SAMPLE_ENABLE;
60         mtspr(SPRN_MMCRA, mmcra);
61
62         dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
63             mfspr(SPRN_MMCR0));
64         dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
65             mfspr(SPRN_MMCR1));
66         dbg("setup on cpu %d, mmcra %lx\n", smp_processor_id(),
67             mfspr(SPRN_MMCRA));
68 }
69
70 static void power4_start(struct op_counter_config *ctr)
71 {
72         int i;
73         unsigned int mmcr0;
74
75         /* set the PMM bit (see comment below) */
76         mtmsrd(mfmsr() | MSR_PMM);
77
78         for (i = 0; i < num_counters; ++i) {
79                 if (ctr[i].enabled) {
80                         ctr_write(i, reset_value[i]);
81                 } else {
82                         ctr_write(i, 0);
83                 }
84         }
85
86         mmcr0 = mfspr(SPRN_MMCR0);
87
88         /*
89          * We must clear the PMAO bit on some (GQ) chips. Just do it
90          * all the time
91          */
92         mmcr0 &= ~MMCR0_PMAO;
93
94         /*
95          * now clear the freeze bit, counting will not start until we
96          * rfid from this excetion, because only at that point will
97          * the PMM bit be cleared
98          */
99         mmcr0 &= ~MMCR0_FC;
100         mtspr(SPRN_MMCR0, mmcr0);
101
102         dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
103 }
104
105 static void power4_stop(void)
106 {
107         unsigned int mmcr0;
108
109         /* freeze counters */
110         mmcr0 = mfspr(SPRN_MMCR0);
111         mmcr0 |= MMCR0_FC;
112         mtspr(SPRN_MMCR0, mmcr0);
113
114         dbg("stop on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
115
116         mb();
117 }
118
119 /* Fake functions used by canonicalize_pc */
120 static void __attribute_used__ hypervisor_bucket(void)
121 {
122 }
123
124 static void __attribute_used__ rtas_bucket(void)
125 {
126 }
127
128 static void __attribute_used__ kernel_unknown_bucket(void)
129 {
130 }
131
132 /* XXX Not currently working */
133 static int mmcra_has_sihv = 0;
134
135 /*
136  * On GQ and newer the MMCRA stores the HV and PR bits at the time
137  * the SIAR was sampled. We use that to work out if the SIAR was sampled in
138  * the hypervisor, our exception vectors or RTAS.
139  */
140 static unsigned long get_pc(void)
141 {
142         unsigned long pc = mfspr(SPRN_SIAR);
143         unsigned long mmcra;
144
145         /* Cant do much about it */
146         if (!mmcra_has_sihv)
147                 return pc;
148
149         mmcra = mfspr(SPRN_MMCRA);
150
151         /* Were we in the hypervisor? */
152         if ((systemcfg->platform == PLATFORM_PSERIES_LPAR) &&
153             (mmcra & MMCRA_SIHV))
154                 /* function descriptor madness */
155                 return *((unsigned long *)hypervisor_bucket);
156
157         /* We were in userspace, nothing to do */
158         if (mmcra & MMCRA_SIPR)
159                 return pc;
160
161         /* Were we in our exception vectors? */
162         if (pc < 0x4000UL)
163                 return (unsigned long)__va(pc);
164
165 #ifdef CONFIG_PPC_PSERIES
166         /* Were we in RTAS? */
167         if (pc >= rtas.base && pc < (rtas.base + rtas.size))
168                 /* function descriptor madness */
169                 return *((unsigned long *)rtas_bucket);
170 #endif
171
172         /* Not sure where we were */
173         if (pc < KERNELBASE)
174                 /* function descriptor madness */
175                 return *((unsigned long *)kernel_unknown_bucket);
176
177         return pc;
178 }
179
180 static int get_kernel(unsigned long pc)
181 {
182         int is_kernel;
183
184         if (!mmcra_has_sihv) {
185                 is_kernel = (pc >= KERNELBASE);
186         } else {
187                 unsigned long mmcra = mfspr(SPRN_MMCRA);
188                 is_kernel = ((mmcra & MMCRA_SIPR) == 0);
189         }
190
191         return is_kernel;
192 }
193
194 static void power4_handle_interrupt(struct pt_regs *regs,
195                                     struct op_counter_config *ctr)
196 {
197         unsigned long pc;
198         int is_kernel;
199         int val;
200         int i;
201         unsigned int cpu = smp_processor_id();
202         unsigned int mmcr0;
203
204         pc = get_pc();
205         is_kernel = get_kernel(pc);
206
207         /* set the PMM bit (see comment below) */
208         mtmsrd(mfmsr() | MSR_PMM);
209
210         for (i = 0; i < num_counters; ++i) {
211                 val = ctr_read(i);
212                 if (val < 0) {
213                         if (ctr[i].enabled) {
214                                 oprofile_add_sample(pc, is_kernel, i, cpu);
215                                 ctr_write(i, reset_value[i]);
216                         } else {
217                                 ctr_write(i, 0);
218                         }
219                 }
220         }
221
222         mmcr0 = mfspr(SPRN_MMCR0);
223
224         /* reset the perfmon trigger */
225         mmcr0 |= MMCR0_PMXE;
226
227         /*
228          * We must clear the PMAO bit on some (GQ) chips. Just do it
229          * all the time
230          */
231         mmcr0 &= ~MMCR0_PMAO;
232
233         /*
234          * now clear the freeze bit, counting will not start until we
235          * rfid from this exception, because only at that point will
236          * the PMM bit be cleared
237          */
238         mmcr0 &= ~MMCR0_FC;
239         mtspr(SPRN_MMCR0, mmcr0);
240 }
241
242 struct op_ppc64_model op_model_power4 = {
243         .reg_setup              = power4_reg_setup,
244         .cpu_setup              = power4_cpu_setup,
245         .start                  = power4_start,
246         .stop                   = power4_stop,
247         .handle_interrupt       = power4_handle_interrupt,
248 };