diff options
Diffstat (limited to 'arch/x86/oprofile/nmi_int.c')
-rw-r--r-- | arch/x86/oprofile/nmi_int.c | 43 |
1 files changed, 39 insertions, 4 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 287513a09819..57f6c9088081 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include <linux/slab.h> | 16 | #include <linux/slab.h> |
17 | #include <linux/moduleparam.h> | 17 | #include <linux/moduleparam.h> |
18 | #include <linux/kdebug.h> | 18 | #include <linux/kdebug.h> |
19 | #include <linux/cpu.h> | ||
19 | #include <asm/nmi.h> | 20 | #include <asm/nmi.h> |
20 | #include <asm/msr.h> | 21 | #include <asm/msr.h> |
21 | #include <asm/apic.h> | 22 | #include <asm/apic.h> |
@@ -29,23 +30,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); | |||
29 | 30 | ||
30 | static int nmi_start(void); | 31 | static int nmi_start(void); |
31 | static void nmi_stop(void); | 32 | static void nmi_stop(void); |
33 | static void nmi_cpu_start(void *dummy); | ||
34 | static void nmi_cpu_stop(void *dummy); | ||
32 | 35 | ||
33 | /* 0 == registered but off, 1 == registered and on */ | 36 | /* 0 == registered but off, 1 == registered and on */ |
34 | static int nmi_enabled = 0; | 37 | static int nmi_enabled = 0; |
35 | 38 | ||
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 | |||
36 | #ifdef CONFIG_PM | 61 | #ifdef CONFIG_PM |
37 | 62 | ||
38 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | 63 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) |
39 | { | 64 | { |
65 | /* Only one CPU left, just stop that one */ | ||
40 | if (nmi_enabled == 1) | 66 | if (nmi_enabled == 1) |
41 | nmi_stop(); | 67 | nmi_cpu_stop(NULL); |
42 | return 0; | 68 | return 0; |
43 | } | 69 | } |
44 | 70 | ||
45 | static int nmi_resume(struct sys_device *dev) | 71 | static int nmi_resume(struct sys_device *dev) |
46 | { | 72 | { |
47 | if (nmi_enabled == 1) | 73 | if (nmi_enabled == 1) |
48 | nmi_start(); | 74 | nmi_cpu_start(NULL); |
49 | return 0; | 75 | return 0; |
50 | } | 76 | } |
51 | 77 | ||
@@ -270,10 +296,12 @@ static void nmi_cpu_shutdown(void *dummy) | |||
270 | 296 | ||
271 | static void nmi_shutdown(void) | 297 | static void nmi_shutdown(void) |
272 | { | 298 | { |
273 | struct op_msrs *msrs = &get_cpu_var(cpu_msrs); | 299 | struct op_msrs *msrs; |
300 | |||
274 | nmi_enabled = 0; | 301 | nmi_enabled = 0; |
275 | on_each_cpu(nmi_cpu_shutdown, NULL, 1); | 302 | on_each_cpu(nmi_cpu_shutdown, NULL, 1); |
276 | unregister_die_notifier(&profile_exceptions_nb); | 303 | unregister_die_notifier(&profile_exceptions_nb); |
304 | msrs = &get_cpu_var(cpu_msrs); | ||
277 | model->shutdown(msrs); | 305 | model->shutdown(msrs); |
278 | free_msrs(); | 306 | free_msrs(); |
279 | put_cpu_var(cpu_msrs); | 307 | put_cpu_var(cpu_msrs); |
@@ -468,6 +496,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
468 | return -ENODEV; | 496 | return -ENODEV; |
469 | } | 497 | } |
470 | 498 | ||
499 | #ifdef CONFIG_SMP | ||
500 | register_cpu_notifier(&oprofile_cpu_nb); | ||
501 | #endif | ||
471 | /* default values, can be overwritten by model */ | 502 | /* default values, can be overwritten by model */ |
472 | ops->create_files = nmi_create_files; | 503 | ops->create_files = nmi_create_files; |
473 | ops->setup = nmi_setup; | 504 | ops->setup = nmi_setup; |
@@ -489,8 +520,12 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
489 | 520 | ||
490 | void op_nmi_exit(void) | 521 | void op_nmi_exit(void) |
491 | { | 522 | { |
492 | if (using_nmi) | 523 | if (using_nmi) { |
493 | exit_sysfs(); | 524 | exit_sysfs(); |
525 | #ifdef CONFIG_SMP | ||
526 | unregister_cpu_notifier(&oprofile_cpu_nb); | ||
527 | #endif | ||
528 | } | ||
494 | if (model->exit) | 529 | if (model->exit) |
495 | model->exit(); | 530 | model->exit(); |
496 | } | 531 | } |