aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/base/core.c
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/core.c
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/core.c')
-rw-r--r--drivers/base/core.c130
1 files changed, 130 insertions, 0 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;