blob: bcec506c266a8d171f0ecbbba52aeeffb85a3723 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
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
22static 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
88static unsigned long reset_value[OP_MAX_COUNTER];
89
90static int num_counters;
91
92static 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
106static 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
131static 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
161static 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
175static 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
213struct 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};