diff options
| author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-05-02 18:25:49 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-05-12 08:14:17 -0400 |
| commit | 0902a9044fa5b7a0456ea4daacec2c2b3189ba8c (patch) | |
| tree | 7161c5cbf23ec6b8ef42f5655340be38e5f0e1a8 | |
| parent | 4f3549d72d1b5c90ecc7e673402f38f4486d22c2 (diff) | |
Driver core: Use generic offline/online for CPU offline/online
Rework the CPU hotplug code in drivers/base/cpu.c to use the
generic offline/online support introduced previously instead of
its own CPU-specific code.
For this purpose, modify cpu_subsys to provide offline and online
callbacks for CONFIG_HOTPLUG_CPU set and remove the code handling
the CPU-specific 'online' sysfs attribute.
This modification is not supposed to change the user-observable
behavior of the kernel (i.e. the 'online' attribute will be present
in exactly the same place in sysfs and should trigger exactly the
same actions as before).
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Toshi Kani <toshi.kani@hp.com>
| -rw-r--r-- | drivers/base/cpu.c | 89 |
1 files changed, 32 insertions, 57 deletions
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c index 3d48fc887ef4..25c8768172e9 100644 --- a/drivers/base/cpu.c +++ b/drivers/base/cpu.c | |||
| @@ -16,12 +16,6 @@ | |||
| 16 | 16 | ||
| 17 | #include "base.h" | 17 | #include "base.h" |
| 18 | 18 | ||
| 19 | struct bus_type cpu_subsys = { | ||
| 20 | .name = "cpu", | ||
| 21 | .dev_name = "cpu", | ||
| 22 | }; | ||
| 23 | EXPORT_SYMBOL_GPL(cpu_subsys); | ||
| 24 | |||
| 25 | static DEFINE_PER_CPU(struct device *, cpu_sys_devices); | 19 | static DEFINE_PER_CPU(struct device *, cpu_sys_devices); |
| 26 | 20 | ||
| 27 | #ifdef CONFIG_HOTPLUG_CPU | 21 | #ifdef CONFIG_HOTPLUG_CPU |
| @@ -34,69 +28,45 @@ static void change_cpu_under_node(struct cpu *cpu, | |||
| 34 | cpu->node_id = to_nid; | 28 | cpu->node_id = to_nid; |
| 35 | } | 29 | } |
| 36 | 30 | ||
| 37 | static ssize_t show_online(struct device *dev, | 31 | static int __ref cpu_subsys_online(struct device *dev) |
| 38 | struct device_attribute *attr, | ||
| 39 | char *buf) | ||
| 40 | { | 32 | { |
| 41 | struct cpu *cpu = container_of(dev, struct cpu, dev); | 33 | struct cpu *cpu = container_of(dev, struct cpu, dev); |
| 34 | int cpuid = dev->id; | ||
| 35 | int from_nid, to_nid; | ||
| 36 | int ret; | ||
| 37 | |||
| 38 | cpu_hotplug_driver_lock(); | ||
| 39 | |||
| 40 | from_nid = cpu_to_node(cpuid); | ||
| 41 | ret = cpu_up(cpuid); | ||
| 42 | /* | ||
| 43 | * When hot adding memory to memoryless node and enabling a cpu | ||
| 44 | * on the node, node number of the cpu may internally change. | ||
| 45 | */ | ||
| 46 | to_nid = cpu_to_node(cpuid); | ||
| 47 | if (from_nid != to_nid) | ||
| 48 | change_cpu_under_node(cpu, from_nid, to_nid); | ||
| 42 | 49 | ||
| 43 | return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); | 50 | cpu_hotplug_driver_unlock(); |
| 51 | return ret; | ||
| 44 | } | 52 | } |
| 45 | 53 | ||
| 46 | static ssize_t __ref store_online(struct device *dev, | 54 | static int cpu_subsys_offline(struct device *dev) |
| 47 | struct device_attribute *attr, | ||
| 48 | const char *buf, size_t count) | ||
| 49 | { | 55 | { |
| 50 | struct cpu *cpu = container_of(dev, struct cpu, dev); | 56 | int ret; |
| 51 | int cpuid = cpu->dev.id; | ||
| 52 | int from_nid, to_nid; | ||
| 53 | ssize_t ret; | ||
| 54 | 57 | ||
| 55 | cpu_hotplug_driver_lock(); | 58 | cpu_hotplug_driver_lock(); |
| 56 | switch (buf[0]) { | 59 | ret = cpu_down(dev->id); |
| 57 | case '0': | ||
| 58 | ret = cpu_down(cpuid); | ||
| 59 | if (!ret) | ||
| 60 | kobject_uevent(&dev->kobj, KOBJ_OFFLINE); | ||
| 61 | break; | ||
| 62 | case '1': | ||
| 63 | from_nid = cpu_to_node(cpuid); | ||
| 64 | ret = cpu_up(cpuid); | ||
| 65 | |||
| 66 | /* | ||
| 67 | * When hot adding memory to memoryless node and enabling a cpu | ||
| 68 | * on the node, node number of the cpu may internally change. | ||
| 69 | */ | ||
| 70 | to_nid = cpu_to_node(cpuid); | ||
| 71 | if (from_nid != to_nid) | ||
| 72 | change_cpu_under_node(cpu, from_nid, to_nid); | ||
| 73 | |||
| 74 | if (!ret) | ||
| 75 | kobject_uevent(&dev->kobj, KOBJ_ONLINE); | ||
| 76 | break; | ||
| 77 | default: | ||
| 78 | ret = -EINVAL; | ||
| 79 | } | ||
| 80 | cpu_hotplug_driver_unlock(); | 60 | cpu_hotplug_driver_unlock(); |
| 81 | |||
| 82 | if (ret >= 0) | ||
| 83 | ret = count; | ||
| 84 | return ret; | 61 | return ret; |
| 85 | } | 62 | } |
| 86 | static DEVICE_ATTR(online, 0644, show_online, store_online); | ||
| 87 | 63 | ||
| 88 | static void __cpuinit register_cpu_control(struct cpu *cpu) | ||
| 89 | { | ||
| 90 | device_create_file(&cpu->dev, &dev_attr_online); | ||
| 91 | } | ||
| 92 | void unregister_cpu(struct cpu *cpu) | 64 | void unregister_cpu(struct cpu *cpu) |
| 93 | { | 65 | { |
| 94 | int logical_cpu = cpu->dev.id; | 66 | int logical_cpu = cpu->dev.id; |
| 95 | 67 | ||
| 96 | unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); | 68 | unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); |
| 97 | 69 | ||
| 98 | device_remove_file(&cpu->dev, &dev_attr_online); | ||
| 99 | |||
| 100 | device_unregister(&cpu->dev); | 70 | device_unregister(&cpu->dev); |
| 101 | per_cpu(cpu_sys_devices, logical_cpu) = NULL; | 71 | per_cpu(cpu_sys_devices, logical_cpu) = NULL; |
| 102 | return; | 72 | return; |
| @@ -123,12 +93,18 @@ static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store); | |||
| 123 | static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); | 93 | static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); |
| 124 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ | 94 | #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ |
| 125 | 95 | ||
| 126 | #else /* ... !CONFIG_HOTPLUG_CPU */ | ||
| 127 | static inline void register_cpu_control(struct cpu *cpu) | ||
| 128 | { | ||
| 129 | } | ||
| 130 | #endif /* CONFIG_HOTPLUG_CPU */ | 96 | #endif /* CONFIG_HOTPLUG_CPU */ |
| 131 | 97 | ||
| 98 | struct bus_type cpu_subsys = { | ||
| 99 | .name = "cpu", | ||
| 100 | .dev_name = "cpu", | ||
| 101 | #ifdef CONFIG_HOTPLUG_CPU | ||
| 102 | .online = cpu_subsys_online, | ||
| 103 | .offline = cpu_subsys_offline, | ||
| 104 | #endif | ||
| 105 | }; | ||
| 106 | EXPORT_SYMBOL_GPL(cpu_subsys); | ||
| 107 | |||
| 132 | #ifdef CONFIG_KEXEC | 108 | #ifdef CONFIG_KEXEC |
| 133 | #include <linux/kexec.h> | 109 | #include <linux/kexec.h> |
| 134 | 110 | ||
| @@ -277,12 +253,11 @@ int __cpuinit register_cpu(struct cpu *cpu, int num) | |||
| 277 | cpu->dev.id = num; | 253 | cpu->dev.id = num; |
| 278 | cpu->dev.bus = &cpu_subsys; | 254 | cpu->dev.bus = &cpu_subsys; |
| 279 | cpu->dev.release = cpu_device_release; | 255 | cpu->dev.release = cpu_device_release; |
| 256 | cpu->dev.offline_disabled = !cpu->hotpluggable; | ||
| 280 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE | 257 | #ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE |
| 281 | cpu->dev.bus->uevent = arch_cpu_uevent; | 258 | cpu->dev.bus->uevent = arch_cpu_uevent; |
| 282 | #endif | 259 | #endif |
| 283 | error = device_register(&cpu->dev); | 260 | error = device_register(&cpu->dev); |
| 284 | if (!error && cpu->hotpluggable) | ||
| 285 | register_cpu_control(cpu); | ||
| 286 | if (!error) | 261 | if (!error) |
| 287 | per_cpu(cpu_sys_devices, num) = &cpu->dev; | 262 | per_cpu(cpu_sys_devices, num) = &cpu->dev; |
| 288 | if (!error) | 263 | if (!error) |
