1 /**
2 * @file op_nmi.c
3 * Setup and handling of NMI PMC interrupts
4 *
5 * @remark Copyright 2002 OProfile authors
6 * @remark Read the file COPYING
7 *
8 * @author John Levon
9 * @author Philippe Elie
10 */
11
12 #include "oprofile.h"
13 #include "op_msr.h"
14 #include "op_apic.h"
15 #include "op_util.h"
16 #include "op_x86_model.h"
17
18 static struct op_msrs cpu_msrs[NR_CPUS];
19 static struct op_x86_model_spec const * model = NULL;
20
get_model(void)21 static struct op_x86_model_spec const * get_model(void)
22 {
23 if (!model) {
24 /* pick out our per-model function table */
25 switch (sysctl.cpu_type) {
26 case CPU_ATHLON:
27 case CPU_HAMMER:
28 model = &op_athlon_spec;
29 break;
30 case CPU_P4:
31 model = &op_p4_spec;
32 break;
33 #ifdef HT_SUPPORT
34 case CPU_P4_HT2:
35 model = &op_p4_ht2_spec;
36 break;
37 #endif
38 default:
39 model = &op_ppro_spec;
40 break;
41 }
42 }
43 return model;
44 }
45
op_do_nmi(struct pt_regs * regs)46 asmlinkage void op_do_nmi(struct pt_regs * regs)
47 {
48 uint const cpu = op_cpu_id();
49 struct op_msrs const * const msrs = &cpu_msrs[cpu];
50
51 model->check_ctrs(cpu, msrs, regs);
52 }
53
54 /* ---------------- PMC setup ------------------ */
55
pmc_setup_ctr(void * dummy)56 static void pmc_setup_ctr(void * dummy)
57 {
58 uint const cpu = op_cpu_id();
59 struct op_msrs const * const msrs = &cpu_msrs[cpu];
60 get_model()->setup_ctrs(msrs);
61 }
62
63
pmc_setup_all(void)64 static int pmc_setup_all(void)
65 {
66 if (smp_call_function(pmc_setup_ctr, NULL, 0, 1))
67 return -EFAULT;
68 pmc_setup_ctr(NULL);
69 return 0;
70 }
71
72
pmc_start(void * info)73 static void pmc_start(void * info)
74 {
75 uint const cpu = op_cpu_id();
76 struct op_msrs const * const msrs = &cpu_msrs[cpu];
77
78 if (info && (*((uint *)info) != cpu))
79 return;
80
81 get_model()->start(msrs);
82 }
83
84
pmc_stop(void * info)85 static void pmc_stop(void * info)
86 {
87 uint const cpu = op_cpu_id();
88 struct op_msrs const * const msrs = &cpu_msrs[cpu];
89
90 if (info && (*((uint *)info) != cpu))
91 return;
92
93 get_model()->stop(msrs);
94 }
95
96
pmc_select_start(uint cpu)97 static void pmc_select_start(uint cpu)
98 {
99 if (cpu == op_cpu_id())
100 pmc_start(NULL);
101 else
102 smp_call_function(pmc_start, &cpu, 0, 1);
103 }
104
105
pmc_select_stop(uint cpu)106 static void pmc_select_stop(uint cpu)
107 {
108 if (cpu == op_cpu_id())
109 pmc_stop(NULL);
110 else
111 smp_call_function(pmc_stop, &cpu, 0, 1);
112 }
113
114
pmc_start_all(void)115 static void pmc_start_all(void)
116 {
117 int cpu, i;
118
119 for (cpu = 0 ; cpu < smp_num_cpus; cpu++) {
120 struct _oprof_data * data = &oprof_data[cpu];
121
122 for (i = 0 ; i < get_model()->num_counters ; ++i) {
123 if (sysctl.ctr[i].enabled)
124 data->ctr_count[i] = sysctl.ctr[i].count;
125 else
126 data->ctr_count[i] = 0;
127 }
128 }
129
130 install_nmi();
131 smp_call_function(pmc_start, NULL, 0, 1);
132 pmc_start(NULL);
133 }
134
135
pmc_stop_all(void)136 static void pmc_stop_all(void)
137 {
138 smp_call_function(pmc_stop, NULL, 0, 1);
139 pmc_stop(NULL);
140 restore_nmi();
141 }
142
143
pmc_check_params(void)144 static int pmc_check_params(void)
145 {
146 int i;
147 int enabled = 0;
148
149 for (i = 0; i < get_model()->num_counters; i++) {
150 if (!sysctl.ctr[i].enabled)
151 continue;
152
153 enabled = 1;
154
155 if (!sysctl.ctr[i].user && !sysctl.ctr[i].kernel) {
156 printk(KERN_ERR "oprofile: neither kernel nor user "
157 "set for counter %d\n", i);
158 return -EINVAL;
159 }
160
161 if (check_range(sysctl.ctr[i].count, 1, OP_MAX_PERF_COUNT,
162 "ctr count value %d not in range (%d %ld)\n"))
163 return -EINVAL;
164
165 }
166
167 if (!enabled) {
168 printk(KERN_ERR "oprofile: no counters have been enabled.\n");
169 return -EINVAL;
170 }
171
172 return 0;
173 }
174
175
free_msr_group(struct op_msr_group * group)176 static void free_msr_group(struct op_msr_group * group)
177 {
178 if (group->addrs)
179 kfree(group->addrs);
180 if (group->saved)
181 kfree(group->saved);
182 group->addrs = NULL;
183 group->saved = NULL;
184 }
185
186
pmc_save_registers(void * dummy)187 static void pmc_save_registers(void * dummy)
188 {
189 uint i;
190 uint const cpu = op_cpu_id();
191 uint const nr_ctrs = get_model()->num_counters;
192 uint const nr_ctrls = get_model()->num_controls;
193 struct op_msr_group * counters = &cpu_msrs[cpu].counters;
194 struct op_msr_group * controls = &cpu_msrs[cpu].controls;
195
196 counters->addrs = NULL;
197 counters->saved = NULL;
198 controls->addrs = NULL;
199 controls->saved = NULL;
200
201 counters->addrs = kmalloc(nr_ctrs * sizeof(uint), GFP_KERNEL);
202 if (!counters->addrs)
203 goto fault;
204
205 counters->saved = kmalloc(
206 nr_ctrs * sizeof(struct op_saved_msr), GFP_KERNEL);
207 if (!counters->saved)
208 goto fault;
209
210 controls->addrs = kmalloc(nr_ctrls * sizeof(uint), GFP_KERNEL);
211 if (!controls->addrs)
212 goto fault;
213
214 controls->saved = kmalloc(
215 nr_ctrls * sizeof(struct op_saved_msr), GFP_KERNEL);
216 if (!controls->saved)
217 goto fault;
218
219 model->fill_in_addresses(&cpu_msrs[cpu]);
220
221 for (i = 0; i < nr_ctrs; ++i) {
222 rdmsr(counters->addrs[i],
223 counters->saved[i].low,
224 counters->saved[i].high);
225 }
226
227 for (i = 0; i < nr_ctrls; ++i) {
228 rdmsr(controls->addrs[i],
229 controls->saved[i].low,
230 controls->saved[i].high);
231 }
232 return;
233
234 fault:
235 free_msr_group(counters);
236 free_msr_group(controls);
237 }
238
239
pmc_restore_registers(void * dummy)240 static void pmc_restore_registers(void * dummy)
241 {
242 uint i;
243 uint const cpu = op_cpu_id();
244 uint const nr_ctrs = get_model()->num_counters;
245 uint const nr_ctrls = get_model()->num_controls;
246 struct op_msr_group * counters = &cpu_msrs[cpu].counters;
247 struct op_msr_group * controls = &cpu_msrs[cpu].controls;
248
249 if (controls->addrs) {
250 for (i = 0; i < nr_ctrls; ++i) {
251 wrmsr(controls->addrs[i],
252 controls->saved[i].low,
253 controls->saved[i].high);
254 }
255 }
256
257 if (counters->addrs) {
258 for (i = 0; i < nr_ctrs; ++i) {
259 wrmsr(counters->addrs[i],
260 counters->saved[i].low,
261 counters->saved[i].high);
262 }
263 }
264
265 free_msr_group(counters);
266 free_msr_group(controls);
267 }
268
269
pmc_init(void)270 static int pmc_init(void)
271 {
272 int err = 0;
273
274 if ((err = smp_call_function(pmc_save_registers, NULL, 0, 1)))
275 goto out;
276
277 pmc_save_registers(NULL);
278
279 if ((err = apic_setup()))
280 goto out_restore;
281
282 if ((err = smp_call_function(lvtpc_apic_setup, NULL, 0, 1))) {
283 lvtpc_apic_restore(NULL);
284 goto out_restore;
285 }
286
287 out:
288 return err;
289 out_restore:
290 smp_call_function(pmc_restore_registers, NULL, 0, 1);
291 pmc_restore_registers(NULL);
292 goto out;
293 }
294
295
pmc_deinit(void)296 static void pmc_deinit(void)
297 {
298 smp_call_function(lvtpc_apic_restore, NULL, 0, 1);
299 lvtpc_apic_restore(NULL);
300
301 apic_restore();
302
303 smp_call_function(pmc_restore_registers, NULL, 0, 1);
304 pmc_restore_registers(NULL);
305 }
306
307
308 static char * names[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8"};
309
pmc_add_sysctls(ctl_table * next)310 static int pmc_add_sysctls(ctl_table * next)
311 {
312 ctl_table * start = next;
313 ctl_table * tab;
314 int i, j;
315
316 /* now init the sysctls */
317 for (i=0; i < get_model()->num_counters; i++) {
318 next->ctl_name = 1;
319 next->procname = names[i];
320 next->mode = 0755;
321
322 if (!(tab = kmalloc(sizeof(ctl_table)*7, GFP_KERNEL)))
323 goto cleanup;
324
325 next->child = tab;
326
327 memset(tab, 0, sizeof(ctl_table)*7);
328 tab[0] = ((ctl_table) { 1, "enabled", &sysctl_parms.ctr[i].enabled, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
329 tab[1] = ((ctl_table) { 1, "event", &sysctl_parms.ctr[i].event, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
330 tab[2] = ((ctl_table) { 1, "count", &sysctl_parms.ctr[i].count, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
331 tab[3] = ((ctl_table) { 1, "unit_mask", &sysctl_parms.ctr[i].unit_mask, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
332 tab[4] = ((ctl_table) { 1, "kernel", &sysctl_parms.ctr[i].kernel, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
333 tab[5] = ((ctl_table) { 1, "user", &sysctl_parms.ctr[i].user, sizeof(int), 0644, NULL, lproc_dointvec, NULL, });
334 next++;
335 }
336
337 return 0;
338
339 cleanup:
340 next = start;
341 for (j = 0; j < i; j++) {
342 kfree(next->child);
343 next++;
344 }
345 return -EFAULT;
346 }
347
348
pmc_remove_sysctls(ctl_table * next)349 static void pmc_remove_sysctls(ctl_table * next)
350 {
351 int i;
352 for (i=0; i < get_model()->num_counters; i++) {
353 kfree(next->child);
354 next++;
355 }
356 }
357
358
359 static struct op_int_operations op_nmi_ops = {
360 init: pmc_init,
361 deinit: pmc_deinit,
362 add_sysctls: pmc_add_sysctls,
363 remove_sysctls: pmc_remove_sysctls,
364 check_params: pmc_check_params,
365 setup: pmc_setup_all,
366 start: pmc_start_all,
367 stop: pmc_stop_all,
368 start_cpu: pmc_select_start,
369 stop_cpu: pmc_select_stop,
370 };
371
372
op_int_interface()373 struct op_int_operations const * op_int_interface()
374 {
375 return &op_nmi_ops;
376 }
377