11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * drivers/base/cpu.c - basic CPU class support 31da177e4SLinus Torvalds */ 41da177e4SLinus Torvalds 51da177e4SLinus Torvalds #include <linux/sysdev.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> 131da177e4SLinus Torvalds 14a1bdc7aaSBen Dooks #include "base.h" 151da177e4SLinus Torvalds 161da177e4SLinus Torvalds struct sysdev_class cpu_sysdev_class = { 171da177e4SLinus Torvalds set_kset_name("cpu"), 181da177e4SLinus Torvalds }; 191da177e4SLinus Torvalds EXPORT_SYMBOL(cpu_sysdev_class); 201da177e4SLinus Torvalds 21ad74557aSAshok Raj static struct sys_device *cpu_sys_devices[NR_CPUS]; 22ad74557aSAshok Raj 231da177e4SLinus Torvalds #ifdef CONFIG_HOTPLUG_CPU 241da177e4SLinus Torvalds static ssize_t show_online(struct sys_device *dev, char *buf) 251da177e4SLinus Torvalds { 261da177e4SLinus Torvalds struct cpu *cpu = container_of(dev, struct cpu, sysdev); 271da177e4SLinus Torvalds 281da177e4SLinus Torvalds return sprintf(buf, "%u\n", !!cpu_online(cpu->sysdev.id)); 291da177e4SLinus Torvalds } 301da177e4SLinus Torvalds 311da177e4SLinus Torvalds static ssize_t store_online(struct sys_device *dev, const char *buf, 321da177e4SLinus Torvalds size_t count) 331da177e4SLinus Torvalds { 341da177e4SLinus Torvalds struct cpu *cpu = container_of(dev, struct cpu, sysdev); 351da177e4SLinus Torvalds ssize_t ret; 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds switch (buf[0]) { 381da177e4SLinus Torvalds case '0': 391da177e4SLinus Torvalds ret = cpu_down(cpu->sysdev.id); 401da177e4SLinus Torvalds if (!ret) 41312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_OFFLINE); 421da177e4SLinus Torvalds break; 431da177e4SLinus Torvalds case '1': 441da177e4SLinus Torvalds ret = cpu_up(cpu->sysdev.id); 45fb69c390SNathan Lynch if (!ret) 46312c004dSKay Sievers kobject_uevent(&dev->kobj, KOBJ_ONLINE); 471da177e4SLinus Torvalds break; 481da177e4SLinus Torvalds default: 491da177e4SLinus Torvalds ret = -EINVAL; 501da177e4SLinus Torvalds } 511da177e4SLinus Torvalds 521da177e4SLinus Torvalds if (ret >= 0) 531da177e4SLinus Torvalds ret = count; 541da177e4SLinus Torvalds return ret; 551da177e4SLinus Torvalds } 569eb3ff40SUlrich Drepper static SYSDEV_ATTR(online, 0644, show_online, store_online); 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static void __devinit register_cpu_control(struct cpu *cpu) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds sysdev_create_file(&cpu->sysdev, &attr_online); 611da177e4SLinus Torvalds } 6276b67ed9SKAMEZAWA Hiroyuki void unregister_cpu(struct cpu *cpu) 631da177e4SLinus Torvalds { 64ad74557aSAshok Raj int logical_cpu = cpu->sysdev.id; 651da177e4SLinus Torvalds 6676b67ed9SKAMEZAWA Hiroyuki unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); 6776b67ed9SKAMEZAWA Hiroyuki 681da177e4SLinus Torvalds sysdev_remove_file(&cpu->sysdev, &attr_online); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds sysdev_unregister(&cpu->sysdev); 71ad74557aSAshok Raj cpu_sys_devices[logical_cpu] = NULL; 721da177e4SLinus Torvalds return; 731da177e4SLinus Torvalds } 741da177e4SLinus Torvalds #else /* ... !CONFIG_HOTPLUG_CPU */ 751da177e4SLinus Torvalds static inline void register_cpu_control(struct cpu *cpu) 761da177e4SLinus Torvalds { 771da177e4SLinus Torvalds } 781da177e4SLinus Torvalds #endif /* CONFIG_HOTPLUG_CPU */ 791da177e4SLinus Torvalds 8051be5606SVivek Goyal #ifdef CONFIG_KEXEC 8151be5606SVivek Goyal #include <linux/kexec.h> 8251be5606SVivek Goyal 8351be5606SVivek Goyal static ssize_t show_crash_notes(struct sys_device *dev, char *buf) 8451be5606SVivek Goyal { 8551be5606SVivek Goyal struct cpu *cpu = container_of(dev, struct cpu, sysdev); 8651be5606SVivek Goyal ssize_t rc; 8751be5606SVivek Goyal unsigned long long addr; 8851be5606SVivek Goyal int cpunum; 8951be5606SVivek Goyal 9051be5606SVivek Goyal cpunum = cpu->sysdev.id; 9151be5606SVivek Goyal 9251be5606SVivek Goyal /* 9351be5606SVivek Goyal * Might be reading other cpu's data based on which cpu read thread 9451be5606SVivek Goyal * has been scheduled. But cpu data (memory) is allocated once during 9551be5606SVivek Goyal * boot up and this data does not change there after. Hence this 9651be5606SVivek Goyal * operation should be safe. No locking required. 9751be5606SVivek Goyal */ 9851be5606SVivek Goyal addr = __pa(per_cpu_ptr(crash_notes, cpunum)); 9951be5606SVivek Goyal rc = sprintf(buf, "%Lx\n", addr); 10051be5606SVivek Goyal return rc; 10151be5606SVivek Goyal } 10251be5606SVivek Goyal static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); 10351be5606SVivek Goyal #endif 10451be5606SVivek Goyal 1051da177e4SLinus Torvalds /* 106405ae7d3SRobert P. J. Day * register_cpu - Setup a sysfs device for a CPU. 10772486f1fSSiddha, Suresh B * @cpu - cpu->hotpluggable field set to 1 will generate a control file in 10872486f1fSSiddha, Suresh B * sysfs for this CPU. 1091da177e4SLinus Torvalds * @num - CPU number to use when creating the device. 1101da177e4SLinus Torvalds * 1111da177e4SLinus Torvalds * Initialize and register the CPU device. 1121da177e4SLinus Torvalds */ 11376b67ed9SKAMEZAWA Hiroyuki int __devinit register_cpu(struct cpu *cpu, int num) 1141da177e4SLinus Torvalds { 1151da177e4SLinus Torvalds int error; 1161da177e4SLinus Torvalds cpu->node_id = cpu_to_node(num); 1171da177e4SLinus Torvalds cpu->sysdev.id = num; 1181da177e4SLinus Torvalds cpu->sysdev.cls = &cpu_sysdev_class; 1191da177e4SLinus Torvalds 1201da177e4SLinus Torvalds error = sysdev_register(&cpu->sysdev); 12176b67ed9SKAMEZAWA Hiroyuki 12272486f1fSSiddha, Suresh B if (!error && cpu->hotpluggable) 1231da177e4SLinus Torvalds register_cpu_control(cpu); 124ad74557aSAshok Raj if (!error) 125ad74557aSAshok Raj cpu_sys_devices[num] = &cpu->sysdev; 12676b67ed9SKAMEZAWA Hiroyuki if (!error) 12776b67ed9SKAMEZAWA Hiroyuki register_cpu_under_node(num, cpu_to_node(num)); 12851be5606SVivek Goyal 12951be5606SVivek Goyal #ifdef CONFIG_KEXEC 13051be5606SVivek Goyal if (!error) 13151be5606SVivek Goyal error = sysdev_create_file(&cpu->sysdev, &attr_crash_notes); 13251be5606SVivek Goyal #endif 1331da177e4SLinus Torvalds return error; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds 136a29d642aSAndrew Morton struct sys_device *get_cpu_sysdev(unsigned cpu) 137ad74557aSAshok Raj { 138ad74557aSAshok Raj if (cpu < NR_CPUS) 139ad74557aSAshok Raj return cpu_sys_devices[cpu]; 140ad74557aSAshok Raj else 141ad74557aSAshok Raj return NULL; 142ad74557aSAshok Raj } 143ad74557aSAshok Raj EXPORT_SYMBOL_GPL(get_cpu_sysdev); 1441da177e4SLinus Torvalds 1451da177e4SLinus Torvalds int __init cpu_dev_init(void) 1461da177e4SLinus Torvalds { 1475c45bf27SSiddha, Suresh B int err; 1485c45bf27SSiddha, Suresh B 1495c45bf27SSiddha, Suresh B err = sysdev_class_register(&cpu_sysdev_class); 1505c45bf27SSiddha, Suresh B #if defined(CONFIG_SCHED_MC) || defined(CONFIG_SCHED_SMT) 1515c45bf27SSiddha, Suresh B if (!err) 1525c45bf27SSiddha, Suresh B err = sched_create_sysfs_power_savings_entries(&cpu_sysdev_class); 1535c45bf27SSiddha, Suresh B #endif 1545c45bf27SSiddha, Suresh B 1555c45bf27SSiddha, Suresh B return err; 1561da177e4SLinus Torvalds } 157