mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
CPU (hotplug) updates:
- Support for locked CSD objects in smp_call_function_single_async() which allows to simplify callsites in the scheduler core and MIPS - Treewide consolidation of CPU hotplug functions which ensures the consistency between the sysfs interface and kernel state. The low level functions cpu_up/down() are now confined to the core code and not longer accessible from random code. -----BEGIN PGP SIGNATURE----- iQJHBAABCgAxFiEEQp8+kY+LLUocC4bMphj1TA10mKEFAl6B9VQTHHRnbHhAbGlu dXRyb25peC5kZQAKCRCmGPVMDXSYodCyD/0WFYAe7LkOfNjkbLa0IeuyLjF9rnCi ilcSXMLpaVwwoQvm7MopwkXUDdmEIyeJ0B641j3mC3AKCRap4+O36H2IEg2byrj7 twOvQNCfxpVVmCCD11FTH9aQa74LEB6AikTgjevhrRWj6eHsal7c2Ak26AzCgrt+ 0eEkOAOWJbLAlbIiPdHlCZ3TMldcs3gg+lRSYd5QCGQVkZFnwpXzyOvpyJEUGGbb R/JuvwJoLhRMiYAJDILoQQQg/J07ODuivse/R8PWaH2djkn+2NyRGrD794PhyyOg QoTU0ZrYD3Z48ACXv+N3jLM7wXMcFzjYtr1vW1E3O/YGA7GVIC6XHGbMQ7tEihY0 ajtwq8DcnpKtuouviYnf7NuKgqdmJXkaZjz3Gms6n8nLXqqSVwuQELWV2CXkxNe6 9kgnnKK+xXMOGI4TUhN8bejvkXqRCmKMeQJcWyf+7RA9UIhAJw5o7WGo8gXfQWUx tazCqDy/inYjqGxckW615fhi2zHfemlYTbSzIGOuMB1TEPKFcrgYAii/VMsYHQVZ 5amkYUXGQ5brlCOzOn38lzp5OkALBnFzD7xgvOcQgWT3ynVpdqADfBytXiEEHh4J KSkSgSSRcS58397nIxnDcJgJouHLvAWYyPZ4UC6mfynuQIic31qMHGVqwdbEKMY3 4M5dGgqIfOBgYw== =jwCg -----END PGP SIGNATURE----- Merge tag 'smp-core-2020-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip Pull core SMP updates from Thomas Gleixner: "CPU (hotplug) updates: - Support for locked CSD objects in smp_call_function_single_async() which allows to simplify callsites in the scheduler core and MIPS - Treewide consolidation of CPU hotplug functions which ensures the consistency between the sysfs interface and kernel state. The low level functions cpu_up/down() are now confined to the core code and not longer accessible from random code" * tag 'smp-core-2020-03-30' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (22 commits) cpu/hotplug: Ignore pm_wakeup_pending() for disable_nonboot_cpus() cpu/hotplug: Hide cpu_up/down() cpu/hotplug: Move bringup of secondary CPUs out of smp_init() torture: Replace cpu_up/down() with add/remove_cpu() firmware: psci: Replace cpu_up/down() with add/remove_cpu() xen/cpuhotplug: Replace cpu_up/down() with device_online/offline() parisc: Replace cpu_up/down() with add/remove_cpu() sparc: Replace cpu_up/down() with add/remove_cpu() powerpc: Replace cpu_up/down() with add/remove_cpu() x86/smp: Replace cpu_up/down() with add/remove_cpu() arm64: hibernate: Use bringup_hibernate_cpu() cpu/hotplug: Provide bringup_hibernate_cpu() arm64: Use reboot_cpu instead of hardconding it to 0 arm64: Don't use disable_nonboot_cpus() ARM: Use reboot_cpu instead of hardcoding it to 0 ARM: Don't use disable_nonboot_cpus() ia64: Replace cpu_down() with smp_shutdown_nonboot_cpus() cpu/hotplug: Create a new function to shutdown nonboot cpus cpu/hotplug: Add new {add,remove}_cpu() functions sched/core: Remove rq.hrtick_csd_pending ...
This commit is contained in:
commit
992a1a3b45
@ -88,11 +88,11 @@ void soft_restart(unsigned long addr)
|
|||||||
* to execute e.g. a RAM-based pin loop is not sufficient. This allows the
|
* to execute e.g. a RAM-based pin loop is not sufficient. This allows the
|
||||||
* kexec'd kernel to use any and all RAM as it sees fit, without having to
|
* kexec'd kernel to use any and all RAM as it sees fit, without having to
|
||||||
* avoid any code or data used by any SW CPU pin loop. The CPU hotplug
|
* avoid any code or data used by any SW CPU pin loop. The CPU hotplug
|
||||||
* functionality embodied in disable_nonboot_cpus() to achieve this.
|
* functionality embodied in smp_shutdown_nonboot_cpus() to achieve this.
|
||||||
*/
|
*/
|
||||||
void machine_shutdown(void)
|
void machine_shutdown(void)
|
||||||
{
|
{
|
||||||
disable_nonboot_cpus();
|
smp_shutdown_nonboot_cpus(reboot_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -166,14 +166,11 @@ int arch_hibernation_header_restore(void *addr)
|
|||||||
sleep_cpu = -EINVAL;
|
sleep_cpu = -EINVAL;
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
if (!cpu_online(sleep_cpu)) {
|
|
||||||
pr_info("Hibernated on a CPU that is offline! Bringing CPU up.\n");
|
ret = bringup_hibernate_cpu(sleep_cpu);
|
||||||
ret = cpu_up(sleep_cpu);
|
if (ret) {
|
||||||
if (ret) {
|
sleep_cpu = -EINVAL;
|
||||||
pr_err("Failed to bring hibernate-CPU up!\n");
|
return ret;
|
||||||
sleep_cpu = -EINVAL;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
resume_hdr = *hdr;
|
resume_hdr = *hdr;
|
||||||
|
@ -141,11 +141,11 @@ void arch_cpu_idle_dead(void)
|
|||||||
* to execute e.g. a RAM-based pin loop is not sufficient. This allows the
|
* to execute e.g. a RAM-based pin loop is not sufficient. This allows the
|
||||||
* kexec'd kernel to use any and all RAM as it sees fit, without having to
|
* kexec'd kernel to use any and all RAM as it sees fit, without having to
|
||||||
* avoid any code or data used by any SW CPU pin loop. The CPU hotplug
|
* avoid any code or data used by any SW CPU pin loop. The CPU hotplug
|
||||||
* functionality embodied in disable_nonboot_cpus() to achieve this.
|
* functionality embodied in smpt_shutdown_nonboot_cpus() to achieve this.
|
||||||
*/
|
*/
|
||||||
void machine_shutdown(void)
|
void machine_shutdown(void)
|
||||||
{
|
{
|
||||||
disable_nonboot_cpus();
|
smp_shutdown_nonboot_cpus(reboot_cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -646,14 +646,8 @@ cpu_halt (void)
|
|||||||
|
|
||||||
void machine_shutdown(void)
|
void machine_shutdown(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_HOTPLUG_CPU
|
smp_shutdown_nonboot_cpus(reboot_cpu);
|
||||||
int cpu;
|
|
||||||
|
|
||||||
for_each_online_cpu(cpu) {
|
|
||||||
if (cpu != smp_processor_id())
|
|
||||||
cpu_down(cpu);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#ifdef CONFIG_KEXEC
|
#ifdef CONFIG_KEXEC
|
||||||
kexec_disable_iosapic();
|
kexec_disable_iosapic();
|
||||||
#endif
|
#endif
|
||||||
|
@ -696,29 +696,22 @@ EXPORT_SYMBOL(flush_tlb_one);
|
|||||||
|
|
||||||
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
|
||||||
static DEFINE_PER_CPU(atomic_t, tick_broadcast_count);
|
|
||||||
static DEFINE_PER_CPU(call_single_data_t, tick_broadcast_csd);
|
static DEFINE_PER_CPU(call_single_data_t, tick_broadcast_csd);
|
||||||
|
|
||||||
void tick_broadcast(const struct cpumask *mask)
|
void tick_broadcast(const struct cpumask *mask)
|
||||||
{
|
{
|
||||||
atomic_t *count;
|
|
||||||
call_single_data_t *csd;
|
call_single_data_t *csd;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
|
||||||
for_each_cpu(cpu, mask) {
|
for_each_cpu(cpu, mask) {
|
||||||
count = &per_cpu(tick_broadcast_count, cpu);
|
|
||||||
csd = &per_cpu(tick_broadcast_csd, cpu);
|
csd = &per_cpu(tick_broadcast_csd, cpu);
|
||||||
|
smp_call_function_single_async(cpu, csd);
|
||||||
if (atomic_inc_return(count) == 1)
|
|
||||||
smp_call_function_single_async(cpu, csd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tick_broadcast_callee(void *info)
|
static void tick_broadcast_callee(void *info)
|
||||||
{
|
{
|
||||||
int cpu = smp_processor_id();
|
|
||||||
tick_receive_broadcast();
|
tick_receive_broadcast();
|
||||||
atomic_set(&per_cpu(tick_broadcast_count, cpu), 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int __init tick_broadcast_init(void)
|
static int __init tick_broadcast_init(void)
|
||||||
|
@ -212,7 +212,7 @@ static int __init processor_probe(struct parisc_device *dev)
|
|||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
if (cpuid) {
|
if (cpuid) {
|
||||||
set_cpu_present(cpuid, true);
|
set_cpu_present(cpuid, true);
|
||||||
cpu_up(cpuid);
|
add_cpu(cpuid);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -212,7 +212,7 @@ static void wake_offline_cpus(void)
|
|||||||
if (!cpu_online(cpu)) {
|
if (!cpu_online(cpu)) {
|
||||||
printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
|
printk(KERN_INFO "kexec: Waking offline cpu %d.\n",
|
||||||
cpu);
|
cpu);
|
||||||
WARN_ON(cpu_up(cpu));
|
WARN_ON(add_cpu(cpu));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -555,7 +555,7 @@ static int dr_cpu_configure(struct ds_info *dp, struct ds_cap_state *cp,
|
|||||||
|
|
||||||
printk(KERN_INFO "ds-%llu: Starting cpu %d...\n",
|
printk(KERN_INFO "ds-%llu: Starting cpu %d...\n",
|
||||||
dp->id, cpu);
|
dp->id, cpu);
|
||||||
err = cpu_up(cpu);
|
err = add_cpu(cpu);
|
||||||
if (err) {
|
if (err) {
|
||||||
__u32 res = DR_CPU_RES_FAILURE;
|
__u32 res = DR_CPU_RES_FAILURE;
|
||||||
__u32 stat = DR_CPU_STAT_UNCONFIGURED;
|
__u32 stat = DR_CPU_STAT_UNCONFIGURED;
|
||||||
@ -611,7 +611,7 @@ static int dr_cpu_unconfigure(struct ds_info *dp,
|
|||||||
|
|
||||||
printk(KERN_INFO "ds-%llu: Shutting down cpu %d...\n",
|
printk(KERN_INFO "ds-%llu: Shutting down cpu %d...\n",
|
||||||
dp->id, cpu);
|
dp->id, cpu);
|
||||||
err = cpu_down(cpu);
|
err = remove_cpu(cpu);
|
||||||
if (err)
|
if (err)
|
||||||
dr_cpu_mark(resp, cpu, ncpus,
|
dr_cpu_mark(resp, cpu, ncpus,
|
||||||
DR_CPU_RES_FAILURE,
|
DR_CPU_RES_FAILURE,
|
||||||
|
@ -59,39 +59,29 @@ __setup("cpu0_hotplug", enable_cpu0_hotplug);
|
|||||||
*/
|
*/
|
||||||
int _debug_hotplug_cpu(int cpu, int action)
|
int _debug_hotplug_cpu(int cpu, int action)
|
||||||
{
|
{
|
||||||
struct device *dev = get_cpu_device(cpu);
|
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!cpu_is_hotpluggable(cpu))
|
if (!cpu_is_hotpluggable(cpu))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
lock_device_hotplug();
|
|
||||||
|
|
||||||
switch (action) {
|
switch (action) {
|
||||||
case 0:
|
case 0:
|
||||||
ret = cpu_down(cpu);
|
ret = remove_cpu(cpu);
|
||||||
if (!ret) {
|
if (!ret)
|
||||||
pr_info("DEBUG_HOTPLUG_CPU0: CPU %u is now offline\n", cpu);
|
pr_info("DEBUG_HOTPLUG_CPU0: CPU %u is now offline\n", cpu);
|
||||||
dev->offline = true;
|
else
|
||||||
kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
|
|
||||||
} else
|
|
||||||
pr_debug("Can't offline CPU%d.\n", cpu);
|
pr_debug("Can't offline CPU%d.\n", cpu);
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
ret = cpu_up(cpu);
|
ret = add_cpu(cpu);
|
||||||
if (!ret) {
|
if (ret)
|
||||||
dev->offline = false;
|
|
||||||
kobject_uevent(&dev->kobj, KOBJ_ONLINE);
|
|
||||||
} else {
|
|
||||||
pr_debug("Can't online CPU%d.\n", cpu);
|
pr_debug("Can't online CPU%d.\n", cpu);
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
unlock_device_hotplug();
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ static void enter_uniprocessor(void)
|
|||||||
put_online_cpus();
|
put_online_cpus();
|
||||||
|
|
||||||
for_each_cpu(cpu, downed_cpus) {
|
for_each_cpu(cpu, downed_cpus) {
|
||||||
err = cpu_down(cpu);
|
err = remove_cpu(cpu);
|
||||||
if (!err)
|
if (!err)
|
||||||
pr_info("CPU%d is down.\n", cpu);
|
pr_info("CPU%d is down.\n", cpu);
|
||||||
else
|
else
|
||||||
@ -406,7 +406,7 @@ static void leave_uniprocessor(void)
|
|||||||
return;
|
return;
|
||||||
pr_notice("Re-enabling CPUs...\n");
|
pr_notice("Re-enabling CPUs...\n");
|
||||||
for_each_cpu(cpu, downed_cpus) {
|
for_each_cpu(cpu, downed_cpus) {
|
||||||
err = cpu_up(cpu);
|
err = add_cpu(cpu);
|
||||||
if (!err)
|
if (!err)
|
||||||
pr_info("enabled CPU%d.\n", cpu);
|
pr_info("enabled CPU%d.\n", cpu);
|
||||||
else
|
else
|
||||||
|
@ -132,7 +132,7 @@ void __init xen_smp_cpus_done(unsigned int max_cpus)
|
|||||||
if (xen_vcpu_nr(cpu) < MAX_VIRT_CPUS)
|
if (xen_vcpu_nr(cpu) < MAX_VIRT_CPUS)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
rc = cpu_down(cpu);
|
rc = remove_cpu(cpu);
|
||||||
|
|
||||||
if (rc == 0) {
|
if (rc == 0) {
|
||||||
/*
|
/*
|
||||||
|
@ -55,7 +55,7 @@ static int cpu_subsys_online(struct device *dev)
|
|||||||
if (from_nid == NUMA_NO_NODE)
|
if (from_nid == NUMA_NO_NODE)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
ret = cpu_up(cpuid);
|
ret = cpu_device_up(dev);
|
||||||
/*
|
/*
|
||||||
* When hot adding memory to memoryless node and enabling a cpu
|
* When hot adding memory to memoryless node and enabling a cpu
|
||||||
* on the node, node number of the cpu may internally change.
|
* on the node, node number of the cpu may internally change.
|
||||||
@ -69,7 +69,7 @@ static int cpu_subsys_online(struct device *dev)
|
|||||||
|
|
||||||
static int cpu_subsys_offline(struct device *dev)
|
static int cpu_subsys_offline(struct device *dev)
|
||||||
{
|
{
|
||||||
return cpu_down(dev->id);
|
return cpu_device_down(dev);
|
||||||
}
|
}
|
||||||
|
|
||||||
void unregister_cpu(struct cpu *cpu)
|
void unregister_cpu(struct cpu *cpu)
|
||||||
|
@ -84,7 +84,7 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus,
|
|||||||
|
|
||||||
/* Try to power down all CPUs in the mask. */
|
/* Try to power down all CPUs in the mask. */
|
||||||
for_each_cpu(cpu, cpus) {
|
for_each_cpu(cpu, cpus) {
|
||||||
int ret = cpu_down(cpu);
|
int ret = remove_cpu(cpu);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* cpu_down() checks the number of online CPUs before the TOS
|
* cpu_down() checks the number of online CPUs before the TOS
|
||||||
@ -116,7 +116,7 @@ static unsigned int down_and_up_cpus(const struct cpumask *cpus,
|
|||||||
|
|
||||||
/* Try to power up all the CPUs that have been offlined. */
|
/* Try to power up all the CPUs that have been offlined. */
|
||||||
for_each_cpu(cpu, offlined_cpus) {
|
for_each_cpu(cpu, offlined_cpus) {
|
||||||
int ret = cpu_up(cpu);
|
int ret = add_cpu(cpu);
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
pr_err("Error occurred (%d) while trying "
|
pr_err("Error occurred (%d) while trying "
|
||||||
|
@ -94,7 +94,7 @@ static int setup_cpu_watcher(struct notifier_block *notifier,
|
|||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
if (vcpu_online(cpu) == 0) {
|
if (vcpu_online(cpu) == 0) {
|
||||||
(void)cpu_down(cpu);
|
device_offline(get_cpu_device(cpu));
|
||||||
set_cpu_present(cpu, false);
|
set_cpu_present(cpu, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,10 +88,13 @@ extern ssize_t arch_cpu_release(const char *, size_t);
|
|||||||
|
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
extern bool cpuhp_tasks_frozen;
|
extern bool cpuhp_tasks_frozen;
|
||||||
int cpu_up(unsigned int cpu);
|
int add_cpu(unsigned int cpu);
|
||||||
|
int cpu_device_up(struct device *dev);
|
||||||
void notify_cpu_starting(unsigned int cpu);
|
void notify_cpu_starting(unsigned int cpu);
|
||||||
extern void cpu_maps_update_begin(void);
|
extern void cpu_maps_update_begin(void);
|
||||||
extern void cpu_maps_update_done(void);
|
extern void cpu_maps_update_done(void);
|
||||||
|
int bringup_hibernate_cpu(unsigned int sleep_cpu);
|
||||||
|
void bringup_nonboot_cpus(unsigned int setup_max_cpus);
|
||||||
|
|
||||||
#else /* CONFIG_SMP */
|
#else /* CONFIG_SMP */
|
||||||
#define cpuhp_tasks_frozen 0
|
#define cpuhp_tasks_frozen 0
|
||||||
@ -117,7 +120,9 @@ extern void lockdep_assert_cpus_held(void);
|
|||||||
extern void cpu_hotplug_disable(void);
|
extern void cpu_hotplug_disable(void);
|
||||||
extern void cpu_hotplug_enable(void);
|
extern void cpu_hotplug_enable(void);
|
||||||
void clear_tasks_mm_cpumask(int cpu);
|
void clear_tasks_mm_cpumask(int cpu);
|
||||||
int cpu_down(unsigned int cpu);
|
int remove_cpu(unsigned int cpu);
|
||||||
|
int cpu_device_down(struct device *dev);
|
||||||
|
extern void smp_shutdown_nonboot_cpus(unsigned int primary_cpu);
|
||||||
|
|
||||||
#else /* CONFIG_HOTPLUG_CPU */
|
#else /* CONFIG_HOTPLUG_CPU */
|
||||||
|
|
||||||
@ -129,6 +134,7 @@ static inline int cpus_read_trylock(void) { return true; }
|
|||||||
static inline void lockdep_assert_cpus_held(void) { }
|
static inline void lockdep_assert_cpus_held(void) { }
|
||||||
static inline void cpu_hotplug_disable(void) { }
|
static inline void cpu_hotplug_disable(void) { }
|
||||||
static inline void cpu_hotplug_enable(void) { }
|
static inline void cpu_hotplug_enable(void) { }
|
||||||
|
static inline void smp_shutdown_nonboot_cpus(unsigned int primary_cpu) { }
|
||||||
#endif /* !CONFIG_HOTPLUG_CPU */
|
#endif /* !CONFIG_HOTPLUG_CPU */
|
||||||
|
|
||||||
/* Wrappers which go away once all code is converted */
|
/* Wrappers which go away once all code is converted */
|
||||||
@ -138,12 +144,18 @@ static inline void get_online_cpus(void) { cpus_read_lock(); }
|
|||||||
static inline void put_online_cpus(void) { cpus_read_unlock(); }
|
static inline void put_online_cpus(void) { cpus_read_unlock(); }
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP_SMP
|
#ifdef CONFIG_PM_SLEEP_SMP
|
||||||
extern int freeze_secondary_cpus(int primary);
|
int __freeze_secondary_cpus(int primary, bool suspend);
|
||||||
|
static inline int freeze_secondary_cpus(int primary)
|
||||||
|
{
|
||||||
|
return __freeze_secondary_cpus(primary, true);
|
||||||
|
}
|
||||||
|
|
||||||
static inline int disable_nonboot_cpus(void)
|
static inline int disable_nonboot_cpus(void)
|
||||||
{
|
{
|
||||||
return freeze_secondary_cpus(0);
|
return __freeze_secondary_cpus(0, false);
|
||||||
}
|
}
|
||||||
extern void enable_nonboot_cpus(void);
|
|
||||||
|
void enable_nonboot_cpus(void);
|
||||||
|
|
||||||
static inline int suspend_disable_secondary_cpus(void)
|
static inline int suspend_disable_secondary_cpus(void)
|
||||||
{
|
{
|
||||||
|
143
kernel/cpu.c
143
kernel/cpu.c
@ -1041,7 +1041,7 @@ static int cpu_down_maps_locked(unsigned int cpu, enum cpuhp_state target)
|
|||||||
return _cpu_down(cpu, 0, target);
|
return _cpu_down(cpu, 0, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cpu_down(unsigned int cpu, enum cpuhp_state target)
|
static int cpu_down(unsigned int cpu, enum cpuhp_state target)
|
||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
@ -1051,11 +1051,72 @@ static int do_cpu_down(unsigned int cpu, enum cpuhp_state target)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_down(unsigned int cpu)
|
/**
|
||||||
|
* cpu_device_down - Bring down a cpu device
|
||||||
|
* @dev: Pointer to the cpu device to offline
|
||||||
|
*
|
||||||
|
* This function is meant to be used by device core cpu subsystem only.
|
||||||
|
*
|
||||||
|
* Other subsystems should use remove_cpu() instead.
|
||||||
|
*/
|
||||||
|
int cpu_device_down(struct device *dev)
|
||||||
{
|
{
|
||||||
return do_cpu_down(cpu, CPUHP_OFFLINE);
|
return cpu_down(dev->id, CPUHP_OFFLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int remove_cpu(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lock_device_hotplug();
|
||||||
|
ret = device_offline(get_cpu_device(cpu));
|
||||||
|
unlock_device_hotplug();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(remove_cpu);
|
||||||
|
|
||||||
|
void smp_shutdown_nonboot_cpus(unsigned int primary_cpu)
|
||||||
|
{
|
||||||
|
unsigned int cpu;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
cpu_maps_update_begin();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make certain the cpu I'm about to reboot on is online.
|
||||||
|
*
|
||||||
|
* This is inline to what migrate_to_reboot_cpu() already do.
|
||||||
|
*/
|
||||||
|
if (!cpu_online(primary_cpu))
|
||||||
|
primary_cpu = cpumask_first(cpu_online_mask);
|
||||||
|
|
||||||
|
for_each_online_cpu(cpu) {
|
||||||
|
if (cpu == primary_cpu)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
error = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);
|
||||||
|
if (error) {
|
||||||
|
pr_err("Failed to offline CPU%d - error=%d",
|
||||||
|
cpu, error);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ensure all but the reboot CPU are offline.
|
||||||
|
*/
|
||||||
|
BUG_ON(num_online_cpus() > 1);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Make sure the CPUs won't be enabled by someone else after this
|
||||||
|
* point. Kexec will reboot to a new kernel shortly resetting
|
||||||
|
* everything along the way.
|
||||||
|
*/
|
||||||
|
cpu_hotplug_disabled++;
|
||||||
|
|
||||||
|
cpu_maps_update_done();
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(cpu_down);
|
|
||||||
|
|
||||||
#else
|
#else
|
||||||
#define takedown_cpu NULL
|
#define takedown_cpu NULL
|
||||||
@ -1124,8 +1185,8 @@ static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The caller of do_cpu_up might have raced with another
|
* The caller of cpu_up() might have raced with another
|
||||||
* caller. Ignore it for now.
|
* caller. Nothing to do.
|
||||||
*/
|
*/
|
||||||
if (st->state >= target)
|
if (st->state >= target)
|
||||||
goto out;
|
goto out;
|
||||||
@ -1169,7 +1230,7 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int do_cpu_up(unsigned int cpu, enum cpuhp_state target)
|
static int cpu_up(unsigned int cpu, enum cpuhp_state target)
|
||||||
{
|
{
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@ -1203,16 +1264,70 @@ out:
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cpu_up(unsigned int cpu)
|
/**
|
||||||
|
* cpu_device_up - Bring up a cpu device
|
||||||
|
* @dev: Pointer to the cpu device to online
|
||||||
|
*
|
||||||
|
* This function is meant to be used by device core cpu subsystem only.
|
||||||
|
*
|
||||||
|
* Other subsystems should use add_cpu() instead.
|
||||||
|
*/
|
||||||
|
int cpu_device_up(struct device *dev)
|
||||||
{
|
{
|
||||||
return do_cpu_up(cpu, CPUHP_ONLINE);
|
return cpu_up(dev->id, CPUHP_ONLINE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int add_cpu(unsigned int cpu)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
lock_device_hotplug();
|
||||||
|
ret = device_online(get_cpu_device(cpu));
|
||||||
|
unlock_device_hotplug();
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(add_cpu);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* bringup_hibernate_cpu - Bring up the CPU that we hibernated on
|
||||||
|
* @sleep_cpu: The cpu we hibernated on and should be brought up.
|
||||||
|
*
|
||||||
|
* On some architectures like arm64, we can hibernate on any CPU, but on
|
||||||
|
* wake up the CPU we hibernated on might be offline as a side effect of
|
||||||
|
* using maxcpus= for example.
|
||||||
|
*/
|
||||||
|
int bringup_hibernate_cpu(unsigned int sleep_cpu)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (!cpu_online(sleep_cpu)) {
|
||||||
|
pr_info("Hibernated on a CPU that is offline! Bringing CPU up.\n");
|
||||||
|
ret = cpu_up(sleep_cpu, CPUHP_ONLINE);
|
||||||
|
if (ret) {
|
||||||
|
pr_err("Failed to bring hibernate-CPU up!\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void bringup_nonboot_cpus(unsigned int setup_max_cpus)
|
||||||
|
{
|
||||||
|
unsigned int cpu;
|
||||||
|
|
||||||
|
for_each_present_cpu(cpu) {
|
||||||
|
if (num_online_cpus() >= setup_max_cpus)
|
||||||
|
break;
|
||||||
|
if (!cpu_online(cpu))
|
||||||
|
cpu_up(cpu, CPUHP_ONLINE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(cpu_up);
|
|
||||||
|
|
||||||
#ifdef CONFIG_PM_SLEEP_SMP
|
#ifdef CONFIG_PM_SLEEP_SMP
|
||||||
static cpumask_var_t frozen_cpus;
|
static cpumask_var_t frozen_cpus;
|
||||||
|
|
||||||
int freeze_secondary_cpus(int primary)
|
int __freeze_secondary_cpus(int primary, bool suspend)
|
||||||
{
|
{
|
||||||
int cpu, error = 0;
|
int cpu, error = 0;
|
||||||
|
|
||||||
@ -1237,7 +1352,7 @@ int freeze_secondary_cpus(int primary)
|
|||||||
if (cpu == primary)
|
if (cpu == primary)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (pm_wakeup_pending()) {
|
if (suspend && pm_wakeup_pending()) {
|
||||||
pr_info("Wakeup pending. Abort CPU freeze\n");
|
pr_info("Wakeup pending. Abort CPU freeze\n");
|
||||||
error = -EBUSY;
|
error = -EBUSY;
|
||||||
break;
|
break;
|
||||||
@ -2028,9 +2143,9 @@ static ssize_t write_cpuhp_target(struct device *dev,
|
|||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (st->state < target)
|
if (st->state < target)
|
||||||
ret = do_cpu_up(dev->id, target);
|
ret = cpu_up(dev->id, target);
|
||||||
else
|
else
|
||||||
ret = do_cpu_down(dev->id, target);
|
ret = cpu_down(dev->id, target);
|
||||||
out:
|
out:
|
||||||
unlock_device_hotplug();
|
unlock_device_hotplug();
|
||||||
return ret ? ret : count;
|
return ret ? ret : count;
|
||||||
|
@ -269,7 +269,6 @@ static void __hrtick_start(void *arg)
|
|||||||
|
|
||||||
rq_lock(rq, &rf);
|
rq_lock(rq, &rf);
|
||||||
__hrtick_restart(rq);
|
__hrtick_restart(rq);
|
||||||
rq->hrtick_csd_pending = 0;
|
|
||||||
rq_unlock(rq, &rf);
|
rq_unlock(rq, &rf);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,12 +292,10 @@ void hrtick_start(struct rq *rq, u64 delay)
|
|||||||
|
|
||||||
hrtimer_set_expires(timer, time);
|
hrtimer_set_expires(timer, time);
|
||||||
|
|
||||||
if (rq == this_rq()) {
|
if (rq == this_rq())
|
||||||
__hrtick_restart(rq);
|
__hrtick_restart(rq);
|
||||||
} else if (!rq->hrtick_csd_pending) {
|
else
|
||||||
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
|
smp_call_function_single_async(cpu_of(rq), &rq->hrtick_csd);
|
||||||
rq->hrtick_csd_pending = 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
@ -322,8 +319,6 @@ void hrtick_start(struct rq *rq, u64 delay)
|
|||||||
static void hrtick_rq_init(struct rq *rq)
|
static void hrtick_rq_init(struct rq *rq)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
rq->hrtick_csd_pending = 0;
|
|
||||||
|
|
||||||
rq->hrtick_csd.flags = 0;
|
rq->hrtick_csd.flags = 0;
|
||||||
rq->hrtick_csd.func = __hrtick_start;
|
rq->hrtick_csd.func = __hrtick_start;
|
||||||
rq->hrtick_csd.info = rq;
|
rq->hrtick_csd.info = rq;
|
||||||
|
@ -992,7 +992,6 @@ struct rq {
|
|||||||
|
|
||||||
#ifdef CONFIG_SCHED_HRTICK
|
#ifdef CONFIG_SCHED_HRTICK
|
||||||
#ifdef CONFIG_SMP
|
#ifdef CONFIG_SMP
|
||||||
int hrtick_csd_pending;
|
|
||||||
call_single_data_t hrtick_csd;
|
call_single_data_t hrtick_csd;
|
||||||
#endif
|
#endif
|
||||||
struct hrtimer hrtick_timer;
|
struct hrtimer hrtick_timer;
|
||||||
|
23
kernel/smp.c
23
kernel/smp.c
@ -329,6 +329,11 @@ EXPORT_SYMBOL(smp_call_function_single);
|
|||||||
* (ie: embedded in an object) and is responsible for synchronizing it
|
* (ie: embedded in an object) and is responsible for synchronizing it
|
||||||
* such that the IPIs performed on the @csd are strictly serialized.
|
* such that the IPIs performed on the @csd are strictly serialized.
|
||||||
*
|
*
|
||||||
|
* If the function is called with one csd which has not yet been
|
||||||
|
* processed by previous call to smp_call_function_single_async(), the
|
||||||
|
* function will return immediately with -EBUSY showing that the csd
|
||||||
|
* object is still in progress.
|
||||||
|
*
|
||||||
* NOTE: Be careful, there is unfortunately no current debugging facility to
|
* NOTE: Be careful, there is unfortunately no current debugging facility to
|
||||||
* validate the correctness of this serialization.
|
* validate the correctness of this serialization.
|
||||||
*/
|
*/
|
||||||
@ -338,14 +343,17 @@ int smp_call_function_single_async(int cpu, call_single_data_t *csd)
|
|||||||
|
|
||||||
preempt_disable();
|
preempt_disable();
|
||||||
|
|
||||||
/* We could deadlock if we have to wait here with interrupts disabled! */
|
if (csd->flags & CSD_FLAG_LOCK) {
|
||||||
if (WARN_ON_ONCE(csd->flags & CSD_FLAG_LOCK))
|
err = -EBUSY;
|
||||||
csd_lock_wait(csd);
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
csd->flags = CSD_FLAG_LOCK;
|
csd->flags = CSD_FLAG_LOCK;
|
||||||
smp_wmb();
|
smp_wmb();
|
||||||
|
|
||||||
err = generic_exec_single(cpu, csd, csd->func, csd->info);
|
err = generic_exec_single(cpu, csd, csd->func, csd->info);
|
||||||
|
|
||||||
|
out:
|
||||||
preempt_enable();
|
preempt_enable();
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@ -589,20 +597,13 @@ void __init setup_nr_cpu_ids(void)
|
|||||||
void __init smp_init(void)
|
void __init smp_init(void)
|
||||||
{
|
{
|
||||||
int num_nodes, num_cpus;
|
int num_nodes, num_cpus;
|
||||||
unsigned int cpu;
|
|
||||||
|
|
||||||
idle_threads_init();
|
idle_threads_init();
|
||||||
cpuhp_threads_init();
|
cpuhp_threads_init();
|
||||||
|
|
||||||
pr_info("Bringing up secondary CPUs ...\n");
|
pr_info("Bringing up secondary CPUs ...\n");
|
||||||
|
|
||||||
/* FIXME: This should be done in userspace --RR */
|
bringup_nonboot_cpus(setup_max_cpus);
|
||||||
for_each_present_cpu(cpu) {
|
|
||||||
if (num_online_cpus() >= setup_max_cpus)
|
|
||||||
break;
|
|
||||||
if (!cpu_online(cpu))
|
|
||||||
cpu_up(cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
num_nodes = num_online_nodes();
|
num_nodes = num_online_nodes();
|
||||||
num_cpus = num_online_cpus();
|
num_cpus = num_online_cpus();
|
||||||
|
@ -101,7 +101,7 @@ bool torture_offline(int cpu, long *n_offl_attempts, long *n_offl_successes,
|
|||||||
torture_type, cpu);
|
torture_type, cpu);
|
||||||
starttime = jiffies;
|
starttime = jiffies;
|
||||||
(*n_offl_attempts)++;
|
(*n_offl_attempts)++;
|
||||||
ret = cpu_down(cpu);
|
ret = remove_cpu(cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
s = "";
|
s = "";
|
||||||
if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
|
if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
|
||||||
@ -159,7 +159,7 @@ bool torture_online(int cpu, long *n_onl_attempts, long *n_onl_successes,
|
|||||||
torture_type, cpu);
|
torture_type, cpu);
|
||||||
starttime = jiffies;
|
starttime = jiffies;
|
||||||
(*n_onl_attempts)++;
|
(*n_onl_attempts)++;
|
||||||
ret = cpu_up(cpu);
|
ret = add_cpu(cpu);
|
||||||
if (ret) {
|
if (ret) {
|
||||||
s = "";
|
s = "";
|
||||||
if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
|
if (!rcu_inkernel_boot_has_ended() && ret == -EBUSY) {
|
||||||
@ -209,17 +209,18 @@ torture_onoff(void *arg)
|
|||||||
for_each_online_cpu(cpu)
|
for_each_online_cpu(cpu)
|
||||||
maxcpu = cpu;
|
maxcpu = cpu;
|
||||||
WARN_ON(maxcpu < 0);
|
WARN_ON(maxcpu < 0);
|
||||||
if (!IS_MODULE(CONFIG_TORTURE_TEST))
|
if (!IS_MODULE(CONFIG_TORTURE_TEST)) {
|
||||||
for_each_possible_cpu(cpu) {
|
for_each_possible_cpu(cpu) {
|
||||||
if (cpu_online(cpu))
|
if (cpu_online(cpu))
|
||||||
continue;
|
continue;
|
||||||
ret = cpu_up(cpu);
|
ret = add_cpu(cpu);
|
||||||
if (ret && verbose) {
|
if (ret && verbose) {
|
||||||
pr_alert("%s" TORTURE_FLAG
|
pr_alert("%s" TORTURE_FLAG
|
||||||
"%s: Initial online %d: errno %d\n",
|
"%s: Initial online %d: errno %d\n",
|
||||||
__func__, torture_type, cpu, ret);
|
__func__, torture_type, cpu, ret);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (maxcpu == 0) {
|
if (maxcpu == 0) {
|
||||||
VERBOSE_TOROUT_STRING("Only one CPU, so CPU-hotplug testing is disabled");
|
VERBOSE_TOROUT_STRING("Only one CPU, so CPU-hotplug testing is disabled");
|
||||||
|
Loading…
Reference in New Issue
Block a user