]> git.proxmox.com Git - mirror_ubuntu-focal-kernel.git/blob - arch/ppc64/oprofile/op_model_rs64.c
Linux-2.6.12-rc2
[mirror_ubuntu-focal-kernel.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 };