Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[pandora-kernel.git] / arch / x86 / oprofile / nmi_int.c
index 3f90289..0227694 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/slab.h>
 #include <linux/moduleparam.h>
 #include <linux/kdebug.h>
+#include <linux/cpu.h>
 #include <asm/nmi.h>
 #include <asm/msr.h>
 #include <asm/apic.h>
@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
 
 static int nmi_start(void);
 static void nmi_stop(void);
+static void nmi_cpu_start(void *dummy);
+static void nmi_cpu_stop(void *dummy);
 
 /* 0 == registered but off, 1 == registered and on */
 static int nmi_enabled = 0;
 
+#ifdef CONFIG_SMP
+static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action,
+                                void *data)
+{
+       int cpu = (unsigned long)data;
+       switch (action) {
+       case CPU_DOWN_FAILED:
+       case CPU_ONLINE:
+               smp_call_function_single(cpu, nmi_cpu_start, NULL, 0);
+               break;
+       case CPU_DOWN_PREPARE:
+               smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1);
+               break;
+       }
+       return NOTIFY_DONE;
+}
+
+static struct notifier_block oprofile_cpu_nb = {
+       .notifier_call = oprofile_cpu_notifier
+};
+#endif
+
 #ifdef CONFIG_PM
 
 static int nmi_suspend(struct sys_device *dev, pm_message_t state)
 {
+       /* Only one CPU left, just stop that one */
        if (nmi_enabled == 1)
-               nmi_stop();
+               nmi_cpu_stop(NULL);
        return 0;
 }
 
 static int nmi_resume(struct sys_device *dev)
 {
        if (nmi_enabled == 1)
-               nmi_start();
+               nmi_cpu_start(NULL);
        return 0;
 }
 
@@ -463,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops)
        }
 
        init_sysfs();
+#ifdef CONFIG_SMP
+       register_cpu_notifier(&oprofile_cpu_nb);
+#endif
        using_nmi = 1;
        ops->create_files = nmi_create_files;
        ops->setup = nmi_setup;
@@ -476,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops)
 
 void op_nmi_exit(void)
 {
-       if (using_nmi)
+       if (using_nmi) {
                exit_sysfs();
+#ifdef CONFIG_SMP
+               unregister_cpu_notifier(&oprofile_cpu_nb);
+#endif
+       }
 }