X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fbase%2Fcpu.c;h=dd712b24ec91900f3b75506af6ecf6467f7ba160;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=82b4430ab3412782e70a80891da5c57674a066bb;hpb=5273a3df6485dc2ad6aa7ddd441b9a21970f003b;p=linux-2.6.git diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 82b4430ab..dd712b24e 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c @@ -9,12 +9,15 @@ #include #include +#include "base.h" struct sysdev_class cpu_sysdev_class = { set_kset_name("cpu"), }; EXPORT_SYMBOL(cpu_sysdev_class); +static struct sys_device *cpu_sys_devices[NR_CPUS]; + #ifdef CONFIG_HOTPLUG_CPU static ssize_t show_online(struct sys_device *dev, char *buf) { @@ -32,9 +35,13 @@ static ssize_t store_online(struct sys_device *dev, const char *buf, switch (buf[0]) { case '0': ret = cpu_down(cpu->sysdev.id); + if (!ret) + kobject_uevent(&dev->kobj, KOBJ_OFFLINE); break; case '1': ret = cpu_up(cpu->sysdev.id); + if (!ret) + kobject_uevent(&dev->kobj, KOBJ_ONLINE); break; default: ret = -EINVAL; @@ -46,23 +53,63 @@ static ssize_t store_online(struct sys_device *dev, const char *buf, } static SYSDEV_ATTR(online, 0600, show_online, store_online); -static void __init register_cpu_control(struct cpu *cpu) +static void __devinit register_cpu_control(struct cpu *cpu) { sysdev_create_file(&cpu->sysdev, &attr_online); } +void unregister_cpu(struct cpu *cpu, struct node *root) +{ + int logical_cpu = cpu->sysdev.id; + + if (root) + sysfs_remove_link(&root->sysdev.kobj, + kobject_name(&cpu->sysdev.kobj)); + sysdev_remove_file(&cpu->sysdev, &attr_online); + + sysdev_unregister(&cpu->sysdev); + cpu_sys_devices[logical_cpu] = NULL; + return; +} #else /* ... !CONFIG_HOTPLUG_CPU */ static inline void register_cpu_control(struct cpu *cpu) { } #endif /* CONFIG_HOTPLUG_CPU */ +#ifdef CONFIG_KEXEC +#include + +static ssize_t show_crash_notes(struct sys_device *dev, char *buf) +{ + struct cpu *cpu = container_of(dev, struct cpu, sysdev); + ssize_t rc; + unsigned long long addr; + int cpunum; + + cpunum = cpu->sysdev.id; + + /* + * Might be reading other cpu's data based on which cpu read thread + * has been scheduled. But cpu data (memory) is allocated once during + * boot up and this data does not change there after. Hence this + * operation should be safe. No locking required. + */ + addr = __pa(per_cpu_ptr(crash_notes, cpunum)); + rc = sprintf(buf, "%Lx\n", addr); + return rc; +} +static SYSDEV_ATTR(crash_notes, 0400, show_crash_notes, NULL); +#endif + /* * register_cpu - Setup a driverfs device for a CPU. + * @cpu - Callers can set the cpu->no_control field to 1, to indicate not to + * generate a control file in sysfs for this CPU. * @num - CPU number to use when creating the device. * * Initialize and register the CPU device. */ -int __init register_cpu(struct cpu *cpu, int num, struct node *root) +int __devinit register_cpu(struct cpu *cpu, int num, struct node *root) { int error; @@ -75,12 +122,26 @@ int __init register_cpu(struct cpu *cpu, int num, struct node *root) error = sysfs_create_link(&root->sysdev.kobj, &cpu->sysdev.kobj, kobject_name(&cpu->sysdev.kobj)); - if (!error) + if (!error && !cpu->no_control) register_cpu_control(cpu); + if (!error) + cpu_sys_devices[num] = &cpu->sysdev; + +#ifdef CONFIG_KEXEC + if (!error) + error = sysdev_create_file(&cpu->sysdev, &attr_crash_notes); +#endif return error; } - +struct sys_device *get_cpu_sysdev(unsigned cpu) +{ + if (cpu < NR_CPUS) + return cpu_sys_devices[cpu]; + else + return NULL; +} +EXPORT_SYMBOL_GPL(get_cpu_sysdev); int __init cpu_dev_init(void) {