oprofile/nmi timer: Convert to hotplug state machine

Install the callbacks via the state machine and let the core invoke
the callbacks on the already online CPUs.

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: oprofile-list@lists.sf.net
Cc: Robert Richter <rric@kernel.org>
Cc: rt@linutronix.de
Link: http://lkml.kernel.org/r/20161126231350.10321-6-bigeasy@linutronix.de
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
Sebastian Andrzej Siewior 2016-11-27 00:13:33 +01:00 committed by Thomas Gleixner
parent 9c6bafab03
commit 14660b7ea3

View File

@ -59,25 +59,16 @@ static void nmi_timer_stop_cpu(int cpu)
perf_event_disable(event); perf_event_disable(event);
} }
static int nmi_timer_cpu_notifier(struct notifier_block *b, unsigned long action, static int nmi_timer_cpu_online(unsigned int cpu)
void *data)
{ {
int cpu = (unsigned long)data; nmi_timer_start_cpu(cpu);
switch (action) { return 0;
case CPU_DOWN_FAILED: }
case CPU_ONLINE: static int nmi_timer_cpu_predown(unsigned int cpu)
nmi_timer_start_cpu(cpu); {
break; nmi_timer_stop_cpu(cpu);
case CPU_DOWN_PREPARE: return 0;
nmi_timer_stop_cpu(cpu);
break;
}
return NOTIFY_DONE;
} }
static struct notifier_block nmi_timer_cpu_nb = {
.notifier_call = nmi_timer_cpu_notifier
};
static int nmi_timer_start(void) static int nmi_timer_start(void)
{ {
@ -103,13 +94,14 @@ static void nmi_timer_stop(void)
put_online_cpus(); put_online_cpus();
} }
static enum cpuhp_state hp_online;
static void nmi_timer_shutdown(void) static void nmi_timer_shutdown(void)
{ {
struct perf_event *event; struct perf_event *event;
int cpu; int cpu;
cpu_notifier_register_begin(); cpuhp_remove_state(hp_online);
__unregister_cpu_notifier(&nmi_timer_cpu_nb);
for_each_possible_cpu(cpu) { for_each_possible_cpu(cpu) {
event = per_cpu(nmi_timer_events, cpu); event = per_cpu(nmi_timer_events, cpu);
if (!event) if (!event)
@ -118,13 +110,11 @@ static void nmi_timer_shutdown(void)
per_cpu(nmi_timer_events, cpu) = NULL; per_cpu(nmi_timer_events, cpu) = NULL;
perf_event_release_kernel(event); perf_event_release_kernel(event);
} }
cpu_notifier_register_done();
} }
static int nmi_timer_setup(void) static int nmi_timer_setup(void)
{ {
int cpu, err; int err;
u64 period; u64 period;
/* clock cycles per tick: */ /* clock cycles per tick: */
@ -132,24 +122,14 @@ static int nmi_timer_setup(void)
do_div(period, HZ); do_div(period, HZ);
nmi_timer_attr.sample_period = period; nmi_timer_attr.sample_period = period;
cpu_notifier_register_begin(); err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "oprofile/nmi:online",
err = __register_cpu_notifier(&nmi_timer_cpu_nb); nmi_timer_cpu_online, nmi_timer_cpu_predown);
if (err) if (err < 0) {
goto out; nmi_timer_shutdown();
return err;
/* can't attach events to offline cpus: */
for_each_online_cpu(cpu) {
err = nmi_timer_start_cpu(cpu);
if (err) {
cpu_notifier_register_done();
nmi_timer_shutdown();
return err;
}
} }
hp_online = err;
out: return 0;
cpu_notifier_register_done();
return err;
} }
int __init op_nmi_timer_init(struct oprofile_operations *ops) int __init op_nmi_timer_init(struct oprofile_operations *ops)