• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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