|
|
|
@ -339,10 +339,11 @@ fail: |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void nmi_cpu_setup(void *dummy) |
|
|
|
|
static void nmi_cpu_setup(void) |
|
|
|
|
{ |
|
|
|
|
int cpu = smp_processor_id(); |
|
|
|
|
struct op_msrs *msrs = &per_cpu(cpu_msrs, cpu); |
|
|
|
|
|
|
|
|
|
nmi_cpu_save_registers(msrs); |
|
|
|
|
raw_spin_lock(&oprofilefs_lock); |
|
|
|
|
model->setup_ctrs(model, msrs); |
|
|
|
@ -369,7 +370,7 @@ static void nmi_cpu_restore_registers(struct op_msrs *msrs) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void nmi_cpu_shutdown(void *dummy) |
|
|
|
|
static void nmi_cpu_shutdown(void) |
|
|
|
|
{ |
|
|
|
|
unsigned int v; |
|
|
|
|
int cpu = smp_processor_id(); |
|
|
|
@ -387,24 +388,26 @@ static void nmi_cpu_shutdown(void *dummy) |
|
|
|
|
nmi_cpu_restore_registers(msrs); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void nmi_cpu_up(void) |
|
|
|
|
static int nmi_cpu_online(unsigned int cpu) |
|
|
|
|
{ |
|
|
|
|
local_irq_disable(); |
|
|
|
|
if (nmi_enabled) |
|
|
|
|
nmi_cpu_setup(NULL); |
|
|
|
|
nmi_cpu_setup(); |
|
|
|
|
if (ctr_running) |
|
|
|
|
nmi_cpu_start(NULL); |
|
|
|
|
local_irq_enable(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void nmi_cpu_down(void) |
|
|
|
|
static int nmi_cpu_down_prep(unsigned int cpu) |
|
|
|
|
{ |
|
|
|
|
local_irq_disable(); |
|
|
|
|
if (ctr_running) |
|
|
|
|
nmi_cpu_stop(NULL); |
|
|
|
|
if (nmi_enabled) |
|
|
|
|
nmi_cpu_shutdown(NULL); |
|
|
|
|
nmi_cpu_shutdown(); |
|
|
|
|
local_irq_enable(); |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int nmi_create_files(struct dentry *root) |
|
|
|
@ -437,24 +440,7 @@ static int nmi_create_files(struct dentry *root) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int oprofile_cpu_notifier(struct notifier_block *b, unsigned long action, |
|
|
|
|
void *data) |
|
|
|
|
{ |
|
|
|
|
switch (action & ~CPU_TASKS_FROZEN) { |
|
|
|
|
case CPU_DOWN_FAILED: |
|
|
|
|
case CPU_ONLINE: |
|
|
|
|
nmi_cpu_up(); |
|
|
|
|
break; |
|
|
|
|
case CPU_DOWN_PREPARE: |
|
|
|
|
nmi_cpu_down(); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
return NOTIFY_DONE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static struct notifier_block oprofile_cpu_nb = { |
|
|
|
|
.notifier_call = oprofile_cpu_notifier |
|
|
|
|
}; |
|
|
|
|
static enum cpuhp_state cpuhp_nmi_online; |
|
|
|
|
|
|
|
|
|
static int nmi_setup(void) |
|
|
|
|
{ |
|
|
|
@ -497,20 +483,17 @@ static int nmi_setup(void) |
|
|
|
|
if (err) |
|
|
|
|
goto fail; |
|
|
|
|
|
|
|
|
|
cpu_notifier_register_begin(); |
|
|
|
|
|
|
|
|
|
/* Use get/put_online_cpus() to protect 'nmi_enabled' */ |
|
|
|
|
get_online_cpus(); |
|
|
|
|
nmi_enabled = 1; |
|
|
|
|
/* make nmi_enabled visible to the nmi handler: */ |
|
|
|
|
smp_mb(); |
|
|
|
|
on_each_cpu(nmi_cpu_setup, NULL, 1); |
|
|
|
|
__register_cpu_notifier(&oprofile_cpu_nb); |
|
|
|
|
put_online_cpus(); |
|
|
|
|
|
|
|
|
|
cpu_notifier_register_done(); |
|
|
|
|
|
|
|
|
|
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/oprofile:online", |
|
|
|
|
nmi_cpu_online, nmi_cpu_down_prep); |
|
|
|
|
if (err < 0) |
|
|
|
|
goto fail_nmi; |
|
|
|
|
cpuhp_nmi_online = err; |
|
|
|
|
return 0; |
|
|
|
|
fail_nmi: |
|
|
|
|
unregister_nmi_handler(NMI_LOCAL, "oprofile"); |
|
|
|
|
fail: |
|
|
|
|
free_msrs(); |
|
|
|
|
return err; |
|
|
|
@ -520,17 +503,9 @@ static void nmi_shutdown(void) |
|
|
|
|
{ |
|
|
|
|
struct op_msrs *msrs; |
|
|
|
|
|
|
|
|
|
cpu_notifier_register_begin(); |
|
|
|
|
|
|
|
|
|
/* Use get/put_online_cpus() to protect 'nmi_enabled' & 'ctr_running' */ |
|
|
|
|
get_online_cpus(); |
|
|
|
|
on_each_cpu(nmi_cpu_shutdown, NULL, 1); |
|
|
|
|
cpuhp_remove_state(cpuhp_nmi_online); |
|
|
|
|
nmi_enabled = 0; |
|
|
|
|
ctr_running = 0; |
|
|
|
|
__unregister_cpu_notifier(&oprofile_cpu_nb); |
|
|
|
|
put_online_cpus(); |
|
|
|
|
|
|
|
|
|
cpu_notifier_register_done(); |
|
|
|
|
|
|
|
|
|
/* make variables visible to the nmi handler: */ |
|
|
|
|
smp_mb(); |
|
|
|
|