1989d42e8SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0 21da177e4SLinus Torvalds /* 38a25a2fdSKay Sievers * CPU subsystem support 41da177e4SLinus Torvalds */ 51da177e4SLinus Torvalds 6024f7846SBen Hutchings #include <linux/kernel.h> 71da177e4SLinus Torvalds #include <linux/module.h> 81da177e4SLinus Torvalds #include <linux/init.h> 9f6a57033SAl Viro #include <linux/sched.h> 101da177e4SLinus Torvalds #include <linux/cpu.h> 111da177e4SLinus Torvalds #include <linux/topology.h> 121da177e4SLinus Torvalds #include <linux/device.h> 1376b67ed9SKAMEZAWA Hiroyuki #include <linux/node.h> 145a0e3ad6STejun Heo #include <linux/gfp.h> 15fad12ac8SThomas Renninger #include <linux/slab.h> 169f13a1fdSBen Hutchings #include <linux/percpu.h> 17ac212b69SRafael J. Wysocki #include <linux/acpi.h> 18f86e4718SSudeep KarkadaNagesha #include <linux/of.h> 1967bad2fdSArd Biesheuvel #include <linux/cpufeature.h> 206570a9a1SRik van Riel #include <linux/tick.h> 2137efa4b4SAlex Shi #include <linux/pm_qos.h> 22edb93821SFrederic Weisbecker #include <linux/sched/isolation.h> 231da177e4SLinus Torvalds 24a1bdc7aaSBen Dooks #include "base.h" 251da177e4SLinus Torvalds 268a25a2fdSKay Sievers static DEFINE_PER_CPU(struct device *, cpu_sys_devices); 27ad74557aSAshok Raj 28ac212b69SRafael J. Wysocki static int cpu_subsys_match(struct device *dev, struct device_driver *drv) 29ac212b69SRafael J. Wysocki { 30ac212b69SRafael J. Wysocki /* ACPI style match is the only one that may succeed. */ 31ac212b69SRafael J. Wysocki if (acpi_driver_match_device(dev, drv)) 32ac212b69SRafael J. Wysocki return 1; 33ac212b69SRafael J. Wysocki 34ac212b69SRafael J. Wysocki return 0; 35ac212b69SRafael J. Wysocki } 36ac212b69SRafael J. Wysocki 371da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 3834640468SYasuaki Ishimatsu static void change_cpu_under_node(struct cpu *cpu, 3934640468SYasuaki Ishimatsu unsigned int from_nid, unsigned int to_nid) 4034640468SYasuaki Ishimatsu { 4134640468SYasuaki Ishimatsu int cpuid = cpu->dev.id; 4234640468SYasuaki Ishimatsu unregister_cpu_under_node(cpuid, from_nid); 4334640468SYasuaki Ishimatsu register_cpu_under_node(cpuid, to_nid); 4434640468SYasuaki Ishimatsu cpu->node_id = to_nid; 4534640468SYasuaki Ishimatsu } 4634640468SYasuaki Ishimatsu 47eda5867bSMathias Krause static int cpu_subsys_online(struct device *dev) 481da177e4SLinus Torvalds { 498a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 500902a904SRafael J. Wysocki int cpuid = dev->id; 5134640468SYasuaki Ishimatsu int from_nid, to_nid; 526dedcca6SToshi Kani int ret; 530902a904SRafael J. Wysocki 5434640468SYasuaki Ishimatsu from_nid = cpu_to_node(cpuid); 55c7991b0bSRafael J. Wysocki if (from_nid == NUMA_NO_NODE) 566dedcca6SToshi Kani return -ENODEV; 57c7991b0bSRafael J. Wysocki 5834640468SYasuaki Ishimatsu ret = cpu_up(cpuid); 5934640468SYasuaki Ishimatsu /* 6034640468SYasuaki Ishimatsu * When hot adding memory to memoryless node and enabling a cpu 6134640468SYasuaki Ishimatsu * on the node, node number of the cpu may internally change. 6234640468SYasuaki Ishimatsu */ 6334640468SYasuaki Ishimatsu to_nid = cpu_to_node(cpuid); 6434640468SYasuaki Ishimatsu if (from_nid != to_nid) 6534640468SYasuaki Ishimatsu change_cpu_under_node(cpu, from_nid, to_nid); 6634640468SYasuaki Ishimatsu 671da177e4SLinus Torvalds return ret; 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds 700902a904SRafael J. Wysocki static int cpu_subsys_offline(struct device *dev) 711da177e4SLinus Torvalds { 726dedcca6SToshi Kani return cpu_down(dev->id); 731da177e4SLinus Torvalds } 741c4e2d70SIgor Mammedov 7576b67ed9SKAMEZAWA Hiroyuki void unregister_cpu(struct cpu *cpu) 761da177e4SLinus Torvalds { 778a25a2fdSKay Sievers int logical_cpu = cpu->dev.id; 781da177e4SLinus Torvalds 7976b67ed9SKAMEZAWA Hiroyuki unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); 8076b67ed9SKAMEZAWA Hiroyuki 818a25a2fdSKay Sievers device_unregister(&cpu->dev); 82e37d05daSMike Travis per_cpu(cpu_sys_devices, logical_cpu) = NULL; 831da177e4SLinus Torvalds return; 841da177e4SLinus Torvalds } 8512633e80SNathan Fontenot 8612633e80SNathan Fontenot #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 878a25a2fdSKay Sievers static ssize_t cpu_probe_store(struct device *dev, 888a25a2fdSKay Sievers struct device_attribute *attr, 8928812fe1SAndi Kleen const char *buf, 9012633e80SNathan Fontenot size_t count) 9112633e80SNathan Fontenot { 92574b851eSToshi Kani ssize_t cnt; 93574b851eSToshi Kani int ret; 94574b851eSToshi Kani 95574b851eSToshi Kani ret = lock_device_hotplug_sysfs(); 96574b851eSToshi Kani if (ret) 97574b851eSToshi Kani return ret; 98574b851eSToshi Kani 99574b851eSToshi Kani cnt = arch_cpu_probe(buf, count); 100574b851eSToshi Kani 101574b851eSToshi Kani unlock_device_hotplug(); 102574b851eSToshi Kani return cnt; 10312633e80SNathan Fontenot } 10412633e80SNathan Fontenot 1058a25a2fdSKay Sievers static ssize_t cpu_release_store(struct device *dev, 1068a25a2fdSKay Sievers struct device_attribute *attr, 10728812fe1SAndi Kleen const char *buf, 10812633e80SNathan Fontenot size_t count) 10912633e80SNathan Fontenot { 110574b851eSToshi Kani ssize_t cnt; 111574b851eSToshi Kani int ret; 112574b851eSToshi Kani 113574b851eSToshi Kani ret = lock_device_hotplug_sysfs(); 114574b851eSToshi Kani if (ret) 115574b851eSToshi Kani return ret; 116574b851eSToshi Kani 117574b851eSToshi Kani cnt = arch_cpu_release(buf, count); 118574b851eSToshi Kani 119574b851eSToshi Kani unlock_device_hotplug(); 120574b851eSToshi Kani return cnt; 12112633e80SNathan Fontenot } 12212633e80SNathan Fontenot 1238a25a2fdSKay Sievers static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); 1248a25a2fdSKay Sievers static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); 12512633e80SNathan Fontenot #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 1261da177e4SLinus Torvalds #endif /* CONFIG_HOTPLUG_CPU */ 1271da177e4SLinus Torvalds 1280902a904SRafael J. Wysocki struct bus_type cpu_subsys = { 1290902a904SRafael J. Wysocki .name = "cpu", 1300902a904SRafael J. Wysocki .dev_name = "cpu", 131ac212b69SRafael J. Wysocki .match = cpu_subsys_match, 1320902a904SRafael J. Wysocki #ifdef CONFIG_HOTPLUG_CPU 1330902a904SRafael J. Wysocki .online = cpu_subsys_online, 1340902a904SRafael J. Wysocki .offline = cpu_subsys_offline, 1350902a904SRafael J. Wysocki #endif 1360902a904SRafael J. Wysocki }; 1370902a904SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_subsys); 1380902a904SRafael J. Wysocki 13951be5606SVivek Goyal #ifdef CONFIG_KEXEC 14051be5606SVivek Goyal #include <linux/kexec.h> 14151be5606SVivek Goyal 1428a25a2fdSKay Sievers static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, 1434a0b2b4dSAndi Kleen char *buf) 14451be5606SVivek Goyal { 1458a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 14651be5606SVivek Goyal ssize_t rc; 14751be5606SVivek Goyal unsigned long long addr; 14851be5606SVivek Goyal int cpunum; 14951be5606SVivek Goyal 1508a25a2fdSKay Sievers cpunum = cpu->dev.id; 15151be5606SVivek Goyal 15251be5606SVivek Goyal /* 15351be5606SVivek Goyal * Might be reading other cpu's data based on which cpu read thread 15451be5606SVivek Goyal * has been scheduled. But cpu data (memory) is allocated once during 15551be5606SVivek Goyal * boot up and this data does not change there after. Hence this 15651be5606SVivek Goyal * operation should be safe. No locking required. 15751be5606SVivek Goyal */ 1583b034b0dSVivek Goyal addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); 15951be5606SVivek Goyal rc = sprintf(buf, "%Lx\n", addr); 16051be5606SVivek Goyal return rc; 16151be5606SVivek Goyal } 1628a25a2fdSKay Sievers static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); 163eca4549fSZhang Yanfei 164eca4549fSZhang Yanfei static ssize_t show_crash_notes_size(struct device *dev, 165eca4549fSZhang Yanfei struct device_attribute *attr, 166eca4549fSZhang Yanfei char *buf) 167eca4549fSZhang Yanfei { 168eca4549fSZhang Yanfei ssize_t rc; 169eca4549fSZhang Yanfei 170bcfb87fbSArnd Bergmann rc = sprintf(buf, "%zu\n", sizeof(note_buf_t)); 171eca4549fSZhang Yanfei return rc; 172eca4549fSZhang Yanfei } 173eca4549fSZhang Yanfei static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL); 174c055da9fSIgor Mammedov 175c055da9fSIgor Mammedov static struct attribute *crash_note_cpu_attrs[] = { 176c055da9fSIgor Mammedov &dev_attr_crash_notes.attr, 177c055da9fSIgor Mammedov &dev_attr_crash_notes_size.attr, 178c055da9fSIgor Mammedov NULL 179c055da9fSIgor Mammedov }; 180c055da9fSIgor Mammedov 181c055da9fSIgor Mammedov static struct attribute_group crash_note_cpu_attr_group = { 182c055da9fSIgor Mammedov .attrs = crash_note_cpu_attrs, 183c055da9fSIgor Mammedov }; 18451be5606SVivek Goyal #endif 18551be5606SVivek Goyal 186c055da9fSIgor Mammedov static const struct attribute_group *common_cpu_attr_groups[] = { 187c055da9fSIgor Mammedov #ifdef CONFIG_KEXEC 188c055da9fSIgor Mammedov &crash_note_cpu_attr_group, 189c055da9fSIgor Mammedov #endif 190c055da9fSIgor Mammedov NULL 191c055da9fSIgor Mammedov }; 192c055da9fSIgor Mammedov 1931c4e2d70SIgor Mammedov static const struct attribute_group *hotplugable_cpu_attr_groups[] = { 1941c4e2d70SIgor Mammedov #ifdef CONFIG_KEXEC 1951c4e2d70SIgor Mammedov &crash_note_cpu_attr_group, 1961c4e2d70SIgor Mammedov #endif 1971c4e2d70SIgor Mammedov NULL 1981c4e2d70SIgor Mammedov }; 1991c4e2d70SIgor Mammedov 2001da177e4SLinus Torvalds /* 2019d1fe323SMike Travis * Print cpu online, possible, present, and system maps 2029d1fe323SMike Travis */ 203265d2e2eSAndi Kleen 204265d2e2eSAndi Kleen struct cpu_attr { 2058a25a2fdSKay Sievers struct device_attribute attr; 206848e2391SRasmus Villemoes const struct cpumask *const map; 207265d2e2eSAndi Kleen }; 208265d2e2eSAndi Kleen 2098a25a2fdSKay Sievers static ssize_t show_cpus_attr(struct device *dev, 2108a25a2fdSKay Sievers struct device_attribute *attr, 211265d2e2eSAndi Kleen char *buf) 2129d1fe323SMike Travis { 213265d2e2eSAndi Kleen struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); 2149d1fe323SMike Travis 215848e2391SRasmus Villemoes return cpumap_print_to_pagebuf(true, buf, ca->map); 2169d1fe323SMike Travis } 2179d1fe323SMike Travis 218265d2e2eSAndi Kleen #define _CPU_ATTR(name, map) \ 2198a25a2fdSKay Sievers { __ATTR(name, 0444, show_cpus_attr, NULL), map } 2209d1fe323SMike Travis 2218a25a2fdSKay Sievers /* Keep in sync with cpu_subsys_attrs */ 222265d2e2eSAndi Kleen static struct cpu_attr cpu_attrs[] = { 223848e2391SRasmus Villemoes _CPU_ATTR(online, &__cpu_online_mask), 224848e2391SRasmus Villemoes _CPU_ATTR(possible, &__cpu_possible_mask), 225848e2391SRasmus Villemoes _CPU_ATTR(present, &__cpu_present_mask), 226265d2e2eSAndi Kleen }; 2279d1fe323SMike Travis 228e057d7aeSMike Travis /* 229e057d7aeSMike Travis * Print values for NR_CPUS and offlined cpus 230e057d7aeSMike Travis */ 2318a25a2fdSKay Sievers static ssize_t print_cpus_kernel_max(struct device *dev, 2328a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 233e057d7aeSMike Travis { 2348fd2d2d5SMike Travis int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); 235e057d7aeSMike Travis return n; 236e057d7aeSMike Travis } 2378a25a2fdSKay Sievers static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); 238e057d7aeSMike Travis 239e057d7aeSMike Travis /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ 240e057d7aeSMike Travis unsigned int total_cpus; 241e057d7aeSMike Travis 2428a25a2fdSKay Sievers static ssize_t print_cpus_offline(struct device *dev, 2438a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 244e057d7aeSMike Travis { 245e057d7aeSMike Travis int n = 0, len = PAGE_SIZE-2; 246e057d7aeSMike Travis cpumask_var_t offline; 247e057d7aeSMike Travis 248e057d7aeSMike Travis /* display offline cpus < nr_cpu_ids */ 249e057d7aeSMike Travis if (!alloc_cpumask_var(&offline, GFP_KERNEL)) 250e057d7aeSMike Travis return -ENOMEM; 251cdc6e3d3SJan Beulich cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); 252f799b1a7STejun Heo n = scnprintf(buf, len, "%*pbl", cpumask_pr_args(offline)); 253e057d7aeSMike Travis free_cpumask_var(offline); 254e057d7aeSMike Travis 255e057d7aeSMike Travis /* display offline cpus >= nr_cpu_ids */ 256e057d7aeSMike Travis if (total_cpus && nr_cpu_ids < total_cpus) { 257e057d7aeSMike Travis if (n && n < len) 258e057d7aeSMike Travis buf[n++] = ','; 259e057d7aeSMike Travis 260e057d7aeSMike Travis if (nr_cpu_ids == total_cpus-1) 2619b130ad5SAlexey Dobriyan n += snprintf(&buf[n], len - n, "%u", nr_cpu_ids); 262e057d7aeSMike Travis else 2639b130ad5SAlexey Dobriyan n += snprintf(&buf[n], len - n, "%u-%d", 264e057d7aeSMike Travis nr_cpu_ids, total_cpus-1); 265e057d7aeSMike Travis } 266e057d7aeSMike Travis 267e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "\n"); 268e057d7aeSMike Travis return n; 269e057d7aeSMike Travis } 2708a25a2fdSKay Sievers static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); 271e057d7aeSMike Travis 27259f30abeSRik van Riel static ssize_t print_cpus_isolated(struct device *dev, 27359f30abeSRik van Riel struct device_attribute *attr, char *buf) 27459f30abeSRik van Riel { 27559f30abeSRik van Riel int n = 0, len = PAGE_SIZE-2; 276edb93821SFrederic Weisbecker cpumask_var_t isolated; 27759f30abeSRik van Riel 278edb93821SFrederic Weisbecker if (!alloc_cpumask_var(&isolated, GFP_KERNEL)) 279edb93821SFrederic Weisbecker return -ENOMEM; 280edb93821SFrederic Weisbecker 281edb93821SFrederic Weisbecker cpumask_andnot(isolated, cpu_possible_mask, 282edb93821SFrederic Weisbecker housekeeping_cpumask(HK_FLAG_DOMAIN)); 283edb93821SFrederic Weisbecker n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(isolated)); 284edb93821SFrederic Weisbecker 285edb93821SFrederic Weisbecker free_cpumask_var(isolated); 28659f30abeSRik van Riel 28759f30abeSRik van Riel return n; 28859f30abeSRik van Riel } 28959f30abeSRik van Riel static DEVICE_ATTR(isolated, 0444, print_cpus_isolated, NULL); 29059f30abeSRik van Riel 2916570a9a1SRik van Riel #ifdef CONFIG_NO_HZ_FULL 2926570a9a1SRik van Riel static ssize_t print_cpus_nohz_full(struct device *dev, 2936570a9a1SRik van Riel struct device_attribute *attr, char *buf) 2946570a9a1SRik van Riel { 2956570a9a1SRik van Riel int n = 0, len = PAGE_SIZE-2; 2966570a9a1SRik van Riel 2976570a9a1SRik van Riel n = scnprintf(buf, len, "%*pbl\n", cpumask_pr_args(tick_nohz_full_mask)); 2986570a9a1SRik van Riel 2996570a9a1SRik van Riel return n; 3006570a9a1SRik van Riel } 3016570a9a1SRik van Riel static DEVICE_ATTR(nohz_full, 0444, print_cpus_nohz_full, NULL); 3026570a9a1SRik van Riel #endif 3036570a9a1SRik van Riel 3042885e25cSGreg Kroah-Hartman static void cpu_device_release(struct device *dev) 3052885e25cSGreg Kroah-Hartman { 3062885e25cSGreg Kroah-Hartman /* 3072885e25cSGreg Kroah-Hartman * This is an empty function to prevent the driver core from spitting a 3082885e25cSGreg Kroah-Hartman * warning at us. Yes, I know this is directly opposite of what the 3092885e25cSGreg Kroah-Hartman * documentation for the driver core and kobjects say, and the author 3102885e25cSGreg Kroah-Hartman * of this code has already been publically ridiculed for doing 3112885e25cSGreg Kroah-Hartman * something as foolish as this. However, at this point in time, it is 3122885e25cSGreg Kroah-Hartman * the only way to handle the issue of statically allocated cpu 3132885e25cSGreg Kroah-Hartman * devices. The different architectures will have their cpu device 3142885e25cSGreg Kroah-Hartman * code reworked to properly handle this in the near future, so this 3152885e25cSGreg Kroah-Hartman * function will then be changed to correctly free up the memory held 3162885e25cSGreg Kroah-Hartman * by the cpu device. 3172885e25cSGreg Kroah-Hartman * 3182885e25cSGreg Kroah-Hartman * Never copy this way of doing things, or you too will be made fun of 31930a4840aSRalf Baechle * on the linux-kernel list, you have been warned. 3202885e25cSGreg Kroah-Hartman */ 3212885e25cSGreg Kroah-Hartman } 3222885e25cSGreg Kroah-Hartman 32367bad2fdSArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 32467bad2fdSArd Biesheuvel static ssize_t print_cpu_modalias(struct device *dev, 32567bad2fdSArd Biesheuvel struct device_attribute *attr, 32667bad2fdSArd Biesheuvel char *buf) 32767bad2fdSArd Biesheuvel { 32867bad2fdSArd Biesheuvel ssize_t n; 32967bad2fdSArd Biesheuvel u32 i; 33067bad2fdSArd Biesheuvel 33167bad2fdSArd Biesheuvel n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", 33267bad2fdSArd Biesheuvel CPU_FEATURE_TYPEVAL); 33367bad2fdSArd Biesheuvel 33467bad2fdSArd Biesheuvel for (i = 0; i < MAX_CPU_FEATURES; i++) 33567bad2fdSArd Biesheuvel if (cpu_have_feature(i)) { 33667bad2fdSArd Biesheuvel if (PAGE_SIZE < n + sizeof(",XXXX\n")) { 33767bad2fdSArd Biesheuvel WARN(1, "CPU features overflow page\n"); 33867bad2fdSArd Biesheuvel break; 33967bad2fdSArd Biesheuvel } 34067bad2fdSArd Biesheuvel n += sprintf(&buf[n], ",%04X", i); 34167bad2fdSArd Biesheuvel } 34267bad2fdSArd Biesheuvel buf[n++] = '\n'; 34367bad2fdSArd Biesheuvel return n; 34467bad2fdSArd Biesheuvel } 34567bad2fdSArd Biesheuvel 34667bad2fdSArd Biesheuvel static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) 34767bad2fdSArd Biesheuvel { 34867bad2fdSArd Biesheuvel char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 34967bad2fdSArd Biesheuvel if (buf) { 35067bad2fdSArd Biesheuvel print_cpu_modalias(NULL, NULL, buf); 35167bad2fdSArd Biesheuvel add_uevent_var(env, "MODALIAS=%s", buf); 35267bad2fdSArd Biesheuvel kfree(buf); 35367bad2fdSArd Biesheuvel } 35467bad2fdSArd Biesheuvel return 0; 35567bad2fdSArd Biesheuvel } 35667bad2fdSArd Biesheuvel #endif 35767bad2fdSArd Biesheuvel 3589d1fe323SMike Travis /* 359405ae7d3SRobert P. J. Day * register_cpu - Setup a sysfs device for a CPU. 36072486f1fSSiddha, Suresh B * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 36172486f1fSSiddha, Suresh B * sysfs for this CPU. 3621da177e4SLinus Torvalds * @num - CPU number to use when creating the device. 3631da177e4SLinus Torvalds * 3641da177e4SLinus Torvalds * Initialize and register the CPU device. 3651da177e4SLinus Torvalds */ 366a83048ebSPaul Gortmaker int register_cpu(struct cpu *cpu, int num) 3671da177e4SLinus Torvalds { 3681da177e4SLinus Torvalds int error; 3698a25a2fdSKay Sievers 3701da177e4SLinus Torvalds cpu->node_id = cpu_to_node(num); 37129bb5d4fSGreg Kroah-Hartman memset(&cpu->dev, 0x00, sizeof(struct device)); 3728a25a2fdSKay Sievers cpu->dev.id = num; 3738a25a2fdSKay Sievers cpu->dev.bus = &cpu_subsys; 3742885e25cSGreg Kroah-Hartman cpu->dev.release = cpu_device_release; 3750902a904SRafael J. Wysocki cpu->dev.offline_disabled = !cpu->hotpluggable; 3761001b4d4SToshi Kani cpu->dev.offline = !cpu_online(num); 377f86e4718SSudeep KarkadaNagesha cpu->dev.of_node = of_get_cpu_node(num, NULL); 3782b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 37967bad2fdSArd Biesheuvel cpu->dev.bus->uevent = cpu_uevent; 380fad12ac8SThomas Renninger #endif 381c055da9fSIgor Mammedov cpu->dev.groups = common_cpu_attr_groups; 3821c4e2d70SIgor Mammedov if (cpu->hotpluggable) 3831c4e2d70SIgor Mammedov cpu->dev.groups = hotplugable_cpu_attr_groups; 3848a25a2fdSKay Sievers error = device_register(&cpu->dev); 3853aaba245SArvind Yadav if (error) { 3863aaba245SArvind Yadav put_device(&cpu->dev); 38759fffa34SAlex Shi return error; 3883aaba245SArvind Yadav } 38959fffa34SAlex Shi 3908a25a2fdSKay Sievers per_cpu(cpu_sys_devices, num) = &cpu->dev; 39176b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(num, cpu_to_node(num)); 3920759e80bSRafael J. Wysocki dev_pm_qos_expose_latency_limit(&cpu->dev, 3930759e80bSRafael J. Wysocki PM_QOS_RESUME_LATENCY_NO_CONSTRAINT); 39451be5606SVivek Goyal 39559fffa34SAlex Shi return 0; 3961da177e4SLinus Torvalds } 3971da177e4SLinus Torvalds 3988a25a2fdSKay Sievers struct device *get_cpu_device(unsigned cpu) 399ad74557aSAshok Raj { 400e37d05daSMike Travis if (cpu < nr_cpu_ids && cpu_possible(cpu)) 401e37d05daSMike Travis return per_cpu(cpu_sys_devices, cpu); 402ad74557aSAshok Raj else 403ad74557aSAshok Raj return NULL; 404ad74557aSAshok Raj } 4058a25a2fdSKay Sievers EXPORT_SYMBOL_GPL(get_cpu_device); 4068a25a2fdSKay Sievers 4073d52943bSSudeep Holla static void device_create_release(struct device *dev) 4083d52943bSSudeep Holla { 4093d52943bSSudeep Holla kfree(dev); 4103d52943bSSudeep Holla } 4113d52943bSSudeep Holla 412fa548d79SMathieu Malaterre __printf(4, 0) 4133d52943bSSudeep Holla static struct device * 4143d52943bSSudeep Holla __cpu_device_create(struct device *parent, void *drvdata, 4153d52943bSSudeep Holla const struct attribute_group **groups, 4163d52943bSSudeep Holla const char *fmt, va_list args) 4173d52943bSSudeep Holla { 4183d52943bSSudeep Holla struct device *dev = NULL; 4193d52943bSSudeep Holla int retval = -ENODEV; 4203d52943bSSudeep Holla 4213d52943bSSudeep Holla dev = kzalloc(sizeof(*dev), GFP_KERNEL); 4223d52943bSSudeep Holla if (!dev) { 4233d52943bSSudeep Holla retval = -ENOMEM; 4243d52943bSSudeep Holla goto error; 4253d52943bSSudeep Holla } 4263d52943bSSudeep Holla 4273d52943bSSudeep Holla device_initialize(dev); 4283d52943bSSudeep Holla dev->parent = parent; 4293d52943bSSudeep Holla dev->groups = groups; 4303d52943bSSudeep Holla dev->release = device_create_release; 43185945c28SSudeep Holla device_set_pm_not_required(dev); 4323d52943bSSudeep Holla dev_set_drvdata(dev, drvdata); 4333d52943bSSudeep Holla 4343d52943bSSudeep Holla retval = kobject_set_name_vargs(&dev->kobj, fmt, args); 4353d52943bSSudeep Holla if (retval) 4363d52943bSSudeep Holla goto error; 4373d52943bSSudeep Holla 4383d52943bSSudeep Holla retval = device_add(dev); 4393d52943bSSudeep Holla if (retval) 4403d52943bSSudeep Holla goto error; 4413d52943bSSudeep Holla 4423d52943bSSudeep Holla return dev; 4433d52943bSSudeep Holla 4443d52943bSSudeep Holla error: 4453d52943bSSudeep Holla put_device(dev); 4463d52943bSSudeep Holla return ERR_PTR(retval); 4473d52943bSSudeep Holla } 4483d52943bSSudeep Holla 4493d52943bSSudeep Holla struct device *cpu_device_create(struct device *parent, void *drvdata, 4503d52943bSSudeep Holla const struct attribute_group **groups, 4513d52943bSSudeep Holla const char *fmt, ...) 4523d52943bSSudeep Holla { 4533d52943bSSudeep Holla va_list vargs; 4543d52943bSSudeep Holla struct device *dev; 4553d52943bSSudeep Holla 4563d52943bSSudeep Holla va_start(vargs, fmt); 4573d52943bSSudeep Holla dev = __cpu_device_create(parent, drvdata, groups, fmt, vargs); 4583d52943bSSudeep Holla va_end(vargs); 4593d52943bSSudeep Holla return dev; 4603d52943bSSudeep Holla } 4613d52943bSSudeep Holla EXPORT_SYMBOL_GPL(cpu_device_create); 4623d52943bSSudeep Holla 4632b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 46467bad2fdSArd Biesheuvel static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); 465fad12ac8SThomas Renninger #endif 466fad12ac8SThomas Renninger 4678a25a2fdSKay Sievers static struct attribute *cpu_root_attrs[] = { 4688a25a2fdSKay Sievers #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 4698a25a2fdSKay Sievers &dev_attr_probe.attr, 4708a25a2fdSKay Sievers &dev_attr_release.attr, 4718a25a2fdSKay Sievers #endif 4728a25a2fdSKay Sievers &cpu_attrs[0].attr.attr, 4738a25a2fdSKay Sievers &cpu_attrs[1].attr.attr, 4748a25a2fdSKay Sievers &cpu_attrs[2].attr.attr, 4758a25a2fdSKay Sievers &dev_attr_kernel_max.attr, 4768a25a2fdSKay Sievers &dev_attr_offline.attr, 47759f30abeSRik van Riel &dev_attr_isolated.attr, 4786570a9a1SRik van Riel #ifdef CONFIG_NO_HZ_FULL 4796570a9a1SRik van Riel &dev_attr_nohz_full.attr, 4806570a9a1SRik van Riel #endif 4812b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 482fad12ac8SThomas Renninger &dev_attr_modalias.attr, 483fad12ac8SThomas Renninger #endif 4848a25a2fdSKay Sievers NULL 4858a25a2fdSKay Sievers }; 4868a25a2fdSKay Sievers 4878a25a2fdSKay Sievers static struct attribute_group cpu_root_attr_group = { 4888a25a2fdSKay Sievers .attrs = cpu_root_attrs, 4898a25a2fdSKay Sievers }; 4908a25a2fdSKay Sievers 4918a25a2fdSKay Sievers static const struct attribute_group *cpu_root_attr_groups[] = { 4928a25a2fdSKay Sievers &cpu_root_attr_group, 4938a25a2fdSKay Sievers NULL, 4948a25a2fdSKay Sievers }; 4951da177e4SLinus Torvalds 4962987557fSJosh Triplett bool cpu_is_hotpluggable(unsigned cpu) 4972987557fSJosh Triplett { 4987affca35SLinus Torvalds struct device *dev = get_cpu_device(cpu); 4997affca35SLinus Torvalds return dev && container_of(dev, struct cpu, dev)->hotpluggable; 5002987557fSJosh Triplett } 5012987557fSJosh Triplett EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); 5022987557fSJosh Triplett 5039f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 5049f13a1fdSBen Hutchings static DEFINE_PER_CPU(struct cpu, cpu_devices); 5059f13a1fdSBen Hutchings #endif 5069f13a1fdSBen Hutchings 5079f13a1fdSBen Hutchings static void __init cpu_dev_register_generic(void) 5089f13a1fdSBen Hutchings { 5099f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 5109f13a1fdSBen Hutchings int i; 5119f13a1fdSBen Hutchings 5129f13a1fdSBen Hutchings for_each_possible_cpu(i) { 5139f13a1fdSBen Hutchings if (register_cpu(&per_cpu(cpu_devices, i), i)) 5149f13a1fdSBen Hutchings panic("Failed to register CPU device"); 5159f13a1fdSBen Hutchings } 5169f13a1fdSBen Hutchings #endif 5179f13a1fdSBen Hutchings } 5189f13a1fdSBen Hutchings 51987590ce6SThomas Gleixner #ifdef CONFIG_GENERIC_CPU_VULNERABILITIES 52087590ce6SThomas Gleixner 52187590ce6SThomas Gleixner ssize_t __weak cpu_show_meltdown(struct device *dev, 52287590ce6SThomas Gleixner struct device_attribute *attr, char *buf) 52387590ce6SThomas Gleixner { 52487590ce6SThomas Gleixner return sprintf(buf, "Not affected\n"); 52587590ce6SThomas Gleixner } 52687590ce6SThomas Gleixner 52787590ce6SThomas Gleixner ssize_t __weak cpu_show_spectre_v1(struct device *dev, 52887590ce6SThomas Gleixner struct device_attribute *attr, char *buf) 52987590ce6SThomas Gleixner { 53087590ce6SThomas Gleixner return sprintf(buf, "Not affected\n"); 53187590ce6SThomas Gleixner } 53287590ce6SThomas Gleixner 53387590ce6SThomas Gleixner ssize_t __weak cpu_show_spectre_v2(struct device *dev, 53487590ce6SThomas Gleixner struct device_attribute *attr, char *buf) 53587590ce6SThomas Gleixner { 53687590ce6SThomas Gleixner return sprintf(buf, "Not affected\n"); 53787590ce6SThomas Gleixner } 53887590ce6SThomas Gleixner 539c456442cSKonrad Rzeszutek Wilk ssize_t __weak cpu_show_spec_store_bypass(struct device *dev, 540c456442cSKonrad Rzeszutek Wilk struct device_attribute *attr, char *buf) 541c456442cSKonrad Rzeszutek Wilk { 542c456442cSKonrad Rzeszutek Wilk return sprintf(buf, "Not affected\n"); 543c456442cSKonrad Rzeszutek Wilk } 544c456442cSKonrad Rzeszutek Wilk 54517dbca11SAndi Kleen ssize_t __weak cpu_show_l1tf(struct device *dev, 54617dbca11SAndi Kleen struct device_attribute *attr, char *buf) 54717dbca11SAndi Kleen { 54817dbca11SAndi Kleen return sprintf(buf, "Not affected\n"); 54917dbca11SAndi Kleen } 55017dbca11SAndi Kleen 5518a4b06d3SThomas Gleixner ssize_t __weak cpu_show_mds(struct device *dev, 5528a4b06d3SThomas Gleixner struct device_attribute *attr, char *buf) 5538a4b06d3SThomas Gleixner { 5548a4b06d3SThomas Gleixner return sprintf(buf, "Not affected\n"); 5558a4b06d3SThomas Gleixner } 5568a4b06d3SThomas Gleixner 5576608b45aSPawan Gupta ssize_t __weak cpu_show_tsx_async_abort(struct device *dev, 5586608b45aSPawan Gupta struct device_attribute *attr, 5596608b45aSPawan Gupta char *buf) 5606608b45aSPawan Gupta { 5616608b45aSPawan Gupta return sprintf(buf, "Not affected\n"); 5626608b45aSPawan Gupta } 5636608b45aSPawan Gupta 564db4d30fbSVineela Tummalapalli ssize_t __weak cpu_show_itlb_multihit(struct device *dev, 565db4d30fbSVineela Tummalapalli struct device_attribute *attr, char *buf) 566db4d30fbSVineela Tummalapalli { 567db4d30fbSVineela Tummalapalli return sprintf(buf, "Not affected\n"); 568db4d30fbSVineela Tummalapalli } 569db4d30fbSVineela Tummalapalli 57087590ce6SThomas Gleixner static DEVICE_ATTR(meltdown, 0444, cpu_show_meltdown, NULL); 57187590ce6SThomas Gleixner static DEVICE_ATTR(spectre_v1, 0444, cpu_show_spectre_v1, NULL); 57287590ce6SThomas Gleixner static DEVICE_ATTR(spectre_v2, 0444, cpu_show_spectre_v2, NULL); 573c456442cSKonrad Rzeszutek Wilk static DEVICE_ATTR(spec_store_bypass, 0444, cpu_show_spec_store_bypass, NULL); 57417dbca11SAndi Kleen static DEVICE_ATTR(l1tf, 0444, cpu_show_l1tf, NULL); 5758a4b06d3SThomas Gleixner static DEVICE_ATTR(mds, 0444, cpu_show_mds, NULL); 5766608b45aSPawan Gupta static DEVICE_ATTR(tsx_async_abort, 0444, cpu_show_tsx_async_abort, NULL); 577db4d30fbSVineela Tummalapalli static DEVICE_ATTR(itlb_multihit, 0444, cpu_show_itlb_multihit, NULL); 57887590ce6SThomas Gleixner 57987590ce6SThomas Gleixner static struct attribute *cpu_root_vulnerabilities_attrs[] = { 58087590ce6SThomas Gleixner &dev_attr_meltdown.attr, 58187590ce6SThomas Gleixner &dev_attr_spectre_v1.attr, 58287590ce6SThomas Gleixner &dev_attr_spectre_v2.attr, 583c456442cSKonrad Rzeszutek Wilk &dev_attr_spec_store_bypass.attr, 58417dbca11SAndi Kleen &dev_attr_l1tf.attr, 5858a4b06d3SThomas Gleixner &dev_attr_mds.attr, 5866608b45aSPawan Gupta &dev_attr_tsx_async_abort.attr, 587db4d30fbSVineela Tummalapalli &dev_attr_itlb_multihit.attr, 58887590ce6SThomas Gleixner NULL 58987590ce6SThomas Gleixner }; 59087590ce6SThomas Gleixner 59187590ce6SThomas Gleixner static const struct attribute_group cpu_root_vulnerabilities_group = { 59287590ce6SThomas Gleixner .name = "vulnerabilities", 59387590ce6SThomas Gleixner .attrs = cpu_root_vulnerabilities_attrs, 59487590ce6SThomas Gleixner }; 59587590ce6SThomas Gleixner 59687590ce6SThomas Gleixner static void __init cpu_register_vulnerabilities(void) 59787590ce6SThomas Gleixner { 59887590ce6SThomas Gleixner if (sysfs_create_group(&cpu_subsys.dev_root->kobj, 59987590ce6SThomas Gleixner &cpu_root_vulnerabilities_group)) 60087590ce6SThomas Gleixner pr_err("Unable to register CPU vulnerabilities\n"); 60187590ce6SThomas Gleixner } 60287590ce6SThomas Gleixner 60387590ce6SThomas Gleixner #else 60487590ce6SThomas Gleixner static inline void cpu_register_vulnerabilities(void) { } 60587590ce6SThomas Gleixner #endif 60687590ce6SThomas Gleixner 607024f7846SBen Hutchings void __init cpu_dev_init(void) 6081da177e4SLinus Torvalds { 609024f7846SBen Hutchings if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) 610024f7846SBen Hutchings panic("Failed to register CPU subsystem"); 6115c45bf27SSiddha, Suresh B 6129f13a1fdSBen Hutchings cpu_dev_register_generic(); 61387590ce6SThomas Gleixner cpu_register_vulnerabilities(); 6141da177e4SLinus Torvalds } 615