|
@@ -15,6 +15,7 @@
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/moduleparam.h>
|
|
#include <linux/kdebug.h>
|
|
#include <linux/kdebug.h>
|
|
|
|
+#include <linux/cpu.h>
|
|
#include <asm/nmi.h>
|
|
#include <asm/nmi.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/apic.h>
|
|
#include <asm/apic.h>
|
|
@@ -28,23 +29,48 @@ static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
|
|
|
|
|
|
static int nmi_start(void);
|
|
static int nmi_start(void);
|
|
static void nmi_stop(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 */
|
|
/* 0 == registered but off, 1 == registered and on */
|
|
static int nmi_enabled = 0;
|
|
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
|
|
#ifdef CONFIG_PM
|
|
|
|
|
|
static int nmi_suspend(struct sys_device *dev, pm_message_t state)
|
|
static int nmi_suspend(struct sys_device *dev, pm_message_t state)
|
|
{
|
|
{
|
|
|
|
+ /* Only one CPU left, just stop that one */
|
|
if (nmi_enabled == 1)
|
|
if (nmi_enabled == 1)
|
|
- nmi_stop();
|
|
|
|
|
|
+ nmi_cpu_stop(NULL);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
static int nmi_resume(struct sys_device *dev)
|
|
static int nmi_resume(struct sys_device *dev)
|
|
{
|
|
{
|
|
if (nmi_enabled == 1)
|
|
if (nmi_enabled == 1)
|
|
- nmi_start();
|
|
|
|
|
|
+ nmi_cpu_start(NULL);
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -463,6 +489,9 @@ int __init op_nmi_init(struct oprofile_operations *ops)
|
|
}
|
|
}
|
|
|
|
|
|
init_sysfs();
|
|
init_sysfs();
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+ register_cpu_notifier(&oprofile_cpu_nb);
|
|
|
|
+#endif
|
|
using_nmi = 1;
|
|
using_nmi = 1;
|
|
ops->create_files = nmi_create_files;
|
|
ops->create_files = nmi_create_files;
|
|
ops->setup = nmi_setup;
|
|
ops->setup = nmi_setup;
|
|
@@ -476,6 +505,10 @@ int __init op_nmi_init(struct oprofile_operations *ops)
|
|
|
|
|
|
void op_nmi_exit(void)
|
|
void op_nmi_exit(void)
|
|
{
|
|
{
|
|
- if (using_nmi)
|
|
|
|
|
|
+ if (using_nmi) {
|
|
exit_sysfs();
|
|
exit_sysfs();
|
|
|
|
+#ifdef CONFIG_SMP
|
|
|
|
+ unregister_cpu_notifier(&oprofile_cpu_nb);
|
|
|
|
+#endif
|
|
|
|
+ }
|
|
}
|
|
}
|