Merge branch 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull smp hotplug updates from Thomas Gleixner:
 "This is the next part of the hotplug rework.

   - Convert all notifiers with a priority assigned

   - Convert all CPU_STARTING/DYING notifiers

     The final removal of the STARTING/DYING infrastructure will happen
     when the merge window closes.

  Another 700 hundred line of unpenetrable maze gone :)"

* 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (70 commits)
  timers/core: Correct callback order during CPU hot plug
  leds/trigger/cpu: Move from CPU_STARTING to ONLINE level
  powerpc/numa: Convert to hotplug state machine
  arm/perf: Fix hotplug state machine conversion
  irqchip/armada: Avoid unused function warnings
  ARC/time: Convert to hotplug state machine
  clocksource/atlas7: Convert to hotplug state machine
  clocksource/armada-370-xp: Convert to hotplug state machine
  clocksource/exynos_mct: Convert to hotplug state machine
  clocksource/arm_global_timer: Convert to hotplug state machine
  rcu: Convert rcutree to hotplug state machine
  KVM/arm/arm64/vgic-new: Convert to hotplug state machine
  smp/cfd: Convert core to hotplug state machine
  x86/x2apic: Convert to CPU hotplug state machine
  profile: Convert to hotplug state machine
  timers/core: Convert to hotplug state machine
  hrtimer: Convert to hotplug state machine
  x86/tboot: Convert to hotplug state machine
  arm64/armv8 deprecated: Convert to hotplug state machine
  hwtracing/coresight-etm4x: Convert to hotplug state machine
  ...
This commit is contained in:
Linus Torvalds 2016-07-29 13:55:30 -07:00
commit a6408f6cb6
75 changed files with 1321 additions and 2018 deletions

View File

@ -296,30 +296,23 @@ static irqreturn_t timer_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int arc_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
static int arc_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
evt->cpumask = cpumask_of(smp_processor_id());
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
clockevents_config_and_register(evt, arc_timer_freq,
0, ULONG_MAX);
enable_percpu_irq(arc_timer_irq, 0);
break;
case CPU_DYING:
disable_percpu_irq(arc_timer_irq);
break;
}
return NOTIFY_OK;
clockevents_config_and_register(evt, arc_timer_freq, 0, ARC_TIMER_MAX);
enable_percpu_irq(arc_timer_irq, 0);
return 0;
}
static struct notifier_block arc_timer_cpu_nb = {
.notifier_call = arc_timer_cpu_notify,
};
static int arc_timer_dying_cpu(unsigned int cpu)
{
disable_percpu_irq(arc_timer_irq);
return 0;
}
/*
* clockevent setup for boot CPU
@ -329,12 +322,6 @@ static int __init arc_clockevent_setup(struct device_node *node)
struct clock_event_device *evt = this_cpu_ptr(&arc_clockevent_device);
int ret;
ret = register_cpu_notifier(&arc_timer_cpu_nb);
if (ret) {
pr_err("Failed to register cpu notifier");
return ret;
}
arc_timer_irq = irq_of_parse_and_map(node, 0);
if (arc_timer_irq <= 0) {
pr_err("clockevent: missing irq");
@ -347,11 +334,6 @@ static int __init arc_clockevent_setup(struct device_node *node)
return ret;
}
evt->irq = arc_timer_irq;
evt->cpumask = cpumask_of(smp_processor_id());
clockevents_config_and_register(evt, arc_timer_freq,
0, ARC_TIMER_MAX);
/* Needs apriori irq_set_percpu_devid() done in intc map function */
ret = request_percpu_irq(arc_timer_irq, timer_irq_handler,
"Timer0 (per-cpu-tick)", evt);
@ -360,8 +342,14 @@ static int __init arc_clockevent_setup(struct device_node *node)
return ret;
}
enable_percpu_irq(arc_timer_irq, 0);
ret = cpuhp_setup_state(CPUHP_AP_ARC_TIMER_STARTING,
"AP_ARC_TIMER_STARTING",
arc_timer_starting_cpu,
arc_timer_dying_cpu);
if (ret) {
pr_err("Failed to setup hotplug state");
return ret;
}
return 0;
}

View File

@ -310,24 +310,17 @@ static void twd_timer_setup(void)
enable_percpu_irq(clk->irq, 0);
}
static int twd_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
static int twd_timer_starting_cpu(unsigned int cpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
twd_timer_setup();
break;
case CPU_DYING:
twd_timer_stop();
break;
}
return NOTIFY_OK;
twd_timer_setup();
return 0;
}
static struct notifier_block twd_timer_cpu_nb = {
.notifier_call = twd_timer_cpu_notify,
};
static int twd_timer_dying_cpu(unsigned int cpu)
{
twd_timer_stop();
return 0;
}
static int __init twd_local_timer_common_register(struct device_node *np)
{
@ -345,9 +338,9 @@ static int __init twd_local_timer_common_register(struct device_node *np)
goto out_free;
}
err = register_cpu_notifier(&twd_timer_cpu_nb);
if (err)
goto out_irq;
cpuhp_setup_state_nocalls(CPUHP_AP_ARM_TWD_STARTING,
"AP_ARM_TWD_STARTING",
twd_timer_starting_cpu, twd_timer_dying_cpu);
twd_get_clock(np);
if (!of_property_read_bool(np, "always-on"))
@ -365,8 +358,6 @@ static int __init twd_local_timer_common_register(struct device_node *np)
return 0;
out_irq:
free_percpu_irq(twd_ppi, twd_evt);
out_free:
iounmap(twd_base);
twd_base = NULL;

View File

@ -111,20 +111,12 @@ static struct notifier_block mvebu_hwcc_pci_nb __maybe_unused = {
.notifier_call = mvebu_hwcc_notifier,
};
static int armada_xp_clear_shared_l2_notifier_func(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int armada_xp_clear_l2_starting(unsigned int cpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
armada_xp_clear_shared_l2();
return NOTIFY_OK;
armada_xp_clear_shared_l2();
return 0;
}
static struct notifier_block armada_xp_clear_shared_l2_notifier = {
.notifier_call = armada_xp_clear_shared_l2_notifier_func,
.priority = 100,
};
static void __init armada_370_coherency_init(struct device_node *np)
{
struct resource res;
@ -155,8 +147,9 @@ static void __init armada_370_coherency_init(struct device_node *np)
of_node_put(cpu_config_np);
register_cpu_notifier(&armada_xp_clear_shared_l2_notifier);
cpuhp_setup_state_nocalls(CPUHP_AP_ARM_MVEBU_COHERENCY,
"AP_ARM_MVEBU_COHERENCY",
armada_xp_clear_l2_starting, NULL);
exit:
set_cpu_coherent();
}

View File

@ -597,17 +597,16 @@ static void l2c310_configure(void __iomem *base)
L310_POWER_CTRL);
}
static int l2c310_cpu_enable_flz(struct notifier_block *nb, unsigned long act, void *data)
static int l2c310_starting_cpu(unsigned int cpu)
{
switch (act & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
break;
case CPU_DYING:
set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
break;
}
return NOTIFY_OK;
set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
return 0;
}
static int l2c310_dying_cpu(unsigned int cpu)
{
set_auxcr(get_auxcr() & ~(BIT(3) | BIT(2) | BIT(1)));
return 0;
}
static void __init l2c310_enable(void __iomem *base, unsigned num_lock)
@ -678,10 +677,10 @@ static void __init l2c310_enable(void __iomem *base, unsigned num_lock)
power_ctrl & L310_STNDBY_MODE_EN ? "en" : "dis");
}
if (aux & L310_AUX_CTRL_FULL_LINE_ZERO) {
set_auxcr(get_auxcr() | BIT(3) | BIT(2) | BIT(1));
cpu_notifier(l2c310_cpu_enable_flz, 0);
}
if (aux & L310_AUX_CTRL_FULL_LINE_ZERO)
cpuhp_setup_state(CPUHP_AP_ARM_L2X0_STARTING,
"AP_ARM_L2X0_STARTING", l2c310_starting_cpu,
l2c310_dying_cpu);
}
static void __init l2c310_fixup(void __iomem *base, u32 cache_id,

View File

@ -643,19 +643,19 @@ int vfp_restore_user_hwstate(struct user_vfp __user *ufp,
* hardware state at every thread switch. We clear our held state when
* a CPU has been killed, indicating that the VFP hardware doesn't contain
* a threads VFP state. When a CPU starts up, we re-enable access to the
* VFP hardware.
*
* Both CPU_DYING and CPU_STARTING are called on the CPU which
* VFP hardware. The callbacks below are called on the CPU which
* is being offlined/onlined.
*/
static int vfp_hotplug(struct notifier_block *b, unsigned long action,
void *hcpu)
static int vfp_dying_cpu(unsigned int cpu)
{
if (action == CPU_DYING || action == CPU_DYING_FROZEN)
vfp_current_hw_state[(long)hcpu] = NULL;
else if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
vfp_enable(NULL);
return NOTIFY_OK;
vfp_force_reload(cpu, current_thread_info());
return 0;
}
static int vfp_starting_cpu(unsigned int unused)
{
vfp_enable(NULL);
return 0;
}
void vfp_kmode_exception(void)
@ -732,6 +732,10 @@ static int __init vfp_init(void)
unsigned int vfpsid;
unsigned int cpu_arch = cpu_architecture();
/*
* Enable the access to the VFP on all online CPUs so the
* following test on FPSID will succeed.
*/
if (cpu_arch >= CPU_ARCH_ARMv6)
on_each_cpu(vfp_enable, NULL, 1);
@ -794,7 +798,9 @@ static int __init vfp_init(void)
VFP_arch = (vfpsid & FPSID_ARCH_MASK) >> FPSID_ARCH_BIT;
}
hotcpu_notifier(vfp_hotplug, 0);
cpuhp_setup_state_nocalls(CPUHP_AP_ARM_VFP_STARTING,
"AP_ARM_VFP_STARTING", vfp_starting_cpu,
vfp_dying_cpu);
vfp_vector = vfp_support_entry;

View File

@ -153,12 +153,11 @@ static struct notifier_block xen_pvclock_gtod_notifier = {
.notifier_call = xen_pvclock_gtod_notify,
};
static void xen_percpu_init(void)
static int xen_starting_cpu(unsigned int cpu)
{
struct vcpu_register_vcpu_info info;
struct vcpu_info *vcpup;
int err;
int cpu = get_cpu();
/*
* VCPUOP_register_vcpu_info cannot be called twice for the same
@ -186,7 +185,13 @@ static void xen_percpu_init(void)
after_register_vcpu_info:
enable_percpu_irq(xen_events_irq, 0);
put_cpu();
return 0;
}
static int xen_dying_cpu(unsigned int cpu)
{
disable_percpu_irq(xen_events_irq);
return 0;
}
static void xen_restart(enum reboot_mode reboot_mode, const char *cmd)
@ -205,28 +210,6 @@ static void xen_power_off(void)
BUG_ON(rc);
}
static int xen_cpu_notification(struct notifier_block *self,
unsigned long action,
void *hcpu)
{
switch (action) {
case CPU_STARTING:
xen_percpu_init();
break;
case CPU_DYING:
disable_percpu_irq(xen_events_irq);
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block xen_cpu_notifier = {
.notifier_call = xen_cpu_notification,
};
static irqreturn_t xen_arm_callback(int irq, void *arg)
{
xen_hvm_evtchn_do_upcall();
@ -425,16 +408,14 @@ static int __init xen_guest_init(void)
return -EINVAL;
}
xen_percpu_init();
register_cpu_notifier(&xen_cpu_notifier);
xen_time_setup_guest();
if (xen_initial_domain())
pvclock_gtod_register_notifier(&xen_pvclock_gtod_notifier);
return 0;
return cpuhp_setup_state(CPUHP_AP_ARM_XEN_STARTING,
"AP_ARM_XEN_STARTING", xen_starting_cpu,
xen_dying_cpu);
}
early_initcall(xen_guest_init);

View File

@ -121,7 +121,7 @@ static int run_all_cpu_set_hw_mode(struct insn_emulation *insn, bool enable)
* 0 - If all the hooks ran successfully.
* -EINVAL - At least one hook is not supported by the CPU.
*/
static int run_all_insn_set_hw_mode(unsigned long cpu)
static int run_all_insn_set_hw_mode(unsigned int cpu)
{
int rc = 0;
unsigned long flags;
@ -131,7 +131,7 @@ static int run_all_insn_set_hw_mode(unsigned long cpu)
list_for_each_entry(insn, &insn_emulation, node) {
bool enable = (insn->current_mode == INSN_HW);
if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(enable)) {
pr_warn("CPU[%ld] cannot support the emulation of %s",
pr_warn("CPU[%u] cannot support the emulation of %s",
cpu, insn->ops->name);
rc = -EINVAL;
}
@ -611,20 +611,6 @@ static struct insn_emulation_ops setend_ops = {
.set_hw_mode = setend_set_hw_mode,
};
static int insn_cpu_hotplug_notify(struct notifier_block *b,
unsigned long action, void *hcpu)
{
int rc = 0;
if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
rc = run_all_insn_set_hw_mode((unsigned long)hcpu);
return notifier_from_errno(rc);
}
static struct notifier_block insn_cpu_hotplug_notifier = {
.notifier_call = insn_cpu_hotplug_notify,
};
/*
* Invoked as late_initcall, since not needed before init spawned.
*/
@ -643,7 +629,9 @@ static int __init armv8_deprecated_init(void)
pr_info("setend instruction emulation is not supported on the system");
}
register_cpu_notifier(&insn_cpu_hotplug_notifier);
cpuhp_setup_state_nocalls(CPUHP_AP_ARM64_ISNDEP_STARTING,
"AP_ARM64_ISNDEP_STARTING",
run_all_insn_set_hw_mode, NULL);
register_insn_emulation_sysctl(ctl_abi);
return 0;

View File

@ -453,29 +453,13 @@ static struct pmu pmu = {
.read = bfin_pmu_read,
};
static void bfin_pmu_setup(int cpu)
static int bfin_pmu_prepare_cpu(unsigned int cpu)
{
struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
bfin_write_PFCTL(0);
memset(cpuhw, 0, sizeof(struct cpu_hw_events));
}
static int
bfin_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
bfin_write_PFCTL(0);
bfin_pmu_setup(cpu);
break;
default:
break;
}
return NOTIFY_OK;
return 0;
}
static int __init bfin_pmu_init(void)
@ -491,8 +475,8 @@ static int __init bfin_pmu_init(void)
ret = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
if (!ret)
perf_cpu_notifier(bfin_pmu_notifier);
cpuhp_setup_state(CPUHP_PERF_BFIN, "PERF_BFIN",
bfin_pmu_prepare_cpu, NULL);
return ret;
}
early_initcall(bfin_pmu_init);

View File

@ -806,25 +806,16 @@ static struct metag_pmu _metag_pmu = {
};
/* PMU CPU hotplug notifier */
static int metag_pmu_cpu_notify(struct notifier_block *b, unsigned long action,
void *hcpu)
static int metag_pmu_starting_cpu(unsigned int cpu)
{
unsigned int cpu = (unsigned int)hcpu;
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
return NOTIFY_DONE;
memset(cpuc, 0, sizeof(struct cpu_hw_events));
raw_spin_lock_init(&cpuc->pmu_lock);
return NOTIFY_OK;
return 0;
}
static struct notifier_block metag_pmu_notifier = {
.notifier_call = metag_pmu_cpu_notify,
};
/* PMU Initialisation */
static int __init init_hw_perf_events(void)
{
@ -876,16 +867,13 @@ static int __init init_hw_perf_events(void)
metag_out32(0, PERF_COUNT(0));
metag_out32(0, PERF_COUNT(1));
for_each_possible_cpu(cpu) {
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
cpuhp_setup_state(CPUHP_AP_PERF_METAG_STARTING,
"AP_PERF_METAG_STARTING", metag_pmu_starting_cpu,
NULL);
memset(cpuc, 0, sizeof(struct cpu_hw_events));
raw_spin_lock_init(&cpuc->pmu_lock);
}
register_cpu_notifier(&metag_pmu_notifier);
ret = perf_pmu_register(&pmu, metag_pmu->name, PERF_TYPE_RAW);
out:
if (ret)
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_METAG_STARTING);
return ret;
}
early_initcall(init_hw_perf_events);

View File

@ -168,33 +168,26 @@ static int loongson3_perfcount_handler(void)
return handled;
}
static int loongson3_cpu_callback(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int loongson3_starting_cpu(unsigned int cpu)
{
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
write_c0_perflo1(reg.control1);
write_c0_perflo2(reg.control2);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
write_c0_perflo1(0xc0000000);
write_c0_perflo2(0x40000000);
break;
}
return NOTIFY_OK;
write_c0_perflo1(reg.control1);
write_c0_perflo2(reg.control2);
return 0;
}
static struct notifier_block loongson3_notifier_block = {
.notifier_call = loongson3_cpu_callback
};
static int loongson3_dying_cpu(unsigned int cpu)
{
write_c0_perflo1(0xc0000000);
write_c0_perflo2(0x40000000);
return 0;
}
static int __init loongson3_init(void)
{
on_each_cpu(reset_counters, NULL, 1);
register_hotcpu_notifier(&loongson3_notifier_block);
cpuhp_setup_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
"AP_MIPS_OP_LOONGSON3_STARTING",
loongson3_starting_cpu, loongson3_dying_cpu);
save_perf_irq = perf_irq;
perf_irq = loongson3_perfcount_handler;
@ -204,7 +197,7 @@ static int __init loongson3_init(void)
static void loongson3_exit(void)
{
on_each_cpu(reset_counters, NULL, 1);
unregister_hotcpu_notifier(&loongson3_notifier_block);
cpuhp_remove_state_nocalls(CPUHP_AP_MIPS_OP_LOONGSON3_STARTING);
perf_irq = save_perf_irq;
}

View File

@ -581,30 +581,22 @@ static void verify_cpu_node_mapping(int cpu, int node)
}
}
static int cpu_numa_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
/* Must run before sched domains notifier. */
static int ppc_numa_cpu_prepare(unsigned int cpu)
{
unsigned long lcpu = (unsigned long)hcpu;
int ret = NOTIFY_DONE, nid;
int nid;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
nid = numa_setup_cpu(lcpu);
verify_cpu_node_mapping((int)lcpu, nid);
ret = NOTIFY_OK;
break;
nid = numa_setup_cpu(cpu);
verify_cpu_node_mapping(cpu, nid);
return 0;
}
static int ppc_numa_cpu_dead(unsigned int cpu)
{
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
unmap_cpu_from_node(lcpu);
ret = NOTIFY_OK;
break;
unmap_cpu_from_node(cpu);
#endif
}
return ret;
return 0;
}
/*
@ -913,11 +905,6 @@ static void __init dump_numa_memory_topology(void)
}
}
static struct notifier_block ppc64_numa_nb = {
.notifier_call = cpu_numa_callback,
.priority = 1 /* Must run before sched domains notifier. */
};
/* Initialize NODE_DATA for a node on the local memory */
static void __init setup_node_data(int nid, u64 start_pfn, u64 end_pfn)
{
@ -985,15 +972,18 @@ void __init initmem_init(void)
setup_node_to_cpumask_map();
reset_numa_cpu_lookup_table();
register_cpu_notifier(&ppc64_numa_nb);
/*
* We need the numa_cpu_lookup_table to be accurate for all CPUs,
* even before we online them, so that we can use cpu_to_{node,mem}
* early in boot, cf. smp_prepare_cpus().
* _nocalls() + manual invocation is used because cpuhp is not yet
* initialized for the boot CPU.
*/
for_each_present_cpu(cpu) {
numa_setup_cpu((unsigned long)cpu);
}
cpuhp_setup_state_nocalls(CPUHP_POWER_NUMA_PREPARE, "POWER_NUMA_PREPARE",
ppc_numa_cpu_prepare, ppc_numa_cpu_dead);
for_each_present_cpu(cpu)
numa_setup_cpu(cpu);
}
static int __init early_numa(char *p)

View File

@ -2158,31 +2158,15 @@ static void perf_event_interrupt(struct pt_regs *regs)
irq_exit();
}
static void power_pmu_setup(int cpu)
int power_pmu_prepare_cpu(unsigned int cpu)
{
struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
if (!ppmu)
return;
memset(cpuhw, 0, sizeof(*cpuhw));
cpuhw->mmcr[0] = MMCR0_FC;
}
static int
power_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
power_pmu_setup(cpu);
break;
default:
break;
if (ppmu) {
memset(cpuhw, 0, sizeof(*cpuhw));
cpuhw->mmcr[0] = MMCR0_FC;
}
return NOTIFY_OK;
return 0;
}
int register_power_pmu(struct power_pmu *pmu)
@ -2205,7 +2189,7 @@ int register_power_pmu(struct power_pmu *pmu)
#endif /* CONFIG_PPC64 */
perf_pmu_register(&power_pmu, "cpu", PERF_TYPE_RAW);
perf_cpu_notifier(power_pmu_notifier);
cpuhp_setup_state(CPUHP_PERF_POWER, "PERF_POWER",
power_pmu_prepare_cpu, NULL);
return 0;
}

View File

@ -664,30 +664,22 @@ static struct pmu cpumf_pmu = {
.cancel_txn = cpumf_pmu_cancel_txn,
};
static int cpumf_pmu_notifier(struct notifier_block *self, unsigned long action,
void *hcpu)
static int cpumf_pmf_setup(unsigned int cpu, int flags)
{
int flags;
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
return 0;
}
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
case CPU_DOWN_FAILED:
flags = PMC_INIT;
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
break;
case CPU_DOWN_PREPARE:
flags = PMC_RELEASE;
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
break;
default:
break;
}
static int s390_pmu_online_cpu(unsigned int cpu)
{
return cpumf_pmf_setup(cpu, PMC_INIT);
}
return NOTIFY_OK;
static int s390_pmu_offline_cpu(unsigned int cpu)
{
return cpumf_pmf_setup(cpu, PMC_RELEASE);
}
static int __init cpumf_pmu_init(void)
@ -707,7 +699,7 @@ static int __init cpumf_pmu_init(void)
if (rc) {
pr_err("Registering for CPU-measurement alerts "
"failed with rc=%i\n", rc);
goto out;
return rc;
}
cpumf_pmu.attr_groups = cpumf_cf_event_group();
@ -716,10 +708,10 @@ static int __init cpumf_pmu_init(void)
pr_err("Registering the cpum_cf PMU failed with rc=%i\n", rc);
unregister_external_irq(EXT_IRQ_MEASURE_ALERT,
cpumf_measurement_alert);
goto out;
return rc;
}
perf_cpu_notifier(cpumf_pmu_notifier);
out:
return rc;
return cpuhp_setup_state(CPUHP_AP_PERF_S390_CF_ONLINE,
"AP_PERF_S390_CF_ONLINE",
s390_pmu_online_cpu, s390_pmu_offline_cpu);
}
early_initcall(cpumf_pmu_init);

View File

@ -1504,37 +1504,28 @@ static void cpumf_measurement_alert(struct ext_code ext_code,
sf_disable();
}
}
static int cpumf_pmu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
static int cpusf_pmu_setup(unsigned int cpu, int flags)
{
int flags;
/* Ignore the notification if no events are scheduled on the PMU.
* This might be racy...
*/
if (!atomic_read(&num_events))
return NOTIFY_OK;
return 0;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
case CPU_DOWN_FAILED:
flags = PMC_INIT;
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
break;
case CPU_DOWN_PREPARE:
flags = PMC_RELEASE;
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
break;
default:
break;
}
local_irq_disable();
setup_pmc_cpu(&flags);
local_irq_enable();
return 0;
}
return NOTIFY_OK;
static int s390_pmu_sf_online_cpu(unsigned int cpu)
{
return cpusf_pmu_setup(cpu, PMC_INIT);
}
static int s390_pmu_sf_offline_cpu(unsigned int cpu)
{
return cpusf_pmu_setup(cpu, PMC_RELEASE);
}
static int param_get_sfb_size(char *buffer, const struct kernel_param *kp)
@ -1634,7 +1625,9 @@ static int __init init_cpum_sampling_pmu(void)
cpumf_measurement_alert);
goto out;
}
perf_cpu_notifier(cpumf_pmu_notifier);
cpuhp_setup_state(CPUHP_AP_PERF_S390_SF_ONLINE, "AP_PERF_S390_SF_ONLINE",
s390_pmu_sf_online_cpu, s390_pmu_sf_offline_cpu);
out:
return err;
}

View File

@ -352,28 +352,12 @@ static struct pmu pmu = {
.read = sh_pmu_read,
};
static void sh_pmu_setup(int cpu)
static int sh_pmu_prepare_cpu(unsigned int cpu)
{
struct cpu_hw_events *cpuhw = &per_cpu(cpu_hw_events, cpu);
memset(cpuhw, 0, sizeof(struct cpu_hw_events));
}
static int
sh_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
sh_pmu_setup(cpu);
break;
default:
break;
}
return NOTIFY_OK;
return 0;
}
int register_sh_pmu(struct sh_pmu *_pmu)
@ -394,6 +378,7 @@ int register_sh_pmu(struct sh_pmu *_pmu)
WARN_ON(_pmu->num_events > MAX_HWEVENTS);
perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
perf_cpu_notifier(sh_pmu_notifier);
cpuhp_setup_state(CPUHP_PERF_SUPERH, "PERF_SUPERH", sh_pmu_prepare_cpu,
NULL);
return 0;
}

View File

@ -331,15 +331,9 @@ static void vgetcpu_cpu_init(void *arg)
write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
}
static int
vgetcpu_cpu_notifier(struct notifier_block *n, unsigned long action, void *arg)
static int vgetcpu_online(unsigned int cpu)
{
long cpu = (long)arg;
if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
smp_call_function_single(cpu, vgetcpu_cpu_init, NULL, 1);
return NOTIFY_DONE;
return smp_call_function_single(cpu, vgetcpu_cpu_init, NULL, 1);
}
static int __init init_vdso(void)
@ -350,15 +344,9 @@ static int __init init_vdso(void)
init_vdso_image(&vdso_image_x32);
#endif
cpu_notifier_register_begin();
on_each_cpu(vgetcpu_cpu_init, NULL, 1);
/* notifier priority > KVM */
__hotcpu_notifier(vgetcpu_cpu_notifier, 30);
cpu_notifier_register_done();
return 0;
return cpuhp_setup_state(CPUHP_AP_X86_VDSO_VMA_ONLINE,
"AP_X86_VDSO_VMA_ONLINE", vgetcpu_online, NULL);
}
subsys_initcall(init_vdso);
#endif /* CONFIG_X86_64 */

View File

@ -370,13 +370,13 @@ static int amd_pmu_cpu_prepare(int cpu)
WARN_ON_ONCE(cpuc->amd_nb);
if (!x86_pmu.amd_nb_constraints)
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)

View File

@ -725,13 +725,10 @@ static __init int perf_ibs_pmu_init(struct perf_ibs *perf_ibs, char *name)
return ret;
}
static __init int perf_event_ibs_init(void)
static __init void perf_event_ibs_init(void)
{
struct attribute **attr = ibs_op_format_attrs;
if (!ibs_caps)
return -ENODEV; /* ibs not supported by the cpu */
perf_ibs_pmu_init(&perf_ibs_fetch, "ibs_fetch");
if (ibs_caps & IBS_CAPS_OPCNT) {
@ -742,13 +739,11 @@ static __init int perf_event_ibs_init(void)
register_nmi_handler(NMI_LOCAL, perf_ibs_nmi_handler, 0, "perf_ibs");
pr_info("perf: AMD IBS detected (0x%08x)\n", ibs_caps);
return 0;
}
#else /* defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_AMD) */
static __init int perf_event_ibs_init(void) { return 0; }
static __init void perf_event_ibs_init(void) { }
#endif
@ -925,7 +920,7 @@ static inline int get_ibs_lvt_offset(void)
return val & IBSCTL_LVT_OFFSET_MASK;
}
static void setup_APIC_ibs(void *dummy)
static void setup_APIC_ibs(void)
{
int offset;
@ -940,7 +935,7 @@ static void setup_APIC_ibs(void *dummy)
smp_processor_id());
}
static void clear_APIC_ibs(void *dummy)
static void clear_APIC_ibs(void)
{
int offset;
@ -949,18 +944,24 @@ static void clear_APIC_ibs(void *dummy)
setup_APIC_eilvt(offset, 0, APIC_EILVT_MSG_FIX, 1);
}
static int x86_pmu_amd_ibs_starting_cpu(unsigned int cpu)
{
setup_APIC_ibs();
return 0;
}
#ifdef CONFIG_PM
static int perf_ibs_suspend(void)
{
clear_APIC_ibs(NULL);
clear_APIC_ibs();
return 0;
}
static void perf_ibs_resume(void)
{
ibs_eilvt_setup();
setup_APIC_ibs(NULL);
setup_APIC_ibs();
}
static struct syscore_ops perf_ibs_syscore_ops = {
@ -979,27 +980,15 @@ static inline void perf_ibs_pm_init(void) { }
#endif
static int
perf_ibs_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
static int x86_pmu_amd_ibs_dying_cpu(unsigned int cpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
setup_APIC_ibs(NULL);
break;
case CPU_DYING:
clear_APIC_ibs(NULL);
break;
default:
break;
}
return NOTIFY_OK;
clear_APIC_ibs();
return 0;
}
static __init int amd_ibs_init(void)
{
u32 caps;
int ret = -EINVAL;
caps = __get_ibs_caps();
if (!caps)
@ -1008,22 +997,25 @@ static __init int amd_ibs_init(void)
ibs_eilvt_setup();
if (!ibs_eilvt_valid())
goto out;
return -EINVAL;
perf_ibs_pm_init();
cpu_notifier_register_begin();
ibs_caps = caps;
/* make ibs_caps visible to other cpus: */
smp_mb();
smp_call_function(setup_APIC_ibs, NULL, 1);
__perf_cpu_notifier(perf_ibs_cpu_notifier);
cpu_notifier_register_done();
/*
* x86_pmu_amd_ibs_starting_cpu will be called from core on
* all online cpus.
*/
cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
"AP_PERF_X86_AMD_IBS_STARTING",
x86_pmu_amd_ibs_starting_cpu,
x86_pmu_amd_ibs_dying_cpu);
ret = perf_event_ibs_init();
out:
if (ret)
pr_err("Failed to setup IBS, %d\n", ret);
return ret;
perf_event_ibs_init();
return 0;
}
/* Since we need the pci subsystem to init ibs we can't do this earlier: */

View File

@ -228,12 +228,12 @@ static struct pmu pmu_class = {
.read = pmu_event_read,
};
static void power_cpu_exit(int cpu)
static int power_cpu_exit(unsigned int cpu)
{
int target;
if (!cpumask_test_and_clear_cpu(cpu, &cpu_mask))
return;
return 0;
/*
* Find a new CPU on the same compute unit, if was set in cpumask
@ -245,9 +245,10 @@ static void power_cpu_exit(int cpu)
cpumask_set_cpu(target, &cpu_mask);
perf_pmu_migrate_context(&pmu_class, cpu, target);
}
return 0;
}
static void power_cpu_init(int cpu)
static int power_cpu_init(unsigned int cpu)
{
int target;
@ -255,7 +256,7 @@ static void power_cpu_init(int cpu)
* 1) If any CPU is set at cpu_mask in the same compute unit, do
* nothing.
* 2) If no CPU is set at cpu_mask in the same compute unit,
* set current STARTING CPU.
* set current ONLINE CPU.
*
* Note: if there is a CPU aside of the new one already in the
* sibling mask, then it is also in cpu_mask.
@ -263,33 +264,9 @@ static void power_cpu_init(int cpu)
target = cpumask_any_but(topology_sibling_cpumask(cpu), cpu);
if (target >= nr_cpumask_bits)
cpumask_set_cpu(cpu, &cpu_mask);
return 0;
}
static int
power_cpu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_FAILED:
case CPU_STARTING:
power_cpu_init(cpu);
break;
case CPU_DOWN_PREPARE:
power_cpu_exit(cpu);
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block power_cpu_notifier_nb = {
.notifier_call = power_cpu_notifier,
.priority = CPU_PRI_PERF,
};
static const struct x86_cpu_id cpu_match[] = {
{ .vendor = X86_VENDOR_AMD, .family = 0x15 },
{},
@ -297,7 +274,7 @@ static const struct x86_cpu_id cpu_match[] = {
static int __init amd_power_pmu_init(void)
{
int cpu, target, ret;
int ret;
if (!x86_match_cpu(cpu_match))
return 0;
@ -312,38 +289,25 @@ static int __init amd_power_pmu_init(void)
return -ENODEV;
}
cpu_notifier_register_begin();
/* Choose one online core of each compute unit. */
for_each_online_cpu(cpu) {
target = cpumask_first(topology_sibling_cpumask(cpu));
if (!cpumask_test_cpu(target, &cpu_mask))
cpumask_set_cpu(target, &cpu_mask);
}
cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_POWER_ONLINE,
"AP_PERF_X86_AMD_POWER_ONLINE",
power_cpu_init, power_cpu_exit);
ret = perf_pmu_register(&pmu_class, "power", -1);
if (WARN_ON(ret)) {
pr_warn("AMD Power PMU registration failed\n");
goto out;
return ret;
}
__register_cpu_notifier(&power_cpu_notifier_nb);
pr_info("AMD Power PMU detected\n");
out:
cpu_notifier_register_done();
return ret;
}
module_init(amd_power_pmu_init);
static void __exit amd_power_pmu_exit(void)
{
cpu_notifier_register_begin();
__unregister_cpu_notifier(&power_cpu_notifier_nb);
cpu_notifier_register_done();
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_AMD_POWER_ONLINE);
perf_pmu_unregister(&pmu_class);
}
module_exit(amd_power_pmu_exit);

View File

@ -358,7 +358,7 @@ amd_uncore_find_online_sibling(struct amd_uncore *this,
return this;
}
static void amd_uncore_cpu_starting(unsigned int cpu)
static int amd_uncore_cpu_starting(unsigned int cpu)
{
unsigned int eax, ebx, ecx, edx;
struct amd_uncore *uncore;
@ -384,6 +384,8 @@ static void amd_uncore_cpu_starting(unsigned int cpu)
uncore = amd_uncore_find_online_sibling(uncore, amd_uncore_l2);
*per_cpu_ptr(amd_uncore_l2, cpu) = uncore;
}
return 0;
}
static void uncore_online(unsigned int cpu,
@ -398,13 +400,15 @@ static void uncore_online(unsigned int cpu,
cpumask_set_cpu(cpu, uncore->active_mask);
}
static void amd_uncore_cpu_online(unsigned int cpu)
static int amd_uncore_cpu_online(unsigned int cpu)
{
if (amd_uncore_nb)
uncore_online(cpu, amd_uncore_nb);
if (amd_uncore_l2)
uncore_online(cpu, amd_uncore_l2);
return 0;
}
static void uncore_down_prepare(unsigned int cpu,
@ -433,13 +437,15 @@ static void uncore_down_prepare(unsigned int cpu,
}
}
static void amd_uncore_cpu_down_prepare(unsigned int cpu)
static int amd_uncore_cpu_down_prepare(unsigned int cpu)
{
if (amd_uncore_nb)
uncore_down_prepare(cpu, amd_uncore_nb);
if (amd_uncore_l2)
uncore_down_prepare(cpu, amd_uncore_l2);
return 0;
}
static void uncore_dead(unsigned int cpu, struct amd_uncore * __percpu *uncores)
@ -454,74 +460,19 @@ static void uncore_dead(unsigned int cpu, struct amd_uncore * __percpu *uncores)
*per_cpu_ptr(uncores, cpu) = NULL;
}
static void amd_uncore_cpu_dead(unsigned int cpu)
static int amd_uncore_cpu_dead(unsigned int cpu)
{
if (amd_uncore_nb)
uncore_dead(cpu, amd_uncore_nb);
if (amd_uncore_l2)
uncore_dead(cpu, amd_uncore_l2);
}
static int
amd_uncore_cpu_notifier(struct notifier_block *self, unsigned long action,
void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
if (amd_uncore_cpu_up_prepare(cpu))
return notifier_from_errno(-ENOMEM);
break;
case CPU_STARTING:
amd_uncore_cpu_starting(cpu);
break;
case CPU_ONLINE:
amd_uncore_cpu_online(cpu);
break;
case CPU_DOWN_PREPARE:
amd_uncore_cpu_down_prepare(cpu);
break;
case CPU_UP_CANCELED:
case CPU_DEAD:
amd_uncore_cpu_dead(cpu);
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block amd_uncore_cpu_notifier_block = {
.notifier_call = amd_uncore_cpu_notifier,
.priority = CPU_PRI_PERF + 1,
};
static void __init init_cpu_already_online(void *dummy)
{
unsigned int cpu = smp_processor_id();
amd_uncore_cpu_starting(cpu);
amd_uncore_cpu_online(cpu);
}
static void cleanup_cpu_online(void *dummy)
{
unsigned int cpu = smp_processor_id();
amd_uncore_cpu_dead(cpu);
return 0;
}
static int __init amd_uncore_init(void)
{
unsigned int cpu, cpu2;
int ret = -ENODEV;
if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)
@ -558,38 +509,29 @@ static int __init amd_uncore_init(void)
ret = 0;
}
if (ret)
goto fail_nodev;
cpu_notifier_register_begin();
/* init cpus already online before registering for hotplug notifier */
for_each_online_cpu(cpu) {
ret = amd_uncore_cpu_up_prepare(cpu);
if (ret)
goto fail_online;
smp_call_function_single(cpu, init_cpu_already_online, NULL, 1);
}
__register_cpu_notifier(&amd_uncore_cpu_notifier_block);
cpu_notifier_register_done();
/*
* Install callbacks. Core will call them for each online cpu.
*/
if (cpuhp_setup_state(CPUHP_PERF_X86_AMD_UNCORE_PREP,
"PERF_X86_AMD_UNCORE_PREP",
amd_uncore_cpu_up_prepare, amd_uncore_cpu_dead))
goto fail_l2;
if (cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
"AP_PERF_X86_AMD_UNCORE_STARTING",
amd_uncore_cpu_starting, NULL))
goto fail_prep;
if (cpuhp_setup_state(CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE,
"AP_PERF_X86_AMD_UNCORE_ONLINE",
amd_uncore_cpu_online,
amd_uncore_cpu_down_prepare))
goto fail_start;
return 0;
fail_online:
for_each_online_cpu(cpu2) {
if (cpu2 == cpu)
break;
smp_call_function_single(cpu, cleanup_cpu_online, NULL, 1);
}
cpu_notifier_register_done();
/* amd_uncore_nb/l2 should have been freed by cleanup_cpu_online */
amd_uncore_nb = amd_uncore_l2 = NULL;
if (boot_cpu_has(X86_FEATURE_PERFCTR_L2))
perf_pmu_unregister(&amd_l2_pmu);
fail_start:
cpuhp_remove_state(CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING);
fail_prep:
cpuhp_remove_state(CPUHP_PERF_X86_AMD_UNCORE_PREP);
fail_l2:
if (boot_cpu_has(X86_FEATURE_PERFCTR_NB))
perf_pmu_unregister(&amd_nb_pmu);

View File

@ -1477,49 +1477,49 @@ NOKPROBE_SYMBOL(perf_event_nmi_handler);
struct event_constraint emptyconstraint;
struct event_constraint unconstrained;
static int
x86_pmu_notifier(struct notifier_block *self, unsigned long action, void *hcpu)
static int x86_pmu_prepare_cpu(unsigned int cpu)
{
unsigned int cpu = (long)hcpu;
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
int i, ret = NOTIFY_OK;
int i;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
for (i = 0 ; i < X86_PERF_KFREE_MAX; i++)
cpuc->kfree_on_online[i] = NULL;
if (x86_pmu.cpu_prepare)
ret = x86_pmu.cpu_prepare(cpu);
break;
for (i = 0 ; i < X86_PERF_KFREE_MAX; i++)
cpuc->kfree_on_online[i] = NULL;
if (x86_pmu.cpu_prepare)
return x86_pmu.cpu_prepare(cpu);
return 0;
}
case CPU_STARTING:
if (x86_pmu.cpu_starting)
x86_pmu.cpu_starting(cpu);
break;
static int x86_pmu_dead_cpu(unsigned int cpu)
{
if (x86_pmu.cpu_dead)
x86_pmu.cpu_dead(cpu);
return 0;
}
case CPU_ONLINE:
for (i = 0 ; i < X86_PERF_KFREE_MAX; i++) {
kfree(cpuc->kfree_on_online[i]);
cpuc->kfree_on_online[i] = NULL;
}
break;
static int x86_pmu_online_cpu(unsigned int cpu)
{
struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu);
int i;
case CPU_DYING:
if (x86_pmu.cpu_dying)
x86_pmu.cpu_dying(cpu);
break;
case CPU_UP_CANCELED:
case CPU_DEAD:
if (x86_pmu.cpu_dead)
x86_pmu.cpu_dead(cpu);
break;
default:
break;
for (i = 0 ; i < X86_PERF_KFREE_MAX; i++) {
kfree(cpuc->kfree_on_online[i]);
cpuc->kfree_on_online[i] = NULL;
}
return 0;
}
return ret;
static int x86_pmu_starting_cpu(unsigned int cpu)
{
if (x86_pmu.cpu_starting)
x86_pmu.cpu_starting(cpu);
return 0;
}
static int 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)
@ -1787,10 +1787,39 @@ static int __init init_hw_perf_events(void)
pr_info("... fixed-purpose events: %d\n", x86_pmu.num_counters_fixed);
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.
*/
err = cpuhp_setup_state(CPUHP_PERF_X86_PREPARE, "PERF_X86_PREPARE",
x86_pmu_prepare_cpu, x86_pmu_dead_cpu);
if (err)
return err;
err = cpuhp_setup_state(CPUHP_AP_PERF_X86_STARTING,
"AP_PERF_X86_STARTING", x86_pmu_starting_cpu,
x86_pmu_dying_cpu);
if (err)
goto out;
err = cpuhp_setup_state(CPUHP_AP_PERF_X86_ONLINE, "AP_PERF_X86_ONLINE",
x86_pmu_online_cpu, NULL);
if (err)
goto out1;
err = perf_pmu_register(&pmu, "cpu", PERF_TYPE_RAW);
if (err)
goto out2;
return 0;
out2:
cpuhp_remove_state(CPUHP_AP_PERF_X86_ONLINE);
out1:
cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING);
out:
cpuhp_remove_state(CPUHP_PERF_X86_PREPARE);
return err;
}
early_initcall(init_hw_perf_events);

View File

@ -3109,7 +3109,7 @@ static int intel_pmu_cpu_prepare(int cpu)
cpuc->excl_thread_id = 0;
}
return NOTIFY_OK;
return 0;
err_constraint_list:
kfree(cpuc->constraint_list);
@ -3120,7 +3120,7 @@ static int intel_pmu_cpu_prepare(int cpu)
cpuc->shared_regs = NULL;
err:
return NOTIFY_BAD;
return -ENOMEM;
}
static void intel_pmu_cpu_starting(int cpu)

View File

@ -1577,7 +1577,7 @@ static inline void cqm_pick_event_reader(int cpu)
cpumask_set_cpu(cpu, &cqm_cpumask);
}
static void intel_cqm_cpu_starting(unsigned int cpu)
static int intel_cqm_cpu_starting(unsigned int cpu)
{
struct intel_pqr_state *state = &per_cpu(pqr_state, cpu);
struct cpuinfo_x86 *c = &cpu_data(cpu);
@ -1588,39 +1588,26 @@ static void intel_cqm_cpu_starting(unsigned int cpu)
WARN_ON(c->x86_cache_max_rmid != cqm_max_rmid);
WARN_ON(c->x86_cache_occ_scale != cqm_l3_scale);
cqm_pick_event_reader(cpu);
return 0;
}
static void intel_cqm_cpu_exit(unsigned int cpu)
static int intel_cqm_cpu_exit(unsigned int cpu)
{
int target;
/* Is @cpu the current cqm reader for this package ? */
if (!cpumask_test_and_clear_cpu(cpu, &cqm_cpumask))
return;
return 0;
/* Find another online reader in this package */
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
if (target < nr_cpu_ids)
cpumask_set_cpu(target, &cqm_cpumask);
}
static int intel_cqm_cpu_notifier(struct notifier_block *nb,
unsigned long action, void *hcpu)
{
unsigned int cpu = (unsigned long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
intel_cqm_cpu_exit(cpu);
break;
case CPU_STARTING:
intel_cqm_cpu_starting(cpu);
cqm_pick_event_reader(cpu);
break;
}
return NOTIFY_OK;
return 0;
}
static const struct x86_cpu_id intel_cqm_match[] = {
@ -1682,7 +1669,7 @@ static int intel_mbm_init(void)
static int __init intel_cqm_init(void)
{
char *str = NULL, scale[20];
int i, cpu, ret;
int cpu, ret;
if (x86_match_cpu(intel_cqm_match))
cqm_enabled = true;
@ -1705,8 +1692,7 @@ static int __init intel_cqm_init(void)
*
* Also, check that the scales match on all cpus.
*/
cpu_notifier_register_begin();
get_online_cpus();
for_each_online_cpu(cpu) {
struct cpuinfo_x86 *c = &cpu_data(cpu);
@ -1743,11 +1729,6 @@ static int __init intel_cqm_init(void)
if (ret)
goto out;
for_each_online_cpu(i) {
intel_cqm_cpu_starting(i);
cqm_pick_event_reader(i);
}
if (mbm_enabled)
ret = intel_mbm_init();
if (ret && !cqm_enabled)
@ -1772,12 +1753,18 @@ static int __init intel_cqm_init(void)
pr_info("Intel MBM enabled\n");
/*
* Register the hot cpu notifier once we are sure cqm
* Setup the hot cpu notifier once we are sure cqm
* is enabled to avoid notifier leak.
*/
__perf_cpu_notifier(intel_cqm_cpu_notifier);
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_STARTING,
"AP_PERF_X86_CQM_STARTING",
intel_cqm_cpu_starting, NULL);
cpuhp_setup_state(CPUHP_AP_PERF_X86_CQM_ONLINE, "AP_PERF_X86_CQM_ONLINE",
NULL, intel_cqm_cpu_exit);
out:
cpu_notifier_register_done();
put_online_cpus();
if (ret) {
kfree(str);
cqm_cleanup();

View File

@ -366,7 +366,7 @@ static int cstate_pmu_event_add(struct perf_event *event, int mode)
* Check if exiting cpu is the designated reader. If so migrate the
* events when there is a valid target available
*/
static void cstate_cpu_exit(int cpu)
static int cstate_cpu_exit(unsigned int cpu)
{
unsigned int target;
@ -391,9 +391,10 @@ static void cstate_cpu_exit(int cpu)
perf_pmu_migrate_context(&cstate_pkg_pmu, cpu, target);
}
}
return 0;
}
static void cstate_cpu_init(int cpu)
static int cstate_cpu_init(unsigned int cpu)
{
unsigned int target;
@ -415,31 +416,10 @@ static void cstate_cpu_init(int cpu)
topology_core_cpumask(cpu));
if (has_cstate_pkg && target >= nr_cpu_ids)
cpumask_set_cpu(cpu, &cstate_pkg_cpu_mask);
return 0;
}
static int cstate_cpu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
cstate_cpu_init(cpu);
break;
case CPU_DOWN_PREPARE:
cstate_cpu_exit(cpu);
break;
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block cstate_cpu_nb = {
.notifier_call = cstate_cpu_notifier,
.priority = CPU_PRI_PERF + 1,
};
static struct pmu cstate_core_pmu = {
.attr_groups = core_attr_groups,
.name = "cstate_core",
@ -600,18 +580,20 @@ static inline void cstate_cleanup(void)
static int __init cstate_init(void)
{
int cpu, err;
int err;
cpu_notifier_register_begin();
for_each_online_cpu(cpu)
cstate_cpu_init(cpu);
cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_STARTING,
"AP_PERF_X86_CSTATE_STARTING", cstate_cpu_init,
NULL);
cpuhp_setup_state(CPUHP_AP_PERF_X86_CSTATE_ONLINE,
"AP_PERF_X86_CSTATE_ONLINE", NULL, cstate_cpu_exit);
if (has_cstate_core) {
err = perf_pmu_register(&cstate_core_pmu, cstate_core_pmu.name, -1);
if (err) {
has_cstate_core = false;
pr_info("Failed to register cstate core pmu\n");
goto out;
return err;
}
}
@ -621,12 +603,10 @@ static int __init cstate_init(void)
has_cstate_pkg = false;
pr_info("Failed to register cstate pkg pmu\n");
cstate_cleanup();
goto out;
return err;
}
}
__register_cpu_notifier(&cstate_cpu_nb);
out:
cpu_notifier_register_done();
return err;
}
@ -652,9 +632,8 @@ module_init(cstate_pmu_init);
static void __exit cstate_pmu_exit(void)
{
cpu_notifier_register_begin();
__unregister_cpu_notifier(&cstate_cpu_nb);
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_ONLINE);
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_CSTATE_STARTING);
cstate_cleanup();
cpu_notifier_register_done();
}
module_exit(cstate_pmu_exit);

View File

@ -556,14 +556,14 @@ const struct attribute_group *rapl_attr_groups[] = {
NULL,
};
static void rapl_cpu_exit(int cpu)
static int rapl_cpu_offline(unsigned int cpu)
{
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
int target;
/* Check if exiting cpu is used for collecting rapl events */
if (!cpumask_test_and_clear_cpu(cpu, &rapl_cpu_mask))
return;
return 0;
pmu->cpu = -1;
/* Find a new cpu to collect rapl events */
@ -575,9 +575,10 @@ static void rapl_cpu_exit(int cpu)
pmu->cpu = target;
perf_pmu_migrate_context(pmu->pmu, cpu, target);
}
return 0;
}
static void rapl_cpu_init(int cpu)
static int rapl_cpu_online(unsigned int cpu)
{
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
int target;
@ -588,13 +589,14 @@ static void rapl_cpu_init(int cpu)
*/
target = cpumask_any_and(&rapl_cpu_mask, topology_core_cpumask(cpu));
if (target < nr_cpu_ids)
return;
return 0;
cpumask_set_cpu(cpu, &rapl_cpu_mask);
pmu->cpu = cpu;
return 0;
}
static int rapl_cpu_prepare(int cpu)
static int rapl_cpu_prepare(unsigned int cpu)
{
struct rapl_pmu *pmu = cpu_to_rapl_pmu(cpu);
@ -615,33 +617,6 @@ static int rapl_cpu_prepare(int cpu)
return 0;
}
static int rapl_cpu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
rapl_cpu_prepare(cpu);
break;
case CPU_DOWN_FAILED:
case CPU_ONLINE:
rapl_cpu_init(cpu);
break;
case CPU_DOWN_PREPARE:
rapl_cpu_exit(cpu);
break;
}
return NOTIFY_OK;
}
static struct notifier_block rapl_cpu_nb = {
.notifier_call = rapl_cpu_notifier,
.priority = CPU_PRI_PERF + 1,
};
static int rapl_check_hw_unit(bool apply_quirk)
{
u64 msr_rapl_power_unit_bits;
@ -692,24 +667,6 @@ static void __init rapl_advertise(void)
}
}
static int __init rapl_prepare_cpus(void)
{
unsigned int cpu, pkg;
int ret;
for_each_online_cpu(cpu) {
pkg = topology_logical_package_id(cpu);
if (rapl_pmus->pmus[pkg])
continue;
ret = rapl_cpu_prepare(cpu);
if (ret)
return ret;
rapl_cpu_init(cpu);
}
return 0;
}
static void cleanup_rapl_pmus(void)
{
int i;
@ -837,35 +794,44 @@ static int __init rapl_pmu_init(void)
if (ret)
return ret;
cpu_notifier_register_begin();
/*
* Install callbacks. Core will call them for each online cpu.
*/
ret = rapl_prepare_cpus();
ret = cpuhp_setup_state(CPUHP_PERF_X86_RAPL_PREP, "PERF_X86_RAPL_PREP",
rapl_cpu_prepare, NULL);
if (ret)
goto out;
ret = cpuhp_setup_state(CPUHP_AP_PERF_X86_RAPL_ONLINE,
"AP_PERF_X86_RAPL_ONLINE",
rapl_cpu_online, rapl_cpu_offline);
if (ret)
goto out1;
ret = perf_pmu_register(&rapl_pmus->pmu, "power", -1);
if (ret)
goto out;
goto out2;
__register_cpu_notifier(&rapl_cpu_nb);
cpu_notifier_register_done();
rapl_advertise();
return 0;
out2:
cpuhp_remove_state(CPUHP_AP_PERF_X86_RAPL_ONLINE);
out1:
cpuhp_remove_state(CPUHP_PERF_X86_RAPL_PREP);
out:
pr_warn("Initialization failed (%d), disabled\n", ret);
cleanup_rapl_pmus();
cpu_notifier_register_done();
return ret;
}
module_init(rapl_pmu_init);
static void __exit intel_rapl_exit(void)
{
cpu_notifier_register_begin();
__unregister_cpu_notifier(&rapl_cpu_nb);
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_RAPL_ONLINE);
cpuhp_remove_state_nocalls(CPUHP_PERF_X86_RAPL_PREP);
perf_pmu_unregister(&rapl_pmus->pmu);
cleanup_rapl_pmus();
cpu_notifier_register_done();
}
module_exit(intel_rapl_exit);

View File

@ -1052,7 +1052,7 @@ static void uncore_pci_exit(void)
}
}
static void uncore_cpu_dying(int cpu)
static int uncore_cpu_dying(unsigned int cpu)
{
struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
@ -1069,16 +1069,19 @@ static void uncore_cpu_dying(int cpu)
uncore_box_exit(box);
}
}
return 0;
}
static void uncore_cpu_starting(int cpu, bool init)
static int first_init;
static int uncore_cpu_starting(unsigned int cpu)
{
struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
struct intel_uncore_box *box;
int i, pkg, ncpus = 1;
if (init) {
if (first_init) {
/*
* On init we get the number of online cpus in the package
* and set refcount for all of them.
@ -1099,9 +1102,11 @@ static void uncore_cpu_starting(int cpu, bool init)
uncore_box_init(box);
}
}
return 0;
}
static int uncore_cpu_prepare(int cpu)
static int uncore_cpu_prepare(unsigned int cpu)
{
struct intel_uncore_type *type, **types = uncore_msr_uncores;
struct intel_uncore_pmu *pmu;
@ -1164,13 +1169,13 @@ static void uncore_change_context(struct intel_uncore_type **uncores,
uncore_change_type_ctx(*uncores, old_cpu, new_cpu);
}
static void uncore_event_exit_cpu(int cpu)
static int uncore_event_cpu_offline(unsigned int cpu)
{
int target;
/* Check if exiting cpu is used for collecting uncore events */
if (!cpumask_test_and_clear_cpu(cpu, &uncore_cpu_mask))
return;
return 0;
/* Find a new cpu to collect uncore events */
target = cpumask_any_but(topology_core_cpumask(cpu), cpu);
@ -1183,9 +1188,10 @@ static void uncore_event_exit_cpu(int cpu)
uncore_change_context(uncore_msr_uncores, cpu, target);
uncore_change_context(uncore_pci_uncores, cpu, target);
return 0;
}
static void uncore_event_init_cpu(int cpu)
static int uncore_event_cpu_online(unsigned int cpu)
{
int target;
@ -1195,50 +1201,15 @@ static void uncore_event_init_cpu(int cpu)
*/
target = cpumask_any_and(&uncore_cpu_mask, topology_core_cpumask(cpu));
if (target < nr_cpu_ids)
return;
return 0;
cpumask_set_cpu(cpu, &uncore_cpu_mask);
uncore_change_context(uncore_msr_uncores, -1, cpu);
uncore_change_context(uncore_pci_uncores, -1, cpu);
return 0;
}
static int uncore_cpu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
return notifier_from_errno(uncore_cpu_prepare(cpu));
case CPU_STARTING:
uncore_cpu_starting(cpu, false);
case CPU_DOWN_FAILED:
uncore_event_init_cpu(cpu);
break;
case CPU_UP_CANCELED:
case CPU_DYING:
uncore_cpu_dying(cpu);
break;
case CPU_DOWN_PREPARE:
uncore_event_exit_cpu(cpu);
break;
}
return NOTIFY_OK;
}
static struct notifier_block uncore_cpu_nb = {
.notifier_call = uncore_cpu_notifier,
/*
* to migrate uncore events, our notifier should be executed
* before perf core's notifier.
*/
.priority = CPU_PRI_PERF + 1,
};
static int __init type_pmu_register(struct intel_uncore_type *type)
{
int i, ret;
@ -1282,41 +1253,6 @@ static int __init uncore_cpu_init(void)
return ret;
}
static void __init uncore_cpu_setup(void *dummy)
{
uncore_cpu_starting(smp_processor_id(), true);
}
/* Lazy to avoid allocation of a few bytes for the normal case */
static __initdata DECLARE_BITMAP(packages, MAX_LOCAL_APIC);
static int __init uncore_cpumask_init(bool msr)
{
unsigned int cpu;
for_each_online_cpu(cpu) {
unsigned int pkg = topology_logical_package_id(cpu);
int ret;
if (test_and_set_bit(pkg, packages))
continue;
/*
* The first online cpu of each package allocates and takes
* the refcounts for all other online cpus in that package.
* If msrs are not enabled no allocation is required.
*/
if (msr) {
ret = uncore_cpu_prepare(cpu);
if (ret)
return ret;
}
uncore_event_init_cpu(cpu);
smp_call_function_single(cpu, uncore_cpu_setup, NULL, 1);
}
__register_cpu_notifier(&uncore_cpu_nb);
return 0;
}
#define X86_UNCORE_MODEL_MATCH(model, init) \
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&init }
@ -1440,11 +1376,33 @@ static int __init intel_uncore_init(void)
if (cret && pret)
return -ENODEV;
cpu_notifier_register_begin();
ret = uncore_cpumask_init(!cret);
if (ret)
goto err;
cpu_notifier_register_done();
/*
* Install callbacks. Core will call them for each online cpu.
*
* The first online cpu of each package allocates and takes
* the refcounts for all other online cpus in that package.
* If msrs are not enabled no allocation is required and
* uncore_cpu_prepare() is not called for each online cpu.
*/
if (!cret) {
ret = cpuhp_setup_state(CPUHP_PERF_X86_UNCORE_PREP,
"PERF_X86_UNCORE_PREP",
uncore_cpu_prepare, NULL);
if (ret)
goto err;
} else {
cpuhp_setup_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP,
"PERF_X86_UNCORE_PREP",
uncore_cpu_prepare, NULL);
}
first_init = 1;
cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_STARTING,
"AP_PERF_X86_UNCORE_STARTING",
uncore_cpu_starting, uncore_cpu_dying);
first_init = 0;
cpuhp_setup_state(CPUHP_AP_PERF_X86_UNCORE_ONLINE,
"AP_PERF_X86_UNCORE_ONLINE",
uncore_event_cpu_online, uncore_event_cpu_offline);
return 0;
err:
@ -1452,17 +1410,16 @@ static int __init intel_uncore_init(void)
on_each_cpu_mask(&uncore_cpu_mask, uncore_exit_boxes, NULL, 1);
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
cpu_notifier_register_done();
return ret;
}
module_init(intel_uncore_init);
static void __exit intel_uncore_exit(void)
{
cpu_notifier_register_begin();
__unregister_cpu_notifier(&uncore_cpu_nb);
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_ONLINE);
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_X86_UNCORE_STARTING);
cpuhp_remove_state_nocalls(CPUHP_PERF_X86_UNCORE_PREP);
uncore_types_exit(uncore_msr_uncores);
uncore_pci_exit();
cpu_notifier_register_done();
}
module_exit(intel_uncore_exit);

View File

@ -215,26 +215,18 @@ void apbt_setup_secondary_clock(void)
* cpu timers during the offline process due to the ordering of notification.
* the extra interrupt is harmless.
*/
static int apbt_cpuhp_notify(struct notifier_block *n,
unsigned long action, void *hcpu)
static int apbt_cpu_dead(unsigned int cpu)
{
unsigned long cpu = (unsigned long)hcpu;
struct apbt_dev *adev = &per_cpu(cpu_apbt_dev, cpu);
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DEAD:
dw_apb_clockevent_pause(adev->timer);
if (system_state == SYSTEM_RUNNING) {
pr_debug("skipping APBT CPU %lu offline\n", cpu);
} else {
pr_debug("APBT clockevent for cpu %lu offline\n", cpu);
dw_apb_clockevent_stop(adev->timer);
}
break;
default:
pr_debug("APBT notified %lu, no action\n", action);
dw_apb_clockevent_pause(adev->timer);
if (system_state == SYSTEM_RUNNING) {
pr_debug("skipping APBT CPU %u offline\n", cpu);
} else {
pr_debug("APBT clockevent for cpu %u offline\n", cpu);
dw_apb_clockevent_stop(adev->timer);
}
return NOTIFY_OK;
return 0;
}
static __init int apbt_late_init(void)
@ -242,9 +234,8 @@ static __init int apbt_late_init(void)
if (intel_mid_timer_options == INTEL_MID_TIMER_LAPIC_APBT ||
!apb_timer_block_enabled)
return 0;
/* This notifier should be called after workqueue is ready */
hotcpu_notifier(apbt_cpuhp_notify, -20);
return 0;
return cpuhp_setup_state(CPUHP_X86_APB_DEAD, "X86_APB_DEAD", NULL,
apbt_cpu_dead);
}
fs_initcall(apbt_late_init);
#else

View File

@ -152,68 +152,48 @@ static void init_x2apic_ldr(void)
}
}
/*
* At CPU state changes, update the x2apic cluster sibling info.
*/
static int
update_clusterinfo(struct notifier_block *nfb, unsigned long action, void *hcpu)
/*
* At CPU state changes, update the x2apic cluster sibling info.
*/
int x2apic_prepare_cpu(unsigned int cpu)
{
unsigned int this_cpu = (unsigned long)hcpu;
unsigned int cpu;
int err = 0;
if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL))
return -ENOMEM;
switch (action) {
case CPU_UP_PREPARE:
if (!zalloc_cpumask_var(&per_cpu(cpus_in_cluster, this_cpu),
GFP_KERNEL)) {
err = -ENOMEM;
} else if (!zalloc_cpumask_var(&per_cpu(ipi_mask, this_cpu),
GFP_KERNEL)) {
free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
err = -ENOMEM;
}
break;
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
for_each_online_cpu(cpu) {
if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
continue;
cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
}
free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
free_cpumask_var(per_cpu(ipi_mask, this_cpu));
break;
if (!zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL)) {
free_cpumask_var(per_cpu(cpus_in_cluster, cpu));
return -ENOMEM;
}
return notifier_from_errno(err);
return 0;
}
static struct notifier_block x2apic_cpu_notifier = {
.notifier_call = update_clusterinfo,
};
static int x2apic_init_cpu_notifier(void)
int x2apic_dead_cpu(unsigned int this_cpu)
{
int cpu = smp_processor_id();
int cpu;
zalloc_cpumask_var(&per_cpu(cpus_in_cluster, cpu), GFP_KERNEL);
zalloc_cpumask_var(&per_cpu(ipi_mask, cpu), GFP_KERNEL);
BUG_ON(!per_cpu(cpus_in_cluster, cpu) || !per_cpu(ipi_mask, cpu));
cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu));
register_hotcpu_notifier(&x2apic_cpu_notifier);
return 1;
for_each_online_cpu(cpu) {
if (x2apic_cluster(this_cpu) != x2apic_cluster(cpu))
continue;
cpumask_clear_cpu(this_cpu, per_cpu(cpus_in_cluster, cpu));
cpumask_clear_cpu(cpu, per_cpu(cpus_in_cluster, this_cpu));
}
free_cpumask_var(per_cpu(cpus_in_cluster, this_cpu));
free_cpumask_var(per_cpu(ipi_mask, this_cpu));
return 0;
}
static int x2apic_cluster_probe(void)
{
if (x2apic_mode)
return x2apic_init_cpu_notifier();
else
int cpu = smp_processor_id();
if (!x2apic_mode)
return 0;
cpumask_set_cpu(cpu, per_cpu(cpus_in_cluster, cpu));
cpuhp_setup_state(CPUHP_X2APIC_PREPARE, "X2APIC_PREPARE",
x2apic_prepare_cpu, x2apic_dead_cpu);
return 1;
}
static const struct cpumask *x2apic_cluster_target_cpus(void)

View File

@ -710,31 +710,29 @@ static void hpet_work(struct work_struct *w)
complete(&hpet_work->complete);
}
static int hpet_cpuhp_notify(struct notifier_block *n,
unsigned long action, void *hcpu)
static int hpet_cpuhp_online(unsigned int cpu)
{
unsigned long cpu = (unsigned long)hcpu;
struct hpet_work_struct work;
INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work);
init_completion(&work.complete);
/* FIXME: add schedule_work_on() */
schedule_delayed_work_on(cpu, &work.work, 0);
wait_for_completion(&work.complete);
destroy_delayed_work_on_stack(&work.work);
return 0;
}
static int hpet_cpuhp_dead(unsigned int cpu)
{
struct hpet_dev *hdev = per_cpu(cpu_hpet_dev, cpu);
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_ONLINE:
INIT_DELAYED_WORK_ONSTACK(&work.work, hpet_work);
init_completion(&work.complete);
/* FIXME: add schedule_work_on() */
schedule_delayed_work_on(cpu, &work.work, 0);
wait_for_completion(&work.complete);
destroy_delayed_work_on_stack(&work.work);
break;
case CPU_DEAD:
if (hdev) {
free_irq(hdev->irq, hdev);
hdev->flags &= ~HPET_DEV_USED;
per_cpu(cpu_hpet_dev, cpu) = NULL;
}
break;
}
return NOTIFY_OK;
if (!hdev)
return 0;
free_irq(hdev->irq, hdev);
hdev->flags &= ~HPET_DEV_USED;
per_cpu(cpu_hpet_dev, cpu) = NULL;
return 0;
}
#else
@ -750,11 +748,8 @@ static void hpet_reserve_msi_timers(struct hpet_data *hd)
}
#endif
static int hpet_cpuhp_notify(struct notifier_block *n,
unsigned long action, void *hcpu)
{
return NOTIFY_OK;
}
#define hpet_cpuhp_online NULL
#define hpet_cpuhp_dead NULL
#endif
@ -931,7 +926,7 @@ int __init hpet_enable(void)
*/
static __init int hpet_late_init(void)
{
int cpu;
int ret;
if (boot_hpet_disable)
return -ENODEV;
@ -961,16 +956,20 @@ static __init int hpet_late_init(void)
if (boot_cpu_has(X86_FEATURE_ARAT))
return 0;
cpu_notifier_register_begin();
for_each_online_cpu(cpu) {
hpet_cpuhp_notify(NULL, CPU_ONLINE, (void *)(long)cpu);
}
/* This notifier should be called after workqueue is ready */
__hotcpu_notifier(hpet_cpuhp_notify, -20);
cpu_notifier_register_done();
ret = cpuhp_setup_state(CPUHP_AP_X86_HPET_ONLINE, "AP_X86_HPET_ONLINE",
hpet_cpuhp_online, NULL);
if (ret)
return ret;
ret = cpuhp_setup_state(CPUHP_X86_HPET_DEAD, "X86_HPET_DEAD", NULL,
hpet_cpuhp_dead);
if (ret)
goto err_cpuhp;
return 0;
err_cpuhp:
cpuhp_remove_state(CPUHP_AP_X86_HPET_ONLINE);
return ret;
}
fs_initcall(hpet_late_init);

View File

@ -323,25 +323,16 @@ static int tboot_wait_for_aps(int num_aps)
return !(atomic_read((atomic_t *)&tboot->num_in_wfs) == num_aps);
}
static int tboot_cpu_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
static int tboot_dying_cpu(unsigned int cpu)
{
switch (action) {
case CPU_DYING:
atomic_inc(&ap_wfs_count);
if (num_online_cpus() == 1)
if (tboot_wait_for_aps(atomic_read(&ap_wfs_count)))
return NOTIFY_BAD;
break;
atomic_inc(&ap_wfs_count);
if (num_online_cpus() == 1) {
if (tboot_wait_for_aps(atomic_read(&ap_wfs_count)))
return -EBUSY;
}
return NOTIFY_OK;
return 0;
}
static struct notifier_block tboot_cpu_notifier =
{
.notifier_call = tboot_cpu_callback,
};
#ifdef CONFIG_DEBUG_FS
#define TBOOT_LOG_UUID { 0x26, 0x25, 0x19, 0xc0, 0x30, 0x6b, 0xb4, 0x4d, \
@ -417,8 +408,8 @@ static __init int tboot_late_init(void)
tboot_create_trampoline();
atomic_set(&ap_wfs_count, 0);
register_hotcpu_notifier(&tboot_cpu_notifier);
cpuhp_setup_state(CPUHP_AP_X86_TBOOT_DYING, "AP_X86_TBOOT_DYING", NULL,
tboot_dying_cpu);
#ifdef CONFIG_DEBUG_FS
debugfs_create_file("tboot_log", S_IRUSR,
arch_debugfs_dir, NULL, &tboot_log_fops);

View File

@ -5552,9 +5552,10 @@ int kvm_fast_pio_out(struct kvm_vcpu *vcpu, int size, unsigned short port)
}
EXPORT_SYMBOL_GPL(kvm_fast_pio_out);
static void tsc_bad(void *info)
static int kvmclock_cpu_down_prep(unsigned int cpu)
{
__this_cpu_write(cpu_tsc_khz, 0);
return 0;
}
static void tsc_khz_changed(void *data)
@ -5659,35 +5660,18 @@ static struct notifier_block kvmclock_cpufreq_notifier_block = {
.notifier_call = kvmclock_cpufreq_notifier
};
static int kvmclock_cpu_notifier(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int kvmclock_cpu_online(unsigned int cpu)
{
unsigned int cpu = (unsigned long)hcpu;
switch (action) {
case CPU_ONLINE:
case CPU_DOWN_FAILED:
smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
break;
case CPU_DOWN_PREPARE:
smp_call_function_single(cpu, tsc_bad, NULL, 1);
break;
}
return NOTIFY_OK;
tsc_khz_changed(NULL);
return 0;
}
static struct notifier_block kvmclock_cpu_notifier_block = {
.notifier_call = kvmclock_cpu_notifier,
.priority = -INT_MAX
};
static void kvm_timer_init(void)
{
int cpu;
max_tsc_khz = tsc_khz;
cpu_notifier_register_begin();
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC)) {
#ifdef CONFIG_CPU_FREQ
struct cpufreq_policy policy;
@ -5702,12 +5686,9 @@ static void kvm_timer_init(void)
CPUFREQ_TRANSITION_NOTIFIER);
}
pr_debug("kvm: max_tsc_khz = %ld\n", max_tsc_khz);
for_each_online_cpu(cpu)
smp_call_function_single(cpu, tsc_khz_changed, NULL, 1);
__register_hotcpu_notifier(&kvmclock_cpu_notifier_block);
cpu_notifier_register_done();
cpuhp_setup_state(CPUHP_AP_X86_KVM_CLK_ONLINE, "AP_X86_KVM_CLK_ONLINE",
kvmclock_cpu_online, kvmclock_cpu_down_prep);
}
static DEFINE_PER_CPU(struct kvm_vcpu *, current_vcpu);
@ -5896,7 +5877,7 @@ void kvm_arch_exit(void)
if (!boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
cpufreq_unregister_notifier(&kvmclock_cpufreq_notifier_block,
CPUFREQ_TRANSITION_NOTIFIER);
unregister_hotcpu_notifier(&kvmclock_cpu_notifier_block);
cpuhp_remove_state_nocalls(CPUHP_AP_X86_KVM_CLK_ONLINE);
#ifdef CONFIG_X86_64
pvclock_gtod_unregister_notifier(&pvclock_gtod_notifier);
#endif

View File

@ -404,7 +404,7 @@ static struct pmu xtensa_pmu = {
.read = xtensa_pmu_read,
};
static void xtensa_pmu_setup(void)
static int xtensa_pmu_setup(int cpu)
{
unsigned i;
@ -413,21 +413,7 @@ static void xtensa_pmu_setup(void)
set_er(0, XTENSA_PMU_PMCTRL(i));
set_er(get_er(XTENSA_PMU_PMSTAT(i)), XTENSA_PMU_PMSTAT(i));
}
}
static int xtensa_pmu_notifier(struct notifier_block *self,
unsigned long action, void *data)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
xtensa_pmu_setup();
break;
default:
break;
}
return NOTIFY_OK;
return 0;
}
static int __init xtensa_pmu_init(void)
@ -435,7 +421,13 @@ static int __init xtensa_pmu_init(void)
int ret;
int irq = irq_create_mapping(NULL, XCHAL_PROFILING_INTERRUPT);
perf_cpu_notifier(xtensa_pmu_notifier);
ret = cpuhp_setup_state(CPUHP_AP_PERF_XTENSA_STARTING,
"AP_PERF_XTENSA_STARTING", xtensa_pmu_setup,
NULL);
if (ret) {
pr_err("xtensa_pmu: failed to register CPU-hotplug.\n");
return ret;
}
#if XTENSA_FAKE_NMI
enable_irq(irq);
#else

View File

@ -118,12 +118,13 @@ static int acpi_cpu_soft_notify(struct notifier_block *nfb,
struct acpi_device *device;
action &= ~CPU_TASKS_FROZEN;
/*
* CPU_STARTING and CPU_DYING must not sleep. Return here since
* acpi_bus_get_device() may sleep.
*/
if (action == CPU_STARTING || action == CPU_DYING)
switch (action) {
case CPU_ONLINE:
case CPU_DEAD:
break;
default:
return NOTIFY_DONE;
}
if (!pr || acpi_bus_get_device(pr->handle, &device))
return NOTIFY_DONE;

View File

@ -144,12 +144,15 @@ struct cci_pmu {
int num_cntrs;
atomic_t active_events;
struct mutex reserve_mutex;
struct notifier_block cpu_nb;
struct list_head entry;
cpumask_t cpus;
};
#define to_cci_pmu(c) (container_of(c, struct cci_pmu, pmu))
static DEFINE_MUTEX(cci_pmu_mutex);
static LIST_HEAD(cci_pmu_list);
enum cci_models {
#ifdef CONFIG_ARM_CCI400_PMU
CCI400_R0,
@ -1503,31 +1506,26 @@ static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
return perf_pmu_register(&cci_pmu->pmu, name, -1);
}
static int cci_pmu_cpu_notifier(struct notifier_block *self,
unsigned long action, void *hcpu)
static int cci_pmu_offline_cpu(unsigned int cpu)
{
struct cci_pmu *cci_pmu = container_of(self,
struct cci_pmu, cpu_nb);
unsigned int cpu = (long)hcpu;
struct cci_pmu *cci_pmu;
unsigned int target;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
mutex_lock(&cci_pmu_mutex);
list_for_each_entry(cci_pmu, &cci_pmu_list, entry) {
if (!cpumask_test_and_clear_cpu(cpu, &cci_pmu->cpus))
break;
continue;
target = cpumask_any_but(cpu_online_mask, cpu);
if (target >= nr_cpu_ids) // UP, last CPU
break;
if (target >= nr_cpu_ids)
continue;
/*
* TODO: migrate context once core races on event->ctx have
* been fixed.
*/
cpumask_set_cpu(target, &cci_pmu->cpus);
default:
break;
}
return NOTIFY_OK;
mutex_unlock(&cci_pmu_mutex);
return 0;
}
static struct cci_pmu_model cci_pmu_models[] = {
@ -1766,24 +1764,13 @@ static int cci_pmu_probe(struct platform_device *pdev)
atomic_set(&cci_pmu->active_events, 0);
cpumask_set_cpu(smp_processor_id(), &cci_pmu->cpus);
cci_pmu->cpu_nb = (struct notifier_block) {
.notifier_call = cci_pmu_cpu_notifier,
/*
* to migrate uncore events, our notifier should be executed
* before perf core's notifier.
*/
.priority = CPU_PRI_PERF + 1,
};
ret = register_cpu_notifier(&cci_pmu->cpu_nb);
ret = cci_pmu_init(cci_pmu, pdev);
if (ret)
return ret;
ret = cci_pmu_init(cci_pmu, pdev);
if (ret) {
unregister_cpu_notifier(&cci_pmu->cpu_nb);
return ret;
}
mutex_lock(&cci_pmu_mutex);
list_add(&cci_pmu->entry, &cci_pmu_list);
mutex_unlock(&cci_pmu_mutex);
pr_info("ARM %s PMU driver probed", cci_pmu->model->name);
return 0;
@ -1817,6 +1804,12 @@ static int __init cci_platform_init(void)
{
int ret;
ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_CCI_ONLINE,
"AP_PERF_ARM_CCI_ONLINE", NULL,
cci_pmu_offline_cpu);
if (ret)
return ret;
ret = platform_driver_register(&cci_pmu_driver);
if (ret)
return ret;

View File

@ -167,7 +167,7 @@ struct arm_ccn_dt {
struct hrtimer hrtimer;
cpumask_t cpu;
struct notifier_block cpu_nb;
struct list_head entry;
struct pmu pmu;
};
@ -189,6 +189,8 @@ struct arm_ccn {
struct arm_ccn_dt dt;
};
static DEFINE_MUTEX(arm_ccn_mutex);
static LIST_HEAD(arm_ccn_list);
static int arm_ccn_node_to_xp(int node)
{
@ -1171,30 +1173,27 @@ static enum hrtimer_restart arm_ccn_pmu_timer_handler(struct hrtimer *hrtimer)
}
static int arm_ccn_pmu_cpu_notifier(struct notifier_block *nb,
unsigned long action, void *hcpu)
static int arm_ccn_pmu_offline_cpu(unsigned int cpu)
{
struct arm_ccn_dt *dt = container_of(nb, struct arm_ccn_dt, cpu_nb);
struct arm_ccn *ccn = container_of(dt, struct arm_ccn, dt);
unsigned int cpu = (long)hcpu; /* for (long) see kernel/cpu.c */
struct arm_ccn_dt *dt;
unsigned int target;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
mutex_lock(&arm_ccn_mutex);
list_for_each_entry(dt, &arm_ccn_list, entry) {
struct arm_ccn *ccn = container_of(dt, struct arm_ccn, dt);
if (!cpumask_test_and_clear_cpu(cpu, &dt->cpu))
break;
continue;
target = cpumask_any_but(cpu_online_mask, cpu);
if (target >= nr_cpu_ids)
break;
continue;
perf_pmu_migrate_context(&dt->pmu, cpu, target);
cpumask_set_cpu(target, &dt->cpu);
if (ccn->irq)
WARN_ON(irq_set_affinity_hint(ccn->irq, &dt->cpu) != 0);
default:
break;
}
return NOTIFY_OK;
mutex_unlock(&arm_ccn_mutex);
return 0;
}
@ -1266,16 +1265,6 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
/* Pick one CPU which we will use to collect data from CCN... */
cpumask_set_cpu(smp_processor_id(), &ccn->dt.cpu);
/*
* ... and change the selection when it goes offline. Priority is
* picked to have a chance to migrate events before perf is notified.
*/
ccn->dt.cpu_nb.notifier_call = arm_ccn_pmu_cpu_notifier;
ccn->dt.cpu_nb.priority = CPU_PRI_PERF + 1,
err = register_cpu_notifier(&ccn->dt.cpu_nb);
if (err)
goto error_cpu_notifier;
/* Also make sure that the overflow interrupt is handled by this CPU */
if (ccn->irq) {
err = irq_set_affinity_hint(ccn->irq, &ccn->dt.cpu);
@ -1289,12 +1278,13 @@ static int arm_ccn_pmu_init(struct arm_ccn *ccn)
if (err)
goto error_pmu_register;
mutex_lock(&arm_ccn_mutex);
list_add(&ccn->dt.entry, &arm_ccn_list);
mutex_unlock(&arm_ccn_mutex);
return 0;
error_pmu_register:
error_set_affinity:
unregister_cpu_notifier(&ccn->dt.cpu_nb);
error_cpu_notifier:
ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
for (i = 0; i < ccn->num_xps; i++)
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
@ -1306,9 +1296,12 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
{
int i;
mutex_lock(&arm_ccn_mutex);
list_del(&ccn->dt.entry);
mutex_unlock(&arm_ccn_mutex);
if (ccn->irq)
irq_set_affinity_hint(ccn->irq, NULL);
unregister_cpu_notifier(&ccn->dt.cpu_nb);
for (i = 0; i < ccn->num_xps; i++)
writel(0, ccn->xp[i].base + CCN_XP_DT_CONTROL);
writel(0, ccn->dt.base + CCN_DT_PMCR);
@ -1316,7 +1309,6 @@ static void arm_ccn_pmu_cleanup(struct arm_ccn *ccn)
ida_simple_remove(&arm_ccn_pmu_ida, ccn->dt.id);
}
static int arm_ccn_for_each_valid_region(struct arm_ccn *ccn,
int (*callback)(struct arm_ccn *ccn, int region,
void __iomem *base, u32 type, u32 id))
@ -1533,7 +1525,13 @@ static struct platform_driver arm_ccn_driver = {
static int __init arm_ccn_init(void)
{
int i;
int i, ret;
ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE,
"AP_PERF_ARM_CCN_ONLINE", NULL,
arm_ccn_pmu_offline_cpu);
if (ret)
return ret;
for (i = 0; i < ARRAY_SIZE(arm_ccn_pmu_events); i++)
arm_ccn_pmu_events_attrs[i] = &arm_ccn_pmu_events[i].attr.attr;
@ -1543,6 +1541,7 @@ static int __init arm_ccn_init(void)
static void __exit arm_ccn_exit(void)
{
cpuhp_remove_state_nocalls(CPUHP_AP_PERF_ARM_CCN_ONLINE);
platform_driver_unregister(&arm_ccn_driver);
}

View File

@ -370,8 +370,10 @@ static bool arch_timer_has_nonsecure_ppi(void)
arch_timer_ppi[PHYS_NONSECURE_PPI]);
}
static int arch_timer_setup(struct clock_event_device *clk)
static int arch_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
__arch_timer_setup(ARCH_CP15_TIMER, clk);
enable_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], 0);
@ -527,29 +529,14 @@ static void arch_timer_stop(struct clock_event_device *clk)
clk->set_state_shutdown(clk);
}
static int arch_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
static int arch_timer_dying_cpu(unsigned int cpu)
{
/*
* Grab cpu pointer in each case to avoid spurious
* preemptible warnings
*/
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
arch_timer_setup(this_cpu_ptr(arch_timer_evt));
break;
case CPU_DYING:
arch_timer_stop(this_cpu_ptr(arch_timer_evt));
break;
}
struct clock_event_device *clk = this_cpu_ptr(arch_timer_evt);
return NOTIFY_OK;
arch_timer_stop(clk);
return 0;
}
static struct notifier_block arch_timer_cpu_nb = {
.notifier_call = arch_timer_cpu_notify,
};
#ifdef CONFIG_CPU_PM
static unsigned int saved_cntkctl;
static int arch_timer_cpu_pm_notify(struct notifier_block *self,
@ -570,11 +557,21 @@ static int __init arch_timer_cpu_pm_init(void)
{
return cpu_pm_register_notifier(&arch_timer_cpu_pm_notifier);
}
static void __init arch_timer_cpu_pm_deinit(void)
{
WARN_ON(cpu_pm_unregister_notifier(&arch_timer_cpu_pm_notifier));
}
#else
static int __init arch_timer_cpu_pm_init(void)
{
return 0;
}
static void __init arch_timer_cpu_pm_deinit(void)
{
}
#endif
static int __init arch_timer_register(void)
@ -621,22 +618,23 @@ static int __init arch_timer_register(void)
goto out_free;
}
err = register_cpu_notifier(&arch_timer_cpu_nb);
if (err)
goto out_free_irq;
err = arch_timer_cpu_pm_init();
if (err)
goto out_unreg_notify;
/* Immediately configure the timer on the boot CPU */
arch_timer_setup(this_cpu_ptr(arch_timer_evt));
/* Register and immediately configure the timer on the boot CPU */
err = cpuhp_setup_state(CPUHP_AP_ARM_ARCH_TIMER_STARTING,
"AP_ARM_ARCH_TIMER_STARTING",
arch_timer_starting_cpu, arch_timer_dying_cpu);
if (err)
goto out_unreg_cpupm;
return 0;
out_unreg_cpupm:
arch_timer_cpu_pm_deinit();
out_unreg_notify:
unregister_cpu_notifier(&arch_timer_cpu_nb);
out_free_irq:
free_percpu_irq(arch_timer_ppi[arch_timer_uses_ppi], arch_timer_evt);
if (arch_timer_has_nonsecure_ppi())
free_percpu_irq(arch_timer_ppi[PHYS_NONSECURE_PPI],

View File

@ -165,9 +165,9 @@ static irqreturn_t gt_clockevent_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int gt_clockevents_init(struct clock_event_device *clk)
static int gt_starting_cpu(unsigned int cpu)
{
int cpu = smp_processor_id();
struct clock_event_device *clk = this_cpu_ptr(gt_evt);
clk->name = "arm_global_timer";
clk->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
@ -186,10 +186,13 @@ static int gt_clockevents_init(struct clock_event_device *clk)
return 0;
}
static void gt_clockevents_stop(struct clock_event_device *clk)
static int gt_dying_cpu(unsigned int cpu)
{
struct clock_event_device *clk = this_cpu_ptr(gt_evt);
gt_clockevent_shutdown(clk);
disable_percpu_irq(clk->irq);
return 0;
}
static cycle_t gt_clocksource_read(struct clocksource *cs)
@ -252,24 +255,6 @@ static int __init gt_clocksource_init(void)
return clocksource_register_hz(&gt_clocksource, gt_clk_rate);
}
static int gt_cpu_notify(struct notifier_block *self, unsigned long action,
void *hcpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
gt_clockevents_init(this_cpu_ptr(gt_evt));
break;
case CPU_DYING:
gt_clockevents_stop(this_cpu_ptr(gt_evt));
break;
}
return NOTIFY_OK;
}
static struct notifier_block gt_cpu_nb = {
.notifier_call = gt_cpu_notify,
};
static int __init global_timer_of_register(struct device_node *np)
{
struct clk *gt_clk;
@ -325,18 +310,14 @@ static int __init global_timer_of_register(struct device_node *np)
goto out_free;
}
err = register_cpu_notifier(&gt_cpu_nb);
if (err) {
pr_warn("global-timer: unable to register cpu notifier.\n");
goto out_irq;
}
/* Immediately configure the timer on the boot CPU */
/* Register and immediately configure the timer on the boot CPU */
err = gt_clocksource_init();
if (err)
goto out_irq;
err = gt_clockevents_init(this_cpu_ptr(gt_evt));
err = cpuhp_setup_state(CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
"AP_ARM_GLOBAL_TIMER_STARTING",
gt_starting_cpu, gt_dying_cpu);
if (err)
goto out_irq;

View File

@ -16,10 +16,9 @@
static DEFINE_PER_CPU(struct clock_event_device, dummy_timer_evt);
static void dummy_timer_setup(void)
static int dummy_timer_starting_cpu(unsigned int cpu)
{
int cpu = smp_processor_id();
struct clock_event_device *evt = raw_cpu_ptr(&dummy_timer_evt);
struct clock_event_device *evt = per_cpu_ptr(&dummy_timer_evt, cpu);
evt->name = "dummy_timer";
evt->features = CLOCK_EVT_FEAT_PERIODIC |
@ -29,36 +28,13 @@ static void dummy_timer_setup(void)
evt->cpumask = cpumask_of(cpu);
clockevents_register_device(evt);
return 0;
}
static int dummy_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
if ((action & ~CPU_TASKS_FROZEN) == CPU_STARTING)
dummy_timer_setup();
return NOTIFY_OK;
}
static struct notifier_block dummy_timer_cpu_nb = {
.notifier_call = dummy_timer_cpu_notify,
};
static int __init dummy_timer_register(void)
{
int err = 0;
cpu_notifier_register_begin();
err = __register_cpu_notifier(&dummy_timer_cpu_nb);
if (err)
goto out;
/* We won't get a call on the boot CPU, so register immediately */
if (num_possible_cpus() > 1)
dummy_timer_setup();
out:
cpu_notifier_register_done();
return err;
return cpuhp_setup_state(CPUHP_AP_DUMMY_TIMER_STARTING,
"AP_DUMMY_TIMER_STARTING",
dummy_timer_starting_cpu, NULL);
}
early_initcall(dummy_timer_register);

View File

@ -443,10 +443,11 @@ static irqreturn_t exynos4_mct_tick_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
static int exynos4_mct_starting_cpu(unsigned int cpu)
{
struct mct_clock_event_device *mevt =
per_cpu_ptr(&percpu_mct_tick, cpu);
struct clock_event_device *evt = &mevt->evt;
unsigned int cpu = smp_processor_id();
mevt->base = EXYNOS4_MCT_L_BASE(cpu);
snprintf(mevt->name, sizeof(mevt->name), "mct_tick%d", cpu);
@ -480,8 +481,10 @@ static int exynos4_local_timer_setup(struct mct_clock_event_device *mevt)
return 0;
}
static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt)
static int exynos4_mct_dying_cpu(unsigned int cpu)
{
struct mct_clock_event_device *mevt =
per_cpu_ptr(&percpu_mct_tick, cpu);
struct clock_event_device *evt = &mevt->evt;
evt->set_state_shutdown(evt);
@ -491,39 +494,12 @@ static void exynos4_local_timer_stop(struct mct_clock_event_device *mevt)
} else {
disable_percpu_irq(mct_irqs[MCT_L0_IRQ]);
}
return 0;
}
static int exynos4_mct_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
struct mct_clock_event_device *mevt;
/*
* Grab cpu pointer in each case to avoid spurious
* preemptible warnings
*/
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
mevt = this_cpu_ptr(&percpu_mct_tick);
exynos4_local_timer_setup(mevt);
break;
case CPU_DYING:
mevt = this_cpu_ptr(&percpu_mct_tick);
exynos4_local_timer_stop(mevt);
break;
}
return NOTIFY_OK;
}
static struct notifier_block exynos4_mct_cpu_nb = {
.notifier_call = exynos4_mct_cpu_notify,
};
static int __init exynos4_timer_resources(struct device_node *np, void __iomem *base)
{
int err, cpu;
struct mct_clock_event_device *mevt = this_cpu_ptr(&percpu_mct_tick);
struct clk *mct_clk, *tick_clk;
tick_clk = np ? of_clk_get_by_name(np, "fin_pll") :
@ -570,12 +546,14 @@ static int __init exynos4_timer_resources(struct device_node *np, void __iomem *
}
}
err = register_cpu_notifier(&exynos4_mct_cpu_nb);
/* Install hotplug callbacks which configure the timer on this CPU */
err = cpuhp_setup_state(CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
"AP_EXYNOS4_MCT_TIMER_STARTING",
exynos4_mct_starting_cpu,
exynos4_mct_dying_cpu);
if (err)
goto out_irq;
/* Immediately configure the timer on the boot CPU */
exynos4_local_timer_setup(mevt);
return 0;
out_irq:

View File

@ -90,7 +90,7 @@ unsigned long long sched_clock(void)
return ticks << HARDWARE_TO_NS_SHIFT;
}
static void arch_timer_setup(unsigned int cpu)
static int arch_timer_starting_cpu(unsigned int cpu)
{
unsigned int txdivtime;
struct clock_event_device *clk = &per_cpu(local_clockevent, cpu);
@ -132,27 +132,9 @@ static void arch_timer_setup(unsigned int cpu)
val = core_reg_read(TXUCT_ID, TXTIMER_REGNUM, thread0);
__core_reg_set(TXTIMER, val);
}
return 0;
}
static int arch_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
int cpu = (long)hcpu;
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
arch_timer_setup(cpu);
break;
}
return NOTIFY_OK;
}
static struct notifier_block arch_timer_cpu_nb = {
.notifier_call = arch_timer_cpu_notify,
};
int __init metag_generic_timer_init(void)
{
/*
@ -170,11 +152,8 @@ int __init metag_generic_timer_init(void)
setup_irq(tbisig_map(TBID_SIGNUM_TRT), &metag_timer_irq);
/* Configure timer on boot CPU */
arch_timer_setup(smp_processor_id());
/* Hook cpu boot to configure other CPU's timers */
register_cpu_notifier(&arch_timer_cpu_nb);
return 0;
/* Hook cpu boot to configure the CPU's timers */
return cpuhp_setup_state(CPUHP_AP_METAG_TIMER_STARTING,
"AP_METAG_TIMER_STARTING",
arch_timer_starting_cpu, NULL);
}

View File

@ -49,10 +49,9 @@ struct irqaction gic_compare_irqaction = {
.name = "timer",
};
static void gic_clockevent_cpu_init(struct clock_event_device *cd)
static void gic_clockevent_cpu_init(unsigned int cpu,
struct clock_event_device *cd)
{
unsigned int cpu = smp_processor_id();
cd->name = "MIPS GIC";
cd->features = CLOCK_EVT_FEAT_ONESHOT |
CLOCK_EVT_FEAT_C3STOP;
@ -79,19 +78,10 @@ static void gic_update_frequency(void *data)
clockevents_update_freq(this_cpu_ptr(&gic_clockevent_device), rate);
}
static int gic_cpu_notifier(struct notifier_block *nb, unsigned long action,
void *data)
static int gic_starting_cpu(unsigned int cpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device));
break;
case CPU_DYING:
gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device));
break;
}
return NOTIFY_OK;
gic_clockevent_cpu_init(cpu, this_cpu_ptr(&gic_clockevent_device));
return 0;
}
static int gic_clk_notifier(struct notifier_block *nb, unsigned long action,
@ -105,10 +95,11 @@ static int gic_clk_notifier(struct notifier_block *nb, unsigned long action,
return NOTIFY_OK;
}
static struct notifier_block gic_cpu_nb = {
.notifier_call = gic_cpu_notifier,
};
static int gic_dying_cpu(unsigned int cpu)
{
gic_clockevent_cpu_exit(this_cpu_ptr(&gic_clockevent_device));
return 0;
}
static struct notifier_block gic_clk_nb = {
.notifier_call = gic_clk_notifier,
@ -125,12 +116,9 @@ static int gic_clockevent_init(void)
if (ret < 0)
return ret;
ret = register_cpu_notifier(&gic_cpu_nb);
if (ret < 0)
pr_warn("GIC: Unable to register CPU notifier\n");
gic_clockevent_cpu_init(this_cpu_ptr(&gic_clockevent_device));
cpuhp_setup_state(CPUHP_AP_MIPS_GIC_TIMER_STARTING,
"AP_MIPS_GIC_TIMER_STARTING", gic_starting_cpu,
gic_dying_cpu);
return 0;
}

View File

@ -105,9 +105,9 @@ static struct clocksource msm_clocksource = {
static int msm_timer_irq;
static int msm_timer_has_ppi;
static int msm_local_timer_setup(struct clock_event_device *evt)
static int msm_local_timer_starting_cpu(unsigned int cpu)
{
int cpu = smp_processor_id();
struct clock_event_device *evt = per_cpu_ptr(msm_evt, cpu);
int err;
evt->irq = msm_timer_irq;
@ -135,35 +135,15 @@ static int msm_local_timer_setup(struct clock_event_device *evt)
return 0;
}
static void msm_local_timer_stop(struct clock_event_device *evt)
static int msm_local_timer_dying_cpu(unsigned int cpu)
{
struct clock_event_device *evt = per_cpu_ptr(msm_evt, cpu);
evt->set_state_shutdown(evt);
disable_percpu_irq(evt->irq);
return 0;
}
static int msm_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
/*
* Grab cpu pointer in each case to avoid spurious
* preemptible warnings
*/
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
msm_local_timer_setup(this_cpu_ptr(msm_evt));
break;
case CPU_DYING:
msm_local_timer_stop(this_cpu_ptr(msm_evt));
break;
}
return NOTIFY_OK;
}
static struct notifier_block msm_timer_cpu_nb = {
.notifier_call = msm_timer_cpu_notify,
};
static u64 notrace msm_sched_clock_read(void)
{
return msm_clocksource.read(&msm_clocksource);
@ -200,14 +180,15 @@ static int __init msm_timer_init(u32 dgt_hz, int sched_bits, int irq,
if (res) {
pr_err("request_percpu_irq failed\n");
} else {
res = register_cpu_notifier(&msm_timer_cpu_nb);
/* Install and invoke hotplug callbacks */
res = cpuhp_setup_state(CPUHP_AP_QCOM_TIMER_STARTING,
"AP_QCOM_TIMER_STARTING",
msm_local_timer_starting_cpu,
msm_local_timer_dying_cpu);
if (res) {
free_percpu_irq(irq, msm_evt);
goto err;
}
/* Immediately configure the timer on the boot CPU */
msm_local_timer_setup(raw_cpu_ptr(msm_evt));
}
err:

View File

@ -170,10 +170,10 @@ static irqreturn_t armada_370_xp_timer_interrupt(int irq, void *dev_id)
/*
* Setup the local clock events for a CPU.
*/
static int armada_370_xp_timer_setup(struct clock_event_device *evt)
static int armada_370_xp_timer_starting_cpu(unsigned int cpu)
{
struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu);
u32 clr = 0, set = 0;
int cpu = smp_processor_id();
if (timer25Mhz)
set = TIMER0_25MHZ;
@ -200,35 +200,15 @@ static int armada_370_xp_timer_setup(struct clock_event_device *evt)
return 0;
}
static void armada_370_xp_timer_stop(struct clock_event_device *evt)
static int armada_370_xp_timer_dying_cpu(unsigned int cpu)
{
struct clock_event_device *evt = per_cpu_ptr(armada_370_xp_evt, cpu);
evt->set_state_shutdown(evt);
disable_percpu_irq(evt->irq);
return 0;
}
static int armada_370_xp_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
/*
* Grab cpu pointer in each case to avoid spurious
* preemptible warnings
*/
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
break;
case CPU_DYING:
armada_370_xp_timer_stop(this_cpu_ptr(armada_370_xp_evt));
break;
}
return NOTIFY_OK;
}
static struct notifier_block armada_370_xp_timer_cpu_nb = {
.notifier_call = armada_370_xp_timer_cpu_notify,
};
static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
static int armada_370_xp_timer_suspend(void)
@ -322,8 +302,6 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
return res;
}
register_cpu_notifier(&armada_370_xp_timer_cpu_nb);
armada_370_xp_evt = alloc_percpu(struct clock_event_device);
if (!armada_370_xp_evt)
return -ENOMEM;
@ -341,9 +319,12 @@ static int __init armada_370_xp_timer_common_init(struct device_node *np)
return res;
}
res = armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
res = cpuhp_setup_state(CPUHP_AP_ARMADA_TIMER_STARTING,
"AP_ARMADA_TIMER_STARTING",
armada_370_xp_timer_starting_cpu,
armada_370_xp_timer_dying_cpu);
if (res) {
pr_err("Failed to setup timer");
pr_err("Failed to setup hotplug state and timer");
return res;
}

View File

@ -172,9 +172,9 @@ static struct irqaction sirfsoc_timer1_irq = {
.handler = sirfsoc_timer_interrupt,
};
static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
static int sirfsoc_local_timer_starting_cpu(unsigned int cpu)
{
int cpu = smp_processor_id();
struct clock_event_device *ce = per_cpu_ptr(sirfsoc_clockevent, cpu);
struct irqaction *action;
if (cpu == 0)
@ -203,50 +203,27 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
return 0;
}
static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
static int sirfsoc_local_timer_dying_cpu(unsigned int cpu)
{
int cpu = smp_processor_id();
sirfsoc_timer_count_disable(1);
if (cpu == 0)
remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
else
remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
return 0;
}
static int sirfsoc_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
/*
* Grab cpu pointer in each case to avoid spurious
* preemptible warnings
*/
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
break;
case CPU_DYING:
sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
break;
}
return NOTIFY_OK;
}
static struct notifier_block sirfsoc_cpu_nb = {
.notifier_call = sirfsoc_cpu_notify,
};
static int __init sirfsoc_clockevent_init(void)
{
sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
BUG_ON(!sirfsoc_clockevent);
BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
/* Immediately configure the timer on the boot CPU */
return sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
/* Install and invoke hotplug callbacks */
return cpuhp_setup_state(CPUHP_AP_MARCO_TIMER_STARTING,
"AP_MARCO_TIMER_STARTING",
sirfsoc_local_timer_starting_cpu,
sirfsoc_local_timer_dying_cpu);
}
/* initialize the kernel jiffy timer source */

View File

@ -51,6 +51,8 @@ module_param_named(boot_enable, boot_enable, int, S_IRUGO);
static int etm_count;
static struct etm_drvdata *etmdrvdata[NR_CPUS];
static enum cpuhp_state hp_online;
/*
* Memory mapped writes to clear os lock are not supported on some processors
* and OS lock must be unlocked before any memory mapped access on such
@ -481,8 +483,7 @@ static int etm_enable_sysfs(struct coresight_device *csdev)
/*
* Configure the ETM only if the CPU is online. If it isn't online
* hw configuration will take place when 'CPU_STARTING' is received
* in @etm_cpu_callback.
* hw configuration will take place on the local CPU during bring up.
*/
if (cpu_online(drvdata->cpu)) {
ret = smp_call_function_single(drvdata->cpu,
@ -641,47 +642,44 @@ static const struct coresight_ops etm_cs_ops = {
.source_ops = &etm_source_ops,
};
static int etm_cpu_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
static int etm_online_cpu(unsigned int cpu)
{
unsigned int cpu = (unsigned long)hcpu;
if (!etmdrvdata[cpu])
goto out;
return 0;
switch (action & (~CPU_TASKS_FROZEN)) {
case CPU_STARTING:
spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock) {
etm_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
}
if (local_read(&etmdrvdata[cpu]->mode))
etm_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
case CPU_ONLINE:
if (etmdrvdata[cpu]->boot_enable &&
!etmdrvdata[cpu]->sticky_enable)
coresight_enable(etmdrvdata[cpu]->csdev);
break;
case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock);
if (local_read(&etmdrvdata[cpu]->mode))
etm_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
}
out:
return NOTIFY_OK;
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
coresight_enable(etmdrvdata[cpu]->csdev);
return 0;
}
static struct notifier_block etm_cpu_notifier = {
.notifier_call = etm_cpu_callback,
};
static int etm_starting_cpu(unsigned int cpu)
{
if (!etmdrvdata[cpu])
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock) {
etm_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
}
if (local_read(&etmdrvdata[cpu]->mode))
etm_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
static int etm_dying_cpu(unsigned int cpu)
{
if (!etmdrvdata[cpu])
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
if (local_read(&etmdrvdata[cpu]->mode))
etm_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
static bool etm_arch_supported(u8 arch)
{
@ -806,9 +804,17 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
etm_init_arch_data, drvdata, 1))
dev_err(dev, "ETM arch init failed\n");
if (!etm_count++)
register_hotcpu_notifier(&etm_cpu_notifier);
if (!etm_count++) {
cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING,
"AP_ARM_CORESIGHT_STARTING",
etm_starting_cpu, etm_dying_cpu);
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"AP_ARM_CORESIGHT_ONLINE",
etm_online_cpu, NULL);
if (ret < 0)
goto err_arch_supported;
hp_online = ret;
}
put_online_cpus();
if (etm_arch_supported(drvdata->arch) == false) {
@ -839,7 +845,6 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
pm_runtime_put(&adev->dev);
dev_info(dev, "%s initialized\n", (char *)id->data);
if (boot_enable) {
coresight_enable(drvdata->csdev);
drvdata->boot_enable = true;
@ -848,8 +853,11 @@ static int etm_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
err_arch_supported:
if (--etm_count == 0)
unregister_hotcpu_notifier(&etm_cpu_notifier);
if (--etm_count == 0) {
cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT_STARTING);
if (hp_online)
cpuhp_remove_state_nocalls(hp_online);
}
return ret;
}

View File

@ -48,6 +48,8 @@ static int etm4_count;
static struct etmv4_drvdata *etmdrvdata[NR_CPUS];
static void etm4_set_default(struct etmv4_config *config);
static enum cpuhp_state hp_online;
static void etm4_os_unlock(struct etmv4_drvdata *drvdata)
{
/* Writing any value to ETMOSLAR unlocks the trace registers */
@ -673,47 +675,44 @@ void etm4_config_trace_mode(struct etmv4_config *config)
config->addr_acc[ETM_DEFAULT_ADDR_COMP + 1] = addr_acc;
}
static int etm4_cpu_callback(struct notifier_block *nfb, unsigned long action,
void *hcpu)
static int etm4_online_cpu(unsigned int cpu)
{
unsigned int cpu = (unsigned long)hcpu;
if (!etmdrvdata[cpu])
goto out;
return 0;
switch (action & (~CPU_TASKS_FROZEN)) {
case CPU_STARTING:
spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock) {
etm4_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
}
if (local_read(&etmdrvdata[cpu]->mode))
etm4_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
case CPU_ONLINE:
if (etmdrvdata[cpu]->boot_enable &&
!etmdrvdata[cpu]->sticky_enable)
coresight_enable(etmdrvdata[cpu]->csdev);
break;
case CPU_DYING:
spin_lock(&etmdrvdata[cpu]->spinlock);
if (local_read(&etmdrvdata[cpu]->mode))
etm4_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
break;
}
out:
return NOTIFY_OK;
if (etmdrvdata[cpu]->boot_enable && !etmdrvdata[cpu]->sticky_enable)
coresight_enable(etmdrvdata[cpu]->csdev);
return 0;
}
static struct notifier_block etm4_cpu_notifier = {
.notifier_call = etm4_cpu_callback,
};
static int etm4_starting_cpu(unsigned int cpu)
{
if (!etmdrvdata[cpu])
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
if (!etmdrvdata[cpu]->os_unlock) {
etm4_os_unlock(etmdrvdata[cpu]);
etmdrvdata[cpu]->os_unlock = true;
}
if (local_read(&etmdrvdata[cpu]->mode))
etm4_enable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
static int etm4_dying_cpu(unsigned int cpu)
{
if (!etmdrvdata[cpu])
return 0;
spin_lock(&etmdrvdata[cpu]->spinlock);
if (local_read(&etmdrvdata[cpu]->mode))
etm4_disable_hw(etmdrvdata[cpu]);
spin_unlock(&etmdrvdata[cpu]->spinlock);
return 0;
}
static void etm4_init_trace_id(struct etmv4_drvdata *drvdata)
{
@ -767,8 +766,17 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
etm4_init_arch_data, drvdata, 1))
dev_err(dev, "ETM arch init failed\n");
if (!etm4_count++)
register_hotcpu_notifier(&etm4_cpu_notifier);
if (!etm4_count++) {
cpuhp_setup_state_nocalls(CPUHP_AP_ARM_CORESIGHT4_STARTING,
"AP_ARM_CORESIGHT4_STARTING",
etm4_starting_cpu, etm4_dying_cpu);
ret = cpuhp_setup_state_nocalls(CPUHP_AP_ONLINE_DYN,
"AP_ARM_CORESIGHT4_ONLINE",
etm4_online_cpu, NULL);
if (ret < 0)
goto err_arch_supported;
hp_online = ret;
}
put_online_cpus();
@ -809,8 +817,11 @@ static int etm4_probe(struct amba_device *adev, const struct amba_id *id)
return 0;
err_arch_supported:
if (--etm4_count == 0)
unregister_hotcpu_notifier(&etm4_cpu_notifier);
if (--etm4_count == 0) {
cpuhp_remove_state_nocalls(CPUHP_AP_ARM_CORESIGHT4_STARTING);
if (hp_online)
cpuhp_remove_state_nocalls(hp_online);
}
return ret;
}

View File

@ -345,38 +345,20 @@ static void armada_mpic_send_doorbell(const struct cpumask *mask,
ARMADA_370_XP_SW_TRIG_INT_OFFS);
}
static int armada_xp_mpic_secondary_init(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int armada_xp_mpic_starting_cpu(unsigned int cpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) {
armada_xp_mpic_perf_init();
armada_xp_mpic_smp_cpu_init();
}
return NOTIFY_OK;
armada_xp_mpic_perf_init();
armada_xp_mpic_smp_cpu_init();
return 0;
}
static struct notifier_block armada_370_xp_mpic_cpu_notifier = {
.notifier_call = armada_xp_mpic_secondary_init,
.priority = 100,
};
static int mpic_cascaded_secondary_init(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int mpic_cascaded_starting_cpu(unsigned int cpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN) {
armada_xp_mpic_perf_init();
enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
}
return NOTIFY_OK;
armada_xp_mpic_perf_init();
enable_percpu_irq(parent_irq, IRQ_TYPE_NONE);
return 0;
}
static struct notifier_block mpic_cascaded_cpu_notifier = {
.notifier_call = mpic_cascaded_secondary_init,
.priority = 100,
};
#endif /* CONFIG_SMP */
#endif
static const struct irq_domain_ops armada_370_xp_mpic_irq_ops = {
.map = armada_370_xp_mpic_irq_map,
@ -595,11 +577,15 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
set_handle_irq(armada_370_xp_handle_irq);
#ifdef CONFIG_SMP
set_smp_cross_call(armada_mpic_send_doorbell);
register_cpu_notifier(&armada_370_xp_mpic_cpu_notifier);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_XP_STARTING,
"AP_IRQ_ARMADA_XP_STARTING",
armada_xp_mpic_starting_cpu, NULL);
#endif
} else {
#ifdef CONFIG_SMP
register_cpu_notifier(&mpic_cascaded_cpu_notifier);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_ARMADA_CASC_STARTING,
"AP_IRQ_ARMADA_CASC_STARTING",
mpic_cascaded_starting_cpu, NULL);
#endif
irq_set_chained_handler(parent_irq,
armada_370_xp_mpic_handle_cascade_irq);

View File

@ -202,26 +202,19 @@ static void bcm2836_arm_irqchip_send_ipi(const struct cpumask *mask,
}
}
/* Unmasks the IPI on the CPU when it's online. */
static int bcm2836_arm_irqchip_cpu_notify(struct notifier_block *nfb,
unsigned long action, void *hcpu)
static int bcm2836_cpu_starting(unsigned int cpu)
{
unsigned int cpu = (unsigned long)hcpu;
unsigned int int_reg = LOCAL_MAILBOX_INT_CONTROL0;
unsigned int mailbox = 0;
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
bcm2836_arm_irqchip_unmask_per_cpu_irq(int_reg, mailbox, cpu);
else if (action == CPU_DYING)
bcm2836_arm_irqchip_mask_per_cpu_irq(int_reg, mailbox, cpu);
return NOTIFY_OK;
bcm2836_arm_irqchip_unmask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0,
cpu);
return 0;
}
static struct notifier_block bcm2836_arm_irqchip_cpu_notifier = {
.notifier_call = bcm2836_arm_irqchip_cpu_notify,
.priority = 100,
};
static int bcm2836_cpu_dying(unsigned int cpu)
{
bcm2836_arm_irqchip_mask_per_cpu_irq(LOCAL_MAILBOX_INT_CONTROL0, 0,
cpu);
return 0;
}
#ifdef CONFIG_ARM
static int __init bcm2836_smp_boot_secondary(unsigned int cpu,
@ -251,10 +244,9 @@ bcm2836_arm_irqchip_smp_init(void)
{
#ifdef CONFIG_SMP
/* Unmask IPIs to the boot CPU. */
bcm2836_arm_irqchip_cpu_notify(&bcm2836_arm_irqchip_cpu_notifier,
CPU_STARTING,
(void *)(uintptr_t)smp_processor_id());
register_cpu_notifier(&bcm2836_arm_irqchip_cpu_notifier);
cpuhp_setup_state(CPUHP_AP_IRQ_BCM2836_STARTING,
"AP_IRQ_BCM2836_STARTING", bcm2836_cpu_starting,
bcm2836_cpu_dying);
set_smp_cross_call(bcm2836_arm_irqchip_send_ipi);

View File

@ -538,22 +538,12 @@ static void gic_cpu_init(void)
}
#ifdef CONFIG_SMP
static int gic_secondary_init(struct notifier_block *nfb,
unsigned long action, void *hcpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
gic_cpu_init();
return NOTIFY_OK;
}
/*
* Notifier for enabling the GIC CPU interface. Set an arbitrarily high
* priority because the GIC needs to be up before the ARM generic timers.
*/
static struct notifier_block gic_cpu_notifier = {
.notifier_call = gic_secondary_init,
.priority = 100,
};
static int gic_starting_cpu(unsigned int cpu)
{
gic_cpu_init();
return 0;
}
static u16 gic_compute_target_list(int *base_cpu, const struct cpumask *mask,
unsigned long cluster_id)
@ -634,7 +624,9 @@ static void gic_raise_softirq(const struct cpumask *mask, unsigned int irq)
static void gic_smp_init(void)
{
set_smp_cross_call(gic_raise_softirq);
register_cpu_notifier(&gic_cpu_notifier);
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GICV3_STARTING,
"AP_IRQ_GICV3_STARTING", gic_starting_cpu,
NULL);
}
static int gic_set_affinity(struct irq_data *d, const struct cpumask *mask_val,

View File

@ -984,25 +984,12 @@ static int gic_irq_domain_translate(struct irq_domain *d,
return -EINVAL;
}
#ifdef CONFIG_SMP
static int gic_secondary_init(struct notifier_block *nfb, unsigned long action,
void *hcpu)
static int gic_starting_cpu(unsigned int cpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
gic_cpu_init(&gic_data[0]);
return NOTIFY_OK;
gic_cpu_init(&gic_data[0]);
return 0;
}
/*
* Notifier for enabling the GIC CPU interface. Set an arbitrarily high
* priority because the GIC needs to be up before the ARM generic timers.
*/
static struct notifier_block gic_cpu_notifier = {
.notifier_call = gic_secondary_init,
.priority = 100,
};
#endif
static int gic_irq_domain_alloc(struct irq_domain *domain, unsigned int virq,
unsigned int nr_irqs, void *arg)
{
@ -1177,8 +1164,10 @@ static int __init __gic_init_bases(struct gic_chip_data *gic,
gic_cpu_map[i] = 0xff;
#ifdef CONFIG_SMP
set_smp_cross_call(gic_raise_softirq);
register_cpu_notifier(&gic_cpu_notifier);
#endif
cpuhp_setup_state_nocalls(CPUHP_AP_IRQ_GIC_STARTING,
"AP_IRQ_GIC_STARTING",
gic_starting_cpu, NULL);
set_handle_irq(gic_handle_irq);
if (static_key_true(&supports_deactivate))
pr_info("GIC: Using split EOI/Deactivate mode\n");

View File

@ -342,26 +342,12 @@ static int hip04_irq_domain_xlate(struct irq_domain *d,
return ret;
}
#ifdef CONFIG_SMP
static int hip04_irq_secondary_init(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
static int hip04_irq_starting_cpu(unsigned int cpu)
{
if (action == CPU_STARTING || action == CPU_STARTING_FROZEN)
hip04_irq_cpu_init(&hip04_data);
return NOTIFY_OK;
hip04_irq_cpu_init(&hip04_data);
return 0;
}
/*
* Notifier for enabling the INTC CPU interface. Set an arbitrarily high
* priority because the GIC needs to be up before the ARM generic timers.
*/
static struct notifier_block hip04_irq_cpu_notifier = {
.notifier_call = hip04_irq_secondary_init,
.priority = 100,
};
#endif
static const struct irq_domain_ops hip04_irq_domain_ops = {
.map = hip04_irq_domain_map,
.xlate = hip04_irq_domain_xlate,
@ -417,13 +403,12 @@ hip04_of_init(struct device_node *node, struct device_node *parent)
#ifdef CONFIG_SMP
set_smp_cross_call(hip04_raise_softirq);
register_cpu_notifier(&hip04_irq_cpu_notifier);
#endif
set_handle_irq(hip04_handle_irq);
hip04_irq_dist_init(&hip04_data);
hip04_irq_cpu_init(&hip04_data);
cpuhp_setup_state(CPUHP_AP_IRQ_HIP04_STARTING, "AP_IRQ_HIP04_STARTING",
hip04_irq_starting_cpu, NULL);
return 0;
}
IRQCHIP_DECLARE(hip04_intc, "hisilicon,hip04-intc", hip04_of_init);

View File

@ -92,29 +92,22 @@ static struct syscore_ops ledtrig_cpu_syscore_ops = {
.resume = ledtrig_cpu_syscore_resume,
};
static int ledtrig_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
static int ledtrig_online_cpu(unsigned int cpu)
{
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_STARTING:
ledtrig_cpu(CPU_LED_START);
break;
case CPU_DYING:
ledtrig_cpu(CPU_LED_STOP);
break;
}
return NOTIFY_OK;
ledtrig_cpu(CPU_LED_START);
return 0;
}
static struct notifier_block ledtrig_cpu_nb = {
.notifier_call = ledtrig_cpu_notify,
};
static int ledtrig_prepare_down_cpu(unsigned int cpu)
{
ledtrig_cpu(CPU_LED_STOP);
return 0;
}
static int __init ledtrig_cpu_init(void)
{
int cpu;
int ret;
/* Supports up to 9999 cpu cores */
BUILD_BUG_ON(CONFIG_NR_CPUS > 9999);
@ -133,7 +126,12 @@ static int __init ledtrig_cpu_init(void)
}
register_syscore_ops(&ledtrig_cpu_syscore_ops);
register_cpu_notifier(&ledtrig_cpu_nb);
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_LEDTRIG_STARTING",
ledtrig_online_cpu, ledtrig_prepare_down_cpu);
if (ret < 0)
pr_err("CPU hotplug notifier for ledtrig-cpu could not be registered: %d\n",
ret);
pr_info("ledtrig-cpu: registered to indicate activity on CPUs\n");

View File

@ -688,30 +688,29 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
return 0;
}
static DEFINE_MUTEX(arm_pmu_mutex);
static LIST_HEAD(arm_pmu_list);
/*
* PMU hardware loses all context when a CPU goes offline.
* When a CPU is hotplugged back in, since some hardware registers are
* UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
* junk values out of them.
*/
static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
void *hcpu)
static int arm_perf_starting_cpu(unsigned int cpu)
{
int cpu = (unsigned long)hcpu;
struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb);
struct arm_pmu *pmu;
if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
return NOTIFY_DONE;
mutex_lock(&arm_pmu_mutex);
list_for_each_entry(pmu, &arm_pmu_list, entry) {
if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
return NOTIFY_DONE;
if (pmu->reset)
pmu->reset(pmu);
else
return NOTIFY_DONE;
return NOTIFY_OK;
if (!cpumask_test_cpu(cpu, &pmu->supported_cpus))
continue;
if (pmu->reset)
pmu->reset(pmu);
}
mutex_unlock(&arm_pmu_mutex);
return 0;
}
#ifdef CONFIG_CPU_PM
@ -822,10 +821,9 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
if (!cpu_hw_events)
return -ENOMEM;
cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify;
err = register_cpu_notifier(&cpu_pmu->hotplug_nb);
if (err)
goto out_hw_events;
mutex_lock(&arm_pmu_mutex);
list_add_tail(&cpu_pmu->entry, &arm_pmu_list);
mutex_unlock(&arm_pmu_mutex);
err = cpu_pm_pmu_register(cpu_pmu);
if (err)
@ -861,8 +859,9 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
return 0;
out_unregister:
unregister_cpu_notifier(&cpu_pmu->hotplug_nb);
out_hw_events:
mutex_lock(&arm_pmu_mutex);
list_del(&cpu_pmu->entry);
mutex_unlock(&arm_pmu_mutex);
free_percpu(cpu_hw_events);
return err;
}
@ -870,7 +869,9 @@ static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
{
cpu_pm_pmu_unregister(cpu_pmu);
unregister_cpu_notifier(&cpu_pmu->hotplug_nb);
mutex_lock(&arm_pmu_mutex);
list_del(&cpu_pmu->entry);
mutex_unlock(&arm_pmu_mutex);
free_percpu(cpu_pmu->hw_events);
}
@ -1061,3 +1062,17 @@ int arm_pmu_device_probe(struct platform_device *pdev,
kfree(pmu);
return ret;
}
static int arm_pmu_hp_init(void)
{
int ret;
ret = cpuhp_setup_state_nocalls(CPUHP_AP_PERF_ARM_STARTING,
"AP_PERF_ARM_STARTING",
arm_perf_starting_cpu, NULL);
if (ret)
pr_err("CPU hotplug notifier for ARM PMU could not be registered: %d\n",
ret);
return ret;
}
subsys_initcall(arm_pmu_hp_init);

View File

@ -55,17 +55,6 @@ extern ssize_t arch_cpu_release(const char *, size_t);
#endif
struct notifier_block;
/*
* CPU notifier priorities.
*/
enum {
CPU_PRI_PERF = 20,
/* bring up workqueues before normal notifiers and down after */
CPU_PRI_WORKQUEUE_UP = 5,
CPU_PRI_WORKQUEUE_DOWN = -5,
};
#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */
#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */
#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */

View File

@ -4,19 +4,95 @@
enum cpuhp_state {
CPUHP_OFFLINE,
CPUHP_CREATE_THREADS,
CPUHP_PERF_PREPARE,
CPUHP_PERF_X86_PREPARE,
CPUHP_PERF_X86_UNCORE_PREP,
CPUHP_PERF_X86_AMD_UNCORE_PREP,
CPUHP_PERF_X86_RAPL_PREP,
CPUHP_PERF_BFIN,
CPUHP_PERF_POWER,
CPUHP_PERF_SUPERH,
CPUHP_X86_HPET_DEAD,
CPUHP_X86_APB_DEAD,
CPUHP_WORKQUEUE_PREP,
CPUHP_POWER_NUMA_PREPARE,
CPUHP_HRTIMERS_PREPARE,
CPUHP_PROFILE_PREPARE,
CPUHP_X2APIC_PREPARE,
CPUHP_SMPCFD_PREPARE,
CPUHP_RCUTREE_PREP,
CPUHP_NOTIFY_PREPARE,
CPUHP_TIMERS_DEAD,
CPUHP_BRINGUP_CPU,
CPUHP_AP_IDLE_DEAD,
CPUHP_AP_OFFLINE,
CPUHP_AP_SCHED_STARTING,
CPUHP_AP_RCUTREE_DYING,
CPUHP_AP_IRQ_GIC_STARTING,
CPUHP_AP_IRQ_GICV3_STARTING,
CPUHP_AP_IRQ_HIP04_STARTING,
CPUHP_AP_IRQ_ARMADA_XP_STARTING,
CPUHP_AP_IRQ_ARMADA_CASC_STARTING,
CPUHP_AP_IRQ_BCM2836_STARTING,
CPUHP_AP_ARM_MVEBU_COHERENCY,
CPUHP_AP_PERF_X86_UNCORE_STARTING,
CPUHP_AP_PERF_X86_AMD_UNCORE_STARTING,
CPUHP_AP_PERF_X86_STARTING,
CPUHP_AP_PERF_X86_AMD_IBS_STARTING,
CPUHP_AP_PERF_X86_CQM_STARTING,
CPUHP_AP_PERF_X86_CSTATE_STARTING,
CPUHP_AP_PERF_XTENSA_STARTING,
CPUHP_AP_PERF_METAG_STARTING,
CPUHP_AP_MIPS_OP_LOONGSON3_STARTING,
CPUHP_AP_ARM_VFP_STARTING,
CPUHP_AP_PERF_ARM_STARTING,
CPUHP_AP_ARM_L2X0_STARTING,
CPUHP_AP_ARM_ARCH_TIMER_STARTING,
CPUHP_AP_ARM_GLOBAL_TIMER_STARTING,
CPUHP_AP_DUMMY_TIMER_STARTING,
CPUHP_AP_EXYNOS4_MCT_TIMER_STARTING,
CPUHP_AP_ARM_TWD_STARTING,
CPUHP_AP_METAG_TIMER_STARTING,
CPUHP_AP_QCOM_TIMER_STARTING,
CPUHP_AP_ARMADA_TIMER_STARTING,
CPUHP_AP_MARCO_TIMER_STARTING,
CPUHP_AP_MIPS_GIC_TIMER_STARTING,
CPUHP_AP_ARC_TIMER_STARTING,
CPUHP_AP_KVM_STARTING,
CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
CPUHP_AP_KVM_ARM_VGIC_STARTING,
CPUHP_AP_KVM_ARM_TIMER_STARTING,
CPUHP_AP_ARM_XEN_STARTING,
CPUHP_AP_ARM_CORESIGHT_STARTING,
CPUHP_AP_ARM_CORESIGHT4_STARTING,
CPUHP_AP_ARM64_ISNDEP_STARTING,
CPUHP_AP_SMPCFD_DYING,
CPUHP_AP_X86_TBOOT_DYING,
CPUHP_AP_NOTIFY_STARTING,
CPUHP_AP_ONLINE,
CPUHP_TEARDOWN_CPU,
CPUHP_AP_ONLINE_IDLE,
CPUHP_AP_SMPBOOT_THREADS,
CPUHP_AP_X86_VDSO_VMA_ONLINE,
CPUHP_AP_PERF_ONLINE,
CPUHP_AP_PERF_X86_ONLINE,
CPUHP_AP_PERF_X86_UNCORE_ONLINE,
CPUHP_AP_PERF_X86_AMD_UNCORE_ONLINE,
CPUHP_AP_PERF_X86_AMD_POWER_ONLINE,
CPUHP_AP_PERF_X86_RAPL_ONLINE,
CPUHP_AP_PERF_X86_CQM_ONLINE,
CPUHP_AP_PERF_X86_CSTATE_ONLINE,
CPUHP_AP_PERF_S390_CF_ONLINE,
CPUHP_AP_PERF_S390_SF_ONLINE,
CPUHP_AP_PERF_ARM_CCI_ONLINE,
CPUHP_AP_PERF_ARM_CCN_ONLINE,
CPUHP_AP_WORKQUEUE_ONLINE,
CPUHP_AP_RCUTREE_ONLINE,
CPUHP_AP_NOTIFY_ONLINE,
CPUHP_AP_ONLINE_DYN,
CPUHP_AP_ONLINE_DYN_END = CPUHP_AP_ONLINE_DYN + 30,
CPUHP_AP_X86_HPET_ONLINE,
CPUHP_AP_X86_KVM_CLK_ONLINE,
CPUHP_AP_ACTIVE,
CPUHP_ONLINE,
};

View File

@ -494,4 +494,11 @@ extern void __init hrtimers_init(void);
/* Show pending timers: */
extern void sysrq_timer_list_show(void);
int hrtimers_prepare_cpu(unsigned int cpu);
#ifdef CONFIG_HOTPLUG_CPU
int hrtimers_dead_cpu(unsigned int cpu);
#else
#define hrtimers_dead_cpu NULL
#endif
#endif

View File

@ -109,7 +109,7 @@ struct arm_pmu {
DECLARE_BITMAP(pmceid_bitmap, ARMV8_PMUV3_MAX_COMMON_EVENTS);
struct platform_device *plat_device;
struct pmu_hw_events __percpu *hw_events;
struct notifier_block hotplug_nb;
struct list_head entry;
struct notifier_block cpu_pm_nb;
};

View File

@ -1309,41 +1309,6 @@ static __always_inline bool perf_raw_frag_last(const struct perf_raw_frag *frag)
#define perf_output_put(handle, x) perf_output_copy((handle), &(x), sizeof(x))
/*
* This has to have a higher priority than migration_notifier in sched/core.c.
*/
#define perf_cpu_notifier(fn) \
do { \
static struct notifier_block fn##_nb = \
{ .notifier_call = fn, .priority = CPU_PRI_PERF }; \
unsigned long cpu = smp_processor_id(); \
unsigned long flags; \
\
cpu_notifier_register_begin(); \
fn(&fn##_nb, (unsigned long)CPU_UP_PREPARE, \
(void *)(unsigned long)cpu); \
local_irq_save(flags); \
fn(&fn##_nb, (unsigned long)CPU_STARTING, \
(void *)(unsigned long)cpu); \
local_irq_restore(flags); \
fn(&fn##_nb, (unsigned long)CPU_ONLINE, \
(void *)(unsigned long)cpu); \
__register_cpu_notifier(&fn##_nb); \
cpu_notifier_register_done(); \
} while (0)
/*
* Bare-bones version of perf_cpu_notifier(), which doesn't invoke the
* callback for already online CPUs.
*/
#define __perf_cpu_notifier(fn) \
do { \
static struct notifier_block fn##_nb = \
{ .notifier_call = fn, .priority = CPU_PRI_PERF }; \
\
__register_cpu_notifier(&fn##_nb); \
} while (0)
struct perf_pmu_events_attr {
struct device_attribute attr;
u64 id;
@ -1385,4 +1350,13 @@ _name##_show(struct device *dev, \
\
static struct device_attribute format_attr_##_name = __ATTR_RO(_name)
/* Performance counter hotplug functions */
#ifdef CONFIG_PERF_EVENTS
int perf_event_init_cpu(unsigned int cpu);
int perf_event_exit_cpu(unsigned int cpu);
#else
#define perf_event_init_cpu NULL
#define perf_event_exit_cpu NULL
#endif
#endif /* _LINUX_PERF_EVENT_H */

View File

@ -243,4 +243,11 @@ static inline void rcu_all_qs(void)
barrier(); /* Avoid RCU read-side critical sections leaking across. */
}
/* RCUtree hotplug events */
#define rcutree_prepare_cpu NULL
#define rcutree_online_cpu NULL
#define rcutree_offline_cpu NULL
#define rcutree_dead_cpu NULL
#define rcutree_dying_cpu NULL
#endif /* __LINUX_RCUTINY_H */

View File

@ -111,4 +111,11 @@ bool rcu_is_watching(void);
void rcu_all_qs(void);
/* RCUtree hotplug events */
int rcutree_prepare_cpu(unsigned int cpu);
int rcutree_online_cpu(unsigned int cpu);
int rcutree_offline_cpu(unsigned int cpu);
int rcutree_dead_cpu(unsigned int cpu);
int rcutree_dying_cpu(unsigned int cpu);
#endif /* __LINUX_RCUTREE_H */

View File

@ -196,4 +196,9 @@ extern void arch_enable_nonboot_cpus_end(void);
void smp_setup_processor_id(void);
/* SMP core functions */
int smpcfd_prepare_cpu(unsigned int cpu);
int smpcfd_dead_cpu(unsigned int cpu);
int smpcfd_dying_cpu(unsigned int cpu);
#endif /* __LINUX_SMP_H */

View File

@ -273,4 +273,10 @@ unsigned long __round_jiffies_up_relative(unsigned long j, int cpu);
unsigned long round_jiffies_up(unsigned long j);
unsigned long round_jiffies_up_relative(unsigned long j);
#ifdef CONFIG_HOTPLUG_CPU
int timers_dead_cpu(unsigned int cpu);
#else
#define timers_dead_cpu NULL
#endif
#endif

View File

@ -625,4 +625,10 @@ void wq_watchdog_touch(int cpu);
static inline void wq_watchdog_touch(int cpu) { }
#endif /* CONFIG_WQ_WATCHDOG */
#ifdef CONFIG_SMP
int workqueue_prepare_cpu(unsigned int cpu);
int workqueue_online_cpu(unsigned int cpu);
int workqueue_offline_cpu(unsigned int cpu);
#endif
#endif

View File

@ -517,6 +517,13 @@ static int cpuhp_invoke_ap_callback(int cpu, enum cpuhp_state state,
if (!cpu_online(cpu))
return 0;
/*
* If we are up and running, use the hotplug thread. For early calls
* we invoke the thread function directly.
*/
if (!st->thread)
return cpuhp_invoke_callback(cpu, state, cb);
st->cb_state = state;
st->cb = cb;
/*
@ -1173,6 +1180,31 @@ static struct cpuhp_step cpuhp_bp_states[] = {
.teardown = NULL,
.cant_stop = true,
},
[CPUHP_PERF_PREPARE] = {
.name = "perf prepare",
.startup = perf_event_init_cpu,
.teardown = perf_event_exit_cpu,
},
[CPUHP_WORKQUEUE_PREP] = {
.name = "workqueue prepare",
.startup = workqueue_prepare_cpu,
.teardown = NULL,
},
[CPUHP_HRTIMERS_PREPARE] = {
.name = "hrtimers prepare",
.startup = hrtimers_prepare_cpu,
.teardown = hrtimers_dead_cpu,
},
[CPUHP_SMPCFD_PREPARE] = {
.name = "SMPCFD prepare",
.startup = smpcfd_prepare_cpu,
.teardown = smpcfd_dead_cpu,
},
[CPUHP_RCUTREE_PREP] = {
.name = "RCU-tree prepare",
.startup = rcutree_prepare_cpu,
.teardown = rcutree_dead_cpu,
},
/*
* Preparatory and dead notifiers. Will be replaced once the notifiers
* are converted to states.
@ -1184,6 +1216,16 @@ static struct cpuhp_step cpuhp_bp_states[] = {
.skip_onerr = true,
.cant_stop = true,
},
/*
* On the tear-down path, timers_dead_cpu() must be invoked
* before blk_mq_queue_reinit_notify() from notify_dead(),
* otherwise a RCU stall occurs.
*/
[CPUHP_TIMERS_DEAD] = {
.name = "timers dead",
.startup = NULL,
.teardown = timers_dead_cpu,
},
/* Kicks the plugged cpu into life */
[CPUHP_BRINGUP_CPU] = {
.name = "cpu:bringup",
@ -1191,6 +1233,10 @@ static struct cpuhp_step cpuhp_bp_states[] = {
.teardown = NULL,
.cant_stop = true,
},
[CPUHP_AP_SMPCFD_DYING] = {
.startup = NULL,
.teardown = smpcfd_dying_cpu,
},
/*
* Handled on controll processor until the plugged processor manages
* this itself.
@ -1227,6 +1273,10 @@ static struct cpuhp_step cpuhp_ap_states[] = {
.startup = sched_cpu_starting,
.teardown = sched_cpu_dying,
},
[CPUHP_AP_RCUTREE_DYING] = {
.startup = NULL,
.teardown = rcutree_dying_cpu,
},
/*
* Low level startup/teardown notifiers. Run with interrupts
* disabled. Will be removed once the notifiers are converted to
@ -1250,6 +1300,22 @@ static struct cpuhp_step cpuhp_ap_states[] = {
.startup = smpboot_unpark_threads,
.teardown = NULL,
},
[CPUHP_AP_PERF_ONLINE] = {
.name = "perf online",
.startup = perf_event_init_cpu,
.teardown = perf_event_exit_cpu,
},
[CPUHP_AP_WORKQUEUE_ONLINE] = {
.name = "workqueue online",
.startup = workqueue_online_cpu,
.teardown = workqueue_offline_cpu,
},
[CPUHP_AP_RCUTREE_ONLINE] = {
.name = "RCU-tree online",
.startup = rcutree_online_cpu,
.teardown = rcutree_offline_cpu,
},
/*
* Online/down_prepare notifiers. Will be removed once the notifiers
* are converted to states.

View File

@ -10357,7 +10357,7 @@ static void __init perf_event_init_all_cpus(void)
}
}
static void perf_event_init_cpu(int cpu)
int perf_event_init_cpu(unsigned int cpu)
{
struct swevent_htable *swhash = &per_cpu(swevent_htable, cpu);
@ -10370,6 +10370,7 @@ static void perf_event_init_cpu(int cpu)
rcu_assign_pointer(swhash->swevent_hlist, hlist);
}
mutex_unlock(&swhash->hlist_mutex);
return 0;
}
#if defined CONFIG_HOTPLUG_CPU || defined CONFIG_KEXEC_CORE
@ -10401,14 +10402,17 @@ static void perf_event_exit_cpu_context(int cpu)
}
srcu_read_unlock(&pmus_srcu, idx);
}
#else
static void perf_event_exit_cpu(int cpu)
static void perf_event_exit_cpu_context(int cpu) { }
#endif
int perf_event_exit_cpu(unsigned int cpu)
{
perf_event_exit_cpu_context(cpu);
return 0;
}
#else
static inline void perf_event_exit_cpu(int cpu) { }
#endif
static int
perf_reboot(struct notifier_block *notifier, unsigned long val, void *v)
@ -10430,46 +10434,6 @@ static struct notifier_block perf_reboot_notifier = {
.priority = INT_MIN,
};
static int
perf_cpu_notify(struct notifier_block *self, unsigned long action, void *hcpu)
{
unsigned int cpu = (long)hcpu;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
/*
* This must be done before the CPU comes alive, because the
* moment we can run tasks we can encounter (software) events.
*
* Specifically, someone can have inherited events on kthreadd
* or a pre-existing worker thread that gets re-bound.
*/
perf_event_init_cpu(cpu);
break;
case CPU_DOWN_PREPARE:
/*
* This must be done before the CPU dies because after that an
* active event might want to IPI the CPU and that'll not work
* so great for dead CPUs.
*
* XXX smp_call_function_single() return -ENXIO without a warn
* so we could possibly deal with this.
*
* This is safe against new events arriving because
* sys_perf_event_open() serializes against hotplug using
* get_online_cpus().
*/
perf_event_exit_cpu(cpu);
break;
default:
break;
}
return NOTIFY_OK;
}
void __init perf_event_init(void)
{
int ret;
@ -10482,7 +10446,7 @@ void __init perf_event_init(void)
perf_pmu_register(&perf_cpu_clock, NULL, -1);
perf_pmu_register(&perf_task_clock, NULL, -1);
perf_tp_register();
perf_cpu_notifier(perf_cpu_notify);
perf_event_init_cpu(smp_processor_id());
register_reboot_notifier(&perf_reboot_notifier);
ret = init_hw_breakpoint();

View File

@ -328,68 +328,57 @@ static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
put_cpu();
}
static int profile_cpu_callback(struct notifier_block *info,
unsigned long action, void *__cpu)
static int profile_dead_cpu(unsigned int cpu)
{
int node, cpu = (unsigned long)__cpu;
struct page *page;
int i;
if (prof_cpu_mask != NULL)
cpumask_clear_cpu(cpu, prof_cpu_mask);
for (i = 0; i < 2; i++) {
if (per_cpu(cpu_profile_hits, cpu)[i]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[i]);
per_cpu(cpu_profile_hits, cpu)[i] = NULL;
__free_page(page);
}
}
return 0;
}
static int profile_prepare_cpu(unsigned int cpu)
{
int i, node = cpu_to_mem(cpu);
struct page *page;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
node = cpu_to_mem(cpu);
per_cpu(cpu_profile_flip, cpu) = 0;
if (!per_cpu(cpu_profile_hits, cpu)[1]) {
page = __alloc_pages_node(node,
GFP_KERNEL | __GFP_ZERO,
0);
if (!page)
return notifier_from_errno(-ENOMEM);
per_cpu(cpu_profile_hits, cpu)[1] = page_address(page);
per_cpu(cpu_profile_flip, cpu) = 0;
for (i = 0; i < 2; i++) {
if (per_cpu(cpu_profile_hits, cpu)[i])
continue;
page = __alloc_pages_node(node, GFP_KERNEL | __GFP_ZERO, 0);
if (!page) {
profile_dead_cpu(cpu);
return -ENOMEM;
}
if (!per_cpu(cpu_profile_hits, cpu)[0]) {
page = __alloc_pages_node(node,
GFP_KERNEL | __GFP_ZERO,
0);
if (!page)
goto out_free;
per_cpu(cpu_profile_hits, cpu)[0] = page_address(page);
}
break;
out_free:
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
per_cpu(cpu_profile_hits, cpu)[1] = NULL;
__free_page(page);
return notifier_from_errno(-ENOMEM);
case CPU_ONLINE:
case CPU_ONLINE_FROZEN:
if (prof_cpu_mask != NULL)
cpumask_set_cpu(cpu, prof_cpu_mask);
break;
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
case CPU_DEAD:
case CPU_DEAD_FROZEN:
if (prof_cpu_mask != NULL)
cpumask_clear_cpu(cpu, prof_cpu_mask);
if (per_cpu(cpu_profile_hits, cpu)[0]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
per_cpu(cpu_profile_hits, cpu)[0] = NULL;
__free_page(page);
}
if (per_cpu(cpu_profile_hits, cpu)[1]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
per_cpu(cpu_profile_hits, cpu)[1] = NULL;
__free_page(page);
}
break;
per_cpu(cpu_profile_hits, cpu)[i] = page_address(page);
}
return NOTIFY_OK;
return 0;
}
static int profile_online_cpu(unsigned int cpu)
{
if (prof_cpu_mask != NULL)
cpumask_set_cpu(cpu, prof_cpu_mask);
return 0;
}
#else /* !CONFIG_SMP */
#define profile_flip_buffers() do { } while (0)
#define profile_discard_flip_buffers() do { } while (0)
#define profile_cpu_callback NULL
static void do_profile_hits(int type, void *__pc, unsigned int nr_hits)
{
@ -531,83 +520,43 @@ static const struct file_operations proc_profile_operations = {
.llseek = default_llseek,
};
#ifdef CONFIG_SMP
static void profile_nop(void *unused)
{
}
static int create_hash_tables(void)
{
int cpu;
for_each_online_cpu(cpu) {
int node = cpu_to_mem(cpu);
struct page *page;
page = __alloc_pages_node(node,
GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
0);
if (!page)
goto out_cleanup;
per_cpu(cpu_profile_hits, cpu)[1]
= (struct profile_hit *)page_address(page);
page = __alloc_pages_node(node,
GFP_KERNEL | __GFP_ZERO | __GFP_THISNODE,
0);
if (!page)
goto out_cleanup;
per_cpu(cpu_profile_hits, cpu)[0]
= (struct profile_hit *)page_address(page);
}
return 0;
out_cleanup:
prof_on = 0;
smp_mb();
on_each_cpu(profile_nop, NULL, 1);
for_each_online_cpu(cpu) {
struct page *page;
if (per_cpu(cpu_profile_hits, cpu)[0]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[0]);
per_cpu(cpu_profile_hits, cpu)[0] = NULL;
__free_page(page);
}
if (per_cpu(cpu_profile_hits, cpu)[1]) {
page = virt_to_page(per_cpu(cpu_profile_hits, cpu)[1]);
per_cpu(cpu_profile_hits, cpu)[1] = NULL;
__free_page(page);
}
}
return -1;
}
#else
#define create_hash_tables() ({ 0; })
#endif
int __ref create_proc_profile(void) /* false positive from hotcpu_notifier */
int __ref create_proc_profile(void)
{
struct proc_dir_entry *entry;
#ifdef CONFIG_SMP
enum cpuhp_state online_state;
#endif
int err = 0;
if (!prof_on)
return 0;
#ifdef CONFIG_SMP
err = cpuhp_setup_state(CPUHP_PROFILE_PREPARE, "PROFILE_PREPARE",
profile_prepare_cpu, profile_dead_cpu);
if (err)
return err;
cpu_notifier_register_begin();
if (create_hash_tables()) {
err = -ENOMEM;
goto out;
}
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "AP_PROFILE_ONLINE",
profile_online_cpu, NULL);
if (err < 0)
goto err_state_prep;
online_state = err;
err = 0;
#endif
entry = proc_create("profile", S_IWUSR | S_IRUGO,
NULL, &proc_profile_operations);
if (!entry)
goto out;
goto err_state_onl;
proc_set_size(entry, (1 + prof_len) * sizeof(atomic_t));
__hotcpu_notifier(profile_cpu_callback, 0);
out:
cpu_notifier_register_done();
return err;
err_state_onl:
#ifdef CONFIG_SMP
cpuhp_remove_state(online_state);
err_state_prep:
cpuhp_remove_state(CPUHP_PROFILE_PREPARE);
#endif
return err;
}
subsys_initcall(create_proc_profile);

View File

@ -1073,11 +1073,11 @@ EXPORT_SYMBOL_GPL(rcu_is_watching);
* offline to continue to use RCU for one jiffy after marking itself
* offline in the cpu_online_mask. This leniency is necessary given the
* non-atomic nature of the online and offline processing, for example,
* the fact that a CPU enters the scheduler after completing the CPU_DYING
* notifiers.
* the fact that a CPU enters the scheduler after completing the teardown
* of the CPU.
*
* This is also why RCU internally marks CPUs online during the
* CPU_UP_PREPARE phase and offline during the CPU_DEAD phase.
* This is also why RCU internally marks CPUs online during in the
* preparation phase and offline after the CPU has been taken down.
*
* Disable checking if in an NMI handler because we cannot safely report
* errors from NMI handlers anyway.
@ -3806,12 +3806,58 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp)
raw_spin_unlock_irqrestore_rcu_node(rnp, flags);
}
static void rcu_prepare_cpu(int cpu)
int rcutree_prepare_cpu(unsigned int cpu)
{
struct rcu_state *rsp;
for_each_rcu_flavor(rsp)
rcu_init_percpu_data(cpu, rsp);
rcu_prepare_kthreads(cpu);
rcu_spawn_all_nocb_kthreads(cpu);
return 0;
}
static void rcutree_affinity_setting(unsigned int cpu, int outgoing)
{
struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu);
rcu_boost_kthread_setaffinity(rdp->mynode, outgoing);
}
int rcutree_online_cpu(unsigned int cpu)
{
sync_sched_exp_online_cleanup(cpu);
rcutree_affinity_setting(cpu, -1);
return 0;
}
int rcutree_offline_cpu(unsigned int cpu)
{
rcutree_affinity_setting(cpu, cpu);
return 0;
}
int rcutree_dying_cpu(unsigned int cpu)
{
struct rcu_state *rsp;
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
return 0;
}
int rcutree_dead_cpu(unsigned int cpu)
{
struct rcu_state *rsp;
for_each_rcu_flavor(rsp) {
rcu_cleanup_dead_cpu(cpu, rsp);
do_nocb_deferred_wakeup(per_cpu_ptr(rsp->rda, cpu));
}
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
@ -3851,52 +3897,6 @@ void rcu_report_dead(unsigned int cpu)
}
#endif
/*
* Handle CPU online/offline notification events.
*/
int rcu_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
long cpu = (long)hcpu;
struct rcu_data *rdp = per_cpu_ptr(rcu_state_p->rda, cpu);
struct rcu_node *rnp = rdp->mynode;
struct rcu_state *rsp;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
rcu_prepare_cpu(cpu);
rcu_prepare_kthreads(cpu);
rcu_spawn_all_nocb_kthreads(cpu);
break;
case CPU_ONLINE:
case CPU_DOWN_FAILED:
sync_sched_exp_online_cleanup(cpu);
rcu_boost_kthread_setaffinity(rnp, -1);
break;
case CPU_DOWN_PREPARE:
rcu_boost_kthread_setaffinity(rnp, cpu);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
for_each_rcu_flavor(rsp)
rcu_cleanup_dying_cpu(rsp);
break;
case CPU_DEAD:
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
for_each_rcu_flavor(rsp) {
rcu_cleanup_dead_cpu(cpu, rsp);
do_nocb_deferred_wakeup(per_cpu_ptr(rsp->rda, cpu));
}
break;
default:
break;
}
return NOTIFY_OK;
}
static int rcu_pm_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
@ -4208,10 +4208,9 @@ void __init rcu_init(void)
* this is called early in boot, before either interrupts
* or the scheduler are operational.
*/
cpu_notifier(rcu_cpu_notify, 0);
pm_notifier(rcu_pm_notify, 0);
for_each_online_cpu(cpu)
rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
rcutree_prepare_cpu(cpu);
}
#include "tree_exp.h"

View File

@ -33,69 +33,54 @@ static DEFINE_PER_CPU_SHARED_ALIGNED(struct llist_head, call_single_queue);
static void flush_smp_call_function_queue(bool warn_cpu_offline);
static int
hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)
int smpcfd_prepare_cpu(unsigned int cpu)
{
long cpu = (long)hcpu;
struct call_function_data *cfd = &per_cpu(cfd_data, cpu);
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
cpu_to_node(cpu)))
return notifier_from_errno(-ENOMEM);
cfd->csd = alloc_percpu(struct call_single_data);
if (!cfd->csd) {
free_cpumask_var(cfd->cpumask);
return notifier_from_errno(-ENOMEM);
}
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
/* Fall-through to the CPU_DEAD[_FROZEN] case. */
case CPU_DEAD:
case CPU_DEAD_FROZEN:
if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,
cpu_to_node(cpu)))
return -ENOMEM;
cfd->csd = alloc_percpu(struct call_single_data);
if (!cfd->csd) {
free_cpumask_var(cfd->cpumask);
free_percpu(cfd->csd);
break;
return -ENOMEM;
}
case CPU_DYING:
case CPU_DYING_FROZEN:
/*
* The IPIs for the smp-call-function callbacks queued by other
* CPUs might arrive late, either due to hardware latencies or
* because this CPU disabled interrupts (inside stop-machine)
* before the IPIs were sent. So flush out any pending callbacks
* explicitly (without waiting for the IPIs to arrive), to
* ensure that the outgoing CPU doesn't go offline with work
* still pending.
*/
flush_smp_call_function_queue(false);
break;
#endif
};
return NOTIFY_OK;
return 0;
}
static struct notifier_block hotplug_cfd_notifier = {
.notifier_call = hotplug_cfd,
};
int smpcfd_dead_cpu(unsigned int cpu)
{
struct call_function_data *cfd = &per_cpu(cfd_data, cpu);
free_cpumask_var(cfd->cpumask);
free_percpu(cfd->csd);
return 0;
}
int smpcfd_dying_cpu(unsigned int cpu)
{
/*
* The IPIs for the smp-call-function callbacks queued by other
* CPUs might arrive late, either due to hardware latencies or
* because this CPU disabled interrupts (inside stop-machine)
* before the IPIs were sent. So flush out any pending callbacks
* explicitly (without waiting for the IPIs to arrive), to
* ensure that the outgoing CPU doesn't go offline with work
* still pending.
*/
flush_smp_call_function_queue(false);
return 0;
}
void __init call_function_init(void)
{
void *cpu = (void *)(long)smp_processor_id();
int i;
for_each_possible_cpu(i)
init_llist_head(&per_cpu(call_single_queue, i));
hotplug_cfd(&hotplug_cfd_notifier, CPU_UP_PREPARE, cpu);
register_cpu_notifier(&hotplug_cfd_notifier);
smpcfd_prepare_cpu(smp_processor_id());
}
/*

View File

@ -1590,7 +1590,7 @@ SYSCALL_DEFINE2(nanosleep, struct timespec __user *, rqtp,
/*
* Functions related to boot-time initialization:
*/
static void init_hrtimers_cpu(int cpu)
int hrtimers_prepare_cpu(unsigned int cpu)
{
struct hrtimer_cpu_base *cpu_base = &per_cpu(hrtimer_bases, cpu);
int i;
@ -1602,6 +1602,7 @@ static void init_hrtimers_cpu(int cpu)
cpu_base->cpu = cpu;
hrtimer_init_hres(cpu_base);
return 0;
}
#ifdef CONFIG_HOTPLUG_CPU
@ -1636,7 +1637,7 @@ static void migrate_hrtimer_list(struct hrtimer_clock_base *old_base,
}
}
static void migrate_hrtimers(int scpu)
int hrtimers_dead_cpu(unsigned int scpu)
{
struct hrtimer_cpu_base *old_base, *new_base;
int i;
@ -1665,45 +1666,14 @@ static void migrate_hrtimers(int scpu)
/* Check, if we got expired work to do */
__hrtimer_peek_ahead_timers();
local_irq_enable();
return 0;
}
#endif /* CONFIG_HOTPLUG_CPU */
static int hrtimer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
int scpu = (long)hcpu;
switch (action) {
case CPU_UP_PREPARE:
case CPU_UP_PREPARE_FROZEN:
init_hrtimers_cpu(scpu);
break;
#ifdef CONFIG_HOTPLUG_CPU
case CPU_DEAD:
case CPU_DEAD_FROZEN:
migrate_hrtimers(scpu);
break;
#endif
default:
break;
}
return NOTIFY_OK;
}
static struct notifier_block hrtimers_nb = {
.notifier_call = hrtimer_cpu_notify,
};
void __init hrtimers_init(void)
{
hrtimer_cpu_notify(&hrtimers_nb, (unsigned long)CPU_UP_PREPARE,
(void *)(long)smp_processor_id());
register_cpu_notifier(&hrtimers_nb);
hrtimers_prepare_cpu(smp_processor_id());
}
/**

View File

@ -1804,7 +1804,7 @@ static void migrate_timer_list(struct timer_base *new_base, struct hlist_head *h
}
}
static void migrate_timers(int cpu)
int timers_dead_cpu(unsigned int cpu)
{
struct timer_base *old_base;
struct timer_base *new_base;
@ -1831,29 +1831,9 @@ static void migrate_timers(int cpu)
spin_unlock_irq(&new_base->lock);
put_cpu_ptr(&timer_bases);
}
return 0;
}
static int timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *hcpu)
{
switch (action) {
case CPU_DEAD:
case CPU_DEAD_FROZEN:
migrate_timers((long)hcpu);
break;
default:
break;
}
return NOTIFY_OK;
}
static inline void timer_register_cpu_notifier(void)
{
cpu_notifier(timer_cpu_notify, 0);
}
#else
static inline void timer_register_cpu_notifier(void) { }
#endif /* CONFIG_HOTPLUG_CPU */
static void __init init_timer_cpu(int cpu)
@ -1881,7 +1861,6 @@ void __init init_timers(void)
{
init_timer_cpus();
init_timer_stats();
timer_register_cpu_notifier();
open_softirq(TIMER_SOFTIRQ, run_timer_softirq);
}

View File

@ -4607,84 +4607,65 @@ static void restore_unbound_workers_cpumask(struct worker_pool *pool, int cpu)
WARN_ON_ONCE(set_cpus_allowed_ptr(worker->task, &cpumask) < 0);
}
/*
* Workqueues should be brought up before normal priority CPU notifiers.
* This will be registered high priority CPU notifier.
*/
static int workqueue_cpu_up_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
int workqueue_prepare_cpu(unsigned int cpu)
{
struct worker_pool *pool;
for_each_cpu_worker_pool(pool, cpu) {
if (pool->nr_workers)
continue;
if (!create_worker(pool))
return -ENOMEM;
}
return 0;
}
int workqueue_online_cpu(unsigned int cpu)
{
int cpu = (unsigned long)hcpu;
struct worker_pool *pool;
struct workqueue_struct *wq;
int pi;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_UP_PREPARE:
for_each_cpu_worker_pool(pool, cpu) {
if (pool->nr_workers)
continue;
if (!create_worker(pool))
return NOTIFY_BAD;
}
break;
mutex_lock(&wq_pool_mutex);
case CPU_DOWN_FAILED:
case CPU_ONLINE:
mutex_lock(&wq_pool_mutex);
for_each_pool(pool, pi) {
mutex_lock(&pool->attach_mutex);
for_each_pool(pool, pi) {
mutex_lock(&pool->attach_mutex);
if (pool->cpu == cpu)
rebind_workers(pool);
else if (pool->cpu < 0)
restore_unbound_workers_cpumask(pool, cpu);
if (pool->cpu == cpu)
rebind_workers(pool);
else if (pool->cpu < 0)
restore_unbound_workers_cpumask(pool, cpu);
mutex_unlock(&pool->attach_mutex);
}
/* update NUMA affinity of unbound workqueues */
list_for_each_entry(wq, &workqueues, list)
wq_update_unbound_numa(wq, cpu, true);
mutex_unlock(&wq_pool_mutex);
break;
mutex_unlock(&pool->attach_mutex);
}
return NOTIFY_OK;
/* update NUMA affinity of unbound workqueues */
list_for_each_entry(wq, &workqueues, list)
wq_update_unbound_numa(wq, cpu, true);
mutex_unlock(&wq_pool_mutex);
return 0;
}
/*
* Workqueues should be brought down after normal priority CPU notifiers.
* This will be registered as low priority CPU notifier.
*/
static int workqueue_cpu_down_callback(struct notifier_block *nfb,
unsigned long action,
void *hcpu)
int workqueue_offline_cpu(unsigned int cpu)
{
int cpu = (unsigned long)hcpu;
struct work_struct unbind_work;
struct workqueue_struct *wq;
switch (action & ~CPU_TASKS_FROZEN) {
case CPU_DOWN_PREPARE:
/* unbinding per-cpu workers should happen on the local CPU */
INIT_WORK_ONSTACK(&unbind_work, wq_unbind_fn);
queue_work_on(cpu, system_highpri_wq, &unbind_work);
/* unbinding per-cpu workers should happen on the local CPU */
INIT_WORK_ONSTACK(&unbind_work, wq_unbind_fn);
queue_work_on(cpu, system_highpri_wq, &unbind_work);
/* update NUMA affinity of unbound workqueues */
mutex_lock(&wq_pool_mutex);
list_for_each_entry(wq, &workqueues, list)
wq_update_unbound_numa(wq, cpu, false);
mutex_unlock(&wq_pool_mutex);
/* update NUMA affinity of unbound workqueues */
mutex_lock(&wq_pool_mutex);
list_for_each_entry(wq, &workqueues, list)
wq_update_unbound_numa(wq, cpu, false);
mutex_unlock(&wq_pool_mutex);
/* wait for per-cpu unbinding to finish */
flush_work(&unbind_work);
destroy_work_on_stack(&unbind_work);
break;
}
return NOTIFY_OK;
/* wait for per-cpu unbinding to finish */
flush_work(&unbind_work);
destroy_work_on_stack(&unbind_work);
return 0;
}
#ifdef CONFIG_SMP
@ -5486,9 +5467,6 @@ static int __init init_workqueues(void)
pwq_cache = KMEM_CACHE(pool_workqueue, SLAB_PANIC);
cpu_notifier(workqueue_cpu_up_callback, CPU_PRI_WORKQUEUE_UP);
hotcpu_notifier(workqueue_cpu_down_callback, CPU_PRI_WORKQUEUE_DOWN);
wq_numa_init();
/* initialize CPU pools */

View File

@ -405,26 +405,17 @@ u64 kvm_arm_timer_get_reg(struct kvm_vcpu *vcpu, u64 regid)
return (u64)-1;
}
static int kvm_timer_cpu_notify(struct notifier_block *self,
unsigned long action, void *cpu)
static int kvm_timer_starting_cpu(unsigned int cpu)
{
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
kvm_timer_init_interrupt(NULL);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
disable_percpu_irq(host_vtimer_irq);
break;
}
return NOTIFY_OK;
kvm_timer_init_interrupt(NULL);
return 0;
}
static struct notifier_block kvm_timer_cpu_nb = {
.notifier_call = kvm_timer_cpu_notify,
};
static int kvm_timer_dying_cpu(unsigned int cpu)
{
disable_percpu_irq(host_vtimer_irq);
return 0;
}
int kvm_timer_hyp_init(void)
{
@ -449,12 +440,6 @@ int kvm_timer_hyp_init(void)
goto out;
}
err = __register_cpu_notifier(&kvm_timer_cpu_nb);
if (err) {
kvm_err("Cannot register timer CPU notifier\n");
goto out_free;
}
wqueue = create_singlethread_workqueue("kvm_arch_timer");
if (!wqueue) {
err = -ENOMEM;
@ -462,8 +447,10 @@ int kvm_timer_hyp_init(void)
}
kvm_info("virtual timer IRQ%d\n", host_vtimer_irq);
on_each_cpu(kvm_timer_init_interrupt, NULL, 1);
cpuhp_setup_state(CPUHP_AP_KVM_ARM_TIMER_STARTING,
"AP_KVM_ARM_TIMER_STARTING", kvm_timer_starting_cpu,
kvm_timer_dying_cpu);
goto out;
out_free:
free_percpu_irq(host_vtimer_irq, kvm_get_running_vcpus());

View File

@ -2326,32 +2326,18 @@ int vgic_has_attr_regs(const struct vgic_io_range *ranges, phys_addr_t offset)
return -ENXIO;
}
static void vgic_init_maintenance_interrupt(void *info)
static int vgic_starting_cpu(unsigned int cpu)
{
enable_percpu_irq(vgic->maint_irq, 0);
return 0;
}
static int vgic_cpu_notify(struct notifier_block *self,
unsigned long action, void *cpu)
static int vgic_dying_cpu(unsigned int cpu)
{
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
vgic_init_maintenance_interrupt(NULL);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
disable_percpu_irq(vgic->maint_irq);
break;
}
return NOTIFY_OK;
disable_percpu_irq(vgic->maint_irq);
return 0;
}
static struct notifier_block vgic_cpu_nb = {
.notifier_call = vgic_cpu_notify,
};
static int kvm_vgic_probe(void)
{
const struct gic_kvm_info *gic_kvm_info;
@ -2392,19 +2378,10 @@ int kvm_vgic_hyp_init(void)
return ret;
}
ret = __register_cpu_notifier(&vgic_cpu_nb);
if (ret) {
kvm_err("Cannot register vgic CPU notifier\n");
goto out_free_irq;
}
on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
cpuhp_setup_state(CPUHP_AP_KVM_ARM_VGIC_STARTING,
"AP_KVM_ARM_VGIC_STARTING", vgic_starting_cpu,
vgic_dying_cpu);
return 0;
out_free_irq:
free_percpu_irq(vgic->maint_irq, kvm_get_running_vcpus());
return ret;
}
int kvm_irq_map_gsi(struct kvm *kvm,

View File

@ -353,32 +353,19 @@ int kvm_vgic_map_resources(struct kvm *kvm)
/* GENERIC PROBE */
static void vgic_init_maintenance_interrupt(void *info)
static int vgic_init_cpu_starting(unsigned int cpu)
{
enable_percpu_irq(kvm_vgic_global_state.maint_irq, 0);
return 0;
}
static int vgic_cpu_notify(struct notifier_block *self,
unsigned long action, void *cpu)
static int vgic_init_cpu_dying(unsigned int cpu)
{
switch (action) {
case CPU_STARTING:
case CPU_STARTING_FROZEN:
vgic_init_maintenance_interrupt(NULL);
break;
case CPU_DYING:
case CPU_DYING_FROZEN:
disable_percpu_irq(kvm_vgic_global_state.maint_irq);
break;
}
return NOTIFY_OK;
disable_percpu_irq(kvm_vgic_global_state.maint_irq);
return 0;
}
static struct notifier_block vgic_cpu_nb = {
.notifier_call = vgic_cpu_notify,
};
static irqreturn_t vgic_maintenance_handler(int irq, void *data)
{
/*
@ -434,14 +421,14 @@ int kvm_vgic_hyp_init(void)
return ret;
}
ret = __register_cpu_notifier(&vgic_cpu_nb);
ret = cpuhp_setup_state(CPUHP_AP_KVM_ARM_VGIC_INIT_STARTING,
"AP_KVM_ARM_VGIC_INIT_STARTING",
vgic_init_cpu_starting, vgic_init_cpu_dying);
if (ret) {
kvm_err("Cannot register vgic CPU notifier\n");
goto out_free_irq;
}
on_each_cpu(vgic_init_maintenance_interrupt, NULL, 1);
kvm_info("vgic interrupt IRQ%d\n", kvm_vgic_global_state.maint_irq);
return 0;

View File

@ -3155,12 +3155,13 @@ static void hardware_enable_nolock(void *junk)
}
}
static void hardware_enable(void)
static int kvm_starting_cpu(unsigned int cpu)
{
raw_spin_lock(&kvm_count_lock);
if (kvm_usage_count)
hardware_enable_nolock(NULL);
raw_spin_unlock(&kvm_count_lock);
return 0;
}
static void hardware_disable_nolock(void *junk)
@ -3173,12 +3174,13 @@ static void hardware_disable_nolock(void *junk)
kvm_arch_hardware_disable();
}
static void hardware_disable(void)
static int kvm_dying_cpu(unsigned int cpu)
{
raw_spin_lock(&kvm_count_lock);
if (kvm_usage_count)
hardware_disable_nolock(NULL);
raw_spin_unlock(&kvm_count_lock);
return 0;
}
static void hardware_disable_all_nolock(void)
@ -3219,21 +3221,6 @@ static int hardware_enable_all(void)
return r;
}
static int kvm_cpu_hotplug(struct notifier_block *notifier, unsigned long val,
void *v)
{
val &= ~CPU_TASKS_FROZEN;
switch (val) {
case CPU_DYING:
hardware_disable();
break;
case CPU_STARTING:
hardware_enable();
break;
}
return NOTIFY_OK;
}
static int kvm_reboot(struct notifier_block *notifier, unsigned long val,
void *v)
{
@ -3500,10 +3487,6 @@ int kvm_io_bus_unregister_dev(struct kvm *kvm, enum kvm_bus bus_idx,
return r;
}
static struct notifier_block kvm_cpu_notifier = {
.notifier_call = kvm_cpu_hotplug,
};
static int kvm_debugfs_open(struct inode *inode, struct file *file,
int (*get)(void *, u64 *), int (*set)(void *, u64),
const char *fmt)
@ -3754,7 +3737,8 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
goto out_free_1;
}
r = register_cpu_notifier(&kvm_cpu_notifier);
r = cpuhp_setup_state_nocalls(CPUHP_AP_KVM_STARTING, "AP_KVM_STARTING",
kvm_starting_cpu, kvm_dying_cpu);
if (r)
goto out_free_2;
register_reboot_notifier(&kvm_reboot_notifier);
@ -3808,7 +3792,7 @@ int kvm_init(void *opaque, unsigned vcpu_size, unsigned vcpu_align,
kmem_cache_destroy(kvm_vcpu_cache);
out_free_3:
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
cpuhp_remove_state_nocalls(CPUHP_AP_KVM_STARTING);
out_free_2:
out_free_1:
kvm_arch_hardware_unsetup();
@ -3831,7 +3815,7 @@ void kvm_exit(void)
kvm_async_pf_deinit();
unregister_syscore_ops(&kvm_syscore_ops);
unregister_reboot_notifier(&kvm_reboot_notifier);
unregister_cpu_notifier(&kvm_cpu_notifier);
cpuhp_remove_state_nocalls(CPUHP_AP_KVM_STARTING);
on_each_cpu(hardware_disable_nolock, NULL, 1);
kvm_arch_hardware_unsetup();
kvm_arch_exit();