aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-28 06:58:05 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-06-28 06:58:05 -0400
commita204dbc61b7f4cb1a7e2cb3ad057b135164782da (patch)
treef82151c04a30f49c3dee8926d184575ad2e7b1e2 /drivers/base
parent45e00374db944b1c12987b501bcaa279b3e36d93 (diff)
parent08f502c1c343031f0d126bd00e87dede38269d12 (diff)
Merge branch 'acpi-hotplug'
* acpi-hotplug: ACPI: Do not use CONFIG_ACPI_HOTPLUG_MEMORY_MODULE ACPI / cpufreq: Add ACPI processor device IDs to acpi-cpufreq Memory hotplug: Move alternative function definitions to header ACPI / processor: Fix potential NULL pointer dereference in acpi_processor_add() Memory hotplug / ACPI: Simplify memory removal ACPI / scan: Add second pass of companion offlining to hot-remove code Driver core / MM: Drop offline_memory_block() ACPI / processor: Pass processor object handle to acpi_bind_one() ACPI: Drop removal_type field from struct acpi_device Driver core / memory: Simplify __memory_block_change_state() ACPI / processor: Initialize per_cpu(processors, pr->id) properly CPU: Fix sysfs cpu/online of offlined CPUs Driver core: Introduce offline/online callbacks for memory blocks ACPI / memhotplug: Bind removable memory blocks to ACPI device nodes ACPI / processor: Use common hotplug infrastructure ACPI / hotplug: Use device offline/online for graceful hot-removal Driver core: Use generic offline/online for CPU offline/online Driver core: Add offline/online device operations
Diffstat (limited to 'drivers/base')
-rw-r--r--drivers/base/core.c130
-rw-r--r--drivers/base/cpu.c101
-rw-r--r--drivers/base/memory.c114
3 files changed, 248 insertions, 97 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 2499cefdcdf2..2166f34b7d84 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -403,6 +403,36 @@ static ssize_t store_uevent(struct device *dev, struct device_attribute *attr,
403static struct device_attribute uevent_attr = 403static struct device_attribute uevent_attr =
404 __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent); 404 __ATTR(uevent, S_IRUGO | S_IWUSR, show_uevent, store_uevent);
405 405
406static ssize_t show_online(struct device *dev, struct device_attribute *attr,
407 char *buf)
408{
409 bool val;
410
411 lock_device_hotplug();
412 val = !dev->offline;
413 unlock_device_hotplug();
414 return sprintf(buf, "%u\n", val);
415}
416
417static ssize_t store_online(struct device *dev, struct device_attribute *attr,
418 const char *buf, size_t count)
419{
420 bool val;
421 int ret;
422
423 ret = strtobool(buf, &val);
424 if (ret < 0)
425 return ret;
426
427 lock_device_hotplug();
428 ret = val ? device_online(dev) : device_offline(dev);
429 unlock_device_hotplug();
430 return ret < 0 ? ret : count;
431}
432
433static struct device_attribute online_attr =
434 __ATTR(online, S_IRUGO | S_IWUSR, show_online, store_online);
435
406static int device_add_attributes(struct device *dev, 436static int device_add_attributes(struct device *dev,
407 struct device_attribute *attrs) 437 struct device_attribute *attrs)
408{ 438{
@@ -516,6 +546,12 @@ static int device_add_attrs(struct device *dev)
516 if (error) 546 if (error)
517 goto err_remove_type_groups; 547 goto err_remove_type_groups;
518 548
549 if (device_supports_offline(dev) && !dev->offline_disabled) {
550 error = device_create_file(dev, &online_attr);
551 if (error)
552 goto err_remove_type_groups;
553 }
554
519 return 0; 555 return 0;
520 556
521 err_remove_type_groups: 557 err_remove_type_groups:
@@ -536,6 +572,7 @@ static void device_remove_attrs(struct device *dev)
536 struct class *class = dev->class; 572 struct class *class = dev->class;
537 const struct device_type *type = dev->type; 573 const struct device_type *type = dev->type;
538 574
575 device_remove_file(dev, &online_attr);
539 device_remove_groups(dev, dev->groups); 576 device_remove_groups(dev, dev->groups);
540 577
541 if (type) 578 if (type)
@@ -1433,6 +1470,99 @@ EXPORT_SYMBOL_GPL(put_device);
1433EXPORT_SYMBOL_GPL(device_create_file); 1470EXPORT_SYMBOL_GPL(device_create_file);
1434EXPORT_SYMBOL_GPL(device_remove_file); 1471EXPORT_SYMBOL_GPL(device_remove_file);
1435 1472
1473static DEFINE_MUTEX(device_hotplug_lock);
1474
1475void lock_device_hotplug(void)
1476{
1477 mutex_lock(&device_hotplug_lock);
1478}
1479
1480void unlock_device_hotplug(void)
1481{
1482 mutex_unlock(&device_hotplug_lock);
1483}
1484
1485static int device_check_offline(struct device *dev, void *not_used)
1486{
1487 int ret;
1488
1489 ret = device_for_each_child(dev, NULL, device_check_offline);
1490 if (ret)
1491 return ret;
1492
1493 return device_supports_offline(dev) && !dev->offline ? -EBUSY : 0;
1494}
1495
1496/**
1497 * device_offline - Prepare the device for hot-removal.
1498 * @dev: Device to be put offline.
1499 *
1500 * Execute the device bus type's .offline() callback, if present, to prepare
1501 * the device for a subsequent hot-removal. If that succeeds, the device must
1502 * not be used until either it is removed or its bus type's .online() callback
1503 * is executed.
1504 *
1505 * Call under device_hotplug_lock.
1506 */
1507int device_offline(struct device *dev)
1508{
1509 int ret;
1510
1511 if (dev->offline_disabled)
1512 return -EPERM;
1513
1514 ret = device_for_each_child(dev, NULL, device_check_offline);
1515 if (ret)
1516 return ret;
1517
1518 device_lock(dev);
1519 if (device_supports_offline(dev)) {
1520 if (dev->offline) {
1521 ret = 1;
1522 } else {
1523 ret = dev->bus->offline(dev);
1524 if (!ret) {
1525 kobject_uevent(&dev->kobj, KOBJ_OFFLINE);
1526 dev->offline = true;
1527 }
1528 }
1529 }
1530 device_unlock(dev);
1531
1532 return ret;
1533}
1534
1535/**
1536 * device_online - Put the device back online after successful device_offline().
1537 * @dev: Device to be put back online.
1538 *
1539 * If device_offline() has been successfully executed for @dev, but the device
1540 * has not been removed subsequently, execute its bus type's .online() callback
1541 * to indicate that the device can be used again.
1542 *
1543 * Call under device_hotplug_lock.
1544 */
1545int device_online(struct device *dev)
1546{
1547 int ret = 0;
1548
1549 device_lock(dev);
1550 if (device_supports_offline(dev)) {
1551 if (dev->offline) {
1552 ret = dev->bus->online(dev);
1553 if (!ret) {
1554 kobject_uevent(&dev->kobj, KOBJ_ONLINE);
1555 dev->offline = false;
1556 }
1557 } else {
1558 ret = 1;
1559 }
1560 }
1561 device_unlock(dev);
1562
1563 return ret;
1564}
1565
1436struct root_device { 1566struct root_device {
1437 struct device dev; 1567 struct device dev;
1438 struct module *owner; 1568 struct module *owner;
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index 3d48fc887ef4..1d110dc6f0c1 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -13,17 +13,21 @@
13#include <linux/gfp.h> 13#include <linux/gfp.h>
14#include <linux/slab.h> 14#include <linux/slab.h>
15#include <linux/percpu.h> 15#include <linux/percpu.h>
16#include <linux/acpi.h>
16 17
17#include "base.h" 18#include "base.h"
18 19
19struct bus_type cpu_subsys = {
20 .name = "cpu",
21 .dev_name = "cpu",
22};
23EXPORT_SYMBOL_GPL(cpu_subsys);
24
25static DEFINE_PER_CPU(struct device *, cpu_sys_devices); 20static DEFINE_PER_CPU(struct device *, cpu_sys_devices);
26 21
22static int cpu_subsys_match(struct device *dev, struct device_driver *drv)
23{
24 /* ACPI style match is the only one that may succeed. */
25 if (acpi_driver_match_device(dev, drv))
26 return 1;
27
28 return 0;
29}
30
27#ifdef CONFIG_HOTPLUG_CPU 31#ifdef CONFIG_HOTPLUG_CPU
28static void change_cpu_under_node(struct cpu *cpu, 32static void change_cpu_under_node(struct cpu *cpu,
29 unsigned int from_nid, unsigned int to_nid) 33 unsigned int from_nid, unsigned int to_nid)
@@ -34,69 +38,45 @@ static void change_cpu_under_node(struct cpu *cpu,
34 cpu->node_id = to_nid; 38 cpu->node_id = to_nid;
35} 39}
36 40
37static ssize_t show_online(struct device *dev, 41static int __ref cpu_subsys_online(struct device *dev)
38 struct device_attribute *attr,
39 char *buf)
40{ 42{
41 struct cpu *cpu = container_of(dev, struct cpu, dev); 43 struct cpu *cpu = container_of(dev, struct cpu, dev);
44 int cpuid = dev->id;
45 int from_nid, to_nid;
46 int ret;
42 47
43 return sprintf(buf, "%u\n", !!cpu_online(cpu->dev.id)); 48 cpu_hotplug_driver_lock();
49
50 from_nid = cpu_to_node(cpuid);
51 ret = cpu_up(cpuid);
52 /*
53 * When hot adding memory to memoryless node and enabling a cpu
54 * on the node, node number of the cpu may internally change.
55 */
56 to_nid = cpu_to_node(cpuid);
57 if (from_nid != to_nid)
58 change_cpu_under_node(cpu, from_nid, to_nid);
59
60 cpu_hotplug_driver_unlock();
61 return ret;
44} 62}
45 63
46static ssize_t __ref store_online(struct device *dev, 64static int cpu_subsys_offline(struct device *dev)
47 struct device_attribute *attr,
48 const char *buf, size_t count)
49{ 65{
50 struct cpu *cpu = container_of(dev, struct cpu, dev); 66 int ret;
51 int cpuid = cpu->dev.id;
52 int from_nid, to_nid;
53 ssize_t ret;
54 67
55 cpu_hotplug_driver_lock(); 68 cpu_hotplug_driver_lock();
56 switch (buf[0]) { 69 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(); 70 cpu_hotplug_driver_unlock();
81
82 if (ret >= 0)
83 ret = count;
84 return ret; 71 return ret;
85} 72}
86static DEVICE_ATTR(online, 0644, show_online, store_online);
87 73
88static void __cpuinit register_cpu_control(struct cpu *cpu)
89{
90 device_create_file(&cpu->dev, &dev_attr_online);
91}
92void unregister_cpu(struct cpu *cpu) 74void unregister_cpu(struct cpu *cpu)
93{ 75{
94 int logical_cpu = cpu->dev.id; 76 int logical_cpu = cpu->dev.id;
95 77
96 unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu)); 78 unregister_cpu_under_node(logical_cpu, cpu_to_node(logical_cpu));
97 79
98 device_remove_file(&cpu->dev, &dev_attr_online);
99
100 device_unregister(&cpu->dev); 80 device_unregister(&cpu->dev);
101 per_cpu(cpu_sys_devices, logical_cpu) = NULL; 81 per_cpu(cpu_sys_devices, logical_cpu) = NULL;
102 return; 82 return;
@@ -123,12 +103,19 @@ static DEVICE_ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
123static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store); 103static DEVICE_ATTR(release, S_IWUSR, NULL, cpu_release_store);
124#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */ 104#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
125 105
126#else /* ... !CONFIG_HOTPLUG_CPU */
127static inline void register_cpu_control(struct cpu *cpu)
128{
129}
130#endif /* CONFIG_HOTPLUG_CPU */ 106#endif /* CONFIG_HOTPLUG_CPU */
131 107
108struct bus_type cpu_subsys = {
109 .name = "cpu",
110 .dev_name = "cpu",
111 .match = cpu_subsys_match,
112#ifdef CONFIG_HOTPLUG_CPU
113 .online = cpu_subsys_online,
114 .offline = cpu_subsys_offline,
115#endif
116};
117EXPORT_SYMBOL_GPL(cpu_subsys);
118
132#ifdef CONFIG_KEXEC 119#ifdef CONFIG_KEXEC
133#include <linux/kexec.h> 120#include <linux/kexec.h>
134 121
@@ -277,12 +264,12 @@ int __cpuinit register_cpu(struct cpu *cpu, int num)
277 cpu->dev.id = num; 264 cpu->dev.id = num;
278 cpu->dev.bus = &cpu_subsys; 265 cpu->dev.bus = &cpu_subsys;
279 cpu->dev.release = cpu_device_release; 266 cpu->dev.release = cpu_device_release;
267 cpu->dev.offline_disabled = !cpu->hotpluggable;
268 cpu->dev.offline = !cpu_online(num);
280#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE 269#ifdef CONFIG_ARCH_HAS_CPU_AUTOPROBE
281 cpu->dev.bus->uevent = arch_cpu_uevent; 270 cpu->dev.bus->uevent = arch_cpu_uevent;
282#endif 271#endif
283 error = device_register(&cpu->dev); 272 error = device_register(&cpu->dev);
284 if (!error && cpu->hotpluggable)
285 register_cpu_control(cpu);
286 if (!error) 273 if (!error)
287 per_cpu(cpu_sys_devices, num) = &cpu->dev; 274 per_cpu(cpu_sys_devices, num) = &cpu->dev;
288 if (!error) 275 if (!error)
diff --git a/drivers/base/memory.c b/drivers/base/memory.c
index 14f8a6954da0..4ebf97f99fae 100644
--- a/drivers/base/memory.c
+++ b/drivers/base/memory.c
@@ -37,9 +37,14 @@ static inline int base_memory_block_id(int section_nr)
37 return section_nr / sections_per_block; 37 return section_nr / sections_per_block;
38} 38}
39 39
40static int memory_subsys_online(struct device *dev);
41static int memory_subsys_offline(struct device *dev);
42
40static struct bus_type memory_subsys = { 43static struct bus_type memory_subsys = {
41 .name = MEMORY_CLASS_NAME, 44 .name = MEMORY_CLASS_NAME,
42 .dev_name = MEMORY_CLASS_NAME, 45 .dev_name = MEMORY_CLASS_NAME,
46 .online = memory_subsys_online,
47 .offline = memory_subsys_offline,
43}; 48};
44 49
45static BLOCKING_NOTIFIER_HEAD(memory_chain); 50static BLOCKING_NOTIFIER_HEAD(memory_chain);
@@ -88,6 +93,7 @@ int register_memory(struct memory_block *memory)
88 memory->dev.bus = &memory_subsys; 93 memory->dev.bus = &memory_subsys;
89 memory->dev.id = memory->start_section_nr / sections_per_block; 94 memory->dev.id = memory->start_section_nr / sections_per_block;
90 memory->dev.release = memory_block_release; 95 memory->dev.release = memory_block_release;
96 memory->dev.offline = memory->state == MEM_OFFLINE;
91 97
92 error = device_register(&memory->dev); 98 error = device_register(&memory->dev);
93 return error; 99 return error;
@@ -278,33 +284,64 @@ static int __memory_block_change_state(struct memory_block *mem,
278{ 284{
279 int ret = 0; 285 int ret = 0;
280 286
281 if (mem->state != from_state_req) { 287 if (mem->state != from_state_req)
282 ret = -EINVAL; 288 return -EINVAL;
283 goto out;
284 }
285 289
286 if (to_state == MEM_OFFLINE) 290 if (to_state == MEM_OFFLINE)
287 mem->state = MEM_GOING_OFFLINE; 291 mem->state = MEM_GOING_OFFLINE;
288 292
289 ret = memory_block_action(mem->start_section_nr, to_state, online_type); 293 ret = memory_block_action(mem->start_section_nr, to_state, online_type);
294 mem->state = ret ? from_state_req : to_state;
295 return ret;
296}
290 297
291 if (ret) { 298static int memory_subsys_online(struct device *dev)
292 mem->state = from_state_req; 299{
293 goto out; 300 struct memory_block *mem = container_of(dev, struct memory_block, dev);
294 } 301 int ret;
295 302
296 mem->state = to_state; 303 mutex_lock(&mem->state_mutex);
297 switch (mem->state) { 304
298 case MEM_OFFLINE: 305 ret = mem->state == MEM_ONLINE ? 0 :
299 kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE); 306 __memory_block_change_state(mem, MEM_ONLINE, MEM_OFFLINE,
300 break; 307 ONLINE_KEEP);
301 case MEM_ONLINE: 308
302 kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE); 309 mutex_unlock(&mem->state_mutex);
303 break; 310 return ret;
304 default: 311}
305 break; 312
313static int memory_subsys_offline(struct device *dev)
314{
315 struct memory_block *mem = container_of(dev, struct memory_block, dev);
316 int ret;
317
318 mutex_lock(&mem->state_mutex);
319
320 ret = mem->state == MEM_OFFLINE ? 0 :
321 __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
322
323 mutex_unlock(&mem->state_mutex);
324 return ret;
325}
326
327static int __memory_block_change_state_uevent(struct memory_block *mem,
328 unsigned long to_state, unsigned long from_state_req,
329 int online_type)
330{
331 int ret = __memory_block_change_state(mem, to_state, from_state_req,
332 online_type);
333 if (!ret) {
334 switch (mem->state) {
335 case MEM_OFFLINE:
336 kobject_uevent(&mem->dev.kobj, KOBJ_OFFLINE);
337 break;
338 case MEM_ONLINE:
339 kobject_uevent(&mem->dev.kobj, KOBJ_ONLINE);
340 break;
341 default:
342 break;
343 }
306 } 344 }
307out:
308 return ret; 345 return ret;
309} 346}
310 347
@@ -315,8 +352,8 @@ static int memory_block_change_state(struct memory_block *mem,
315 int ret; 352 int ret;
316 353
317 mutex_lock(&mem->state_mutex); 354 mutex_lock(&mem->state_mutex);
318 ret = __memory_block_change_state(mem, to_state, from_state_req, 355 ret = __memory_block_change_state_uevent(mem, to_state, from_state_req,
319 online_type); 356 online_type);
320 mutex_unlock(&mem->state_mutex); 357 mutex_unlock(&mem->state_mutex);
321 358
322 return ret; 359 return ret;
@@ -326,22 +363,34 @@ store_mem_state(struct device *dev,
326 struct device_attribute *attr, const char *buf, size_t count) 363 struct device_attribute *attr, const char *buf, size_t count)
327{ 364{
328 struct memory_block *mem; 365 struct memory_block *mem;
366 bool offline;
329 int ret = -EINVAL; 367 int ret = -EINVAL;
330 368
331 mem = container_of(dev, struct memory_block, dev); 369 mem = container_of(dev, struct memory_block, dev);
332 370
333 if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) 371 lock_device_hotplug();
372
373 if (!strncmp(buf, "online_kernel", min_t(int, count, 13))) {
374 offline = false;
334 ret = memory_block_change_state(mem, MEM_ONLINE, 375 ret = memory_block_change_state(mem, MEM_ONLINE,
335 MEM_OFFLINE, ONLINE_KERNEL); 376 MEM_OFFLINE, ONLINE_KERNEL);
336 else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) 377 } else if (!strncmp(buf, "online_movable", min_t(int, count, 14))) {
378 offline = false;
337 ret = memory_block_change_state(mem, MEM_ONLINE, 379 ret = memory_block_change_state(mem, MEM_ONLINE,
338 MEM_OFFLINE, ONLINE_MOVABLE); 380 MEM_OFFLINE, ONLINE_MOVABLE);
339 else if (!strncmp(buf, "online", min_t(int, count, 6))) 381 } else if (!strncmp(buf, "online", min_t(int, count, 6))) {
382 offline = false;
340 ret = memory_block_change_state(mem, MEM_ONLINE, 383 ret = memory_block_change_state(mem, MEM_ONLINE,
341 MEM_OFFLINE, ONLINE_KEEP); 384 MEM_OFFLINE, ONLINE_KEEP);
342 else if(!strncmp(buf, "offline", min_t(int, count, 7))) 385 } else if(!strncmp(buf, "offline", min_t(int, count, 7))) {
386 offline = true;
343 ret = memory_block_change_state(mem, MEM_OFFLINE, 387 ret = memory_block_change_state(mem, MEM_OFFLINE,
344 MEM_ONLINE, -1); 388 MEM_ONLINE, -1);
389 }
390 if (!ret)
391 dev->offline = offline;
392
393 unlock_device_hotplug();
345 394
346 if (ret) 395 if (ret)
347 return ret; 396 return ret;
@@ -679,21 +728,6 @@ int unregister_memory_section(struct mem_section *section)
679} 728}
680#endif /* CONFIG_MEMORY_HOTREMOVE */ 729#endif /* CONFIG_MEMORY_HOTREMOVE */
681 730
682/*
683 * offline one memory block. If the memory block has been offlined, do nothing.
684 */
685int offline_memory_block(struct memory_block *mem)
686{
687 int ret = 0;
688
689 mutex_lock(&mem->state_mutex);
690 if (mem->state != MEM_OFFLINE)
691 ret = __memory_block_change_state(mem, MEM_OFFLINE, MEM_ONLINE, -1);
692 mutex_unlock(&mem->state_mutex);
693
694 return ret;
695}
696
697/* return true if the memory block is offlined, otherwise, return false */ 731/* return true if the memory block is offlined, otherwise, return false */
698bool is_memblock_offlined(struct memory_block *mem) 732bool is_memblock_offlined(struct memory_block *mem)
699{ 733{