diff options
Diffstat (limited to 'arch/x86/oprofile/nmi_int.c')
-rw-r--r-- | arch/x86/oprofile/nmi_int.c | 173 |
1 files changed, 88 insertions, 85 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 57f6c9088081..022cd41ea9b4 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -28,85 +28,9 @@ static struct op_x86_model_spec const *model; | |||
28 | static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); | 28 | static DEFINE_PER_CPU(struct op_msrs, cpu_msrs); |
29 | static DEFINE_PER_CPU(unsigned long, saved_lvtpc); | 29 | static DEFINE_PER_CPU(unsigned long, saved_lvtpc); |
30 | 30 | ||
31 | static int nmi_start(void); | ||
32 | static void nmi_stop(void); | ||
33 | static void nmi_cpu_start(void *dummy); | ||
34 | static void nmi_cpu_stop(void *dummy); | ||
35 | |||
36 | /* 0 == registered but off, 1 == registered and on */ | 31 | /* 0 == registered but off, 1 == registered and on */ |
37 | static int nmi_enabled = 0; | 32 | static int nmi_enabled = 0; |
38 | 33 | ||
39 | #ifdef CONFIG_SMP | ||
40 | static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, | ||
41 | void *data) | ||
42 | { | ||
43 | int cpu = (unsigned long)data; | ||
44 | switch (action) { | ||
45 | case CPU_DOWN_FAILED: | ||
46 | case CPU_ONLINE: | ||
47 | smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); | ||
48 | break; | ||
49 | case CPU_DOWN_PREPARE: | ||
50 | smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); | ||
51 | break; | ||
52 | } | ||
53 | return NOTIFY_DONE; | ||
54 | } | ||
55 | |||
56 | static struct notifier_block oprofile_cpu_nb = { | ||
57 | .notifier_call = oprofile_cpu_notifier | ||
58 | }; | ||
59 | #endif | ||
60 | |||
61 | #ifdef CONFIG_PM | ||
62 | |||
63 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | ||
64 | { | ||
65 | /* Only one CPU left, just stop that one */ | ||
66 | if (nmi_enabled == 1) | ||
67 | nmi_cpu_stop(NULL); | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static int nmi_resume(struct sys_device *dev) | ||
72 | { | ||
73 | if (nmi_enabled == 1) | ||
74 | nmi_cpu_start(NULL); | ||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static struct sysdev_class oprofile_sysclass = { | ||
79 | .name = "oprofile", | ||
80 | .resume = nmi_resume, | ||
81 | .suspend = nmi_suspend, | ||
82 | }; | ||
83 | |||
84 | static struct sys_device device_oprofile = { | ||
85 | .id = 0, | ||
86 | .cls = &oprofile_sysclass, | ||
87 | }; | ||
88 | |||
89 | static int __init init_sysfs(void) | ||
90 | { | ||
91 | int error; | ||
92 | |||
93 | error = sysdev_class_register(&oprofile_sysclass); | ||
94 | if (!error) | ||
95 | error = sysdev_register(&device_oprofile); | ||
96 | return error; | ||
97 | } | ||
98 | |||
99 | static void exit_sysfs(void) | ||
100 | { | ||
101 | sysdev_unregister(&device_oprofile); | ||
102 | sysdev_class_unregister(&oprofile_sysclass); | ||
103 | } | ||
104 | |||
105 | #else | ||
106 | #define init_sysfs() do { } while (0) | ||
107 | #define exit_sysfs() do { } while (0) | ||
108 | #endif /* CONFIG_PM */ | ||
109 | |||
110 | static int profile_exceptions_notify(struct notifier_block *self, | 34 | static int profile_exceptions_notify(struct notifier_block *self, |
111 | unsigned long val, void *data) | 35 | unsigned long val, void *data) |
112 | { | 36 | { |
@@ -361,6 +285,77 @@ static int nmi_create_files(struct super_block *sb, struct dentry *root) | |||
361 | return 0; | 285 | return 0; |
362 | } | 286 | } |
363 | 287 | ||
288 | #ifdef CONFIG_SMP | ||
289 | static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, | ||
290 | void *data) | ||
291 | { | ||
292 | int cpu = (unsigned long)data; | ||
293 | switch (action) { | ||
294 | case CPU_DOWN_FAILED: | ||
295 | case CPU_ONLINE: | ||
296 | smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); | ||
297 | break; | ||
298 | case CPU_DOWN_PREPARE: | ||
299 | smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); | ||
300 | break; | ||
301 | } | ||
302 | return NOTIFY_DONE; | ||
303 | } | ||
304 | |||
305 | static struct notifier_block oprofile_cpu_nb = { | ||
306 | .notifier_call = oprofile_cpu_notifier | ||
307 | }; | ||
308 | #endif | ||
309 | |||
310 | #ifdef CONFIG_PM | ||
311 | |||
312 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | ||
313 | { | ||
314 | /* Only one CPU left, just stop that one */ | ||
315 | if (nmi_enabled == 1) | ||
316 | nmi_cpu_stop(NULL); | ||
317 | return 0; | ||
318 | } | ||
319 | |||
320 | static int nmi_resume(struct sys_device *dev) | ||
321 | { | ||
322 | if (nmi_enabled == 1) | ||
323 | nmi_cpu_start(NULL); | ||
324 | return 0; | ||
325 | } | ||
326 | |||
327 | static struct sysdev_class oprofile_sysclass = { | ||
328 | .name = "oprofile", | ||
329 | .resume = nmi_resume, | ||
330 | .suspend = nmi_suspend, | ||
331 | }; | ||
332 | |||
333 | static struct sys_device device_oprofile = { | ||
334 | .id = 0, | ||
335 | .cls = &oprofile_sysclass, | ||
336 | }; | ||
337 | |||
338 | static int __init init_sysfs(void) | ||
339 | { | ||
340 | int error; | ||
341 | |||
342 | error = sysdev_class_register(&oprofile_sysclass); | ||
343 | if (!error) | ||
344 | error = sysdev_register(&device_oprofile); | ||
345 | return error; | ||
346 | } | ||
347 | |||
348 | static void exit_sysfs(void) | ||
349 | { | ||
350 | sysdev_unregister(&device_oprofile); | ||
351 | sysdev_class_unregister(&oprofile_sysclass); | ||
352 | } | ||
353 | |||
354 | #else | ||
355 | #define init_sysfs() do { } while (0) | ||
356 | #define exit_sysfs() do { } while (0) | ||
357 | #endif /* CONFIG_PM */ | ||
358 | |||
364 | static int p4force; | 359 | static int p4force; |
365 | module_param(p4force, int, 0); | 360 | module_param(p4force, int, 0); |
366 | 361 | ||
@@ -420,9 +415,6 @@ static int __init ppro_init(char **cpu_type) | |||
420 | case 15: case 23: | 415 | case 15: case 23: |
421 | *cpu_type = "i386/core_2"; | 416 | *cpu_type = "i386/core_2"; |
422 | break; | 417 | break; |
423 | case 26: | ||
424 | *cpu_type = "i386/core_2"; | ||
425 | break; | ||
426 | default: | 418 | default: |
427 | /* Unknown */ | 419 | /* Unknown */ |
428 | return 0; | 420 | return 0; |
@@ -432,6 +424,16 @@ static int __init ppro_init(char **cpu_type) | |||
432 | return 1; | 424 | return 1; |
433 | } | 425 | } |
434 | 426 | ||
427 | static int __init arch_perfmon_init(char **cpu_type) | ||
428 | { | ||
429 | if (!cpu_has_arch_perfmon) | ||
430 | return 0; | ||
431 | *cpu_type = "i386/arch_perfmon"; | ||
432 | model = &op_arch_perfmon_spec; | ||
433 | arch_perfmon_setup_counters(); | ||
434 | return 1; | ||
435 | } | ||
436 | |||
435 | /* in order to get sysfs right */ | 437 | /* in order to get sysfs right */ |
436 | static int using_nmi; | 438 | static int using_nmi; |
437 | 439 | ||
@@ -439,7 +441,7 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
439 | { | 441 | { |
440 | __u8 vendor = boot_cpu_data.x86_vendor; | 442 | __u8 vendor = boot_cpu_data.x86_vendor; |
441 | __u8 family = boot_cpu_data.x86; | 443 | __u8 family = boot_cpu_data.x86; |
442 | char *cpu_type; | 444 | char *cpu_type = NULL; |
443 | int ret = 0; | 445 | int ret = 0; |
444 | 446 | ||
445 | if (!cpu_has_apic) | 447 | if (!cpu_has_apic) |
@@ -477,19 +479,20 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
477 | switch (family) { | 479 | switch (family) { |
478 | /* Pentium IV */ | 480 | /* Pentium IV */ |
479 | case 0xf: | 481 | case 0xf: |
480 | if (!p4_init(&cpu_type)) | 482 | p4_init(&cpu_type); |
481 | return -ENODEV; | ||
482 | break; | 483 | break; |
483 | 484 | ||
484 | /* A P6-class processor */ | 485 | /* A P6-class processor */ |
485 | case 6: | 486 | case 6: |
486 | if (!ppro_init(&cpu_type)) | 487 | ppro_init(&cpu_type); |
487 | return -ENODEV; | ||
488 | break; | 488 | break; |
489 | 489 | ||
490 | default: | 490 | default: |
491 | return -ENODEV; | 491 | break; |
492 | } | 492 | } |
493 | |||
494 | if (!cpu_type && !arch_perfmon_init(&cpu_type)) | ||
495 | return -ENODEV; | ||
493 | break; | 496 | break; |
494 | 497 | ||
495 | default: | 498 | default: |