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> 149f13a1fdSBen Hutchings #include <linux/percpu.h> 151da177e4SLinus Torvalds 16a1bdc7aaSBen Dooks #include "base.h" 171da177e4SLinus Torvalds 188a25a2fdSKay Sievers struct bus_type cpu_subsys = { 19af5ca3f4SKay Sievers .name = "cpu", 208a25a2fdSKay Sievers .dev_name = "cpu", 211da177e4SLinus Torvalds }; 228a25a2fdSKay Sievers EXPORT_SYMBOL_GPL(cpu_subsys); 231da177e4SLinus Torvalds 248a25a2fdSKay Sievers static DEFINE_PER_CPU(struct device *, cpu_sys_devices); 25ad74557aSAshok Raj 261da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 278a25a2fdSKay Sievers static ssize_t show_online(struct device *dev, 288a25a2fdSKay Sievers struct device_attribute *attr, 294a0b2b4dSAndi Kleen char *buf) 301da177e4SLinus Torvalds { 318a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 321da177e4SLinus Torvalds 338a25a2fdSKay Sievers return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); 341da177e4SLinus Torvalds } 351da177e4SLinus Torvalds 368a25a2fdSKay Sievers static ssize_t __ref store_online(struct device *dev, 378a25a2fdSKay Sievers struct device_attribute *attr, 384a0b2b4dSAndi Kleen const char *buf, size_t count) 391da177e4SLinus Torvalds { 408a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 411da177e4SLinus Torvalds ssize_t ret; 421da177e4SLinus Torvalds 4351badebdSGautham R Shenoy cpu_hotplug_driver_lock(); 441da177e4SLinus Torvalds switch (buf[0]) { 451da177e4SLinus Torvalds case '0': 468a25a2fdSKay Sievers ret = cpu_down(cpu->dev.id); 471da177e4SLinus Torvalds if (!ret) 48312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_OFFLINE); 491da177e4SLinus Torvalds break; 501da177e4SLinus Torvalds case '1': 518a25a2fdSKay Sievers ret = cpu_up(cpu->dev.id); 52fb69c390SNathan Lynch if (!ret) 53312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ONLINE); 541da177e4SLinus Torvalds break; 551da177e4SLinus Torvalds default: 561da177e4SLinus Torvalds ret = -EINVAL; 571da177e4SLinus Torvalds } 5851badebdSGautham R Shenoy cpu_hotplug_driver_unlock(); 591da177e4SLinus Torvalds 601da177e4SLinus Torvalds if (ret >= 0) 611da177e4SLinus Torvalds ret = count; 621da177e4SLinus Torvalds return ret; 631da177e4SLinus Torvalds } 648a25a2fdSKay Sievers static DEVICE_ATTR(online, 0644, show_online, store_online); 651da177e4SLinus Torvalds 666c847402SSam Ravnborg static void __cpuinit register_cpu_control(struct cpu *cpu) 671da177e4SLinus Torvalds { 688a25a2fdSKay Sievers device_create_file(&cpu->dev, &dev_attr_online); 691da177e4SLinus Torvalds } 7076b67ed9SKAMEZAWA Hiroyuki void unregister_cpu(struct cpu *cpu) 711da177e4SLinus Torvalds { 728a25a2fdSKay Sievers int logical_cpu = cpu->dev.id; 731da177e4SLinus Torvalds 7476b67ed9SKAMEZAWA Hiroyuki unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); 7576b67ed9SKAMEZAWA Hiroyuki 768a25a2fdSKay Sievers device_remove_file(&cpu->dev, &dev_attr_online); 771da177e4SLinus Torvalds 788a25a2fdSKay Sievers device_unregister(&cpu->dev); 79e37d05daSMike Travis per_cpu(cpu_sys_devices, logical_cpu) = NULL; 801da177e4SLinus Torvalds return; 811da177e4SLinus Torvalds } 8212633e80SNathan Fontenot 8312633e80SNathan Fontenot #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 848a25a2fdSKay Sievers static ssize_t cpu_probe_store(struct device *dev, 858a25a2fdSKay Sievers struct device_attribute *attr, 8628812fe1SAndi Kleen const char *buf, 8712633e80SNathan Fontenot size_t count) 8812633e80SNathan Fontenot { 8912633e80SNathan Fontenot return arch_cpu_probe(buf, count); 9012633e80SNathan Fontenot } 9112633e80SNathan Fontenot 928a25a2fdSKay Sievers static ssize_t cpu_release_store(struct device *dev, 938a25a2fdSKay Sievers struct device_attribute *attr, 9428812fe1SAndi Kleen const char *buf, 9512633e80SNathan Fontenot size_t count) 9612633e80SNathan Fontenot { 9712633e80SNathan Fontenot return arch_cpu_release(buf, count); 9812633e80SNathan Fontenot } 9912633e80SNathan Fontenot 1008a25a2fdSKay Sievers static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); 1018a25a2fdSKay Sievers static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); 10212633e80SNathan Fontenot #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 10312633e80SNathan Fontenot 1041da177e4SLinus Torvalds #else /* ... !CONFIG_HOTPLUG_CPU */ 1051da177e4SLinus Torvalds static inline void register_cpu_control(struct cpu *cpu) 1061da177e4SLinus Torvalds { 1071da177e4SLinus Torvalds } 1081da177e4SLinus Torvalds #endif /* CONFIG_HOTPLUG_CPU */ 1091da177e4SLinus Torvalds 11051be5606SVivek Goyal #ifdef CONFIG_KEXEC 11151be5606SVivek Goyal #include <linux/kexec.h> 11251be5606SVivek Goyal 1138a25a2fdSKay Sievers static ssize_t show_crash_notes(struct device *dev, struct device_attribute *attr, 1144a0b2b4dSAndi Kleen char *buf) 11551be5606SVivek Goyal { 1168a25a2fdSKay Sievers struct cpu *cpu = container_of(dev, struct cpu, dev); 11751be5606SVivek Goyal ssize_t rc; 11851be5606SVivek Goyal unsigned long long addr; 11951be5606SVivek Goyal int cpunum; 12051be5606SVivek Goyal 1218a25a2fdSKay Sievers cpunum = cpu->dev.id; 12251be5606SVivek Goyal 12351be5606SVivek Goyal /* 12451be5606SVivek Goyal * Might be reading other cpu's data based on which cpu read thread 12551be5606SVivek Goyal * has been scheduled. But cpu data (memory) is allocated once during 12651be5606SVivek Goyal * boot up and this data does not change there after. Hence this 12751be5606SVivek Goyal * operation should be safe. No locking required. 12851be5606SVivek Goyal */ 1293b034b0dSVivek Goyal addr = per_cpu_ptr_to_phys(per_cpu_ptr(crash_notes, cpunum)); 13051be5606SVivek Goyal rc = sprintf(buf, "%Lx\n", addr); 13151be5606SVivek Goyal return rc; 13251be5606SVivek Goyal } 1338a25a2fdSKay Sievers static DEVICE_ATTR(crash_notes, 0400, show_crash_notes, NULL); 13451be5606SVivek Goyal #endif 13551be5606SVivek Goyal 1361da177e4SLinus Torvalds /* 1379d1fe323SMike Travis * Print cpu online, possible, present, and system maps 1389d1fe323SMike Travis */ 139265d2e2eSAndi Kleen 140265d2e2eSAndi Kleen struct cpu_attr { 1418a25a2fdSKay Sievers struct device_attribute attr; 142265d2e2eSAndi Kleen const struct cpumask *const * const map; 143265d2e2eSAndi Kleen }; 144265d2e2eSAndi Kleen 1458a25a2fdSKay Sievers static ssize_t show_cpus_attr(struct device *dev, 1468a25a2fdSKay Sievers struct device_attribute *attr, 147265d2e2eSAndi Kleen char *buf) 1489d1fe323SMike Travis { 149265d2e2eSAndi Kleen struct cpu_attr *ca = container_of(attr, struct cpu_attr, attr); 150265d2e2eSAndi Kleen int n = cpulist_scnprintf(buf, PAGE_SIZE-2, *(ca->map)); 1519d1fe323SMike Travis 1529d1fe323SMike Travis buf[n++] = '\n'; 1539d1fe323SMike Travis buf[n] = '\0'; 1549d1fe323SMike Travis return n; 1559d1fe323SMike Travis } 1569d1fe323SMike Travis 157265d2e2eSAndi Kleen #define _CPU_ATTR(name, map) \ 1588a25a2fdSKay Sievers { __ATTR(name, 0444, show_cpus_attr, NULL), map } 1599d1fe323SMike Travis 1608a25a2fdSKay Sievers /* Keep in sync with cpu_subsys_attrs */ 161265d2e2eSAndi Kleen static struct cpu_attr cpu_attrs[] = { 162265d2e2eSAndi Kleen _CPU_ATTR(online, &cpu_online_mask), 163265d2e2eSAndi Kleen _CPU_ATTR(possible, &cpu_possible_mask), 164265d2e2eSAndi Kleen _CPU_ATTR(present, &cpu_present_mask), 165265d2e2eSAndi Kleen }; 1669d1fe323SMike Travis 167e057d7aeSMike Travis /* 168e057d7aeSMike Travis * Print values for NR_CPUS and offlined cpus 169e057d7aeSMike Travis */ 1708a25a2fdSKay Sievers static ssize_t print_cpus_kernel_max(struct device *dev, 1718a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 172e057d7aeSMike Travis { 1738fd2d2d5SMike Travis int n = snprintf(buf, PAGE_SIZE-2, "%d\n", NR_CPUS - 1); 174e057d7aeSMike Travis return n; 175e057d7aeSMike Travis } 1768a25a2fdSKay Sievers static DEVICE_ATTR(kernel_max, 0444, print_cpus_kernel_max, NULL); 177e057d7aeSMike Travis 178e057d7aeSMike Travis /* arch-optional setting to enable display of offline cpus >= nr_cpu_ids */ 179e057d7aeSMike Travis unsigned int total_cpus; 180e057d7aeSMike Travis 1818a25a2fdSKay Sievers static ssize_t print_cpus_offline(struct device *dev, 1828a25a2fdSKay Sievers struct device_attribute *attr, char *buf) 183e057d7aeSMike Travis { 184e057d7aeSMike Travis int n = 0, len = PAGE_SIZE-2; 185e057d7aeSMike Travis cpumask_var_t offline; 186e057d7aeSMike Travis 187e057d7aeSMike Travis /* display offline cpus < nr_cpu_ids */ 188e057d7aeSMike Travis if (!alloc_cpumask_var(&offline, GFP_KERNEL)) 189e057d7aeSMike Travis return -ENOMEM; 190cdc6e3d3SJan Beulich cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask); 191e057d7aeSMike Travis n = cpulist_scnprintf(buf, len, offline); 192e057d7aeSMike Travis free_cpumask_var(offline); 193e057d7aeSMike Travis 194e057d7aeSMike Travis /* display offline cpus >= nr_cpu_ids */ 195e057d7aeSMike Travis if (total_cpus && nr_cpu_ids < total_cpus) { 196e057d7aeSMike Travis if (n && n < len) 197e057d7aeSMike Travis buf[n++] = ','; 198e057d7aeSMike Travis 199e057d7aeSMike Travis if (nr_cpu_ids == total_cpus-1) 200e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "%d", nr_cpu_ids); 201e057d7aeSMike Travis else 202e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "%d-%d", 203e057d7aeSMike Travis nr_cpu_ids, total_cpus-1); 204e057d7aeSMike Travis } 205e057d7aeSMike Travis 206e057d7aeSMike Travis n += snprintf(&buf[n], len - n, "\n"); 207e057d7aeSMike Travis return n; 208e057d7aeSMike Travis } 2098a25a2fdSKay Sievers static DEVICE_ATTR(offline, 0444, print_cpus_offline, NULL); 210e057d7aeSMike Travis 2119d1fe323SMike Travis /* 212405ae7d3SRobert P. J. Day * register_cpu - Setup a sysfs device for a CPU. 21372486f1fSSiddha, Suresh B * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 21472486f1fSSiddha, Suresh B * sysfs for this CPU. 2151da177e4SLinus Torvalds * @num - CPU number to use when creating the device. 2161da177e4SLinus Torvalds * 2171da177e4SLinus Torvalds * Initialize and register the CPU device. 2181da177e4SLinus Torvalds */ 21933b5f31bSRandy Dunlap int __cpuinit register_cpu(struct cpu *cpu, int num) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds int error; 2228a25a2fdSKay Sievers 2231da177e4SLinus Torvalds cpu->node_id = cpu_to_node(num); 2248a25a2fdSKay Sievers cpu->dev.id = num; 2258a25a2fdSKay Sievers cpu->dev.bus = &cpu_subsys; 2268a25a2fdSKay Sievers error = device_register(&cpu->dev); 22772486f1fSSiddha, Suresh B if (!error && cpu->hotpluggable) 2281da177e4SLinus Torvalds register_cpu_control(cpu); 229ad74557aSAshok Raj if (!error) 2308a25a2fdSKay Sievers per_cpu(cpu_sys_devices, num) = &cpu->dev; 23176b67ed9SKAMEZAWA Hiroyuki if (!error) 23276b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(num, cpu_to_node(num)); 23351be5606SVivek Goyal 23451be5606SVivek Goyal #ifdef CONFIG_KEXEC 23551be5606SVivek Goyal if (!error) 2368a25a2fdSKay Sievers error = device_create_file(&cpu->dev, &dev_attr_crash_notes); 23751be5606SVivek Goyal #endif 2381da177e4SLinus Torvalds return error; 2391da177e4SLinus Torvalds } 2401da177e4SLinus Torvalds 2418a25a2fdSKay Sievers struct device *get_cpu_device(unsigned cpu) 242ad74557aSAshok Raj { 243e37d05daSMike Travis if (cpu < nr_cpu_ids && cpu_possible(cpu)) 244e37d05daSMike Travis return per_cpu(cpu_sys_devices, cpu); 245ad74557aSAshok Raj else 246ad74557aSAshok Raj return NULL; 247ad74557aSAshok Raj } 2488a25a2fdSKay Sievers EXPORT_SYMBOL_GPL(get_cpu_device); 2498a25a2fdSKay Sievers 2508a25a2fdSKay Sievers static struct attribute *cpu_root_attrs[] = { 2518a25a2fdSKay Sievers #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE 2528a25a2fdSKay Sievers &dev_attr_probe.attr, 2538a25a2fdSKay Sievers &dev_attr_release.attr, 2548a25a2fdSKay Sievers #endif 2558a25a2fdSKay Sievers &cpu_attrs[0].attr.attr, 2568a25a2fdSKay Sievers &cpu_attrs[1].attr.attr, 2578a25a2fdSKay Sievers &cpu_attrs[2].attr.attr, 2588a25a2fdSKay Sievers &dev_attr_kernel_max.attr, 2598a25a2fdSKay Sievers &dev_attr_offline.attr, 2608a25a2fdSKay Sievers NULL 2618a25a2fdSKay Sievers }; 2628a25a2fdSKay Sievers 2638a25a2fdSKay Sievers static struct attribute_group cpu_root_attr_group = { 2648a25a2fdSKay Sievers .attrs = cpu_root_attrs, 2658a25a2fdSKay Sievers }; 2668a25a2fdSKay Sievers 2678a25a2fdSKay Sievers static const struct attribute_group *cpu_root_attr_groups[] = { 2688a25a2fdSKay Sievers &cpu_root_attr_group, 2698a25a2fdSKay Sievers NULL, 2708a25a2fdSKay Sievers }; 2711da177e4SLinus Torvalds 2722987557fSJosh Triplett bool cpu_is_hotpluggable(unsigned cpu) 2732987557fSJosh Triplett { 2747affca35SLinus Torvalds struct device *dev = get_cpu_device(cpu); 2757affca35SLinus Torvalds return dev && container_of(dev, struct cpu, dev)->hotpluggable; 2762987557fSJosh Triplett } 2772987557fSJosh Triplett EXPORT_SYMBOL_GPL(cpu_is_hotpluggable); 2782987557fSJosh Triplett 2799f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 2809f13a1fdSBen Hutchings static DEFINE_PER_CPU(struct cpu, cpu_devices); 2819f13a1fdSBen Hutchings #endif 2829f13a1fdSBen Hutchings 2839f13a1fdSBen Hutchings static void __init cpu_dev_register_generic(void) 2849f13a1fdSBen Hutchings { 2859f13a1fdSBen Hutchings #ifdef CONFIG_GENERIC_CPU_DEVICES 2869f13a1fdSBen Hutchings int i; 2879f13a1fdSBen Hutchings 2889f13a1fdSBen Hutchings for_each_possible_cpu(i) { 2899f13a1fdSBen Hutchings if (register_cpu(&per_cpu(cpu_devices, i), i)) 2909f13a1fdSBen Hutchings panic("Failed to register CPU device"); 2919f13a1fdSBen Hutchings } 2929f13a1fdSBen Hutchings #endif 2939f13a1fdSBen Hutchings } 2949f13a1fdSBen Hutchings 295024f7846SBen Hutchings void __init cpu_dev_init(void) 2961da177e4SLinus Torvalds { 297024f7846SBen Hutchings if (subsys_system_register(&cpu_subsys, cpu_root_attr_groups)) 298024f7846SBen Hutchings panic("Failed to register CPU subsystem"); 2995c45bf27SSiddha, Suresh B 3009f13a1fdSBen Hutchings cpu_dev_register_generic(); 3019f13a1fdSBen Hutchings 3028a25a2fdSKay Sievers #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) 303024f7846SBen Hutchings sched_create_sysfs_power_savings_entries(cpu_subsys.dev_root); 3048a25a2fdSKay Sievers #endif 3051da177e4SLinus Torvalds } 306