3339 lines · 81.3 KB · C
RawDownload
		struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);		int cpustate = st->state; 		if (cpustate < state)			continue; 		ret = cpuhp_issue_call(cpu, state, true, NULL);		if (ret) {			if (teardown)				cpuhp_rollback_install(cpu, state, NULL);			cpuhp_store_callbacks(state, NULL, NULL, NULL, false);			goto out;		}	}out:	mutex_unlock(&cpuhp_state_mutex);	/*	 * If the requested state is CPUHP_AP_ONLINE_DYN or CPUHP_BP_PREPARE_DYN,	 * return the dynamically allocated state in case of success.	 */	if (!ret && dynstate)		return state;	return ret;}EXPORT_SYMBOL(__cpuhp_setup_state_cpuslocked); int __cpuhp_setup_state(enum cpuhp_state state,			const char *name, bool invoke,			int (*startup)(unsigned int cpu),			int (*teardown)(unsigned int cpu),			bool multi_instance){	int ret; 	cpus_read_lock();	ret = __cpuhp_setup_state_cpuslocked(state, name, invoke, startup,					     teardown, multi_instance);	cpus_read_unlock();	return ret;}EXPORT_SYMBOL(__cpuhp_setup_state); int __cpuhp_state_remove_instance(enum cpuhp_state state,				  struct hlist_node *node, bool invoke){	struct cpuhp_step *sp = cpuhp_get_step(state);	int cpu; 	BUG_ON(cpuhp_cb_check(state)); 	if (!sp->multi_instance)		return -EINVAL; 	cpus_read_lock();	mutex_lock(&cpuhp_state_mutex); 	if (!invoke || !cpuhp_get_teardown_cb(state))		goto remove;	/*	 * Call the teardown callback for each present cpu depending	 * on the hotplug state of the cpu. This function is not	 * allowed to fail currently!	 */	for_each_present_cpu(cpu) {		struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);		int cpustate = st->state; 		if (cpustate >= state)			cpuhp_issue_call(cpu, state, false, node);	} remove:	hlist_del(node);	mutex_unlock(&cpuhp_state_mutex);	cpus_read_unlock(); 	return 0;}EXPORT_SYMBOL_GPL(__cpuhp_state_remove_instance); /** * __cpuhp_remove_state_cpuslocked - Remove the callbacks for an hotplug machine state * @state:	The state to remove * @invoke:	If true, the teardown function is invoked for cpus where *		cpu state >= @state * * The caller needs to hold cpus read locked while calling this function. * The teardown callback is currently not allowed to fail. Think * about module removal! */void __cpuhp_remove_state_cpuslocked(enum cpuhp_state state, bool invoke){	struct cpuhp_step *sp = cpuhp_get_step(state);	int cpu; 	BUG_ON(cpuhp_cb_check(state)); 	lockdep_assert_cpus_held(); 	mutex_lock(&cpuhp_state_mutex);	if (sp->multi_instance) {		WARN(!hlist_empty(&sp->list),		     "Error: Removing state %d which has instances left.\n",		     state);		goto remove;	} 	if (!invoke || !cpuhp_get_teardown_cb(state))		goto remove; 	/*	 * Call the teardown callback for each present cpu depending	 * on the hotplug state of the cpu. This function is not	 * allowed to fail currently!	 */	for_each_present_cpu(cpu) {		struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, cpu);		int cpustate = st->state; 		if (cpustate >= state)			cpuhp_issue_call(cpu, state, false, NULL);	}remove:	cpuhp_store_callbacks(state, NULL, NULL, NULL, false);	mutex_unlock(&cpuhp_state_mutex);}EXPORT_SYMBOL(__cpuhp_remove_state_cpuslocked); void __cpuhp_remove_state(enum cpuhp_state state, bool invoke){	cpus_read_lock();	__cpuhp_remove_state_cpuslocked(state, invoke);	cpus_read_unlock();}EXPORT_SYMBOL(__cpuhp_remove_state); #ifdef CONFIG_HOTPLUG_SMTstatic void cpuhp_offline_cpu_device(unsigned int cpu){	struct device *dev = get_cpu_device(cpu); 	dev_set_offline(dev);	/* Tell user space about the state change */	kobject_uevent(&dev->kobj, KOBJ_OFFLINE);} static void cpuhp_online_cpu_device(unsigned int cpu){	struct device *dev = get_cpu_device(cpu); 	dev_clear_offline(dev);	/* Tell user space about the state change */	kobject_uevent(&dev->kobj, KOBJ_ONLINE);} int cpuhp_smt_disable(enum cpuhp_smt_control ctrlval){	int cpu, ret = 0; 	cpu_maps_update_begin();	for_each_online_cpu(cpu) {		if (topology_is_primary_thread(cpu))			continue;		/*		 * Disable can be called with CPU_SMT_ENABLED when changing		 * from a higher to lower number of SMT threads per core.		 */		if (ctrlval == CPU_SMT_ENABLED && cpu_smt_thread_allowed(cpu))			continue;		ret = cpu_down_maps_locked(cpu, CPUHP_OFFLINE);		if (ret)			break;		/*		 * As this needs to hold the cpu maps lock it's impossible		 * to call device_offline() because that ends up calling		 * cpu_down() which takes cpu maps lock. cpu maps lock		 * needs to be held as this might race against in kernel		 * abusers of the hotplug machinery (thermal management).		 *		 * So nothing would update device:offline state. That would		 * leave the sysfs entry stale and prevent onlining after		 * smt control has been changed to 'off' again. This is		 * called under the sysfs hotplug lock, so it is properly		 * serialized against the regular offline usage.		 */		cpuhp_offline_cpu_device(cpu);	}	if (!ret)		cpu_smt_control = ctrlval;	cpu_maps_update_done();	return ret;} /* Check if the core a CPU belongs to is online */#if !defined(topology_is_core_online)static inline bool topology_is_core_online(unsigned int cpu){	return true;}#endif int cpuhp_smt_enable(void){	int cpu, ret = 0; 	cpu_maps_update_begin();	cpu_smt_control = CPU_SMT_ENABLED;	for_each_present_cpu(cpu) {		/* Skip online CPUs and CPUs on offline nodes */		if (cpu_online(cpu) || !node_online(cpu_to_node(cpu)))			continue;		if (!cpu_smt_thread_allowed(cpu) || !topology_is_core_online(cpu))			continue;		ret = _cpu_up(cpu, 0, CPUHP_ONLINE);		if (ret)			break;		/* See comment in cpuhp_smt_disable() */		cpuhp_online_cpu_device(cpu);	}	cpu_maps_update_done();	return ret;}#endif #if defined(CONFIG_SYSFS) && defined(CONFIG_HOTPLUG_CPU)static ssize_t state_show(struct device *dev,			  struct device_attribute *attr, char *buf){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 	return sprintf(buf, "%d\n", st->state);}static DEVICE_ATTR_RO(state); static ssize_t target_store(struct device *dev, struct device_attribute *attr,			    const char *buf, size_t count){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);	struct cpuhp_step *sp;	int target, ret; 	ret = kstrtoint(buf, 10, &target);	if (ret)		return ret; #ifdef CONFIG_CPU_HOTPLUG_STATE_CONTROL	if (target < CPUHP_OFFLINE || target > CPUHP_ONLINE)		return -EINVAL;#else	if (target != CPUHP_OFFLINE && target != CPUHP_ONLINE)		return -EINVAL;#endif 	ret = lock_device_hotplug_sysfs();	if (ret)		return ret; 	mutex_lock(&cpuhp_state_mutex);	sp = cpuhp_get_step(target);	ret = !sp->name || sp->cant_stop ? -EINVAL : 0;	mutex_unlock(&cpuhp_state_mutex);	if (ret)		goto out; 	if (st->state < target)		ret = cpu_up(dev->id, target);	else if (st->state > target)		ret = cpu_down(dev->id, target);	else if (WARN_ON(st->target != target))		st->target = target;out:	unlock_device_hotplug();	return ret ? ret : count;} static ssize_t target_show(struct device *dev,			   struct device_attribute *attr, char *buf){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 	return sprintf(buf, "%d\n", st->target);}static DEVICE_ATTR_RW(target); static ssize_t fail_store(struct device *dev, struct device_attribute *attr,			  const char *buf, size_t count){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id);	struct cpuhp_step *sp;	int fail, ret; 	ret = kstrtoint(buf, 10, &fail);	if (ret)		return ret; 	if (fail == CPUHP_INVALID) {		st->fail = fail;		return count;	} 	if (fail < CPUHP_OFFLINE || fail > CPUHP_ONLINE)		return -EINVAL; 	/*	 * Cannot fail STARTING/DYING callbacks.	 */	if (cpuhp_is_atomic_state(fail))		return -EINVAL; 	/*	 * DEAD callbacks cannot fail...	 * ... neither can CPUHP_BRINGUP_CPU during hotunplug. The latter	 * triggering STARTING callbacks, a failure in this state would	 * hinder rollback.	 */	if (fail <= CPUHP_BRINGUP_CPU && st->state > CPUHP_BRINGUP_CPU)		return -EINVAL; 	/*	 * Cannot fail anything that doesn't have callbacks.	 */	mutex_lock(&cpuhp_state_mutex);	sp = cpuhp_get_step(fail);	if (!sp->startup.single && !sp->teardown.single)		ret = -EINVAL;	mutex_unlock(&cpuhp_state_mutex);	if (ret)		return ret; 	st->fail = fail; 	return count;} static ssize_t fail_show(struct device *dev,			 struct device_attribute *attr, char *buf){	struct cpuhp_cpu_state *st = per_cpu_ptr(&cpuhp_state, dev->id); 	return sprintf(buf, "%d\n", st->fail);} static DEVICE_ATTR_RW(fail); static struct attribute *cpuhp_cpu_attrs[] = {	&dev_attr_state.attr,	&dev_attr_target.attr,	&dev_attr_fail.attr,	NULL}; static const struct attribute_group cpuhp_cpu_attr_group = {	.attrs = cpuhp_cpu_attrs,	.name = "hotplug",}; static ssize_t states_show(struct device *dev, struct device_attribute *attr, char *buf){	ssize_t res = 0;	int i; 	mutex_lock(&cpuhp_state_mutex);	for (i = CPUHP_OFFLINE; i <= CPUHP_ONLINE; i++) {		struct cpuhp_step *sp = cpuhp_get_step(i); 		if (sp->name)			res += sysfs_emit_at(buf, res, "%3d: %s\n", i, sp->name);	}	mutex_unlock(&cpuhp_state_mutex);	return res;}static DEVICE_ATTR_RO(states); static struct attribute *cpuhp_cpu_root_attrs[] = {	&dev_attr_states.attr,	NULL}; static const struct attribute_group cpuhp_cpu_root_attr_group = {	.attrs = cpuhp_cpu_root_attrs,	.name = "hotplug",}; #ifdef CONFIG_HOTPLUG_SMT static bool cpu_smt_num_threads_valid(unsigned int threads){	if (IS_ENABLED(CONFIG_SMT_NUM_THREADS_DYNAMIC))		return threads >= 1 && threads <= cpu_smt_max_threads;	return threads == 1 || threads == cpu_smt_max_threads;} static ssize_t__store_smt_control(struct device *dev, struct device_attribute *attr,		    const char *buf, size_t count){	int ctrlval, ret, num_threads, orig_threads;	bool force_off; 	if (cpu_smt_control == CPU_SMT_FORCE_DISABLED)		return -EPERM; 	if (cpu_smt_control == CPU_SMT_NOT_SUPPORTED)		return -ENODEV; 	if (sysfs_streq(buf, "on")) {		ctrlval = CPU_SMT_ENABLED;		num_threads = cpu_smt_max_threads;	} else if (sysfs_streq(buf, "off")) {		ctrlval = CPU_SMT_DISABLED;		num_threads = 1;	} else if (sysfs_streq(buf, "forceoff")) {		ctrlval = CPU_SMT_FORCE_DISABLED;		num_threads = 1;	} else if (kstrtoint(buf, 10, &num_threads) == 0) {		if (num_threads == 1)			ctrlval = CPU_SMT_DISABLED;		else if (cpu_smt_num_threads_valid(num_threads))			ctrlval = CPU_SMT_ENABLED;		else			return -EINVAL;	} else {		return -EINVAL;	} 	ret = lock_device_hotplug_sysfs();	if (ret)		return ret; 	orig_threads = cpu_smt_num_threads;	cpu_smt_num_threads = num_threads; 	force_off = ctrlval != cpu_smt_control && ctrlval == CPU_SMT_FORCE_DISABLED; 	if (num_threads > orig_threads)		ret = cpuhp_smt_enable();	else if (num_threads < orig_threads || force_off)		ret = cpuhp_smt_disable(ctrlval); 	unlock_device_hotplug();	return ret ? ret : count;} #else /* !CONFIG_HOTPLUG_SMT */static ssize_t__store_smt_control(struct device *dev, struct device_attribute *attr,		    const char *buf, size_t count){	return -ENODEV;}#endif /* CONFIG_HOTPLUG_SMT */ static const char *smt_states[] = {	[CPU_SMT_ENABLED]		= "on",	[CPU_SMT_DISABLED]		= "off",	[CPU_SMT_FORCE_DISABLED]	= "forceoff",	[CPU_SMT_NOT_SUPPORTED]		= "notsupported",	[CPU_SMT_NOT_IMPLEMENTED]	= "notimplemented",}; static ssize_t control_show(struct device *dev,			    struct device_attribute *attr, char *buf){	const char *state = smt_states[cpu_smt_control]; #ifdef CONFIG_HOTPLUG_SMT	/*	 * If SMT is enabled but not all threads are enabled then show the	 * number of threads. If all threads are enabled show "on". Otherwise	 * show the state name.	 */	if (cpu_smt_control == CPU_SMT_ENABLED &&	    cpu_smt_num_threads != cpu_smt_max_threads)		return sysfs_emit(buf, "%d\n", cpu_smt_num_threads);#endif 	return sysfs_emit(buf, "%s\n", state);} static ssize_t control_store(struct device *dev, struct device_attribute *attr,			     const char *buf, size_t count){	return __store_smt_control(dev, attr, buf, count);}static DEVICE_ATTR_RW(control); static ssize_t active_show(struct device *dev,			   struct device_attribute *attr, char *buf){	return sysfs_emit(buf, "%d\n", sched_smt_active());}static DEVICE_ATTR_RO(active); static struct attribute *cpuhp_smt_attrs[] = {	&dev_attr_control.attr,	&dev_attr_active.attr,	NULL}; static const struct attribute_group cpuhp_smt_attr_group = {

Lines 2501–3000 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