xref: /openbmc/linux/drivers/base/cpu.c (revision 33b5f31b)
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 = {
17af5ca3f4SKay Sievers 	.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  */
11333b5f31bSRandy Dunlap int __cpuinit 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