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 3f90289410e..8a5f1614a3d 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 | ||
@@ -269,10 +295,12 @@ static void nmi_cpu_shutdown(void *dummy) | |||
269 | 295 | ||
270 | static void nmi_shutdown(void) | 296 | static void nmi_shutdown(void) |
271 | { | 297 | { |
272 | struct op_msrs *msrs = &get_cpu_var(cpu_msrs); | 298 | struct op_msrs *msrs; |
299 | |||
273 | nmi_enabled = 0; | 300 | nmi_enabled = 0; |
274 | on_each_cpu(nmi_cpu_shutdown, NULL, 1); | 301 | on_each_cpu(nmi_cpu_shutdown, NULL, 1); |
275 | unregister_die_notifier(&profile_exceptions_nb); | 302 | unregister_die_notifier(&profile_exceptions_nb); |
303 | msrs = &get_cpu_var(cpu_msrs); | ||
276 | model->shutdown(msrs); | 304 | model->shutdown(msrs); |
277 | free_msrs(); | 305 | free_msrs(); |
278 | put_cpu_var(cpu_msrs); | 306 | put_cpu_var(cpu_msrs); |
@@ -463,6 +491,9 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
463 | } | 491 | } |
464 | 492 | ||
465 | init_sysfs(); | 493 | init_sysfs(); |
494 | #ifdef CONFIG_SMP | ||
495 | register_cpu_notifier(&oprofile_cpu_nb); | ||
496 | #endif | ||
466 | using_nmi = 1; | 497 | using_nmi = 1; |
467 | ops->create_files = nmi_create_files; | 498 | ops->create_files = nmi_create_files; |
468 | ops->setup = nmi_setup; | 499 | ops->setup = nmi_setup; |
@@ -476,6 +507,10 @@ int __init op_nmi_init(struct oprofile_operations *ops) | |||
476 | 507 | ||
477 | void op_nmi_exit(void) | 508 | void op_nmi_exit(void) |
478 | { | 509 | { |
479 | if (using_nmi) | 510 | if (using_nmi) { |
480 | exit_sysfs(); | 511 | exit_sysfs(); |
512 | #ifdef CONFIG_SMP | ||
513 | unregister_cpu_notifier(&oprofile_cpu_nb); | ||
514 | #endif | ||
515 | } | ||
481 | } | 516 | } |