18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * CPU subsystem support
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci
68c2ecf20Sopenharmony_ci#include <linux/kernel.h>
78c2ecf20Sopenharmony_ci#include <linux/module.h>
88c2ecf20Sopenharmony_ci#include <linux/init.h>
98c2ecf20Sopenharmony_ci#include <linux/sched.h>
108c2ecf20Sopenharmony_ci#include <linux/cpu.h>
118c2ecf20Sopenharmony_ci#include <linux/topology.h>
128c2ecf20Sopenharmony_ci#include <linux/device.h>
138c2ecf20Sopenharmony_ci#include <linux/node.h>
148c2ecf20Sopenharmony_ci#include <linux/gfp.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/percpu.h>
178c2ecf20Sopenharmony_ci#include <linux/acpi.h>
188c2ecf20Sopenharmony_ci#include <linux/of.h>
198c2ecf20Sopenharmony_ci#include <linux/cpufeature.h>
208c2ecf20Sopenharmony_ci#include <linux/tick.h>
218c2ecf20Sopenharmony_ci#include <linux/pm_qos.h>
228c2ecf20Sopenharmony_ci#include <linux/sched/isolation.h>
238c2ecf20Sopenharmony_ci
248c2ecf20Sopenharmony_ci#include "base.h"
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct device *, cpu_sys_devices);
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistatic int cpu_subsys_match(struct device *dev, struct device_driver *drv)
298c2ecf20Sopenharmony_ci{
308c2ecf20Sopenharmony_ci	/* ACPI style match is the only one that may succeed. */
318c2ecf20Sopenharmony_ci	if (acpi_driver_match_device(dev, drv))
328c2ecf20Sopenharmony_ci		return 1;
338c2ecf20Sopenharmony_ci
348c2ecf20Sopenharmony_ci	return 0;
358c2ecf20Sopenharmony_ci}
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
388c2ecf20Sopenharmony_cistatic void change_cpu_under_node(struct cpu *cpu,
398c2ecf20Sopenharmony_ci			unsigned int from_nid, unsigned int to_nid)
408c2ecf20Sopenharmony_ci{
418c2ecf20Sopenharmony_ci	int cpuid = cpu->dev.id;
428c2ecf20Sopenharmony_ci	unregister_cpu_under_node(cpuid, from_nid);
438c2ecf20Sopenharmony_ci	register_cpu_under_node(cpuid, to_nid);
448c2ecf20Sopenharmony_ci	cpu->node_id = to_nid;
458c2ecf20Sopenharmony_ci}
468c2ecf20Sopenharmony_ci
478c2ecf20Sopenharmony_cistatic int cpu_subsys_online(struct device *dev)
488c2ecf20Sopenharmony_ci{
498c2ecf20Sopenharmony_ci	struct cpu *cpu = container_of(dev, struct cpu, dev);
508c2ecf20Sopenharmony_ci	int cpuid = dev->id;
518c2ecf20Sopenharmony_ci	int from_nid, to_nid;
528c2ecf20Sopenharmony_ci	int ret;
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_ci	from_nid = cpu_to_node(cpuid);
558c2ecf20Sopenharmony_ci	if (from_nid == NUMA_NO_NODE)
568c2ecf20Sopenharmony_ci		return -ENODEV;
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ci	ret = cpu_device_up(dev);
598c2ecf20Sopenharmony_ci	/*
608c2ecf20Sopenharmony_ci	 * When hot adding memory to memoryless node and enabling a cpu
618c2ecf20Sopenharmony_ci	 * on the node, node number of the cpu may internally change.
628c2ecf20Sopenharmony_ci	 */
638c2ecf20Sopenharmony_ci	to_nid = cpu_to_node(cpuid);
648c2ecf20Sopenharmony_ci	if (from_nid != to_nid)
658c2ecf20Sopenharmony_ci		change_cpu_under_node(cpu, from_nid, to_nid);
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	return ret;
688c2ecf20Sopenharmony_ci}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_cistatic int cpu_subsys_offline(struct device *dev)
718c2ecf20Sopenharmony_ci{
728c2ecf20Sopenharmony_ci	return cpu_device_down(dev);
738c2ecf20Sopenharmony_ci}
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_civoid unregister_cpu(struct cpu *cpu)
768c2ecf20Sopenharmony_ci{
778c2ecf20Sopenharmony_ci	int logical_cpu = cpu->dev.id;
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci	unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci	device_unregister(&cpu->dev);
828c2ecf20Sopenharmony_ci	per_cpu(cpu_sys_devices, logical_cpu) = NULL;
838c2ecf20Sopenharmony_ci	return;
848c2ecf20Sopenharmony_ci}
858c2ecf20Sopenharmony_ci
868c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
878c2ecf20Sopenharmony_cistatic ssize_t cpu_probe_store(struct device *dev,
888c2ecf20Sopenharmony_ci			       struct device_attribute *attr,
898c2ecf20Sopenharmony_ci			       const char *buf,
908c2ecf20Sopenharmony_ci			       size_t count)
918c2ecf20Sopenharmony_ci{
928c2ecf20Sopenharmony_ci	ssize_t cnt;
938c2ecf20Sopenharmony_ci	int ret;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	ret = lock_device_hotplug_sysfs();
968c2ecf20Sopenharmony_ci	if (ret)
978c2ecf20Sopenharmony_ci		return ret;
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_ci	cnt = arch_cpu_probe(buf, count);
1008c2ecf20Sopenharmony_ci
1018c2ecf20Sopenharmony_ci	unlock_device_hotplug();
1028c2ecf20Sopenharmony_ci	return cnt;
1038c2ecf20Sopenharmony_ci}
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_cistatic ssize_t cpu_release_store(struct device *dev,
1068c2ecf20Sopenharmony_ci				 struct device_attribute *attr,
1078c2ecf20Sopenharmony_ci				 const char *buf,
1088c2ecf20Sopenharmony_ci				 size_t count)
1098c2ecf20Sopenharmony_ci{
1108c2ecf20Sopenharmony_ci	ssize_t cnt;
1118c2ecf20Sopenharmony_ci	int ret;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	ret = lock_device_hotplug_sysfs();
1148c2ecf20Sopenharmony_ci	if (ret)
1158c2ecf20Sopenharmony_ci		return ret;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	cnt = arch_cpu_release(buf, count);
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	unlock_device_hotplug();
1208c2ecf20Sopenharmony_ci	return cnt;
1218c2ecf20Sopenharmony_ci}
1228c2ecf20Sopenharmony_ci
1238c2ecf20Sopenharmony_cistatic DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
1248c2ecf20Sopenharmony_cistatic DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store);
1258c2ecf20Sopenharmony_ci#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
1268c2ecf20Sopenharmony_ci#endif /* CONFIG_HOTPLUG_CPU */
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_cistruct bus_type cpu_subsys = {
1298c2ecf20Sopenharmony_ci	.name = "cpu",
1308c2ecf20Sopenharmony_ci	.dev_name = "cpu",
1318c2ecf20Sopenharmony_ci	.match = cpu_subsys_match,
1328c2ecf20Sopenharmony_ci#ifdef CONFIG_HOTPLUG_CPU
1338c2ecf20Sopenharmony_ci	.online = cpu_subsys_online,
1348c2ecf20Sopenharmony_ci	.offline = cpu_subsys_offline,
1358c2ecf20Sopenharmony_ci#endif
1368c2ecf20Sopenharmony_ci};
1378c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cpu_subsys);
1388c2ecf20Sopenharmony_ci
1398c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC
1408c2ecf20Sopenharmony_ci#include <linux/kexec.h>
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_cistatic ssize_t crash_notes_show(struct device *dev,
1438c2ecf20Sopenharmony_ci				struct device_attribute *attr,
1448c2ecf20Sopenharmony_ci				char *buf)
1458c2ecf20Sopenharmony_ci{
1468c2ecf20Sopenharmony_ci	struct cpu *cpu = container_of(dev, struct cpu, dev);
1478c2ecf20Sopenharmony_ci	unsigned long long addr;
1488c2ecf20Sopenharmony_ci	int cpunum;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	cpunum = cpu->dev.id;
1518c2ecf20Sopenharmony_ci
1528c2ecf20Sopenharmony_ci	/*
1538c2ecf20Sopenharmony_ci	 * Might be reading other cpu's data based on which cpu read thread
1548c2ecf20Sopenharmony_ci	 * has been scheduled. But cpu data (memory) is allocated once during
1558c2ecf20Sopenharmony_ci	 * boot up and this data does not change there after. Hence this
1568c2ecf20Sopenharmony_ci	 * operation should be safe. No locking required.
1578c2ecf20Sopenharmony_ci	 */
1588c2ecf20Sopenharmony_ci	addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum));
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "%llx\n", addr);
1618c2ecf20Sopenharmony_ci}
1628c2ecf20Sopenharmony_cistatic DEVICE_ATTR_ADMIN_RO(crash_notes);
1638c2ecf20Sopenharmony_ci
1648c2ecf20Sopenharmony_cistatic ssize_t crash_notes_size_show(struct device *dev,
1658c2ecf20Sopenharmony_ci				     struct device_attribute *attr,
1668c2ecf20Sopenharmony_ci				     char *buf)
1678c2ecf20Sopenharmony_ci{
1688c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "%zu\n", sizeof(note_buf_t));
1698c2ecf20Sopenharmony_ci}
1708c2ecf20Sopenharmony_cistatic DEVICE_ATTR_ADMIN_RO(crash_notes_size);
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_cistatic struct attribute *crash_note_cpu_attrs[] = {
1738c2ecf20Sopenharmony_ci	&dev_attr_crash_notes.attr,
1748c2ecf20Sopenharmony_ci	&dev_attr_crash_notes_size.attr,
1758c2ecf20Sopenharmony_ci	NULL
1768c2ecf20Sopenharmony_ci};
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_cistatic struct attribute_group crash_note_cpu_attr_group = {
1798c2ecf20Sopenharmony_ci	.attrs = crash_note_cpu_attrs,
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci#endif
1828c2ecf20Sopenharmony_ci
1838c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ISOLATION_OPT
1848c2ecf20Sopenharmony_cistatic ssize_t isolate_show(struct device *dev,
1858c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
1868c2ecf20Sopenharmony_ci{
1878c2ecf20Sopenharmony_ci	struct cpu *cpu = container_of(dev, struct cpu, dev);
1888c2ecf20Sopenharmony_ci	ssize_t rc;
1898c2ecf20Sopenharmony_ci	int cpuid = cpu->dev.id;
1908c2ecf20Sopenharmony_ci	unsigned int isolated = cpu_isolated(cpuid);
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	rc = sysfs_emit(buf, "%d\n", isolated);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	return rc;
1958c2ecf20Sopenharmony_ci}
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_cistatic DEVICE_ATTR_RO(isolate);
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_cistatic struct attribute *cpu_isolated_attrs[] = {
2008c2ecf20Sopenharmony_ci	&dev_attr_isolate.attr,
2018c2ecf20Sopenharmony_ci	NULL
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_cistatic struct attribute_group cpu_isolated_attr_group = {
2058c2ecf20Sopenharmony_ci	.attrs = cpu_isolated_attrs,
2068c2ecf20Sopenharmony_ci};
2078c2ecf20Sopenharmony_ci#endif
2088c2ecf20Sopenharmony_ci
2098c2ecf20Sopenharmony_cistatic const struct attribute_group *common_cpu_attr_groups[] = {
2108c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC
2118c2ecf20Sopenharmony_ci	&crash_note_cpu_attr_group,
2128c2ecf20Sopenharmony_ci#endif
2138c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ISOLATION_OPT
2148c2ecf20Sopenharmony_ci	&cpu_isolated_attr_group,
2158c2ecf20Sopenharmony_ci#endif
2168c2ecf20Sopenharmony_ci	NULL
2178c2ecf20Sopenharmony_ci};
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_cistatic const struct attribute_group *hotplugable_cpu_attr_groups[] = {
2208c2ecf20Sopenharmony_ci#ifdef CONFIG_KEXEC
2218c2ecf20Sopenharmony_ci	&crash_note_cpu_attr_group,
2228c2ecf20Sopenharmony_ci#endif
2238c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ISOLATION_OPT
2248c2ecf20Sopenharmony_ci	&cpu_isolated_attr_group,
2258c2ecf20Sopenharmony_ci#endif
2268c2ecf20Sopenharmony_ci	NULL
2278c2ecf20Sopenharmony_ci};
2288c2ecf20Sopenharmony_ci
2298c2ecf20Sopenharmony_ci/*
2308c2ecf20Sopenharmony_ci * Print cpu online, possible, present, and system maps
2318c2ecf20Sopenharmony_ci */
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_cistruct cpu_attr {
2348c2ecf20Sopenharmony_ci	struct device_attribute attr;
2358c2ecf20Sopenharmony_ci	const struct cpumask *const map;
2368c2ecf20Sopenharmony_ci};
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_cistatic ssize_t show_cpus_attr(struct device *dev,
2398c2ecf20Sopenharmony_ci			      struct device_attribute *attr,
2408c2ecf20Sopenharmony_ci			      char *buf)
2418c2ecf20Sopenharmony_ci{
2428c2ecf20Sopenharmony_ci	struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	return cpumap_print_to_pagebuf(true, buf, ca->map);
2458c2ecf20Sopenharmony_ci}
2468c2ecf20Sopenharmony_ci
2478c2ecf20Sopenharmony_ci#define _CPU_ATTR(name, map) \
2488c2ecf20Sopenharmony_ci	{ __ATTR(name, 0444, show_cpus_attr, NULL), map }
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_ci/* Keep in sync with cpu_subsys_attrs */
2518c2ecf20Sopenharmony_cistatic struct cpu_attr cpu_attrs[] = {
2528c2ecf20Sopenharmony_ci	_CPU_ATTR(online, &__cpu_online_mask),
2538c2ecf20Sopenharmony_ci	_CPU_ATTR(possible, &__cpu_possible_mask),
2548c2ecf20Sopenharmony_ci	_CPU_ATTR(present, &__cpu_present_mask),
2558c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ISOLATION_OPT
2568c2ecf20Sopenharmony_ci	_CPU_ATTR(core_ctl_isolated, &__cpu_isolated_mask),
2578c2ecf20Sopenharmony_ci#endif
2588c2ecf20Sopenharmony_ci};
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci/*
2618c2ecf20Sopenharmony_ci * Print values for NR_CPUS and offlined cpus
2628c2ecf20Sopenharmony_ci */
2638c2ecf20Sopenharmony_cistatic ssize_t print_cpus_kernel_max(struct device *dev,
2648c2ecf20Sopenharmony_ci				     struct device_attribute *attr, char *buf)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "%d\n", NR_CPUS - 1);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_cistatic DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL);
2698c2ecf20Sopenharmony_ci
2708c2ecf20Sopenharmony_ci/* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */
2718c2ecf20Sopenharmony_ciunsigned int total_cpus;
2728c2ecf20Sopenharmony_ci
2738c2ecf20Sopenharmony_cistatic ssize_t print_cpus_offline(struct device *dev,
2748c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	int len = 0;
2778c2ecf20Sopenharmony_ci	cpumask_var_t offline;
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci	/* display offline cpus < nr_cpu_ids */
2808c2ecf20Sopenharmony_ci	if (!alloc_cpumask_var(&offline, GFP_KERNEL))
2818c2ecf20Sopenharmony_ci		return -ENOMEM;
2828c2ecf20Sopenharmony_ci	cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask);
2838c2ecf20Sopenharmony_ci	len += sysfs_emit_at(buf, len, "%*pbl", cpumask_pr_args(offline));
2848c2ecf20Sopenharmony_ci	free_cpumask_var(offline);
2858c2ecf20Sopenharmony_ci
2868c2ecf20Sopenharmony_ci	/* display offline cpus >= nr_cpu_ids */
2878c2ecf20Sopenharmony_ci	if (total_cpus && nr_cpu_ids < total_cpus) {
2888c2ecf20Sopenharmony_ci		len += sysfs_emit_at(buf, len, ",");
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci		if (nr_cpu_ids == total_cpus-1)
2918c2ecf20Sopenharmony_ci			len += sysfs_emit_at(buf, len, "%u", nr_cpu_ids);
2928c2ecf20Sopenharmony_ci		else
2938c2ecf20Sopenharmony_ci			len += sysfs_emit_at(buf, len, "%u-%d",
2948c2ecf20Sopenharmony_ci					     nr_cpu_ids, total_cpus - 1);
2958c2ecf20Sopenharmony_ci	}
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci	len += sysfs_emit_at(buf, len, "\n");
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	return len;
3008c2ecf20Sopenharmony_ci}
3018c2ecf20Sopenharmony_cistatic DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL);
3028c2ecf20Sopenharmony_ci
3038c2ecf20Sopenharmony_cistatic ssize_t print_cpus_isolated(struct device *dev,
3048c2ecf20Sopenharmony_ci				  struct device_attribute *attr, char *buf)
3058c2ecf20Sopenharmony_ci{
3068c2ecf20Sopenharmony_ci	int len;
3078c2ecf20Sopenharmony_ci	cpumask_var_t isolated;
3088c2ecf20Sopenharmony_ci
3098c2ecf20Sopenharmony_ci	if (!alloc_cpumask_var(&isolated, GFP_KERNEL))
3108c2ecf20Sopenharmony_ci		return -ENOMEM;
3118c2ecf20Sopenharmony_ci
3128c2ecf20Sopenharmony_ci	cpumask_andnot(isolated, cpu_possible_mask,
3138c2ecf20Sopenharmony_ci		       housekeeping_cpumask(HK_FLAG_DOMAIN));
3148c2ecf20Sopenharmony_ci	len = sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(isolated));
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci	free_cpumask_var(isolated);
3178c2ecf20Sopenharmony_ci
3188c2ecf20Sopenharmony_ci	return len;
3198c2ecf20Sopenharmony_ci}
3208c2ecf20Sopenharmony_cistatic DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL);
3218c2ecf20Sopenharmony_ci
3228c2ecf20Sopenharmony_ci#ifdef CONFIG_NO_HZ_FULL
3238c2ecf20Sopenharmony_cistatic ssize_t print_cpus_nohz_full(struct device *dev,
3248c2ecf20Sopenharmony_ci				    struct device_attribute *attr, char *buf)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask));
3278c2ecf20Sopenharmony_ci}
3288c2ecf20Sopenharmony_cistatic DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL);
3298c2ecf20Sopenharmony_ci#endif
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_cistatic void cpu_device_release(struct device *dev)
3328c2ecf20Sopenharmony_ci{
3338c2ecf20Sopenharmony_ci	/*
3348c2ecf20Sopenharmony_ci	 * This is an empty function to prevent the driver core from spitting a
3358c2ecf20Sopenharmony_ci	 * warning at us.  Yes, I know this is directly opposite of what the
3368c2ecf20Sopenharmony_ci	 * documentation for the driver core and kobjects say, and the author
3378c2ecf20Sopenharmony_ci	 * of this code has already been publically ridiculed for doing
3388c2ecf20Sopenharmony_ci	 * something as foolish as this.  However, at this point in time, it is
3398c2ecf20Sopenharmony_ci	 * the only way to handle the issue of statically allocated cpu
3408c2ecf20Sopenharmony_ci	 * devices.  The different architectures will have their cpu device
3418c2ecf20Sopenharmony_ci	 * code reworked to properly handle this in the near future, so this
3428c2ecf20Sopenharmony_ci	 * function will then be changed to correctly free up the memory held
3438c2ecf20Sopenharmony_ci	 * by the cpu device.
3448c2ecf20Sopenharmony_ci	 *
3458c2ecf20Sopenharmony_ci	 * Never copy this way of doing things, or you too will be made fun of
3468c2ecf20Sopenharmony_ci	 * on the linux-kernel list, you have been warned.
3478c2ecf20Sopenharmony_ci	 */
3488c2ecf20Sopenharmony_ci}
3498c2ecf20Sopenharmony_ci
3508c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
3518c2ecf20Sopenharmony_cistatic ssize_t print_cpu_modalias(struct device *dev,
3528c2ecf20Sopenharmony_ci				  struct device_attribute *attr,
3538c2ecf20Sopenharmony_ci				  char *buf)
3548c2ecf20Sopenharmony_ci{
3558c2ecf20Sopenharmony_ci	int len = 0;
3568c2ecf20Sopenharmony_ci	u32 i;
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	len += sysfs_emit_at(buf, len,
3598c2ecf20Sopenharmony_ci			     "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:",
3608c2ecf20Sopenharmony_ci			     CPU_FEATURE_TYPEVAL);
3618c2ecf20Sopenharmony_ci
3628c2ecf20Sopenharmony_ci	for (i = 0; i < MAX_CPU_FEATURES; i++)
3638c2ecf20Sopenharmony_ci		if (cpu_have_feature(i)) {
3648c2ecf20Sopenharmony_ci			if (len + sizeof(",XXXX\n") >= PAGE_SIZE) {
3658c2ecf20Sopenharmony_ci				WARN(1, "CPU features overflow page\n");
3668c2ecf20Sopenharmony_ci				break;
3678c2ecf20Sopenharmony_ci			}
3688c2ecf20Sopenharmony_ci			len += sysfs_emit_at(buf, len, ",%04X", i);
3698c2ecf20Sopenharmony_ci		}
3708c2ecf20Sopenharmony_ci	len += sysfs_emit_at(buf, len, "\n");
3718c2ecf20Sopenharmony_ci	return len;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_cistatic int cpu_uevent(struct device *dev, struct kobj_uevent_env *env)
3758c2ecf20Sopenharmony_ci{
3768c2ecf20Sopenharmony_ci	char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL);
3778c2ecf20Sopenharmony_ci	if (buf) {
3788c2ecf20Sopenharmony_ci		print_cpu_modalias(NULL, NULL, buf);
3798c2ecf20Sopenharmony_ci		add_uevent_var(env, "MODALIAS=%s", buf);
3808c2ecf20Sopenharmony_ci		kfree(buf);
3818c2ecf20Sopenharmony_ci	}
3828c2ecf20Sopenharmony_ci	return 0;
3838c2ecf20Sopenharmony_ci}
3848c2ecf20Sopenharmony_ci#endif
3858c2ecf20Sopenharmony_ci
3868c2ecf20Sopenharmony_ci/*
3878c2ecf20Sopenharmony_ci * register_cpu - Setup a sysfs device for a CPU.
3888c2ecf20Sopenharmony_ci * @cpu - cpu->hotpluggable field set to 1 will generate a control file in
3898c2ecf20Sopenharmony_ci *	  sysfs for this CPU.
3908c2ecf20Sopenharmony_ci * @num - CPU number to use when creating the device.
3918c2ecf20Sopenharmony_ci *
3928c2ecf20Sopenharmony_ci * Initialize and register the CPU device.
3938c2ecf20Sopenharmony_ci */
3948c2ecf20Sopenharmony_ciint register_cpu(struct cpu *cpu, int num)
3958c2ecf20Sopenharmony_ci{
3968c2ecf20Sopenharmony_ci	int error;
3978c2ecf20Sopenharmony_ci
3988c2ecf20Sopenharmony_ci	cpu->node_id = cpu_to_node(num);
3998c2ecf20Sopenharmony_ci	memset(&cpu->dev, 0x00, sizeof(struct device));
4008c2ecf20Sopenharmony_ci	cpu->dev.id = num;
4018c2ecf20Sopenharmony_ci	cpu->dev.bus = &cpu_subsys;
4028c2ecf20Sopenharmony_ci	cpu->dev.release = cpu_device_release;
4038c2ecf20Sopenharmony_ci	cpu->dev.offline_disabled = !cpu->hotpluggable;
4048c2ecf20Sopenharmony_ci	cpu->dev.offline = !cpu_online(num);
4058c2ecf20Sopenharmony_ci	cpu->dev.of_node = of_get_cpu_node(num, NULL);
4068c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
4078c2ecf20Sopenharmony_ci	cpu->dev.bus->uevent = cpu_uevent;
4088c2ecf20Sopenharmony_ci#endif
4098c2ecf20Sopenharmony_ci	cpu->dev.groups = common_cpu_attr_groups;
4108c2ecf20Sopenharmony_ci	if (cpu->hotpluggable)
4118c2ecf20Sopenharmony_ci		cpu->dev.groups = hotplugable_cpu_attr_groups;
4128c2ecf20Sopenharmony_ci	error = device_register(&cpu->dev);
4138c2ecf20Sopenharmony_ci	if (error) {
4148c2ecf20Sopenharmony_ci		put_device(&cpu->dev);
4158c2ecf20Sopenharmony_ci		return error;
4168c2ecf20Sopenharmony_ci	}
4178c2ecf20Sopenharmony_ci
4188c2ecf20Sopenharmony_ci	per_cpu(cpu_sys_devices, num) = &cpu->dev;
4198c2ecf20Sopenharmony_ci	register_cpu_under_node(num, cpu_to_node(num));
4208c2ecf20Sopenharmony_ci	dev_pm_qos_expose_latency_limit(&cpu->dev,
4218c2ecf20Sopenharmony_ci					PM_QOS_RESUME_LATENCY_NO_CONSTRAINT);
4228c2ecf20Sopenharmony_ci
4238c2ecf20Sopenharmony_ci	return 0;
4248c2ecf20Sopenharmony_ci}
4258c2ecf20Sopenharmony_ci
4268c2ecf20Sopenharmony_cistruct device *get_cpu_device(unsigned cpu)
4278c2ecf20Sopenharmony_ci{
4288c2ecf20Sopenharmony_ci	if (cpu < nr_cpu_ids && cpu_possible(cpu))
4298c2ecf20Sopenharmony_ci		return per_cpu(cpu_sys_devices, cpu);
4308c2ecf20Sopenharmony_ci	else
4318c2ecf20Sopenharmony_ci		return NULL;
4328c2ecf20Sopenharmony_ci}
4338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(get_cpu_device);
4348c2ecf20Sopenharmony_ci
4358c2ecf20Sopenharmony_cistatic void device_create_release(struct device *dev)
4368c2ecf20Sopenharmony_ci{
4378c2ecf20Sopenharmony_ci	kfree(dev);
4388c2ecf20Sopenharmony_ci}
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci__printf(4, 0)
4418c2ecf20Sopenharmony_cistatic struct device *
4428c2ecf20Sopenharmony_ci__cpu_device_create(struct device *parent, void *drvdata,
4438c2ecf20Sopenharmony_ci		    const struct attribute_group **groups,
4448c2ecf20Sopenharmony_ci		    const char *fmt, va_list args)
4458c2ecf20Sopenharmony_ci{
4468c2ecf20Sopenharmony_ci	struct device *dev = NULL;
4478c2ecf20Sopenharmony_ci	int retval = -ENODEV;
4488c2ecf20Sopenharmony_ci
4498c2ecf20Sopenharmony_ci	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
4508c2ecf20Sopenharmony_ci	if (!dev) {
4518c2ecf20Sopenharmony_ci		retval = -ENOMEM;
4528c2ecf20Sopenharmony_ci		goto error;
4538c2ecf20Sopenharmony_ci	}
4548c2ecf20Sopenharmony_ci
4558c2ecf20Sopenharmony_ci	device_initialize(dev);
4568c2ecf20Sopenharmony_ci	dev->parent = parent;
4578c2ecf20Sopenharmony_ci	dev->groups = groups;
4588c2ecf20Sopenharmony_ci	dev->release = device_create_release;
4598c2ecf20Sopenharmony_ci	device_set_pm_not_required(dev);
4608c2ecf20Sopenharmony_ci	dev_set_drvdata(dev, drvdata);
4618c2ecf20Sopenharmony_ci
4628c2ecf20Sopenharmony_ci	retval = kobject_set_name_vargs(&dev->kobj, fmt, args);
4638c2ecf20Sopenharmony_ci	if (retval)
4648c2ecf20Sopenharmony_ci		goto error;
4658c2ecf20Sopenharmony_ci
4668c2ecf20Sopenharmony_ci	retval = device_add(dev);
4678c2ecf20Sopenharmony_ci	if (retval)
4688c2ecf20Sopenharmony_ci		goto error;
4698c2ecf20Sopenharmony_ci
4708c2ecf20Sopenharmony_ci	return dev;
4718c2ecf20Sopenharmony_ci
4728c2ecf20Sopenharmony_cierror:
4738c2ecf20Sopenharmony_ci	put_device(dev);
4748c2ecf20Sopenharmony_ci	return ERR_PTR(retval);
4758c2ecf20Sopenharmony_ci}
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_cistruct device *cpu_device_create(struct device *parent, void *drvdata,
4788c2ecf20Sopenharmony_ci				 const struct attribute_group **groups,
4798c2ecf20Sopenharmony_ci				 const char *fmt, ...)
4808c2ecf20Sopenharmony_ci{
4818c2ecf20Sopenharmony_ci	va_list vargs;
4828c2ecf20Sopenharmony_ci	struct device *dev;
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	va_start(vargs, fmt);
4858c2ecf20Sopenharmony_ci	dev = __cpu_device_create(parent, drvdata, groups, fmt, vargs);
4868c2ecf20Sopenharmony_ci	va_end(vargs);
4878c2ecf20Sopenharmony_ci	return dev;
4888c2ecf20Sopenharmony_ci}
4898c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cpu_device_create);
4908c2ecf20Sopenharmony_ci
4918c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
4928c2ecf20Sopenharmony_cistatic DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL);
4938c2ecf20Sopenharmony_ci#endif
4948c2ecf20Sopenharmony_ci
4958c2ecf20Sopenharmony_cistatic struct attribute *cpu_root_attrs[] = {
4968c2ecf20Sopenharmony_ci#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
4978c2ecf20Sopenharmony_ci	&dev_attr_probe.attr,
4988c2ecf20Sopenharmony_ci	&dev_attr_release.attr,
4998c2ecf20Sopenharmony_ci#endif
5008c2ecf20Sopenharmony_ci	&cpu_attrs[0].attr.attr,
5018c2ecf20Sopenharmony_ci	&cpu_attrs[1].attr.attr,
5028c2ecf20Sopenharmony_ci	&cpu_attrs[2].attr.attr,
5038c2ecf20Sopenharmony_ci#ifdef CONFIG_CPU_ISOLATION_OPT
5048c2ecf20Sopenharmony_ci	&cpu_attrs[3].attr.attr,
5058c2ecf20Sopenharmony_ci#endif
5068c2ecf20Sopenharmony_ci	&dev_attr_kernel_max.attr,
5078c2ecf20Sopenharmony_ci	&dev_attr_offline.attr,
5088c2ecf20Sopenharmony_ci	&dev_attr_isolated.attr,
5098c2ecf20Sopenharmony_ci#ifdef CONFIG_NO_HZ_FULL
5108c2ecf20Sopenharmony_ci	&dev_attr_nohz_full.attr,
5118c2ecf20Sopenharmony_ci#endif
5128c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_AUTOPROBE
5138c2ecf20Sopenharmony_ci	&dev_attr_modalias.attr,
5148c2ecf20Sopenharmony_ci#endif
5158c2ecf20Sopenharmony_ci	NULL
5168c2ecf20Sopenharmony_ci};
5178c2ecf20Sopenharmony_ci
5188c2ecf20Sopenharmony_cistatic struct attribute_group cpu_root_attr_group = {
5198c2ecf20Sopenharmony_ci	.attrs = cpu_root_attrs,
5208c2ecf20Sopenharmony_ci};
5218c2ecf20Sopenharmony_ci
5228c2ecf20Sopenharmony_cistatic const struct attribute_group *cpu_root_attr_groups[] = {
5238c2ecf20Sopenharmony_ci	&cpu_root_attr_group,
5248c2ecf20Sopenharmony_ci	NULL,
5258c2ecf20Sopenharmony_ci};
5268c2ecf20Sopenharmony_ci
5278c2ecf20Sopenharmony_cibool cpu_is_hotpluggable(unsigned cpu)
5288c2ecf20Sopenharmony_ci{
5298c2ecf20Sopenharmony_ci	struct device *dev = get_cpu_device(cpu);
5308c2ecf20Sopenharmony_ci	return dev && container_of(dev, struct cpu, dev)->hotpluggable
5318c2ecf20Sopenharmony_ci		&& tick_nohz_cpu_hotpluggable(cpu);
5328c2ecf20Sopenharmony_ci}
5338c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(cpu_is_hotpluggable);
5348c2ecf20Sopenharmony_ci
5358c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_DEVICES
5368c2ecf20Sopenharmony_cistatic DEFINE_PER_CPU(struct cpu, cpu_devices);
5378c2ecf20Sopenharmony_ci#endif
5388c2ecf20Sopenharmony_ci
5398c2ecf20Sopenharmony_cistatic void __init cpu_dev_register_generic(void)
5408c2ecf20Sopenharmony_ci{
5418c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_DEVICES
5428c2ecf20Sopenharmony_ci	int i;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	for_each_possible_cpu(i) {
5458c2ecf20Sopenharmony_ci		if (register_cpu(&per_cpu(cpu_devices, i), i))
5468c2ecf20Sopenharmony_ci			panic("Failed to register CPU device");
5478c2ecf20Sopenharmony_ci	}
5488c2ecf20Sopenharmony_ci#endif
5498c2ecf20Sopenharmony_ci}
5508c2ecf20Sopenharmony_ci
5518c2ecf20Sopenharmony_ci#ifdef CONFIG_GENERIC_CPU_VULNERABILITIES
5528c2ecf20Sopenharmony_ci
5538c2ecf20Sopenharmony_cissize_t __weak cpu_show_meltdown(struct device *dev,
5548c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
5558c2ecf20Sopenharmony_ci{
5568c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5578c2ecf20Sopenharmony_ci}
5588c2ecf20Sopenharmony_ci
5598c2ecf20Sopenharmony_cissize_t __weak cpu_show_spectre_v1(struct device *dev,
5608c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
5618c2ecf20Sopenharmony_ci{
5628c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5638c2ecf20Sopenharmony_ci}
5648c2ecf20Sopenharmony_ci
5658c2ecf20Sopenharmony_cissize_t __weak cpu_show_spectre_v2(struct device *dev,
5668c2ecf20Sopenharmony_ci				   struct device_attribute *attr, char *buf)
5678c2ecf20Sopenharmony_ci{
5688c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5698c2ecf20Sopenharmony_ci}
5708c2ecf20Sopenharmony_ci
5718c2ecf20Sopenharmony_cissize_t __weak cpu_show_spec_store_bypass(struct device *dev,
5728c2ecf20Sopenharmony_ci					  struct device_attribute *attr, char *buf)
5738c2ecf20Sopenharmony_ci{
5748c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5758c2ecf20Sopenharmony_ci}
5768c2ecf20Sopenharmony_ci
5778c2ecf20Sopenharmony_cissize_t __weak cpu_show_l1tf(struct device *dev,
5788c2ecf20Sopenharmony_ci			     struct device_attribute *attr, char *buf)
5798c2ecf20Sopenharmony_ci{
5808c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5818c2ecf20Sopenharmony_ci}
5828c2ecf20Sopenharmony_ci
5838c2ecf20Sopenharmony_cissize_t __weak cpu_show_mds(struct device *dev,
5848c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
5858c2ecf20Sopenharmony_ci{
5868c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5878c2ecf20Sopenharmony_ci}
5888c2ecf20Sopenharmony_ci
5898c2ecf20Sopenharmony_cissize_t __weak cpu_show_tsx_async_abort(struct device *dev,
5908c2ecf20Sopenharmony_ci					struct device_attribute *attr,
5918c2ecf20Sopenharmony_ci					char *buf)
5928c2ecf20Sopenharmony_ci{
5938c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
5948c2ecf20Sopenharmony_ci}
5958c2ecf20Sopenharmony_ci
5968c2ecf20Sopenharmony_cissize_t __weak cpu_show_itlb_multihit(struct device *dev,
5978c2ecf20Sopenharmony_ci				      struct device_attribute *attr, char *buf)
5988c2ecf20Sopenharmony_ci{
5998c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6008c2ecf20Sopenharmony_ci}
6018c2ecf20Sopenharmony_ci
6028c2ecf20Sopenharmony_cissize_t __weak cpu_show_srbds(struct device *dev,
6038c2ecf20Sopenharmony_ci			      struct device_attribute *attr, char *buf)
6048c2ecf20Sopenharmony_ci{
6058c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6068c2ecf20Sopenharmony_ci}
6078c2ecf20Sopenharmony_ci
6088c2ecf20Sopenharmony_cissize_t __weak cpu_show_mmio_stale_data(struct device *dev,
6098c2ecf20Sopenharmony_ci					struct device_attribute *attr, char *buf)
6108c2ecf20Sopenharmony_ci{
6118c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6128c2ecf20Sopenharmony_ci}
6138c2ecf20Sopenharmony_ci
6148c2ecf20Sopenharmony_cissize_t __weak cpu_show_retbleed(struct device *dev,
6158c2ecf20Sopenharmony_ci				 struct device_attribute *attr, char *buf)
6168c2ecf20Sopenharmony_ci{
6178c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6188c2ecf20Sopenharmony_ci}
6198c2ecf20Sopenharmony_ci
6208c2ecf20Sopenharmony_cissize_t __weak cpu_show_gds(struct device *dev,
6218c2ecf20Sopenharmony_ci			    struct device_attribute *attr, char *buf)
6228c2ecf20Sopenharmony_ci{
6238c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6248c2ecf20Sopenharmony_ci}
6258c2ecf20Sopenharmony_ci
6268c2ecf20Sopenharmony_cissize_t __weak cpu_show_spec_rstack_overflow(struct device *dev,
6278c2ecf20Sopenharmony_ci					     struct device_attribute *attr, char *buf)
6288c2ecf20Sopenharmony_ci{
6298c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6308c2ecf20Sopenharmony_ci}
6318c2ecf20Sopenharmony_ci
6328c2ecf20Sopenharmony_cissize_t __weak cpu_show_reg_file_data_sampling(struct device *dev,
6338c2ecf20Sopenharmony_ci					       struct device_attribute *attr, char *buf)
6348c2ecf20Sopenharmony_ci{
6358c2ecf20Sopenharmony_ci	return sysfs_emit(buf, "Not affected\n");
6368c2ecf20Sopenharmony_ci}
6378c2ecf20Sopenharmony_ci
6388c2ecf20Sopenharmony_cistatic DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL);
6398c2ecf20Sopenharmony_cistatic DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL);
6408c2ecf20Sopenharmony_cistatic DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL);
6418c2ecf20Sopenharmony_cistatic DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL);
6428c2ecf20Sopenharmony_cistatic DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL);
6438c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL);
6448c2ecf20Sopenharmony_cistatic DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL);
6458c2ecf20Sopenharmony_cistatic DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL);
6468c2ecf20Sopenharmony_cistatic DEVICE_ATTR(srbds, 0444, cpu_show_srbds, NULL);
6478c2ecf20Sopenharmony_cistatic DEVICE_ATTR(mmio_stale_data, 0444, cpu_show_mmio_stale_data, NULL);
6488c2ecf20Sopenharmony_cistatic DEVICE_ATTR(retbleed, 0444, cpu_show_retbleed, NULL);
6498c2ecf20Sopenharmony_cistatic DEVICE_ATTR(gather_data_sampling, 0444, cpu_show_gds, NULL);
6508c2ecf20Sopenharmony_cistatic DEVICE_ATTR(spec_rstack_overflow, 0444, cpu_show_spec_rstack_overflow, NULL);
6518c2ecf20Sopenharmony_cistatic DEVICE_ATTR(reg_file_data_sampling, 0444, cpu_show_reg_file_data_sampling, NULL);
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_cistatic struct attribute *cpu_root_vulnerabilities_attrs[] = {
6548c2ecf20Sopenharmony_ci	&dev_attr_meltdown.attr,
6558c2ecf20Sopenharmony_ci	&dev_attr_spectre_v1.attr,
6568c2ecf20Sopenharmony_ci	&dev_attr_spectre_v2.attr,
6578c2ecf20Sopenharmony_ci	&dev_attr_spec_store_bypass.attr,
6588c2ecf20Sopenharmony_ci	&dev_attr_l1tf.attr,
6598c2ecf20Sopenharmony_ci	&dev_attr_mds.attr,
6608c2ecf20Sopenharmony_ci	&dev_attr_tsx_async_abort.attr,
6618c2ecf20Sopenharmony_ci	&dev_attr_itlb_multihit.attr,
6628c2ecf20Sopenharmony_ci	&dev_attr_srbds.attr,
6638c2ecf20Sopenharmony_ci	&dev_attr_mmio_stale_data.attr,
6648c2ecf20Sopenharmony_ci	&dev_attr_retbleed.attr,
6658c2ecf20Sopenharmony_ci	&dev_attr_gather_data_sampling.attr,
6668c2ecf20Sopenharmony_ci	&dev_attr_spec_rstack_overflow.attr,
6678c2ecf20Sopenharmony_ci	&dev_attr_reg_file_data_sampling.attr,
6688c2ecf20Sopenharmony_ci	NULL
6698c2ecf20Sopenharmony_ci};
6708c2ecf20Sopenharmony_ci
6718c2ecf20Sopenharmony_cistatic const struct attribute_group cpu_root_vulnerabilities_group = {
6728c2ecf20Sopenharmony_ci	.name  = "vulnerabilities",
6738c2ecf20Sopenharmony_ci	.attrs = cpu_root_vulnerabilities_attrs,
6748c2ecf20Sopenharmony_ci};
6758c2ecf20Sopenharmony_ci
6768c2ecf20Sopenharmony_cistatic void __init cpu_register_vulnerabilities(void)
6778c2ecf20Sopenharmony_ci{
6788c2ecf20Sopenharmony_ci	if (sysfs_create_group(&cpu_subsys.dev_root->kobj,
6798c2ecf20Sopenharmony_ci			       &cpu_root_vulnerabilities_group))
6808c2ecf20Sopenharmony_ci		pr_err("Unable to register CPU vulnerabilities\n");
6818c2ecf20Sopenharmony_ci}
6828c2ecf20Sopenharmony_ci
6838c2ecf20Sopenharmony_ci#else
6848c2ecf20Sopenharmony_cistatic inline void cpu_register_vulnerabilities(void) { }
6858c2ecf20Sopenharmony_ci#endif
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_civoid __init cpu_dev_init(void)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups))
6908c2ecf20Sopenharmony_ci		panic("Failed to register CPU subsystem");
6918c2ecf20Sopenharmony_ci
6928c2ecf20Sopenharmony_ci	cpu_dev_register_generic();
6938c2ecf20Sopenharmony_ci	cpu_register_vulnerabilities();
6948c2ecf20Sopenharmony_ci}
695