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