Linux-2.6.12-rc2
[linux-3.10.git] / arch / ppc64 / oprofile / op_model_rs64.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
18 #define dbg(args...)
19
20 #include "op_impl.h"
21
22 static void ctrl_write(unsigned int i, unsigned int val)
23 {
24         unsigned int tmp = 0;
25         unsigned long shift = 0, mask = 0;
26
27         dbg("ctrl_write %d %x\n", i, val);
28
29         switch(i) {
30         case 0:
31                 tmp = mfspr(SPRN_MMCR0);
32                 shift = 6;
33                 mask = 0x7F;
34                 break;
35         case 1:
36                 tmp = mfspr(SPRN_MMCR0);
37                 shift = 0;
38                 mask = 0x3F;
39                 break;
40         case 2:
41                 tmp = mfspr(SPRN_MMCR1);
42                 shift = 31 - 4;
43                 mask = 0x1F;
44                 break;
45         case 3:
46                 tmp = mfspr(SPRN_MMCR1);
47                 shift = 31 - 9;
48                 mask = 0x1F;
49                 break;
50         case 4:
51                 tmp = mfspr(SPRN_MMCR1);
52                 shift = 31 - 14;
53                 mask = 0x1F;
54                 break;
55         case 5:
56                 tmp = mfspr(SPRN_MMCR1);
57                 shift = 31 - 19;
58                 mask = 0x1F;
59                 break;
60         case 6:
61                 tmp = mfspr(SPRN_MMCR1);
62                 shift = 31 - 24;
63                 mask = 0x1F;
64                 break;
65         case 7:
66                 tmp = mfspr(SPRN_MMCR1);
67                 shift = 31 - 28;
68                 mask = 0xF;
69                 break;
70         }
71
72         tmp = tmp & ~(mask << shift);
73         tmp |= val << shift;
74
75         switch(i) {
76                 case 0:
77                 case 1:
78                         mtspr(SPRN_MMCR0, tmp);
79                         break;
80                 default:
81                         mtspr(SPRN_MMCR1, tmp);
82         }
83
84         dbg("ctrl_write mmcr0 %lx mmcr1 %lx\n", mfspr(SPRN_MMCR0),
85                mfspr(SPRN_MMCR1));
86 }
87
88 static unsigned long reset_value[OP_MAX_COUNTER];
89
90 static int num_counters;
91
92 static void rs64_reg_setup(struct op_counter_config *ctr,
93                            struct op_system_config *sys,
94                            int num_ctrs)
95 {
96         int i;
97
98         num_counters = num_ctrs;
99
100         for (i = 0; i < num_counters; ++i)
101                 reset_value[i] = 0x80000000UL - ctr[i].count;
102
103         /* XXX setup user and kernel profiling */
104 }
105
106 static void rs64_cpu_setup(void *unused)
107 {
108         unsigned int mmcr0;
109
110         /* reset MMCR0 and set the freeze bit */
111         mmcr0 = MMCR0_FC;
112         mtspr(SPRN_MMCR0, mmcr0);
113
114         /* reset MMCR1, MMCRA */
115         mtspr(SPRN_MMCR1, 0);
116
117         if (cpu_has_feature(CPU_FTR_MMCRA))
118                 mtspr(SPRN_MMCRA, 0);
119
120         mmcr0 |= MMCR0_FCM1|MMCR0_PMXE|MMCR0_FCECE;
121         /* Only applies to POWER3, but should be safe on RS64 */
122         mmcr0 |= MMCR0_PMC1CE|MMCR0_PMCjCE;
123         mtspr(SPRN_MMCR0, mmcr0);
124
125         dbg("setup on cpu %d, mmcr0 %lx\n", smp_processor_id(),
126             mfspr(SPRN_MMCR0));
127         dbg("setup on cpu %d, mmcr1 %lx\n", smp_processor_id(),
128             mfspr(SPRN_MMCR1));
129 }
130
131 static void rs64_start(struct op_counter_config *ctr)
132 {
133         int i;
134         unsigned int mmcr0;
135
136         /* set the PMM bit (see comment below) */
137         mtmsrd(mfmsr() | MSR_PMM);
138
139         for (i = 0; i < num_counters; ++i) {
140                 if (ctr[i].enabled) {
141                         ctr_write(i, reset_value[i]);
142                         ctrl_write(i, ctr[i].event);
143                 } else {
144                         ctr_write(i, 0);
145                 }
146         }
147
148         mmcr0 = mfspr(SPRN_MMCR0);
149
150         /*
151          * now clear the freeze bit, counting will not start until we
152          * rfid from this excetion, because only at that point will
153          * the PMM bit be cleared
154          */
155         mmcr0 &= ~MMCR0_FC;
156         mtspr(SPRN_MMCR0, mmcr0);
157
158         dbg("start on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
159 }
160
161 static void rs64_stop(void)
162 {
163         unsigned int mmcr0;
164
165         /* freeze counters */
166         mmcr0 = mfspr(SPRN_MMCR0);
167         mmcr0 |= MMCR0_FC;
168         mtspr(SPRN_MMCR0, mmcr0);
169
170         dbg("stop on cpu %d, mmcr0 %x\n", smp_processor_id(), mmcr0);
171
172         mb();
173 }
174
175 static void rs64_handle_interrupt(struct pt_regs *regs,
176                                   struct op_counter_config *ctr)
177 {
178         unsigned int mmcr0;
179         int val;
180         int i;
181         unsigned long pc = mfspr(SPRN_SIAR);
182         int is_kernel = (pc >= KERNELBASE);
183
184         /* set the PMM bit (see comment below) */
185         mtmsrd(mfmsr() | MSR_PMM);
186
187         for (i = 0; i < num_counters; ++i) {
188                 val = ctr_read(i);
189                 if (val < 0) {
190                         if (ctr[i].enabled) {
191                                 oprofile_add_pc(pc, is_kernel, i);
192                                 ctr_write(i, reset_value[i]);
193                         } else {
194                                 ctr_write(i, 0);
195                         }
196                 }
197         }
198
199         mmcr0 = mfspr(SPRN_MMCR0);
200
201         /* reset the perfmon trigger */
202         mmcr0 |= MMCR0_PMXE;
203
204         /*
205          * now clear the freeze bit, counting will not start until we
206          * rfid from this exception, because only at that point will
207          * the PMM bit be cleared
208          */
209         mmcr0 &= ~MMCR0_FC;
210         mtspr(SPRN_MMCR0, mmcr0);
211 }
212
213 struct op_ppc64_model op_model_rs64 = {
214         .reg_setup              = rs64_reg_setup,
215         .cpu_setup              = rs64_cpu_setup,
216         .start                  = rs64_start,
217         .stop                   = rs64_stop,
218         .handle_interrupt       = rs64_handle_interrupt,
219 };