aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/oprofile/nmi_int.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/oprofile/nmi_int.c')
-rw-r--r--arch/x86/oprofile/nmi_int.c43
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
30static int nmi_start(void); 31static int nmi_start(void);
31static void nmi_stop(void); 32static void nmi_stop(void);
33static void nmi_cpu_start(void *dummy);
34static 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 */
34static int nmi_enabled = 0; 37static int nmi_enabled = 0;
35 38
39#ifdef CONFIG_SMP
40static 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
56static 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
38static int nmi_suspend(struct sys_device *dev, pm_message_t state) 63static 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
45static int nmi_resume(struct sys_device *dev) 71static 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
271static void nmi_shutdown(void) 297static 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
490void op_nmi_exit(void) 521void 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}