11da177e4SLinus Torvalds /* 28a25a2fdSKay Sievers * CPU subsystem support 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 5024f7846SBen Hutchings #include <linux/kernel.h> 61da177e4SLinus Torvalds #include <linux/module.h> 71da177e4SLinus Torvalds #include <linux/init.h> 8f6a57033SAl Viro #include <linux/sched.h> 91da177e4SLinus Torvalds #include <linux/cpu.h> 101da177e4SLinus Torvalds #include <linux/topology.h> 111da177e4SLinus Torvalds #include <linux/device.h> 1276b67ed9SKAMEZAWA Hiroyuki #include <linux/node.h> 135a0e3ad6STejun Heo #include <linux/gfp.h> 14fad12ac8SThomas Renninger #include <linux/slab.h> 159f13a1fdSBen Hutchings #include <linux/percpu.h> 16ac212b69SRafael J. Wysocki #include <linux/acpi.h> 17f86e4718SSudeep KarkadaNagesha #include <linux/of.h> 1867bad2fdSArd Biesheuvel #include <linux/cpufeature.h> 191da177e4SLinus Torvalds 20a1bdc7aaSBen Dooks #include "base.h" 211da177e4SLinus Torvalds 228a25a2fdSKay Sievers static DEFINE_PER_CPU(struct device *, cpu_sys_devices); 23ad74557aSAshok Raj 24ac212b69SRafael J. Wysocki static int cpu_subsys_match(struct device *dev, struct device_driver *drv) 25ac212b69SRafael J. Wysocki { 26ac212b69SRafael J. Wysocki /* ACPI style match is the only one that may succeed. */ 27ac212b69SRafael J. Wysocki if (acpi_driver_match_device(dev, drv)) 28ac212b69SRafael J. Wysocki return 1; 29ac212b69SRafael J. Wysocki 30ac212b69SRafael J. Wysocki return 0; 31ac212b69SRafael J. Wysocki } 32ac212b69SRafael J. Wysocki 331da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 3434640468SYasuaki Ishimatsu static void change_cpu_under_node(struct cpu *cpu, 3534640468SYasuaki Ishimatsu unsigned int from_nid, unsigned int to_nid) 3634640468SYasuaki Ishimatsu { 3734640468SYasuaki Ishimatsu int cpuid = cpu->dev.id; 3834640468SYasuaki Ishimatsu unregister_cpu_under_node(cpuid, from_nid); 3934640468SYasuaki Ishimatsu register_cpu_under_node(cpuid, to_nid); 4034640468SYasuaki Ishimatsu cpu->node_id = to_nid; 4134640468SYasuaki Ishimatsu } 4234640468SYasuaki Ishimatsu 430902a904SRafael J. Wysocki static int __ref cpu_subsys_online(struct device *dev) 441da177e4SLinus Torvalds { 458a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 460902a904SRafael J. Wysocki int cpuid = dev->id; 4734640468SYasuaki Ishimatsu int from_nid, to_nid; 486dedcca6SToshi Kani int ret; 490902a904SRafael J. Wysocki 5034640468SYasuaki Ishimatsu from_nid = cpu_to_node(cpuid); 51c7991b0bSRafael J. Wysocki if (from_nid == NUMA_NO_NODE) 526dedcca6SToshi Kani return -ENODEV; 53c7991b0bSRafael J. Wysocki 5434640468SYasuaki Ishimatsu ret = cpu_up(cpuid); 5534640468SYasuaki Ishimatsu /* 5634640468SYasuaki Ishimatsu * When hot adding memory to memoryless node and enabling a cpu 5734640468SYasuaki Ishimatsu * on the node, node number of the cpu may internally change. 5834640468SYasuaki Ishimatsu */ 5934640468SYasuaki Ishimatsu to_nid = cpu_to_node(cpuid); 6034640468SYasuaki Ishimatsu if (from_nid != to_nid) 6134640468SYasuaki Ishimatsu change_cpu_under_node(cpu, from_nid, to_nid); 6234640468SYasuaki Ishimatsu 631da177e4SLinus Torvalds return ret; 641da177e4SLinus Torvalds } 651da177e4SLinus Torvalds 660902a904SRafael J. Wysocki static int cpu_subsys_offline(struct device *dev) 671da177e4SLinus Torvalds { 686dedcca6SToshi Kani return cpu_down(dev->id); 691da177e4SLinus Torvalds } 701c4e2d70SIgor Mammedov 7176b67ed9SKAMEZAWA Hiroyuki void unregister_cpu(struct cpu *cpu) 721da177e4SLinus Torvalds { 738a25a2fdSKay Sievers int logical_cpu = cpu->dev.id; 741da177e4SLinus Torvalds 7576b67ed9SKAMEZAWA Hiroyuki unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); 7676b67ed9SKAMEZAWA Hiroyuki 778a25a2fdSKay Sievers device_unregister(&cpu->dev); 78e37d05daSMike Travis per_cpu(cpu_sys_devices, logical_cpu) = NULL; 791da177e4SLinus Torvalds return; 801da177e4SLinus Torvalds } 8112633e80SNathan Fontenot 8212633e80SNathan Fontenot #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 838a25a2fdSKay Sievers static ssize_t cpu_probe_store(struct device *dev, 848a25a2fdSKay Sievers struct device_attribute *attr, 8528812fe1SAndi Kleen const char *buf, 8612633e80SNathan Fontenot size_t count) 8712633e80SNathan Fontenot { 88574b851eSToshi Kani ssize_t cnt; 89574b851eSToshi Kani int ret; 90574b851eSToshi Kani 91574b851eSToshi Kani ret = lock_device_hotplug_sysfs(); 92574b851eSToshi Kani if (ret) 93574b851eSToshi Kani return ret; 94574b851eSToshi Kani 95574b851eSToshi Kani cnt = arch_cpu_probe(buf, count); 96574b851eSToshi Kani 97574b851eSToshi Kani unlock_device_hotplug(); 98574b851eSToshi Kani return cnt; 9912633e80SNathan Fontenot } 10012633e80SNathan Fontenot 1018a25a2fdSKay Sievers static ssize_t cpu_release_store(struct device *dev, 1028a25a2fdSKay Sievers struct device_attribute *attr, 10328812fe1SAndi Kleen const char *buf, 10412633e80SNathan Fontenot size_t count) 10512633e80SNathan Fontenot { 106574b851eSToshi Kani ssize_t cnt; 107574b851eSToshi Kani int ret; 108574b851eSToshi Kani 109574b851eSToshi Kani ret = lock_device_hotplug_sysfs(); 110574b851eSToshi Kani if (ret) 111574b851eSToshi Kani return ret; 112574b851eSToshi Kani 113574b851eSToshi Kani cnt = arch_cpu_release(buf, count); 114574b851eSToshi Kani 115574b851eSToshi Kani unlock_device_hotplug(); 116574b851eSToshi Kani return cnt; 11712633e80SNathan Fontenot } 11812633e80SNathan Fontenot 1198a25a2fdSKay Sievers static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); 1208a25a2fdSKay Sievers static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); 12112633e80SNathan Fontenot #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 1221da177e4SLinus Torvalds #endif /* CONFIG_HOTPLUG_CPU */ 1231da177e4SLinus Torvalds 1240902a904SRafael J. Wysocki struct bus_type cpu_subsys = { 1250902a904SRafael J. Wysocki .name = "cpu", 1260902a904SRafael J. Wysocki .dev_name = "cpu", 127ac212b69SRafael J. Wysocki .match = cpu_subsys_match, 1280902a904SRafael J. Wysocki #ifdef CONFIG_HOTPLUG_CPU 1290902a904SRafael J. Wysocki .online = cpu_subsys_online, 1300902a904SRafael J. Wysocki .offline = cpu_subsys_offline, 1310902a904SRafael J. Wysocki #endif 1320902a904SRafael J. Wysocki }; 1330902a904SRafael J. Wysocki EXPORT_SYMBOL_GPL(cpu_subsys); 1340902a904SRafael J. Wysocki 13551be5606SVivek Goyal #ifdef CONFIG_KEXEC 13651be5606SVivek Goyal #include <linux/kexec.h> 13751be5606SVivek Goyal 1388a25a2fdSKay Sievers static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, 1394a0b2b4dSAndi Kleen char *buf) 14051be5606SVivek Goyal { 1418a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 14251be5606SVivek Goyal ssize_t rc; 14351be5606SVivek Goyal unsigned long long addr; 14451be5606SVivek Goyal int cpunum; 14551be5606SVivek Goyal 1468a25a2fdSKay Sievers cpunum = cpu->dev.id; 14751be5606SVivek Goyal 14851be5606SVivek Goyal /* 14951be5606SVivek Goyal * Might be reading other cpu's data based on which cpu read thread 15051be5606SVivek Goyal * has been scheduled. But cpu data (memory) is allocated once during 15151be5606SVivek Goyal * boot up and this data does not change there after. Hence this 15251be5606SVivek Goyal * operation should be safe. No locking required. 15351be5606SVivek Goyal */ 1543b034b0dSVivek Goyal addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); 15551be5606SVivek Goyal rc = sprintf(buf, "%Lx\n", addr); 15651be5606SVivek Goyal return rc; 15751be5606SVivek Goyal } 1588a25a2fdSKay Sievers static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); 159eca4549fSZhang Yanfei 160eca4549fSZhang Yanfei static ssize_t show_crash_notes_size(struct device *dev, 161eca4549fSZhang Yanfei struct device_attribute *attr, 162eca4549fSZhang Yanfei char *buf) 163eca4549fSZhang Yanfei { 164eca4549fSZhang Yanfei ssize_t rc; 165eca4549fSZhang Yanfei 166bcfb87fbSArnd Bergmann rc = sprintf(buf, "%zu\n", sizeof(note_buf_t)); 167eca4549fSZhang Yanfei return rc; 168eca4549fSZhang Yanfei } 169eca4549fSZhang Yanfei static DEVICE_ATTR(crash_notes_size, 0400, show_crash_notes_size, NULL); 170c055da9fSIgor Mammedov 171c055da9fSIgor Mammedov static struct attribute *crash_note_cpu_attrs[] = { 172c055da9fSIgor Mammedov &dev_attr_crash_notes.attr, 173c055da9fSIgor Mammedov &dev_attr_crash_notes_size.attr, 174c055da9fSIgor Mammedov NULL 175c055da9fSIgor Mammedov }; 176c055da9fSIgor Mammedov 177c055da9fSIgor Mammedov static struct attribute_group crash_note_cpu_attr_group = { 178c055da9fSIgor Mammedov .attrs = crash_note_cpu_attrs, 179c055da9fSIgor Mammedov }; 18051be5606SVivek Goyal #endif 18151be5606SVivek Goyal 182c055da9fSIgor Mammedov static const struct attribute_group *common_cpu_attr_groups[] = { 183c055da9fSIgor Mammedov #ifdef CONFIG_KEXEC 184c055da9fSIgor Mammedov &crash_note_cpu_attr_group, 185c055da9fSIgor Mammedov #endif 186c055da9fSIgor Mammedov NULL 187c055da9fSIgor Mammedov }; 188c055da9fSIgor Mammedov 1891c4e2d70SIgor Mammedov static const struct attribute_group *hotplugable_cpu_attr_groups[] = { 1901c4e2d70SIgor Mammedov #ifdef CONFIG_KEXEC 1911c4e2d70SIgor Mammedov &crash_note_cpu_attr_group, 1921c4e2d70SIgor Mammedov #endif 1931c4e2d70SIgor Mammedov NULL 1941c4e2d70SIgor Mammedov }; 1951c4e2d70SIgor Mammedov 1961da177e4SLinus Torvalds /* 1979d1fe323SMike Travis * Print cpu online, possible, present, and system maps 1989d1fe323SMike Travis */ 199265d2e2eSAndi Kleen 200265d2e2eSAndi Kleen struct cpu_attr { 2018a25a2fdSKay Sievers struct device_attribute attr; 202265d2e2eSAndi Kleen const struct cpumask *const * const map; 203265d2e2eSAndi Kleen }; 204265d2e2eSAndi Kleen 2058a25a2fdSKay Sievers static ssize_t show_cpus_attr(struct device *dev, 2068a25a2fdSKay Sievers struct device_attribute *attr, 207265d2e2eSAndi Kleen char *buf) 2089d1fe323SMike Travis { 209265d2e2eSAndi Kleen struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); 2109d1fe323SMike Travis 2115aaba363SSudeep Holla return cpumap_print_to_pagebuf(true, buf, *ca->map); 2129d1fe323SMike Travis } 2139d1fe323SMike Travis 214265d2e2eSAndi Kleen #define _CPU_ATTR(name, map) \ 2158a25a2fdSKay Sievers { __ATTR(name, 0444, show_cpus_attr, NULL), map } 2169d1fe323SMike Travis 2178a25a2fdSKay Sievers /* Keep in sync with cpu_subsys_attrs */ 218265d2e2eSAndi Kleen static struct cpu_attr cpu_attrs[] = { 219265d2e2eSAndi Kleen _CPU_ATTR(online, &cpu_online_mask), 220265d2e2eSAndi Kleen _CPU_ATTR(possible, &cpu_possible_mask), 221265d2e2eSAndi Kleen _CPU_ATTR(present, &cpu_present_mask), 222265d2e2eSAndi Kleen }; 2239d1fe323SMike Travis 224e057d7aeSMike Travis /* 225e057d7aeSMike Travis * Print values for NR_CPUS and offlined cpus 226e057d7aeSMike Travis */ 2278a25a2fdSKay Sievers static ssize_t print_cpus_kernel_max(struct device *dev, 2288a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 229e057d7aeSMike Travis { 2308fd2d2d5SMike Travis int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); 231e057d7aeSMike Travis return n; 232e057d7aeSMike Travis } 2338a25a2fdSKay Sievers static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); 234e057d7aeSMike Travis 235e057d7aeSMike Travis /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ 236e057d7aeSMike Travis unsigned int total_cpus; 237e057d7aeSMike Travis 2388a25a2fdSKay Sievers static ssize_t print_cpus_offline(struct device *dev, 2398a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 240e057d7aeSMike Travis { 241e057d7aeSMike Travis int n = 0, len = PAGE_SIZE-2; 242e057d7aeSMike Travis cpumask_var_t offline; 243e057d7aeSMike Travis 244e057d7aeSMike Travis /* display offline cpus < nr_cpu_ids */ 245e057d7aeSMike Travis if (!alloc_cpumask_var(&offline, GFP_KERNEL)) 246e057d7aeSMike Travis return -ENOMEM; 247cdc6e3d3SJan Beulich cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); 248e057d7aeSMike Travis n = cpulist_scnprintf(buf, len, offline); 249e057d7aeSMike Travis free_cpumask_var(offline); 250e057d7aeSMike Travis 251e057d7aeSMike Travis /* display offline cpus >= nr_cpu_ids */ 252e057d7aeSMike Travis if (total_cpus && nr_cpu_ids < total_cpus) { 253e057d7aeSMike Travis if (n && n < len) 254e057d7aeSMike Travis buf[n++] = ','; 255e057d7aeSMike Travis 256e057d7aeSMike Travis if (nr_cpu_ids == total_cpus-1) 257e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "%d", nr_cpu_ids); 258e057d7aeSMike Travis else 259e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "%d-%d", 260e057d7aeSMike Travis nr_cpu_ids, total_cpus-1); 261e057d7aeSMike Travis } 262e057d7aeSMike Travis 263e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "\n"); 264e057d7aeSMike Travis return n; 265e057d7aeSMike Travis } 2668a25a2fdSKay Sievers static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); 267e057d7aeSMike Travis 2682885e25cSGreg Kroah-Hartman static void cpu_device_release(struct device *dev) 2692885e25cSGreg Kroah-Hartman { 2702885e25cSGreg Kroah-Hartman /* 2712885e25cSGreg Kroah-Hartman * This is an empty function to prevent the driver core from spitting a 2722885e25cSGreg Kroah-Hartman * warning at us. Yes, I know this is directly opposite of what the 2732885e25cSGreg Kroah-Hartman * documentation for the driver core and kobjects say, and the author 2742885e25cSGreg Kroah-Hartman * of this code has already been publically ridiculed for doing 2752885e25cSGreg Kroah-Hartman * something as foolish as this. However, at this point in time, it is 2762885e25cSGreg Kroah-Hartman * the only way to handle the issue of statically allocated cpu 2772885e25cSGreg Kroah-Hartman * devices. The different architectures will have their cpu device 2782885e25cSGreg Kroah-Hartman * code reworked to properly handle this in the near future, so this 2792885e25cSGreg Kroah-Hartman * function will then be changed to correctly free up the memory held 2802885e25cSGreg Kroah-Hartman * by the cpu device. 2812885e25cSGreg Kroah-Hartman * 2822885e25cSGreg Kroah-Hartman * Never copy this way of doing things, or you too will be made fun of 28330a4840aSRalf Baechle * on the linux-kernel list, you have been warned. 2842885e25cSGreg Kroah-Hartman */ 2852885e25cSGreg Kroah-Hartman } 2862885e25cSGreg Kroah-Hartman 28767bad2fdSArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 28867bad2fdSArd Biesheuvel static ssize_t print_cpu_modalias(struct device *dev, 28967bad2fdSArd Biesheuvel struct device_attribute *attr, 29067bad2fdSArd Biesheuvel char *buf) 29167bad2fdSArd Biesheuvel { 29267bad2fdSArd Biesheuvel ssize_t n; 29367bad2fdSArd Biesheuvel u32 i; 29467bad2fdSArd Biesheuvel 29567bad2fdSArd Biesheuvel n = sprintf(buf, "cpu:type:" CPU_FEATURE_TYPEFMT ":feature:", 29667bad2fdSArd Biesheuvel CPU_FEATURE_TYPEVAL); 29767bad2fdSArd Biesheuvel 29867bad2fdSArd Biesheuvel for (i = 0; i < MAX_CPU_FEATURES; i++) 29967bad2fdSArd Biesheuvel if (cpu_have_feature(i)) { 30067bad2fdSArd Biesheuvel if (PAGE_SIZE < n + sizeof(",XXXX\n")) { 30167bad2fdSArd Biesheuvel WARN(1, "CPU features overflow page\n"); 30267bad2fdSArd Biesheuvel break; 30367bad2fdSArd Biesheuvel } 30467bad2fdSArd Biesheuvel n += sprintf(&buf[n], ",%04X", i); 30567bad2fdSArd Biesheuvel } 30667bad2fdSArd Biesheuvel buf[n++] = '\n'; 30767bad2fdSArd Biesheuvel return n; 30867bad2fdSArd Biesheuvel } 30967bad2fdSArd Biesheuvel 31067bad2fdSArd Biesheuvel static int cpu_uevent(struct device *dev, struct kobj_uevent_env *env) 31167bad2fdSArd Biesheuvel { 31267bad2fdSArd Biesheuvel char *buf = kzalloc(PAGE_SIZE, GFP_KERNEL); 31367bad2fdSArd Biesheuvel if (buf) { 31467bad2fdSArd Biesheuvel print_cpu_modalias(NULL, NULL, buf); 31567bad2fdSArd Biesheuvel add_uevent_var(env, "MODALIAS=%s", buf); 31667bad2fdSArd Biesheuvel kfree(buf); 31767bad2fdSArd Biesheuvel } 31867bad2fdSArd Biesheuvel return 0; 31967bad2fdSArd Biesheuvel } 32067bad2fdSArd Biesheuvel #endif 32167bad2fdSArd Biesheuvel 3229d1fe323SMike Travis /* 323405ae7d3SRobert P. J. Day * register_cpu - Setup a sysfs device for a CPU. 32472486f1fSSiddha, Suresh B * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 32572486f1fSSiddha, Suresh B * sysfs for this CPU. 3261da177e4SLinus Torvalds * @num - CPU number to use when creating the device. 3271da177e4SLinus Torvalds * 3281da177e4SLinus Torvalds * Initialize and register the CPU device. 3291da177e4SLinus Torvalds */ 330a83048ebSPaul Gortmaker int register_cpu(struct cpu *cpu, int num) 3311da177e4SLinus Torvalds { 3321da177e4SLinus Torvalds int error; 3338a25a2fdSKay Sievers 3341da177e4SLinus Torvalds cpu->node_id = cpu_to_node(num); 33529bb5d4fSGreg Kroah-Hartman memset(&cpu->dev, 0x00, sizeof(struct device)); 3368a25a2fdSKay Sievers cpu->dev.id = num; 3378a25a2fdSKay Sievers cpu->dev.bus = &cpu_subsys; 3382885e25cSGreg Kroah-Hartman cpu->dev.release = cpu_device_release; 3390902a904SRafael J. Wysocki cpu->dev.offline_disabled = !cpu->hotpluggable; 3401001b4d4SToshi Kani cpu->dev.offline = !cpu_online(num); 341f86e4718SSudeep KarkadaNagesha cpu->dev.of_node = of_get_cpu_node(num, NULL); 3422b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 34367bad2fdSArd Biesheuvel cpu->dev.bus->uevent = cpu_uevent; 344fad12ac8SThomas Renninger #endif 345c055da9fSIgor Mammedov cpu->dev.groups = common_cpu_attr_groups; 3461c4e2d70SIgor Mammedov if (cpu->hotpluggable) 3471c4e2d70SIgor Mammedov cpu->dev.groups = hotplugable_cpu_attr_groups; 3488a25a2fdSKay Sievers error = device_register(&cpu->dev); 349ad74557aSAshok Raj if (!error) 3508a25a2fdSKay Sievers per_cpu(cpu_sys_devices, num) = &cpu->dev; 35176b67ed9SKAMEZAWA Hiroyuki if (!error) 35276b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(num, cpu_to_node(num)); 35351be5606SVivek Goyal 3541da177e4SLinus Torvalds return error; 3551da177e4SLinus Torvalds } 3561da177e4SLinus Torvalds 3578a25a2fdSKay Sievers struct device *get_cpu_device(unsigned cpu) 358ad74557aSAshok Raj { 359e37d05daSMike Travis if (cpu < nr_cpu_ids && cpu_possible(cpu)) 360e37d05daSMike Travis return per_cpu(cpu_sys_devices, cpu); 361ad74557aSAshok Raj else 362ad74557aSAshok Raj return NULL; 363ad74557aSAshok Raj } 3648a25a2fdSKay Sievers EXPORT_SYMBOL_GPL(get_cpu_device); 3658a25a2fdSKay Sievers 3662b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 36767bad2fdSArd Biesheuvel static DEVICE_ATTR(modalias, 0444, print_cpu_modalias, NULL); 368fad12ac8SThomas Renninger #endif 369fad12ac8SThomas Renninger 3708a25a2fdSKay Sievers static struct attribute *cpu_root_attrs[] = { 3718a25a2fdSKay Sievers #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 3728a25a2fdSKay Sievers &dev_attr_probe.attr, 3738a25a2fdSKay Sievers &dev_attr_release.attr, 3748a25a2fdSKay Sievers #endif 3758a25a2fdSKay Sievers &cpu_attrs[0].attr.attr, 3768a25a2fdSKay Sievers &cpu_attrs[1].attr.attr, 3778a25a2fdSKay Sievers &cpu_attrs[2].attr.attr, 3788a25a2fdSKay Sievers &dev_attr_kernel_max.attr, 3798a25a2fdSKay Sievers &dev_attr_offline.attr, 3802b9c1f03SArd Biesheuvel #ifdef CONFIG_GENERIC_CPU_AUTOPROBE 381fad12ac8SThomas Renninger &dev_attr_modalias.attr, 382fad12ac8SThomas Renninger #endif 3838a25a2fdSKay Sievers NULL 3848a25a2fdSKay Sievers }; 3858a25a2fdSKay Sievers 3868a25a2fdSKay Sievers static struct attribute_group cpu_root_attr_group = { 3878a25a2fdSKay Sievers .attrs = cpu_root_attrs, 3888a25a2fdSKay Sievers }; 3898a25a2fdSKay Sievers 3908a25a2fdSKay Sievers static const struct attribute_group *cpu_root_attr_groups[] = { 3918a25a2fdSKay Sievers &cpu_root_attr_group, 3928a25a2fdSKay Sievers NULL, 3938a25a2fdSKay Sievers }; 3941da177e4SLinus Torvalds 3952987557fSJosh Triplett bool cpu_is_hotpluggable(unsigned cpu) 3962987557fSJosh Triplett { 3977affca35SLinus Torvalds struct device *dev = get_cpu_device(cpu); 3987affca35SLinus Torvalds return dev && container_of(dev, struct cpu, dev)->hotpluggable; 3992987557fSJosh Triplett } 4002987557fSJosh Triplett EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); 4012987557fSJosh Triplett 4029f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 4039f13a1fdSBen Hutchings static DEFINE_PER_CPU(struct cpu, cpu_devices); 4049f13a1fdSBen Hutchings #endif 4059f13a1fdSBen Hutchings 4069f13a1fdSBen Hutchings static void __init cpu_dev_register_generic(void) 4079f13a1fdSBen Hutchings { 4089f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 4099f13a1fdSBen Hutchings int i; 4109f13a1fdSBen Hutchings 4119f13a1fdSBen Hutchings for_each_possible_cpu(i) { 4129f13a1fdSBen Hutchings if (register_cpu(&per_cpu(cpu_devices, i), i)) 4139f13a1fdSBen Hutchings panic("Failed to register CPU device"); 4149f13a1fdSBen Hutchings } 4159f13a1fdSBen Hutchings #endif 4169f13a1fdSBen Hutchings } 4179f13a1fdSBen Hutchings 418024f7846SBen Hutchings void __init cpu_dev_init(void) 4191da177e4SLinus Torvalds { 420024f7846SBen Hutchings if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) 421024f7846SBen Hutchings panic("Failed to register CPU subsystem"); 4225c45bf27SSiddha, Suresh B 4239f13a1fdSBen Hutchings cpu_dev_register_generic(); 4241da177e4SLinus Torvalds } 425