summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-15 13:24:13 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-01-15 13:24:13 +0100
commit05404d8f7b5c831e1a2c24bb782f0fe8ea02354c (patch)
tree907c9119308d98ed919b21339bf399ade8dbf591
parentcecdb193c8d91a42d9489d00618cc3dfff92e55a (diff)
ACPI / scan: Add second pass to acpi_bus_trim()
Make acpi_bus_trim() work in analogy with acpi_bus_scan() and carry out two passes such that ACPI drivers will be detached from device nodes being removed in the first pass and the device nodes themselves will be removed in the second pass. For this purpose split the driver unregistration out of acpi_bus_remove() into a new routine, acpi_bus_device_detach(), that will be executed by acpi_bus_trim() in the additional first pass as a post-order callback. This is necessary, because some ACPI drivers' .remove() routines unregister struct device objects associated with the ACPI device nodes being removed and that needs to happen while the ACPI device nodes are still around (for example, in case they need to be used for power management or similar things at that time). Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Toshi Kani <toshi.kani@hp.com> Acked-by: Yinghai Lu <yinghai@kernel.org> Acked-by: Yasuaki Ishimatsu <isimatu.yasuaki@jp.fujitsu.com>
-rw-r--r--drivers/acpi/scan.c46
1 files changed, 30 insertions, 16 deletions
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 1ee62bd2582..d04d0b33656 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -1374,22 +1374,6 @@ static int acpi_device_set_context(struct acpi_device *device)
return -ENODEV;
}
-static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
- void *not_used, void **ret_not_used)
-{
- struct acpi_device *dev = NULL;
-
- if (acpi_bus_get_device(handle, &dev))
- return AE_OK;
-
- dev->removal_type = ACPI_BUS_REMOVAL_EJECT;
- device_release_driver(&dev->dev);
-
- acpi_device_unregister(dev);
-
- return AE_OK;
-}
-
static int acpi_add_single_object(struct acpi_device **child,
acpi_handle handle, int type,
unsigned long long sta, bool match_driver)
@@ -1642,9 +1626,39 @@ int acpi_bus_add(acpi_handle handle)
}
EXPORT_SYMBOL(acpi_bus_add);
+static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
+{
+ struct acpi_device *device = NULL;
+
+ if (!acpi_bus_get_device(handle, &device)) {
+ device->removal_type = ACPI_BUS_REMOVAL_EJECT;
+ device_release_driver(&device->dev);
+ }
+ return AE_OK;
+}
+
+static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
+ void *not_used, void **ret_not_used)
+{
+ struct acpi_device *device = NULL;
+
+ if (!acpi_bus_get_device(handle, &device))
+ acpi_device_unregister(device);
+
+ return AE_OK;
+}
+
int acpi_bus_trim(struct acpi_device *start)
{
/*
+ * Execute acpi_bus_device_detach() as a post-order callback to detach
+ * all ACPI drivers from the device nodes being removed.
+ */
+ acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
+ acpi_bus_device_detach, NULL, NULL);
+ acpi_bus_device_detach(start->handle, 0, NULL, NULL);
+ /*
* Execute acpi_bus_remove() as a post-order callback to remove device
* nodes in the given namespace scope.
*/