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 final round of converting the notifier mess to the state machine. The removal of the notifiers and the related infrastructure will happen around rc1, as there are conversions outstanding in other trees. The whole exercise removed about 2000 lines of code in total and in course of the conversion several dozen bugs got fixed. The new mechanism allows to test almost every hotplug step standalone, so usage sites can exercise all transitions extensively. There is more room for improvement, like integrating all the pointlessly different architecture mechanisms of synchronizing, setting cpus online etc into the core code" * 'smp-hotplug-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (60 commits) tracing/rb: Init the CPU mask on allocation soc/fsl/qbman: Convert to hotplug state machine soc/fsl/qbman: Convert to hotplug state machine zram: Convert to hotplug state machine KVM/PPC/Book3S HV: Convert to hotplug state machine arm64/cpuinfo: Convert to hotplug state machine arm64/cpuinfo: Make hotplug notifier symmetric mm/compaction: Convert to hotplug state machine iommu/vt-d: Convert to hotplug state machine mm/zswap: Convert pool to hotplug state machine mm/zswap: Convert dst-mem to hotplug state machine mm/zsmalloc: Convert to hotplug state machine mm/vmstat: Convert to hotplug state machine mm/vmstat: Avoid on each online CPU loops mm/vmstat: Drop get_online_cpus() from init_cpu_node_state/vmstat_cpu_dead() tracing/rb: Convert to hotplug state machine oprofile/nmi timer: Convert to hotplug state machine net/iucv: Use explicit clean up labels in iucv_init() x86/pci/amd-bus: Convert to hotplug state machine x86/oprofile/nmi: Convert to hotplug state machine ...
This commit is contained in:
@@ -1792,6 +1792,14 @@ static void mce_start_timer(unsigned int cpu, struct timer_list *t)
|
||||
add_timer_on(t, cpu);
|
||||
}
|
||||
|
||||
static void __mcheck_cpu_setup_timer(void)
|
||||
{
|
||||
struct timer_list *t = this_cpu_ptr(&mce_timer);
|
||||
unsigned int cpu = smp_processor_id();
|
||||
|
||||
setup_pinned_timer(t, mce_timer_fn, cpu);
|
||||
}
|
||||
|
||||
static void __mcheck_cpu_init_timer(void)
|
||||
{
|
||||
struct timer_list *t = this_cpu_ptr(&mce_timer);
|
||||
@@ -1843,7 +1851,7 @@ void mcheck_cpu_init(struct cpuinfo_x86 *c)
|
||||
__mcheck_cpu_init_generic();
|
||||
__mcheck_cpu_init_vendor(c);
|
||||
__mcheck_cpu_init_clear_banks();
|
||||
__mcheck_cpu_init_timer();
|
||||
__mcheck_cpu_setup_timer();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -2303,8 +2311,6 @@ static struct bus_type mce_subsys = {
|
||||
|
||||
DEFINE_PER_CPU(struct device *, mce_device);
|
||||
|
||||
void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
|
||||
|
||||
static inline struct mce_bank *attr_to_bank(struct device_attribute *attr)
|
||||
{
|
||||
return container_of(attr, struct mce_bank, attr);
|
||||
@@ -2457,6 +2463,10 @@ static int mce_device_create(unsigned int cpu)
|
||||
if (!mce_available(&boot_cpu_data))
|
||||
return -EIO;
|
||||
|
||||
dev = per_cpu(mce_device, cpu);
|
||||
if (dev)
|
||||
return 0;
|
||||
|
||||
dev = kzalloc(sizeof *dev, GFP_KERNEL);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
@@ -2516,28 +2526,25 @@ static void mce_device_remove(unsigned int cpu)
|
||||
}
|
||||
|
||||
/* Make sure there are no machine checks on offlined CPUs. */
|
||||
static void mce_disable_cpu(void *h)
|
||||
static void mce_disable_cpu(void)
|
||||
{
|
||||
unsigned long action = *(unsigned long *)h;
|
||||
|
||||
if (!mce_available(raw_cpu_ptr(&cpu_info)))
|
||||
return;
|
||||
|
||||
if (!(action & CPU_TASKS_FROZEN))
|
||||
if (!cpuhp_tasks_frozen)
|
||||
cmci_clear();
|
||||
|
||||
vendor_disable_error_reporting();
|
||||
}
|
||||
|
||||
static void mce_reenable_cpu(void *h)
|
||||
static void mce_reenable_cpu(void)
|
||||
{
|
||||
unsigned long action = *(unsigned long *)h;
|
||||
int i;
|
||||
|
||||
if (!mce_available(raw_cpu_ptr(&cpu_info)))
|
||||
return;
|
||||
|
||||
if (!(action & CPU_TASKS_FROZEN))
|
||||
if (!cpuhp_tasks_frozen)
|
||||
cmci_reenable();
|
||||
for (i = 0; i < mca_cfg.banks; i++) {
|
||||
struct mce_bank *b = &mce_banks[i];
|
||||
@@ -2547,45 +2554,43 @@ static void mce_reenable_cpu(void *h)
|
||||
}
|
||||
}
|
||||
|
||||
/* Get notified when a cpu comes on/off. Be hotplug friendly. */
|
||||
static int
|
||||
mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
|
||||
static int mce_cpu_dead(unsigned int cpu)
|
||||
{
|
||||
unsigned int cpu = (unsigned long)hcpu;
|
||||
struct timer_list *t = &per_cpu(mce_timer, cpu);
|
||||
mce_intel_hcpu_update(cpu);
|
||||
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
case CPU_ONLINE:
|
||||
mce_device_create(cpu);
|
||||
if (threshold_cpu_callback)
|
||||
threshold_cpu_callback(action, cpu);
|
||||
break;
|
||||
case CPU_DEAD:
|
||||
if (threshold_cpu_callback)
|
||||
threshold_cpu_callback(action, cpu);
|
||||
mce_device_remove(cpu);
|
||||
mce_intel_hcpu_update(cpu);
|
||||
|
||||
/* intentionally ignoring frozen here */
|
||||
if (!(action & CPU_TASKS_FROZEN))
|
||||
cmci_rediscover();
|
||||
break;
|
||||
case CPU_DOWN_PREPARE:
|
||||
smp_call_function_single(cpu, mce_disable_cpu, &action, 1);
|
||||
del_timer_sync(t);
|
||||
break;
|
||||
case CPU_DOWN_FAILED:
|
||||
smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
|
||||
mce_start_timer(cpu, t);
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
/* intentionally ignoring frozen here */
|
||||
if (!cpuhp_tasks_frozen)
|
||||
cmci_rediscover();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block mce_cpu_notifier = {
|
||||
.notifier_call = mce_cpu_callback,
|
||||
};
|
||||
static int mce_cpu_online(unsigned int cpu)
|
||||
{
|
||||
struct timer_list *t = &per_cpu(mce_timer, cpu);
|
||||
int ret;
|
||||
|
||||
mce_device_create(cpu);
|
||||
|
||||
ret = mce_threshold_create_device(cpu);
|
||||
if (ret) {
|
||||
mce_device_remove(cpu);
|
||||
return ret;
|
||||
}
|
||||
mce_reenable_cpu();
|
||||
mce_start_timer(cpu, t);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mce_cpu_pre_down(unsigned int cpu)
|
||||
{
|
||||
struct timer_list *t = &per_cpu(mce_timer, cpu);
|
||||
|
||||
mce_disable_cpu();
|
||||
del_timer_sync(t);
|
||||
mce_threshold_remove_device(cpu);
|
||||
mce_device_remove(cpu);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __init void mce_init_banks(void)
|
||||
{
|
||||
@@ -2607,8 +2612,8 @@ static __init void mce_init_banks(void)
|
||||
|
||||
static __init int mcheck_init_device(void)
|
||||
{
|
||||
enum cpuhp_state hp_online;
|
||||
int err;
|
||||
int i = 0;
|
||||
|
||||
if (!mce_available(&boot_cpu_data)) {
|
||||
err = -EIO;
|
||||
@@ -2626,23 +2631,16 @@ static __init int mcheck_init_device(void)
|
||||
if (err)
|
||||
goto err_out_mem;
|
||||
|
||||
cpu_notifier_register_begin();
|
||||
for_each_online_cpu(i) {
|
||||
err = mce_device_create(i);
|
||||
if (err) {
|
||||
/*
|
||||
* Register notifier anyway (and do not unreg it) so
|
||||
* that we don't leave undeleted timers, see notifier
|
||||
* callback above.
|
||||
*/
|
||||
__register_hotcpu_notifier(&mce_cpu_notifier);
|
||||
cpu_notifier_register_done();
|
||||
goto err_device_create;
|
||||
}
|
||||
}
|
||||
err = cpuhp_setup_state(CPUHP_X86_MCE_DEAD, "x86/mce:dead", NULL,
|
||||
mce_cpu_dead);
|
||||
if (err)
|
||||
goto err_out_mem;
|
||||
|
||||
__register_hotcpu_notifier(&mce_cpu_notifier);
|
||||
cpu_notifier_register_done();
|
||||
err = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/mce:online",
|
||||
mce_cpu_online, mce_cpu_pre_down);
|
||||
if (err < 0)
|
||||
goto err_out_online;
|
||||
hp_online = err;
|
||||
|
||||
register_syscore_ops(&mce_syscore_ops);
|
||||
|
||||
@@ -2655,16 +2653,10 @@ static __init int mcheck_init_device(void)
|
||||
|
||||
err_register:
|
||||
unregister_syscore_ops(&mce_syscore_ops);
|
||||
cpuhp_remove_state(hp_online);
|
||||
|
||||
err_device_create:
|
||||
/*
|
||||
* We didn't keep track of which devices were created above, but
|
||||
* even if we had, the set of online cpus might have changed.
|
||||
* Play safe and remove for every possible cpu, since
|
||||
* mce_device_remove() will do the right thing.
|
||||
*/
|
||||
for_each_possible_cpu(i)
|
||||
mce_device_remove(i);
|
||||
err_out_online:
|
||||
cpuhp_remove_state(CPUHP_X86_MCE_DEAD);
|
||||
|
||||
err_out_mem:
|
||||
free_cpumask_var(mce_device_initialized);
|
||||
|
Reference in New Issue
Block a user