3339 lines · 81.3 KB · C
RawDownload
 * * Other subsystems should use remove_cpu() instead. * * Return: %0 on success or a negative errno code */int cpu_device_down(struct device *dev){	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();} #else#define takedown_cpu		NULL#endif /*CONFIG_HOTPLUG_CPU*/ /** * notify_cpu_starting(cpu) - Invoke the callbacks on the starting CPU * @cpu: cpu that just started * * It must be called by the arch code on the new cpu, before the new cpu * enables interrupts and before the "boot" cpu returns from __cpu_up(). */void notify_cpu_starting(unsigned int cpu){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);	enum cpuhp_state target = min((int)st->target, CPUHP_AP_ONLINE); 	rcutree_report_cpu_starting(cpu);	/* Enables RCU usage on this CPU. */	cpumask_set_cpu(cpu, &cpus_booted_once_mask); 	/*	 * STARTING must not fail!	 */	cpuhp_invoke_callback_range_nofail(true, cpu, st, target);} /* * Called from the idle task. Wake up the controlling task which brings the * hotplug thread of the upcoming CPU up and then delegates the rest of the * online bringup to the hotplug thread. */void cpuhp_online_idle(enum cpuhp_state state){	struct cpuhp_cpu_state *st = this_cpu_ptr(&cpuhp_state); 	/* Happens for the boot cpu */	if (state != CPUHP_AP_ONLINE_IDLE)		return; 	cpuhp_ap_update_sync_state(SYNC_STATE_ONLINE); 	/*	 * Unpark the stopper thread before we start the idle loop (and start	 * scheduling); this ensures the stopper task is always available.	 */	stop_machine_unpark(smp_processor_id()); 	st->state = CPUHP_AP_ONLINE_IDLE;	complete_ap_thread(st, true);} /* Requires cpu_add_remove_lock to be held */static int _cpu_up(unsigned int cpu, int tasks_frozen, enum cpuhp_state target){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);	struct task_struct *idle;	int ret = 0; 	cpus_write_lock(); 	if (!cpu_present(cpu)) {		ret = -EINVAL;		goto out;	} 	/*	 * The caller of cpu_up() might have raced with another	 * caller. Nothing to do.	 */	if (st->state >= target)		goto out; 	if (st->state == CPUHP_OFFLINE) {		/* Let it fail before we try to bring the cpu up */		idle = idle_thread_get(cpu);		if (IS_ERR(idle)) {			ret = PTR_ERR(idle);			goto out;		} 		/*		 * Reset stale stack state from the last time this CPU was online.		 */		scs_task_reset(idle);		kasan_unpoison_task_stack(idle);	} 	cpuhp_tasks_frozen = tasks_frozen; 	cpuhp_set_state(cpu, st, target);	/*	 * If the current CPU state is in the range of the AP hotplug thread,	 * then we need to kick the thread once more.	 */	if (st->state > CPUHP_BRINGUP_CPU) {		ret = cpuhp_kick_ap_work(cpu);		/*		 * The AP side has done the error rollback already. Just		 * return the error code..		 */		if (ret)			goto out;	} 	/*	 * Try to reach the target state. We max out on the BP at	 * CPUHP_BRINGUP_CPU. After that the AP hotplug thread is	 * responsible for bringing it up to the target state.	 */	target = min((int)target, CPUHP_BRINGUP_CPU);	ret = cpuhp_up_callbacks(cpu, st, target);out:	cpus_write_unlock();	arch_smt_update();	return ret;} static int cpu_up(unsigned int cpu, enum cpuhp_state target){	int err = 0; 	if (!cpu_possible(cpu)) {		pr_err("can't online cpu %d because it is not configured as may-hotadd at boot time\n",		       cpu);		return -EINVAL;	} 	err = try_online_node(cpu_to_node(cpu));	if (err)		return err; 	cpu_maps_update_begin(); 	if (cpu_hotplug_disabled) {		err = -EBUSY;		goto out;	}	if (!cpu_bootable(cpu)) {		err = -EPERM;		goto out;	} 	err = _cpu_up(cpu, 0, target);out:	cpu_maps_update_done();	return err;} /** * 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. * * Return: %0 on success or a negative errno code */int cpu_device_up(struct device *dev){	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. * * Return: %0 on success or a negative errno code */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;} static void __init cpuhp_bringup_mask(const struct cpumask *mask, unsigned int ncpus,				      enum cpuhp_state target){	unsigned int cpu; 	for_each_cpu(cpu, mask) {		struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu); 		if (cpu_up(cpu, target) && can_rollback_cpu(st)) {			/*			 * If this failed then cpu_up() might have only			 * rolled back to CPUHP_BP_KICK_AP for the final			 * online. Clean it up. NOOP if already rolled back.			 */			WARN_ON(cpuhp_invoke_callback_range(false, cpu, st, CPUHP_OFFLINE));		} 		if (!--ncpus)			break;	}} #ifdef CONFIG_HOTPLUG_PARALLELstatic bool __cpuhp_parallel_bringup __ro_after_init = true; static int __init parallel_bringup_parse_param(char *arg){	return kstrtobool(arg, &__cpuhp_parallel_bringup);}early_param("cpuhp.parallel", parallel_bringup_parse_param); #ifdef CONFIG_HOTPLUG_SMTstatic inline bool cpuhp_smt_aware(void){	return cpu_smt_max_threads > 1;} static inline const struct cpumask *cpuhp_get_primary_thread_mask(void){	return cpu_primary_thread_mask;}#elsestatic inline bool cpuhp_smt_aware(void){	return false;}static inline const struct cpumask *cpuhp_get_primary_thread_mask(void){	return cpu_none_mask;}#endif bool __weak arch_cpuhp_init_parallel_bringup(void){	return true;} /* * On architectures which have enabled parallel bringup this invokes all BP * prepare states for each of the to be onlined APs first. The last state * sends the startup IPI to the APs. The APs proceed through the low level * bringup code in parallel and then wait for the control CPU to release * them one by one for the final onlining procedure. * * This avoids waiting for each AP to respond to the startup IPI in * CPUHP_BRINGUP_CPU. */static bool __init cpuhp_bringup_cpus_parallel(unsigned int ncpus){	const struct cpumask *mask = cpu_present_mask; 	if (__cpuhp_parallel_bringup)		__cpuhp_parallel_bringup = arch_cpuhp_init_parallel_bringup();	if (!__cpuhp_parallel_bringup)		return false; 	if (cpuhp_smt_aware()) {		const struct cpumask *pmask = cpuhp_get_primary_thread_mask();		static struct cpumask tmp_mask __initdata; 		/*		 * X86 requires to prevent that SMT siblings stopped while		 * the primary thread does a microcode update for various		 * reasons. Bring the primary threads up first.		 */		cpumask_and(&tmp_mask, mask, pmask);		cpuhp_bringup_mask(&tmp_mask, ncpus, CPUHP_BP_KICK_AP);		cpuhp_bringup_mask(&tmp_mask, ncpus, CPUHP_ONLINE);		/* Account for the online CPUs */		ncpus -= num_online_cpus();		if (!ncpus)			return true;		/* Create the mask for secondary CPUs */		cpumask_andnot(&tmp_mask, mask, pmask);		mask = &tmp_mask;	} 	/* Bring the not-yet started CPUs up */	cpuhp_bringup_mask(mask, ncpus, CPUHP_BP_KICK_AP);	cpuhp_bringup_mask(mask, ncpus, CPUHP_ONLINE);	return true;}#elsestatic inline bool cpuhp_bringup_cpus_parallel(unsigned int ncpus) { return false; }#endif /* CONFIG_HOTPLUG_PARALLEL */ void __init bringup_nonboot_cpus(unsigned int max_cpus){	if (!max_cpus)		return; 	/* Try parallel bringup optimization if enabled */	if (cpuhp_bringup_cpus_parallel(max_cpus))		return; 	/* Full per CPU serialized bringup */	cpuhp_bringup_mask(cpu_present_mask, max_cpus, CPUHP_ONLINE);} #ifdef CONFIG_PM_SLEEP_SMPstatic cpumask_var_t frozen_cpus; int freeze_secondary_cpus(int primary){	int cpu, error = 0; 	cpu_maps_update_begin();	if (primary == -1) {		primary = cpumask_first(cpu_online_mask);		if (!housekeeping_cpu(primary, HK_TYPE_TIMER))			primary = housekeeping_any_cpu(HK_TYPE_TIMER);	} else {		if (!cpu_online(primary))			primary = cpumask_first(cpu_online_mask);	} 	/*	 * We take down all of the non-boot CPUs in one shot to avoid races	 * with the userspace trying to use the CPU hotplug at the same time	 */	cpumask_clear(frozen_cpus); 	pr_info("Disabling non-boot CPUs ...\n");	for (cpu = nr_cpu_ids - 1; cpu >= 0; cpu--) {		if (!cpu_online(cpu) || cpu == primary)			continue; 		if (pm_wakeup_pending()) {			pr_info("Wakeup pending. Abort CPU freeze\n");			error = -EBUSY;			break;		} 		trace_suspend_resume(TPS("CPU_OFF"), cpu, true);		error = _cpu_down(cpu, 1, CPUHP_OFFLINE);		trace_suspend_resume(TPS("CPU_OFF"), cpu, false);		if (!error)			cpumask_set_cpu(cpu, frozen_cpus);		else {			pr_err("Error taking CPU%d down: %d\n", cpu, error);			break;		}	} 	if (!error)		BUG_ON(num_online_cpus() > 1);	else		pr_err("Non-boot CPUs are not disabled\n"); 	/*	 * Make sure the CPUs won't be enabled by someone else. We need to do	 * this even in case of failure as all freeze_secondary_cpus() users are	 * supposed to do thaw_secondary_cpus() on the failure path.	 */	cpu_hotplug_disabled++; 	cpu_maps_update_done();	return error;} void __weak arch_thaw_secondary_cpus_begin(void){} void __weak arch_thaw_secondary_cpus_end(void){} void thaw_secondary_cpus(void){	int cpu, error; 	/* Allow everyone to use the CPU hotplug again */	cpu_maps_update_begin();	__cpu_hotplug_enable();	if (cpumask_empty(frozen_cpus))		goto out; 	pr_info("Enabling non-boot CPUs ...\n"); 	arch_thaw_secondary_cpus_begin(); 	for_each_cpu(cpu, frozen_cpus) {		trace_suspend_resume(TPS("CPU_ON"), cpu, true);		error = _cpu_up(cpu, 1, CPUHP_ONLINE);		trace_suspend_resume(TPS("CPU_ON"), cpu, false);		if (!error) {			pr_info("CPU%d is up\n", cpu);			continue;		}		pr_warn("Error taking CPU%d up: %d\n", cpu, error);	} 	arch_thaw_secondary_cpus_end(); 	cpumask_clear(frozen_cpus);out:	cpu_maps_update_done();} static int __init alloc_frozen_cpus(void){	if (!alloc_cpumask_var(&frozen_cpus, GFP_KERNEL|__GFP_ZERO))		return -ENOMEM;	return 0;}core_initcall(alloc_frozen_cpus); /* * When callbacks for CPU hotplug notifications are being executed, we must * ensure that the state of the system with respect to the tasks being frozen * or not, as reported by the notification, remains unchanged *throughout the * duration* of the execution of the callbacks. * Hence we need to prevent the freezer from racing with regular CPU hotplug. * * This synchronization is implemented by mutually excluding regular CPU * hotplug and Suspend/Hibernate call paths by hooking onto the Suspend/

Lines 1501–2000 of 3339. Previous lines

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t