Replace the perf_notifier() install mechanism, which invokes magically the callback on the current cpu. Convert the hardware specific callbacks which are invoked from the x86 perf core to return proper error codes instead of totally pointless NOTIFY_BAD return values. Signed-off-by: Thomas Gleixner --- arch/x86/kernel/cpu/perf_event.c | 78 ++++++++++++++++++--------------- arch/x86/kernel/cpu/perf_event_amd.c | 6 +- arch/x86/kernel/cpu/perf_event_intel.c | 6 +- include/linux/cpuhotplug.h | 3 + 4 files changed, 52 insertions(+), 41 deletions(-) Index: linux-2.6/arch/x86/kernel/cpu/perf_event.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event.c +++ linux-2.6/arch/x86/kernel/cpu/perf_event.c @@ -1252,47 +1252,45 @@ perf_event_nmi_handler(unsigned int cmd, struct event_constraint emptyconstraint; struct event_constraint unconstrained; -static int __cpuinit -x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu) +static int __cpuinit x86_pmu_prepare_cpu(unsigned int cpu) { - unsigned int cpu = (long)hcpu; struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); - int ret = NOTIFY_OK; - switch (action & ~CPU_TASKS_FROZEN) { - case CPU_UP_PREPARE: - cpuc->kfree_on_online = NULL; - if (x86_pmu.cpu_prepare) - ret = x86_pmu.cpu_prepare(cpu); - break; - - case CPU_STARTING: - if (x86_pmu.attr_rdpmc) - set_in_cr4(X86_CR4_PCE); - if (x86_pmu.cpu_starting) - x86_pmu.cpu_starting(cpu); - break; + cpuc->kfree_on_online = NULL; + if (x86_pmu.cpu_prepare) + return x86_pmu.cpu_prepare(cpu); + return 0; +} - case CPU_ONLINE: - kfree(cpuc->kfree_on_online); - break; +static int __cpuinit x86_pmu_dead_cpu(unsigned int cpu) +{ + if (x86_pmu.cpu_dead) + x86_pmu.cpu_dead(cpu); + return 0; +} - case CPU_DYING: - if (x86_pmu.cpu_dying) - x86_pmu.cpu_dying(cpu); - break; +static int __cpuinit x86_pmu_online_cpu(unsigned int cpu) +{ + struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); - case CPU_UP_CANCELED: - case CPU_DEAD: - if (x86_pmu.cpu_dead) - x86_pmu.cpu_dead(cpu); - break; + kfree(cpuc->kfree_on_online); + return 0; +} - default: - break; - } +static int __cpuinit x86_pmu_starting_cpu(unsigned int cpu) +{ + if (x86_pmu.attr_rdpmc) + set_in_cr4(X86_CR4_PCE); + if (x86_pmu.cpu_starting) + x86_pmu.cpu_starting(cpu); + return 0; +} - return ret; +static int __cpuinit x86_pmu_dying_cpu(unsigned int cpu) +{ + if (x86_pmu.cpu_dying) + x86_pmu.cpu_dying(cpu); + return 0; } static void __init pmu_check_apic(void) @@ -1485,8 +1483,18 @@ static int __init init_hw_perf_events(vo pr_info("... event mask: %016Lx\n", x86_pmu.intel_ctrl); perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW); - perf_cpu_notifier(x86_pmu_notifier); - + /* + * Install callbacks. Core will call them for each online + * cpu. + * + * FIXME: This should check the return value, but the original + * code did not do that either.... + */ + cpuhp_setup_state(CPUHP_PERF_X86_PREPARE, x86_pmu_prepare_cpu, + x86_pmu_dead_cpu); + cpuhp_setup_state(CPUHP_AP_PERF_X86_STARTING, x86_pmu_starting_cpu, + x86_pmu_dying_cpu); + cpuhp_setup_state(CPUHP_PERF_X86_ONLINE, x86_pmu_online_cpu, NULL); return 0; } early_initcall(init_hw_perf_events); Index: linux-2.6/arch/x86/kernel/cpu/perf_event_amd.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_amd.c +++ linux-2.6/arch/x86/kernel/cpu/perf_event_amd.c @@ -349,13 +349,13 @@ static int amd_pmu_cpu_prepare(int cpu) WARN_ON_ONCE(cpuc->amd_nb); if (boot_cpu_data.x86_max_cores < 2) - return NOTIFY_OK; + return 0; cpuc->amd_nb = amd_alloc_nb(cpu); if (!cpuc->amd_nb) - return NOTIFY_BAD; + return -ENOMEM; - return NOTIFY_OK; + return 0; } static void amd_pmu_cpu_starting(int cpu) Index: linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c =================================================================== --- linux-2.6.orig/arch/x86/kernel/cpu/perf_event_intel.c +++ linux-2.6/arch/x86/kernel/cpu/perf_event_intel.c @@ -1662,13 +1662,13 @@ static int intel_pmu_cpu_prepare(int cpu struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); if (!(x86_pmu.extra_regs || x86_pmu.lbr_sel_map)) - return NOTIFY_OK; + return 0; cpuc->shared_regs = allocate_shared_regs(cpu); if (!cpuc->shared_regs) - return NOTIFY_BAD; + return -ENOMEM; - return NOTIFY_OK; + return 0; } static void intel_pmu_cpu_starting(int cpu) Index: linux-2.6/include/linux/cpuhotplug.h =================================================================== --- linux-2.6.orig/include/linux/cpuhotplug.h +++ linux-2.6/include/linux/cpuhotplug.h @@ -5,6 +5,7 @@ enum cpuhp_states { CPUHP_OFFLINE, CPUHP_CREATE_THREADS, CPUHP_PERF_X86_UNCORE_PREP, + CPUHP_PERF_X86_PREPARE, CPUHP_PERF_PREPARE, CPUHP_NOTIFY_PREPARE, CPUHP_NOTIFY_DEAD, @@ -13,6 +14,7 @@ enum cpuhp_states { CPUHP_AP_OFFLINE, CPUHP_AP_SCHED_STARTING, CPUHP_AP_PERF_X86_UNCORE_STARTING, + CPUHP_AP_PERF_X86_STARTING, CPUHP_AP_NOTIFY_STARTING, CPUHP_AP_NOTIFY_DYING, CPUHP_AP_MAX, @@ -23,6 +25,7 @@ enum cpuhp_states { CPUHP_NOTIFY_ONLINE, CPUHP_NOTIFY_DOWN_PREPARE, CPUHP_PERF_X86_UNCORE_ONLINE, + CPUHP_PERF_X86_ONLINE, CPUHP_MAX, };