diff options
Diffstat (limited to 'arch/x86/oprofile/nmi_int.c')
-rw-r--r-- | arch/x86/oprofile/nmi_int.c | 39 |
1 files changed, 36 insertions, 3 deletions
diff --git a/arch/x86/oprofile/nmi_int.c b/arch/x86/oprofile/nmi_int.c index 3f90289410e6..0227694f7dab 100644 --- a/arch/x86/oprofile/nmi_int.c +++ b/arch/x86/oprofile/nmi_int.c | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/moduleparam.h> | 16 | #include <linux/moduleparam.h> |
17 | #include <linux/kdebug.h> | 17 | #include <linux/kdebug.h> |
18 | #include <linux/cpu.h> | ||
18 | #include <asm/nmi.h> | 19 | #include <asm/nmi.h> |
19 | #include <asm/msr.h> | 20 | #include <asm/msr.h> |
20 | #include <asm/apic.h> | 21 | #include <asm/apic.h> |
@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc); | |||
28 | 29 | ||
29 | static int nmi_start(void); | 30 | static int nmi_start(void); |
30 | static void nmi_stop(void); | 31 | static void nmi_stop(void); |
32 | static void nmi_cpu_start(void *dummy); | ||
33 | static void nmi_cpu_stop(void *dummy); | ||
31 | 34 | ||
32 | /* 0 == registered but off, 1 == registered and on */ | 35 | /* 0 == registered but off, 1 == registered and on */ |
33 | static int nmi_enabled = 0; | 36 | static int nmi_enabled = 0; |
34 | 37 | ||
38 | #ifdef CONFIG_SMP | ||
39 | static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, | ||
40 | void *data) | ||
41 | { | ||
42 | int cpu = (unsigned long)data; | ||
43 | switch (action) { | ||
44 | case CPU_DOWN_FAILED: | ||
45 | case CPU_ONLINE: | ||
46 | smp_call_function_single(cpu, nmi_cpu_start, NULL, 0); | ||
47 | break; | ||
48 | case CPU_DOWN_PREPARE: | ||
49 | smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1); | ||
50 | break; | ||
51 | } | ||
52 | return NOTIFY_DONE; | ||
53 | } | ||
54 | |||
55 | static struct notifier_block oprofile_cpu_nb = { | ||
56 | .notifier_call = oprofile_cpu_notifier | ||
57 | }; | ||
58 | #endif | ||
59 | |||
35 | #ifdef CONFIG_PM | 60 | #ifdef CONFIG_PM |
36 | 61 | ||
37 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) | 62 | static int nmi_suspend(struct sys_device *dev, pm_message_t state) |
38 | { | 63 | { |
64 | /* Only one CPU left, just stop that one */ | ||
39 | if (nmi_enabled == 1) | 65 | if (nmi_enabled == 1) |
40 | nmi_stop(); | 66 | nmi_cpu_stop(NULL); |
41 | return 0; | 67 | return 0; |
42 | } | 68 | } |
43 | 69 | ||
44 | static int nmi_resume(struct sys_device *dev) | 70 | static int nmi_resume(struct sys_device *dev) |
45 | { | 71 | { |
46 | if (nmi_enabled == 1) | 72 | if (nmi_enabled == 1) |
47 | nmi_start(); | 73 | nmi_cpu_start(NULL); |
48 | return 0; | 74 | return 0; |
49 | } | 75 | } |
50 | 76 | ||
@@ -463,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
463 | } | 489 | } |
464 | 490 | ||
465 | init_sysfs(); | 491 | init_sysfs(); |
492 | #ifdef CONFIG_SMP | ||
493 | register_cpu_notifier(&oprofile_cpu_nb); | ||
494 | #endif | ||
466 | using_nmi = 1; | 495 | using_nmi = 1; |
467 | ops->create_files = nmi_create_files; | 496 | ops->create_files = nmi_create_files; |
468 | ops->setup = nmi_setup; | 497 | ops->setup = nmi_setup; |
@@ -476,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
476 | 505 | ||
477 | void op_nmi_exit(void) | 506 | void op_nmi_exit(void) |
478 | { | 507 | { |
479 | if (using_nmi) | 508 | if (using_nmi) { |
480 | exit_sysfs(); | 509 | exit_sysfs(); |
510 | #ifdef CONFIG_SMP | ||
511 | unregister_cpu_notifier(&oprofile_cpu_nb); | ||
512 | #endif | ||
513 | } | ||
481 | } | 514 | } |