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 | } | 
