|
@@ -31,8 +31,9 @@ static struct op_x86_model_spec *model;
|
|
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
|
|
static DEFINE_PER_CPU(struct op_msrs, cpu_msrs);
|
|
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
|
|
static DEFINE_PER_CPU(unsigned long, saved_lvtpc);
|
|
|
|
|
|
-/* 0 == registered but off, 1 == registered and on */
|
|
|
|
-static int nmi_enabled = 0;
|
|
|
|
|
|
+/* must be protected with get_online_cpus()/put_online_cpus(): */
|
|
|
|
+static int nmi_enabled;
|
|
|
|
+static int ctr_running;
|
|
|
|
|
|
struct op_counter_config counter_config[OP_MAX_COUNTER];
|
|
struct op_counter_config counter_config[OP_MAX_COUNTER];
|
|
|
|
|
|
@@ -103,7 +104,10 @@ static void nmi_cpu_start(void *dummy)
|
|
|
|
|
|
static int nmi_start(void)
|
|
static int nmi_start(void)
|
|
{
|
|
{
|
|
|
|
+ get_online_cpus();
|
|
on_each_cpu(nmi_cpu_start, NULL, 1);
|
|
on_each_cpu(nmi_cpu_start, NULL, 1);
|
|
|
|
+ ctr_running = 1;
|
|
|
|
+ put_online_cpus();
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
|
|
@@ -118,7 +122,10 @@ static void nmi_cpu_stop(void *dummy)
|
|
|
|
|
|
static void nmi_stop(void)
|
|
static void nmi_stop(void)
|
|
{
|
|
{
|
|
|
|
+ get_online_cpus();
|
|
on_each_cpu(nmi_cpu_stop, NULL, 1);
|
|
on_each_cpu(nmi_cpu_stop, NULL, 1);
|
|
|
|
+ ctr_running = 0;
|
|
|
|
+ put_online_cpus();
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
|
|
#ifdef CONFIG_OPROFILE_EVENT_MULTIPLEX
|
|
@@ -258,7 +265,10 @@ static int nmi_switch_event(void)
|
|
if (nmi_multiplex_on() < 0)
|
|
if (nmi_multiplex_on() < 0)
|
|
return -EINVAL; /* not necessary */
|
|
return -EINVAL; /* not necessary */
|
|
|
|
|
|
- on_each_cpu(nmi_cpu_switch, NULL, 1);
|
|
|
|
|
|
+ get_online_cpus();
|
|
|
|
+ if (ctr_running)
|
|
|
|
+ on_each_cpu(nmi_cpu_switch, NULL, 1);
|
|
|
|
+ put_online_cpus();
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -386,8 +396,11 @@ static int nmi_setup(void)
|
|
if (err)
|
|
if (err)
|
|
goto fail;
|
|
goto fail;
|
|
|
|
|
|
|
|
+ get_online_cpus();
|
|
on_each_cpu(nmi_cpu_setup, NULL, 1);
|
|
on_each_cpu(nmi_cpu_setup, NULL, 1);
|
|
nmi_enabled = 1;
|
|
nmi_enabled = 1;
|
|
|
|
+ put_online_cpus();
|
|
|
|
+
|
|
return 0;
|
|
return 0;
|
|
fail:
|
|
fail:
|
|
free_msrs();
|
|
free_msrs();
|
|
@@ -433,8 +446,11 @@ static void nmi_shutdown(void)
|
|
{
|
|
{
|
|
struct op_msrs *msrs;
|
|
struct op_msrs *msrs;
|
|
|
|
|
|
- nmi_enabled = 0;
|
|
|
|
|
|
+ get_online_cpus();
|
|
on_each_cpu(nmi_cpu_shutdown, NULL, 1);
|
|
on_each_cpu(nmi_cpu_shutdown, NULL, 1);
|
|
|
|
+ nmi_enabled = 0;
|
|
|
|
+ ctr_running = 0;
|
|
|
|
+ put_online_cpus();
|
|
unregister_die_notifier(&profile_exceptions_nb);
|
|
unregister_die_notifier(&profile_exceptions_nb);
|
|
msrs = &get_cpu_var(cpu_msrs);
|
|
msrs = &get_cpu_var(cpu_msrs);
|
|
model->shutdown(msrs);
|
|
model->shutdown(msrs);
|
|
@@ -442,6 +458,22 @@ static void nmi_shutdown(void)
|
|
put_cpu_var(cpu_msrs);
|
|
put_cpu_var(cpu_msrs);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static void nmi_cpu_up(void *dummy)
|
|
|
|
+{
|
|
|
|
+ if (nmi_enabled)
|
|
|
|
+ nmi_cpu_setup(dummy);
|
|
|
|
+ if (ctr_running)
|
|
|
|
+ nmi_cpu_start(dummy);
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void nmi_cpu_down(void *dummy)
|
|
|
|
+{
|
|
|
|
+ if (ctr_running)
|
|
|
|
+ nmi_cpu_stop(dummy);
|
|
|
|
+ if (nmi_enabled)
|
|
|
|
+ nmi_cpu_shutdown(dummy);
|
|
|
|
+}
|
|
|
|
+
|
|
static int nmi_create_files(struct super_block *sb, struct dentry *root)
|
|
static int nmi_create_files(struct super_block *sb, struct dentry *root)
|
|
{
|
|
{
|
|
unsigned int i;
|
|
unsigned int i;
|
|
@@ -478,10 +510,10 @@ static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action,
|
|
switch (action) {
|
|
switch (action) {
|
|
case CPU_DOWN_FAILED:
|
|
case CPU_DOWN_FAILED:
|
|
case CPU_ONLINE:
|
|
case CPU_ONLINE:
|
|
- smp_call_function_single(cpu, nmi_cpu_start, NULL, 0);
|
|
|
|
|
|
+ smp_call_function_single(cpu, nmi_cpu_up, NULL, 0);
|
|
break;
|
|
break;
|
|
case CPU_DOWN_PREPARE:
|
|
case CPU_DOWN_PREPARE:
|
|
- smp_call_function_single(cpu, nmi_cpu_stop, NULL, 1);
|
|
|
|
|
|
+ smp_call_function_single(cpu, nmi_cpu_down, NULL, 1);
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
return NOTIFY_DONE;
|
|
return NOTIFY_DONE;
|
|
@@ -699,7 +731,11 @@ int __init op_nmi_init(struct oprofile_operations *ops)
|
|
return -ENODEV;
|
|
return -ENODEV;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ get_online_cpus();
|
|
register_cpu_notifier(&oprofile_cpu_nb);
|
|
register_cpu_notifier(&oprofile_cpu_nb);
|
|
|
|
+ nmi_enabled = 0;
|
|
|
|
+ ctr_running = 0;
|
|
|
|
+ put_online_cpus();
|
|
|
|
|
|
/* default values, can be overwritten by model */
|
|
/* default values, can be overwritten by model */
|
|
ops->create_files = nmi_create_files;
|
|
ops->create_files = nmi_create_files;
|
|
@@ -729,7 +765,11 @@ void op_nmi_exit(void)
|
|
{
|
|
{
|
|
if (using_nmi) {
|
|
if (using_nmi) {
|
|
exit_sysfs();
|
|
exit_sysfs();
|
|
|
|
+ get_online_cpus();
|
|
unregister_cpu_notifier(&oprofile_cpu_nb);
|
|
unregister_cpu_notifier(&oprofile_cpu_nb);
|
|
|
|
+ nmi_enabled = 0;
|
|
|
|
+ ctr_running = 0;
|
|
|
|
+ put_online_cpus();
|
|
}
|
|
}
|
|
if (model->exit)
|
|
if (model->exit)
|
|
model->exit();
|
|
model->exit();
|