summaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-02-15 13:58:30 +0100
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-02-15 13:58:30 +0100
commite8f71df723339b6d3861886f58c245812d1994f8 (patch)
tree77264d37afeff152816afa1fea7b960dc8cbbd1e /drivers/acpi
parentMerge branch 'pnp' (diff)
parentACPI / hotplug: Fix concurrency issues and memory leaks (diff)
downloadlinux-e8f71df723339b6d3861886f58c245812d1994f8.tar.xz
linux-e8f71df723339b6d3861886f58c245812d1994f8.zip
Merge branch 'acpi-cleanup'
* acpi-cleanup: (21 commits) ACPI / hotplug: Fix concurrency issues and memory leaks ACPI: Remove the use of CONFIG_ACPI_CONTAINER_MODULE ACPI / scan: Full transition to D3cold in acpi_device_unregister() ACPI / scan: Make acpi_bus_hot_remove_device() acquire the scan lock ACPI: Drop the container.h header file ACPI / Documentation: refer to correct file for acpi_platform_device_ids[] table ACPI / scan: Make container driver use struct acpi_scan_handler ACPI / scan: Remove useless #ifndef from acpi_eject_store() ACPI: Unbind ACPI drv when probe failed ACPI: sysfs eject support for ACPI scan handlers ACPI / scan: Follow priorities of IDs when matching scan handlers ACPI / PCI: pci_slot: replace printk(KERN_xxx) with pr_xxx() ACPI / dock: Fix acpi_bus_get_device() check in drivers/acpi/dock.c ACPI / scan: Clean up acpi_bus_get_parent() ACPI / platform: Use struct acpi_scan_handler for creating devices ACPI / PCI: Make PCI IRQ link driver use struct acpi_scan_handler ACPI / PCI: Make PCI root driver use struct acpi_scan_handler ACPI / scan: Introduce struct acpi_scan_handler ACPI / scan: Make scanning of fixed devices follow the general scheme ACPI: Drop device start operation that is not used ...
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/ac.c4
-rw-r--r--drivers/acpi/acpi_memhotplug.c60
-rw-r--r--drivers/acpi/acpi_pad.c3
-rw-r--r--drivers/acpi/acpi_platform.c59
-rw-r--r--drivers/acpi/battery.c2
-rw-r--r--drivers/acpi/button.c4
-rw-r--r--drivers/acpi/container.c180
-rw-r--r--drivers/acpi/dock.c21
-rw-r--r--drivers/acpi/ec.c2
-rw-r--r--drivers/acpi/fan.c4
-rw-r--r--drivers/acpi/hed.c2
-rw-r--r--drivers/acpi/internal.h15
-rw-r--r--drivers/acpi/pci_link.c47
-rw-r--r--drivers/acpi/pci_root.c38
-rw-r--r--drivers/acpi/pci_slot.c7
-rw-r--r--drivers/acpi/processor_driver.c30
-rw-r--r--drivers/acpi/sbs.c6
-rw-r--r--drivers/acpi/sbshc.c4
-rw-r--r--drivers/acpi/scan.c257
-rw-r--r--drivers/acpi/thermal.c4
-rw-r--r--drivers/acpi/video.c4
22 files changed, 390 insertions, 365 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 38c5078da11d..78105b3a5262 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -337,7 +337,7 @@ config X86_PM_TIMER
systems require this timer.
config ACPI_CONTAINER
- tristate "Container and Module Devices (EXPERIMENTAL)"
+ bool "Container and Module Devices (EXPERIMENTAL)"
depends on EXPERIMENTAL
default (ACPI_HOTPLUG_MEMORY || ACPI_HOTPLUG_CPU || ACPI_HOTPLUG_IO)
help
diff --git a/drivers/acpi/ac.c b/drivers/acpi/ac.c
index d5fdd36190cc..6d5bf649196d 100644
--- a/drivers/acpi/ac.c
+++ b/drivers/acpi/ac.c
@@ -60,7 +60,7 @@ static int acpi_ac_open_fs(struct inode *inode, struct file *file);
#endif
static int acpi_ac_add(struct acpi_device *device);
-static int acpi_ac_remove(struct acpi_device *device, int type);
+static int acpi_ac_remove(struct acpi_device *device);
static void acpi_ac_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id ac_device_ids[] = {
@@ -337,7 +337,7 @@ static int acpi_ac_resume(struct device *dev)
}
#endif
-static int acpi_ac_remove(struct acpi_device *device, int type)
+static int acpi_ac_remove(struct acpi_device *device)
{
struct acpi_ac *ac = NULL;
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 03d18f290118..034d3e72aa92 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -54,7 +54,7 @@ MODULE_LICENSE("GPL");
#define MEMORY_POWER_OFF_STATE 2
static int acpi_memory_device_add(struct acpi_device *device);
-static int acpi_memory_device_remove(struct acpi_device *device, int type);
+static int acpi_memory_device_remove(struct acpi_device *device);
static const struct acpi_device_id memory_device_ids[] = {
{ACPI_MEMORY_DEVICE_HID, 0},
@@ -153,14 +153,16 @@ acpi_memory_get_device_resources(struct acpi_memory_device *mem_device)
return 0;
}
-static int
-acpi_memory_get_device(acpi_handle handle,
- struct acpi_memory_device **mem_device)
+static int acpi_memory_get_device(acpi_handle handle,
+ struct acpi_memory_device **mem_device)
{
struct acpi_device *device = NULL;
- int result;
+ int result = 0;
- if (!acpi_bus_get_device(handle, &device) && device)
+ acpi_scan_lock_acquire();
+
+ acpi_bus_get_device(handle, &device);
+ if (device)
goto end;
/*
@@ -169,23 +171,28 @@ acpi_memory_get_device(acpi_handle handle,
*/
result = acpi_bus_scan(handle);
if (result) {
- acpi_handle_warn(handle, "Cannot add acpi bus\n");
- return -EINVAL;
+ acpi_handle_warn(handle, "ACPI namespace scan failed\n");
+ result = -EINVAL;
+ goto out;
}
result = acpi_bus_get_device(handle, &device);
if (result) {
acpi_handle_warn(handle, "Missing device object\n");
- return -EINVAL;
+ result = -EINVAL;
+ goto out;
}
- end:
+ end:
*mem_device = acpi_driver_data(device);
if (!(*mem_device)) {
dev_err(&device->dev, "driver data not found\n");
- return -ENODEV;
+ result = -ENODEV;
+ goto out;
}
- return 0;
+ out:
+ acpi_scan_lock_release();
+ return result;
}
static int acpi_memory_check_device(struct acpi_memory_device *mem_device)
@@ -305,6 +312,7 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
struct acpi_device *device;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
@@ -327,29 +335,40 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"\nReceived EJECT REQUEST notification for device\n"));
+ status = AE_ERROR;
+ acpi_scan_lock_acquire();
+
if (acpi_bus_get_device(handle, &device)) {
acpi_handle_err(handle, "Device doesn't exist\n");
- break;
+ goto unlock;
}
mem_device = acpi_driver_data(device);
if (!mem_device) {
acpi_handle_err(handle, "Driver Data is NULL\n");
- break;
+ goto unlock;
}
ej_event = kmalloc(sizeof(*ej_event), GFP_KERNEL);
if (!ej_event) {
pr_err(PREFIX "No memory, dropping EJECT\n");
- break;
+ goto unlock;
}
+ get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ }
- /* eject is performed asynchronously */
- return;
+ unlock:
+ acpi_scan_lock_release();
+ if (ACPI_SUCCESS(status))
+ return;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
@@ -360,7 +379,6 @@ static void acpi_memory_device_notify(acpi_handle handle, u32 event, void *data)
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
}
static void acpi_memory_device_free(struct acpi_memory_device *mem_device)
@@ -415,7 +433,7 @@ static int acpi_memory_device_add(struct acpi_device *device)
return result;
}
-static int acpi_memory_device_remove(struct acpi_device *device, int type)
+static int acpi_memory_device_remove(struct acpi_device *device)
{
struct acpi_memory_device *mem_device = NULL;
int result;
diff --git a/drivers/acpi/acpi_pad.c b/drivers/acpi/acpi_pad.c
index 16fa979f7180..31de1043eea0 100644
--- a/drivers/acpi/acpi_pad.c
+++ b/drivers/acpi/acpi_pad.c
@@ -482,8 +482,7 @@ static int acpi_pad_add(struct acpi_device *device)
return 0;
}
-static int acpi_pad_remove(struct acpi_device *device,
- int type)
+static int acpi_pad_remove(struct acpi_device *device)
{
mutex_lock(&isolated_cpus_lock);
acpi_pad_idle_cpus(0);
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 2d1fb4c21605..26fce4b8a632 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -22,6 +22,30 @@
ACPI_MODULE_NAME("platform");
+/* Flags for acpi_create_platform_device */
+#define ACPI_PLATFORM_CLK BIT(0)
+
+/*
+ * The following ACPI IDs are known to be suitable for representing as
+ * platform devices.
+ */
+static const struct acpi_device_id acpi_platform_device_ids[] = {
+
+ { "PNP0D40" },
+
+ /* Haswell LPSS devices */
+ { "INT33C0", ACPI_PLATFORM_CLK },
+ { "INT33C1", ACPI_PLATFORM_CLK },
+ { "INT33C2", ACPI_PLATFORM_CLK },
+ { "INT33C3", ACPI_PLATFORM_CLK },
+ { "INT33C4", ACPI_PLATFORM_CLK },
+ { "INT33C5", ACPI_PLATFORM_CLK },
+ { "INT33C6", ACPI_PLATFORM_CLK },
+ { "INT33C7", ACPI_PLATFORM_CLK },
+
+ { }
+};
+
static int acpi_create_platform_clks(struct acpi_device *adev)
{
static struct platform_device *pdev;
@@ -39,8 +63,7 @@ static int acpi_create_platform_clks(struct acpi_device *adev)
/**
* acpi_create_platform_device - Create platform device for ACPI device node
* @adev: ACPI device node to create a platform device for.
- * @flags: ACPI_PLATFORM_* flags that affect the creation of the platform
- * devices.
+ * @id: ACPI device ID used to match @adev.
*
* Check if the given @adev can be represented as a platform device and, if
* that's the case, create and register a platform device, populate its common
@@ -48,9 +71,10 @@ static int acpi_create_platform_clks(struct acpi_device *adev)
*
* Name of the platform device will be the same as @adev's.
*/
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
- unsigned long flags)
+static int acpi_create_platform_device(struct acpi_device *adev,
+ const struct acpi_device_id *id)
{
+ unsigned long flags = id->driver_data;
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
@@ -59,25 +83,28 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
struct resource *resources;
int count;
- if ((flags & ACPI_PLATFORM_CLK) && acpi_create_platform_clks(adev)) {
- dev_err(&adev->dev, "failed to create clocks\n");
- return NULL;
+ if (flags & ACPI_PLATFORM_CLK) {
+ int ret = acpi_create_platform_clks(adev);
+ if (ret) {
+ dev_err(&adev->dev, "failed to create clocks\n");
+ return ret;
+ }
}
/* If the ACPI node already has a physical device attached, skip it. */
if (adev->physical_node_count)
- return NULL;
+ return 0;
INIT_LIST_HEAD(&resource_list);
count = acpi_dev_get_resources(adev, &resource_list, NULL, NULL);
if (count <= 0)
- return NULL;
+ return 0;
resources = kmalloc(count * sizeof(struct resource), GFP_KERNEL);
if (!resources) {
dev_err(&adev->dev, "No memory for resources\n");
acpi_dev_free_resource_list(&resource_list);
- return NULL;
+ return -ENOMEM;
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
@@ -123,5 +150,15 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
}
kfree(resources);
- return pdev;
+ return 1;
+}
+
+static struct acpi_scan_handler platform_handler = {
+ .ids = acpi_platform_device_ids,
+ .attach = acpi_create_platform_device,
+};
+
+void __init acpi_platform_init(void)
+{
+ acpi_scan_add_handler(&platform_handler);
}
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 7efaeaa53b88..c5cd5b5513e6 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1111,7 +1111,7 @@ fail:
return result;
}
-static int acpi_battery_remove(struct acpi_device *device, int type)
+static int acpi_battery_remove(struct acpi_device *device)
{
struct acpi_battery *battery = NULL;
diff --git a/drivers/acpi/button.c b/drivers/acpi/button.c
index f0d936b65e37..86c7d5445c38 100644
--- a/drivers/acpi/button.c
+++ b/drivers/acpi/button.c
@@ -75,7 +75,7 @@ static const struct acpi_device_id button_device_ids[] = {
MODULE_DEVICE_TABLE(acpi, button_device_ids);
static int acpi_button_add(struct acpi_device *device);
-static int acpi_button_remove(struct acpi_device *device, int type);
+static int acpi_button_remove(struct acpi_device *device);
static void acpi_button_notify(struct acpi_device *device, u32 event);
#ifdef CONFIG_PM_SLEEP
@@ -433,7 +433,7 @@ static int acpi_button_add(struct acpi_device *device)
return error;
}
-static int acpi_button_remove(struct acpi_device *device, int type)
+static int acpi_button_remove(struct acpi_device *device)
{
struct acpi_button *button = acpi_driver_data(device);
diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c
index cc79d3e53a39..5523ba7d764d 100644
--- a/drivers/acpi/container.c
+++ b/drivers/acpi/container.c
@@ -34,46 +34,34 @@
#include <linux/acpi.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
-#include <acpi/container.h>
#define PREFIX "ACPI: "
-#define ACPI_CONTAINER_DEVICE_NAME "ACPI container device"
-#define ACPI_CONTAINER_CLASS "container"
-
-#define INSTALL_NOTIFY_HANDLER 1
-#define UNINSTALL_NOTIFY_HANDLER 2
-
#define _COMPONENT ACPI_CONTAINER_COMPONENT
ACPI_MODULE_NAME("container");
-MODULE_AUTHOR("Anil S Keshavamurthy");
-MODULE_DESCRIPTION("ACPI container driver");
-MODULE_LICENSE("GPL");
-
-static int acpi_container_add(struct acpi_device *device);
-static int acpi_container_remove(struct acpi_device *device, int type);
-
static const struct acpi_device_id container_device_ids[] = {
{"ACPI0004", 0},
{"PNP0A05", 0},
{"PNP0A06", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, container_device_ids);
-static struct acpi_driver acpi_container_driver = {
- .name = "container",
- .class = ACPI_CONTAINER_CLASS,
+static int container_device_attach(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
+{
+ /*
+ * FIXME: This is necessary, so that acpi_eject_store() doesn't return
+ * -ENODEV for containers.
+ */
+ return 1;
+}
+
+static struct acpi_scan_handler container_device_handler = {
.ids = container_device_ids,
- .ops = {
- .add = acpi_container_add,
- .remove = acpi_container_remove,
- },
+ .attach = container_device_attach,
};
-/*******************************************************************/
-
static int is_device_present(acpi_handle handle)
{
acpi_handle temp;
@@ -92,49 +80,6 @@ static int is_device_present(acpi_handle handle)
return ((sta & ACPI_STA_DEVICE_PRESENT) == ACPI_STA_DEVICE_PRESENT);
}
-static bool is_container_device(const char *hid)
-{
- const struct acpi_device_id *container_id;
-
- for (container_id = container_device_ids;
- container_id->id[0]; container_id++) {
- if (!strcmp((char *)container_id->id, hid))
- return true;
- }
-
- return false;
-}
-
-/*******************************************************************/
-static int acpi_container_add(struct acpi_device *device)
-{
- struct acpi_container *container;
-
- container = kzalloc(sizeof(struct acpi_container), GFP_KERNEL);
- if (!container)
- return -ENOMEM;
-
- container->handle = device->handle;
- strcpy(acpi_device_name(device), ACPI_CONTAINER_DEVICE_NAME);
- strcpy(acpi_device_class(device), ACPI_CONTAINER_CLASS);
- device->driver_data = container;
-
- ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device <%s> bid <%s>\n",
- acpi_device_name(device), acpi_device_bid(device)));
-
- return 0;
-}
-
-static int acpi_container_remove(struct acpi_device *device, int type)
-{
- acpi_status status = AE_OK;
- struct acpi_container *pc = NULL;
-
- pc = acpi_driver_data(device);
- kfree(pc);
- return status;
-}
-
static void container_notify_cb(acpi_handle handle, u32 type, void *context)
{
struct acpi_device *device = NULL;
@@ -143,6 +88,8 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
acpi_status status;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_scan_lock_acquire();
+
switch (type) {
case ACPI_NOTIFY_BUS_CHECK:
/* Fall through */
@@ -158,7 +105,7 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
/* device exist and this is a remove request */
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
}
@@ -185,98 +132,59 @@ static void container_notify_cb(acpi_handle handle, u32 type, void *context)
if (!acpi_bus_get_device(handle, &device) && device) {
device->flags.eject_pending = 1;
kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE);
- return;
+ goto out;
}
break;
default:
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, type, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
-static acpi_status
-container_walk_namespace_cb(acpi_handle handle,
- u32 lvl, void *context, void **rv)
+static bool is_container(acpi_handle handle)
{
- char *hid = NULL;
struct acpi_device_info *info;
- acpi_status status;
- int *action = context;
+ bool ret = false;
- status = acpi_get_object_info(handle, &info);
- if (ACPI_FAILURE(status)) {
- return AE_OK;
- }
-
- if (info->valid & ACPI_VALID_HID)
- hid = info->hardware_id.string;
-
- if (hid == NULL) {
- goto end;
- }
+ if (ACPI_FAILURE(acpi_get_object_info(handle, &info)))
+ return false;
- if (!is_container_device(hid))
- goto end;
+ if (info->valid & ACPI_VALID_HID) {
+ const struct acpi_device_id *id;
- switch (*action) {
- case INSTALL_NOTIFY_HANDLER:
- acpi_install_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- container_notify_cb, NULL);
- break;
- case UNINSTALL_NOTIFY_HANDLER:
- acpi_remove_notify_handler(handle,
- ACPI_SYSTEM_NOTIFY,
- container_notify_cb);
- break;
- default:
- break;
+ for (id = container_device_ids; id->id[0]; id++) {
+ ret = !strcmp((char *)id->id, info->hardware_id.string);
+ if (ret)
+ break;
+ }
}
-
- end:
kfree(info);
-
- return AE_OK;
+ return ret;
}
-static int __init acpi_container_init(void)
+static acpi_status acpi_container_register_notify_handler(acpi_handle handle,
+ u32 lvl, void *ctxt,
+ void **retv)
{
- int result = 0;
- int action = INSTALL_NOTIFY_HANDLER;
-
- result = acpi_bus_register_driver(&acpi_container_driver);
- if (result < 0) {
- return (result);
- }
-
- /* register notify handler to every container device */
- acpi_walk_namespace(ACPI_TYPE_DEVICE,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- container_walk_namespace_cb, NULL, &action, NULL);
+ if (is_container(handle))
+ acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
+ container_notify_cb, NULL);
- return (0);
+ return AE_OK;
}
-static void __exit acpi_container_exit(void)
+void __init acpi_container_init(void)
{
- int action = UNINSTALL_NOTIFY_HANDLER;
-
+ acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
+ acpi_container_register_notify_handler, NULL,
+ NULL, NULL);
- acpi_walk_namespace(ACPI_TYPE_DEVICE,
- ACPI_ROOT_OBJECT,
- ACPI_UINT32_MAX,
- container_walk_namespace_cb, NULL, &action, NULL);
-
- acpi_bus_unregister_driver(&acpi_container_driver);
-
- return;
+ acpi_scan_add_handler(&container_device_handler);
}
-
-module_init(acpi_container_init);
-module_exit(acpi_container_exit);
diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c
index 78648f811049..4fdea381ef21 100644
--- a/drivers/acpi/dock.c
+++ b/drivers/acpi/dock.c
@@ -744,7 +744,9 @@ static void acpi_dock_deferred_cb(void *context)
{
struct dock_data *data = context;
+ acpi_scan_lock_acquire();
dock_notify(data->handle, data->event, data->ds);
+ acpi_scan_lock_release();
kfree(data);
}
@@ -757,20 +759,31 @@ static int acpi_dock_notifier_call(struct notifier_block *this,
if (event != ACPI_NOTIFY_BUS_CHECK && event != ACPI_NOTIFY_DEVICE_CHECK
&& event != ACPI_NOTIFY_EJECT_REQUEST)
return 0;
+
+ acpi_scan_lock_acquire();
+
list_for_each_entry(dock_station, &dock_stations, sibling) {
if (dock_station->handle == handle) {
struct dock_data *dd;
+ acpi_status status;
dd = kmalloc(sizeof(*dd), GFP_KERNEL);
if (!dd)
- return 0;
+ break;
+
dd->handle = handle;
dd->event = event;
dd->ds = dock_station;
- acpi_os_hotplug_execute(acpi_dock_deferred_cb, dd);
- return 0 ;
+ status = acpi_os_hotplug_execute(acpi_dock_deferred_cb,
+ dd);
+ if (ACPI_FAILURE(status))
+ kfree(dd);
+
+ break;
}
}
+
+ acpi_scan_lock_release();
return 0;
}
@@ -825,7 +838,7 @@ static ssize_t show_docked(struct device *dev,
struct dock_station *dock_station = dev->platform_data;
- if (ACPI_SUCCESS(acpi_bus_get_device(dock_station->handle, &tmp)))
+ if (!acpi_bus_get_device(dock_station->handle, &tmp))
return snprintf(buf, PAGE_SIZE, "1\n");
return snprintf(buf, PAGE_SIZE, "0\n");
}
diff --git a/drivers/acpi/ec.c b/drivers/acpi/ec.c
index 354007d490d1..d45b2871d33b 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -852,7 +852,7 @@ static int acpi_ec_add(struct acpi_device *device)
return ret;
}
-static int acpi_ec_remove(struct acpi_device *device, int type)
+static int acpi_ec_remove(struct acpi_device *device)
{
struct acpi_ec *ec;
struct acpi_ec_query_handler *handler, *tmp;
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 3bd6a54702d6..f815da82c765 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -45,7 +45,7 @@ MODULE_DESCRIPTION("ACPI Fan Driver");
MODULE_LICENSE("GPL");
static int acpi_fan_add(struct acpi_device *device);
-static int acpi_fan_remove(struct acpi_device *device, int type);
+static int acpi_fan_remove(struct acpi_device *device);
static const struct acpi_device_id fan_device_ids[] = {
{"PNP0C0B", 0},
@@ -172,7 +172,7 @@ static int acpi_fan_add(struct acpi_device *device)
return result;
}
-static int acpi_fan_remove(struct acpi_device *device, int type)
+static int acpi_fan_remove(struct acpi_device *device)
{
struct thermal_cooling_device *cdev = acpi_driver_data(device);
diff --git a/drivers/acpi/hed.c b/drivers/acpi/hed.c
index a0cc796932f7..13b1d39d7cdf 100644
--- a/drivers/acpi/hed.c
+++ b/drivers/acpi/hed.c
@@ -70,7 +70,7 @@ static int acpi_hed_add(struct acpi_device *device)
return 0;
}
-static int acpi_hed_remove(struct acpi_device *device, int type)
+static int acpi_hed_remove(struct acpi_device *device)
{
hed_handle = NULL;
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index da233477d260..79092328cf06 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -25,8 +25,16 @@
int init_acpi_device_notify(void);
int acpi_scan_init(void);
+void acpi_pci_root_init(void);
+void acpi_pci_link_init(void);
+void acpi_platform_init(void);
int acpi_sysfs_init(void);
void acpi_csrt_init(void);
+#ifdef CONFIG_ACPI_CONTAINER
+void acpi_container_init(void);
+#else
+static inline void acpi_container_init(void) {}
+#endif
#ifdef CONFIG_DEBUG_FS
extern struct dentry *acpi_debugfs_dir;
@@ -86,7 +94,6 @@ struct acpi_ec {
extern struct acpi_ec *first_ec;
-int acpi_pci_root_init(void);
int acpi_ec_init(void);
int acpi_ec_ecdt_probe(void);
int acpi_boot_ec_enable(void);
@@ -118,10 +125,4 @@ static inline void suspend_nvs_restore(void) {}
-------------------------------------------------------------------------- */
struct platform_device;
-/* Flags for acpi_create_platform_device */
-#define ACPI_PLATFORM_CLK BIT(0)
-
-struct platform_device *acpi_create_platform_device(struct acpi_device *adev,
- unsigned long flags);
-
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/pci_link.c b/drivers/acpi/pci_link.c
index a12808259dfb..ab764ed34a50 100644
--- a/drivers/acpi/pci_link.c
+++ b/drivers/acpi/pci_link.c
@@ -53,23 +53,19 @@ ACPI_MODULE_NAME("pci_link");
#define ACPI_PCI_LINK_FILE_STATUS "state"
#define ACPI_PCI_LINK_MAX_POSSIBLE 16
-static int acpi_pci_link_add(struct acpi_device *device);
-static int acpi_pci_link_remove(struct acpi_device *device, int type);
+static int acpi_pci_link_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used);
+static void acpi_pci_link_remove(struct acpi_device *device);
static const struct acpi_device_id link_device_ids[] = {
{"PNP0C0F", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, link_device_ids);
-static struct acpi_driver acpi_pci_link_driver = {
- .name = "pci_link",
- .class = ACPI_PCI_LINK_CLASS,
+static struct acpi_scan_handler pci_link_handler = {
.ids = link_device_ids,
- .ops = {
- .add = acpi_pci_link_add,
- .remove = acpi_pci_link_remove,
- },
+ .attach = acpi_pci_link_add,
+ .detach = acpi_pci_link_remove,
};
/*
@@ -692,7 +688,8 @@ int acpi_pci_link_free_irq(acpi_handle handle)
Driver Interface
-------------------------------------------------------------------------- */
-static int acpi_pci_link_add(struct acpi_device *device)
+static int acpi_pci_link_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
int result;
struct acpi_pci_link *link;
@@ -746,7 +743,7 @@ static int acpi_pci_link_add(struct acpi_device *device)
if (result)
kfree(link);
- return result;
+ return result < 0 ? result : 1;
}
static int acpi_pci_link_resume(struct acpi_pci_link *link)
@@ -766,7 +763,7 @@ static void irqrouter_resume(void)
}
}
-static int acpi_pci_link_remove(struct acpi_device *device, int type)
+static void acpi_pci_link_remove(struct acpi_device *device)
{
struct acpi_pci_link *link;
@@ -777,7 +774,6 @@ static int acpi_pci_link_remove(struct acpi_device *device, int type)
mutex_unlock(&acpi_link_lock);
kfree(link);
- return 0;
}
/*
@@ -874,20 +870,10 @@ static struct syscore_ops irqrouter_syscore_ops = {
.resume = irqrouter_resume,
};
-static int __init irqrouter_init_ops(void)
-{
- if (!acpi_disabled && !acpi_noirq)
- register_syscore_ops(&irqrouter_syscore_ops);
-
- return 0;
-}
-
-device_initcall(irqrouter_init_ops);
-
-static int __init acpi_pci_link_init(void)
+void __init acpi_pci_link_init(void)
{
if (acpi_noirq)
- return 0;
+ return;
if (acpi_irq_balance == -1) {
/* no command line switch: enable balancing in IOAPIC mode */
@@ -896,11 +882,6 @@ static int __init acpi_pci_link_init(void)
else
acpi_irq_balance = 0;
}
-
- if (acpi_bus_register_driver(&acpi_pci_link_driver) < 0)
- return -ENODEV;
-
- return 0;
+ register_syscore_ops(&irqrouter_syscore_ops);
+ acpi_scan_add_handler(&pci_link_handler);
}
-
-subsys_initcall(acpi_pci_link_init);
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 22a8458b4ec9..b3cc69c5caf1 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -45,8 +45,9 @@
ACPI_MODULE_NAME("pci_root");
#define ACPI_PCI_ROOT_CLASS "pci_bridge"
#define ACPI_PCI_ROOT_DEVICE_NAME "PCI Root Bridge"
-static int acpi_pci_root_add(struct acpi_device *device);
-static int acpi_pci_root_remove(struct acpi_device *device, int type);
+static int acpi_pci_root_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used);
+static void acpi_pci_root_remove(struct acpi_device *device);
#define ACPI_PCIE_REQ_SUPPORT (OSC_EXT_PCI_CONFIG_SUPPORT \
| OSC_ACTIVE_STATE_PWR_SUPPORT \
@@ -57,16 +58,11 @@ static const struct acpi_device_id root_device_ids[] = {
{"PNP0A03", 0},
{"", 0},
};
-MODULE_DEVICE_TABLE(acpi, root_device_ids);
-static struct acpi_driver acpi_pci_root_driver = {
- .name = "pci_root",
- .class = ACPI_PCI_ROOT_CLASS,
+static struct acpi_scan_handler pci_root_handler = {
.ids = root_device_ids,
- .ops = {
- .add = acpi_pci_root_add,
- .remove = acpi_pci_root_remove,
- },
+ .attach = acpi_pci_root_add,
+ .detach = acpi_pci_root_remove,
};
/* Lock to protect both acpi_pci_roots and acpi_pci_drivers lists */
@@ -428,7 +424,8 @@ out:
}
EXPORT_SYMBOL(acpi_pci_osc_control_set);
-static int acpi_pci_root_add(struct acpi_device *device)
+static int acpi_pci_root_add(struct acpi_device *device,
+ const struct acpi_device_id *not_used)
{
unsigned long long segment, bus;
acpi_status status;
@@ -614,7 +611,7 @@ static int acpi_pci_root_add(struct acpi_device *device)
pci_enable_bridges(root->bus);
pci_bus_add_devices(root->bus);
- return 0;
+ return 1;
out_del_root:
mutex_lock(&acpi_pci_root_lock);
@@ -627,7 +624,7 @@ end:
return result;
}
-static int acpi_pci_root_remove(struct acpi_device *device, int type)
+static void acpi_pci_root_remove(struct acpi_device *device)
{
acpi_status status;
acpi_handle handle;
@@ -655,19 +652,14 @@ static int acpi_pci_root_remove(struct acpi_device *device, int type)
list_del(&root->node);
mutex_unlock(&acpi_pci_root_lock);
kfree(root);
- return 0;
}
-int __init acpi_pci_root_init(void)
+void __init acpi_pci_root_init(void)
{
acpi_hest_init();
- if (acpi_pci_disabled)
- return 0;
-
- pci_acpi_crs_quirks();
- if (acpi_bus_register_driver(&acpi_pci_root_driver) < 0)
- return -ENODEV;
-
- return 0;
+ if (!acpi_pci_disabled) {
+ pci_acpi_crs_quirks();
+ acpi_scan_add_handler(&pci_root_handler);
+ }
}
diff --git a/drivers/acpi/pci_slot.c b/drivers/acpi/pci_slot.c
index d22585f21aeb..2c630c006c2f 100644
--- a/drivers/acpi/pci_slot.c
+++ b/drivers/acpi/pci_slot.c
@@ -50,13 +50,12 @@ module_param(debug, bool, 0644);
ACPI_MODULE_NAME("pci_slot");
#define MY_NAME "pci_slot"
-#define err(format, arg...) printk(KERN_ERR "%s: " format , MY_NAME , ## arg)
-#define info(format, arg...) printk(KERN_INFO "%s: " format , MY_NAME , ## arg)
+#define err(format, arg...) pr_err("%s: " format , MY_NAME , ## arg)
+#define info(format, arg...) pr_info("%s: " format , MY_NAME , ## arg)
#define dbg(format, arg...) \
do { \
if (debug) \
- printk(KERN_DEBUG "%s: " format, \
- MY_NAME , ## arg); \
+ pr_debug("%s: " format, MY_NAME , ## arg); \
} while (0)
#define SLOT_NAME_SIZE 21 /* Inspired by #define in acpiphp.h */
diff --git a/drivers/acpi/processor_driver.c b/drivers/acpi/processor_driver.c
index 9c5929a17d3a..cbf1f122666b 100644
--- a/drivers/acpi/processor_driver.c
+++ b/drivers/acpi/processor_driver.c
@@ -81,7 +81,7 @@ MODULE_DESCRIPTION("ACPI Processor Driver");
MODULE_LICENSE("GPL");
static int acpi_processor_add(struct acpi_device *device);
-static int acpi_processor_remove(struct acpi_device *device, int type);
+static int acpi_processor_remove(struct acpi_device *device);
static void acpi_processor_notify(struct acpi_device *device, u32 event);
static acpi_status acpi_processor_hotadd_init(struct acpi_processor *pr);
static int acpi_processor_handle_eject(struct acpi_processor *pr);
@@ -610,7 +610,7 @@ err_free_pr:
return result;
}
-static int acpi_processor_remove(struct acpi_device *device, int type)
+static int acpi_processor_remove(struct acpi_device *device)
{
struct acpi_processor *pr = NULL;
@@ -623,7 +623,7 @@ static int acpi_processor_remove(struct acpi_device *device, int type)
if (pr->id >= nr_cpu_ids)
goto free;
- if (type == ACPI_BUS_REMOVAL_EJECT) {
+ if (device->removal_type == ACPI_BUS_REMOVAL_EJECT) {
if (acpi_processor_handle_eject(pr))
return -EINVAL;
}
@@ -683,8 +683,11 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
struct acpi_device *device = NULL;
struct acpi_eject_event *ej_event = NULL;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ acpi_status status;
int result;
+ acpi_scan_lock_acquire();
+
switch (event) {
case ACPI_NOTIFY_BUS_CHECK:
case ACPI_NOTIFY_DEVICE_CHECK:
@@ -733,25 +736,32 @@ static void acpi_processor_hotplug_notify(acpi_handle handle,
break;
}
+ get_device(&device->dev);
ej_event->device = device;
ej_event->event = ACPI_NOTIFY_EJECT_REQUEST;
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
- (void *)ej_event);
-
- /* eject is performed asynchronously */
- return;
+ /* The eject is carried out asynchronously. */
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device,
+ ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&device->dev);
+ kfree(ej_event);
+ break;
+ }
+ goto out;
default:
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Unsupported event [0x%x]\n", event));
/* non-hotplug event; possibly handled by other handler */
- return;
+ goto out;
}
/* Inform firmware that the hotplug operation has completed */
(void) acpi_evaluate_hotplug_ost(handle, event, ost_code, NULL);
- return;
+
+ out:
+ acpi_scan_lock_release();
}
static acpi_status is_processor_device(acpi_handle handle)
diff --git a/drivers/acpi/sbs.c b/drivers/acpi/sbs.c
index ff0740e0a9c2..e523245643ac 100644
--- a/drivers/acpi/sbs.c
+++ b/drivers/acpi/sbs.c
@@ -130,7 +130,7 @@ struct acpi_sbs {
#define to_acpi_sbs(x) container_of(x, struct acpi_sbs, charger)
-static int acpi_sbs_remove(struct acpi_device *device, int type);
+static int acpi_sbs_remove(struct acpi_device *device);
static int acpi_battery_get_state(struct acpi_battery *battery);
static inline int battery_scale(int log)
@@ -949,11 +949,11 @@ static int acpi_sbs_add(struct acpi_device *device)
acpi_smbus_register_callback(sbs->hc, acpi_sbs_callback, sbs);
end:
if (result)
- acpi_sbs_remove(device, 0);
+ acpi_sbs_remove(device);
return result;
}
-static int acpi_sbs_remove(struct acpi_device *device, int type)
+static int acpi_sbs_remove(struct acpi_device *device)
{
struct acpi_sbs *sbs;
int id;
diff --git a/drivers/acpi/sbshc.c b/drivers/acpi/sbshc.c
index cf6129a8af7c..b78bc605837e 100644
--- a/drivers/acpi/sbshc.c
+++ b/drivers/acpi/sbshc.c
@@ -33,7 +33,7 @@ struct acpi_smb_hc {
};
static int acpi_smbus_hc_add(struct acpi_device *device);
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type);
+static int acpi_smbus_hc_remove(struct acpi_device *device);
static const struct acpi_device_id sbs_device_ids[] = {
{"ACPI0001", 0},
@@ -296,7 +296,7 @@ static int acpi_smbus_hc_add(struct acpi_device *device)
extern void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit);
-static int acpi_smbus_hc_remove(struct acpi_device *device, int type)
+static int acpi_smbus_hc_remove(struct acpi_device *device)
{
struct acpi_smb_hc *hc;
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index c4358716aadc..daee7497efd3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -29,30 +29,10 @@ extern struct acpi_device *acpi_root;
static const char *dummy_hid = "device";
-/*
- * The following ACPI IDs are known to be suitable for representing as
- * platform devices.
- */
-static const struct acpi_device_id acpi_platform_device_ids[] = {
-
- { "PNP0D40" },
-
- /* Haswell LPSS devices */
- { "INT33C0", ACPI_PLATFORM_CLK },
- { "INT33C1", ACPI_PLATFORM_CLK },
- { "INT33C2", ACPI_PLATFORM_CLK },
- { "INT33C3", ACPI_PLATFORM_CLK },
- { "INT33C4", ACPI_PLATFORM_CLK },
- { "INT33C5", ACPI_PLATFORM_CLK },
- { "INT33C6", ACPI_PLATFORM_CLK },
- { "INT33C7", ACPI_PLATFORM_CLK },
-
- { }
-};
-
static LIST_HEAD(acpi_device_list);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
+static LIST_HEAD(acpi_scan_handlers_list);
DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
@@ -62,6 +42,27 @@ struct acpi_device_bus_id{
struct list_head node;
};
+void acpi_scan_lock_acquire(void)
+{
+ mutex_lock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_acquire);
+
+void acpi_scan_lock_release(void)
+{
+ mutex_unlock(&acpi_scan_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_scan_lock_release);
+
+int acpi_scan_add_handler(struct acpi_scan_handler *handler)
+{
+ if (!handler || !handler->attach)
+ return -EINVAL;
+
+ list_add_tail(&handler->list_node, &acpi_scan_handlers_list);
+ return 0;
+}
+
/*
* Creates hid/cid(s) string needed for modalias and uevent
* e.g. on a device with hid:IBM0001 and cid:ACPI0001 you get:
@@ -116,7 +117,7 @@ static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL);
*/
void acpi_bus_hot_remove_device(void *context)
{
- struct acpi_eject_event *ej_event = (struct acpi_eject_event *) context;
+ struct acpi_eject_event *ej_event = context;
struct acpi_device *device = ej_event->device;
acpi_handle handle = device->handle;
acpi_handle temp;
@@ -125,19 +126,23 @@ void acpi_bus_hot_remove_device(void *context)
acpi_status status = AE_OK;
u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; /* default */
+ mutex_lock(&acpi_scan_lock);
+
+ /* If there is no handle, the device node has been unregistered. */
+ if (!device->handle) {
+ dev_dbg(&device->dev, "ACPI handle missing\n");
+ put_device(&device->dev);
+ goto out;
+ }
+
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"Hot-removing device %s...\n", dev_name(&device->dev)));
acpi_bus_trim(device);
- /* Device node has been released. */
+ /* Device node has been unregistered. */
+ put_device(&device->dev);
device = NULL;
- /* power off device */
- status = acpi_evaluate_object(handle, "_PS3", NULL, NULL);
- if (ACPI_FAILURE(status) && status != AE_NOT_FOUND)
- printk(KERN_WARNING PREFIX
- "Power-off device failed\n");
-
if (ACPI_SUCCESS(acpi_get_handle(handle, "_LCK", &temp))) {
arg_list.count = 1;
arg_list.pointer = &arg;
@@ -157,18 +162,15 @@ void acpi_bus_hot_remove_device(void *context)
status = acpi_evaluate_object(handle, "_EJ0", &arg_list, NULL);
if (ACPI_FAILURE(status)) {
if (status != AE_NOT_FOUND)
- printk(KERN_WARNING PREFIX
- "Eject device failed\n");
- goto err_out;
- }
+ acpi_handle_warn(handle, "Eject failed\n");
- kfree(context);
- return;
+ /* Tell the firmware the hot-remove operation has failed. */
+ acpi_evaluate_hotplug_ost(handle, ej_event->event,
+ ost_code, NULL);
+ }
-err_out:
- /* Inform firmware the hot-remove operation has completed w/ error */
- (void) acpi_evaluate_hotplug_ost(handle,
- ej_event->event, ost_code, NULL);
+ out:
+ mutex_unlock(&acpi_scan_lock);
kfree(context);
return;
}
@@ -213,12 +215,10 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
if ((!count) || (buf[0] != '1')) {
return -EINVAL;
}
-#ifndef FORCE_EJECT
- if (acpi_device->driver == NULL) {
+ if (!acpi_device->driver && !acpi_device->handler) {
ret = -ENODEV;
goto err;
}
-#endif
status = acpi_get_type(acpi_device->handle, &type);
if (ACPI_FAILURE(status) || (!acpi_device->flags.ejectable)) {
ret = -ENODEV;
@@ -231,6 +231,7 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
goto err;
}
+ get_device(&acpi_device->dev);
ej_event->device = acpi_device;
if (acpi_device->flags.eject_pending) {
/* event originated from ACPI eject notification */
@@ -243,7 +244,11 @@ acpi_eject_store(struct device *d, struct device_attribute *attr,
ej_event->event, ACPI_OST_SC_EJECT_IN_PROGRESS, NULL);
}
- acpi_os_hotplug_execute(acpi_bus_hot_remove_device, (void *)ej_event);
+ status = acpi_os_hotplug_execute(acpi_bus_hot_remove_device, ej_event);
+ if (ACPI_FAILURE(status)) {
+ put_device(&acpi_device->dev);
+ kfree(ej_event);
+ }
err:
return ret;
}
@@ -637,8 +642,9 @@ static int acpi_device_probe(struct device * dev)
ret = acpi_device_install_notify_handler(acpi_dev);
if (ret) {
if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev,
- acpi_dev->removal_type);
+ acpi_drv->ops.remove(acpi_dev);
+ acpi_dev->driver = NULL;
+ acpi_dev->driver_data = NULL;
return ret;
}
}
@@ -660,7 +666,7 @@ static int acpi_device_remove(struct device * dev)
if (acpi_drv->ops.notify)
acpi_device_remove_notify_handler(acpi_dev);
if (acpi_drv->ops.remove)
- acpi_drv->ops.remove(acpi_dev, acpi_dev->removal_type);
+ acpi_drv->ops.remove(acpi_dev);
}
acpi_dev->driver = NULL;
acpi_dev->driver_data = NULL;
@@ -792,10 +798,12 @@ static void acpi_device_unregister(struct acpi_device *device)
device_del(&device->dev);
/*
- * Drop the reference counts of all power resources the device depends
- * on and turn off the ones that have no more references.
+ * Transition the device to D3cold to drop the reference counts of all
+ * power resources the device depends on and turn off the ones that have
+ * no more references.
*/
- acpi_power_transition(device, ACPI_STATE_D3_COLD);
+ acpi_device_set_power(device, ACPI_STATE_D3_COLD);
+ device->handle = NULL;
put_device(&device->dev);
}
@@ -883,29 +891,23 @@ EXPORT_SYMBOL(acpi_bus_unregister_driver);
-------------------------------------------------------------------------- */
static struct acpi_device *acpi_bus_get_parent(acpi_handle handle)
{
+ struct acpi_device *device = NULL;
acpi_status status;
- int ret;
- struct acpi_device *device;
/*
* Fixed hardware devices do not appear in the namespace and do not
* have handles, but we fabricate acpi_devices for them, so we have
* to deal with them specially.
*/
- if (handle == NULL)
+ if (!handle)
return acpi_root;
do {
status = acpi_get_parent(handle, &handle);
- if (status == AE_NULL_ENTRY)
- return NULL;
if (ACPI_FAILURE(status))
- return acpi_root;
-
- ret = acpi_bus_get_device(handle, &device);
- if (ret == 0)
- return device;
- } while (1);
+ return status == AE_NULL_ENTRY ? NULL : acpi_root;
+ } while (acpi_bus_get_device(handle, &device));
+ return device;
}
acpi_status
@@ -1441,19 +1443,21 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
acpi_device_get_busid(device);
acpi_device_set_id(device);
acpi_bus_get_flags(device);
+ device->flags.match_driver = false;
device_initialize(&device->dev);
dev_set_uevent_suppress(&device->dev, true);
}
void acpi_device_add_finalize(struct acpi_device *device)
{
+ device->flags.match_driver = true;
dev_set_uevent_suppress(&device->dev, false);
kobject_uevent(&device->dev.kobj, KOBJ_ADD);
}
static int acpi_add_single_object(struct acpi_device **child,
acpi_handle handle, int type,
- unsigned long long sta, bool match_driver)
+ unsigned long long sta)
{
int result;
struct acpi_device *device;
@@ -1469,7 +1473,6 @@ static int acpi_add_single_object(struct acpi_device **child,
acpi_bus_get_power_flags(device);
acpi_bus_get_wakeup_device_flags(device);
- device->flags.match_driver = match_driver;
result = acpi_device_add(device, acpi_device_release);
if (result) {
acpi_device_release(&device->dev);
@@ -1562,12 +1565,10 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_CTRL_DEPTH;
}
- acpi_add_single_object(&device, handle, type, sta, false);
+ acpi_add_single_object(&device, handle, type, sta);
if (!device)
return AE_CTRL_DEPTH;
- device->flags.match_driver = true;
-
out:
if (!*return_value)
*return_value = device;
@@ -1575,33 +1576,68 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
+static int acpi_scan_do_attach_handler(struct acpi_device *device, char *id)
+{
+ struct acpi_scan_handler *handler;
+
+ list_for_each_entry(handler, &acpi_scan_handlers_list, list_node) {
+ const struct acpi_device_id *devid;
+
+ for (devid = handler->ids; devid->id[0]; devid++) {
+ int ret;
+
+ if (strcmp((char *)devid->id, id))
+ continue;
+
+ ret = handler->attach(device, devid);
+ if (ret > 0) {
+ device->handler = handler;
+ return ret;
+ } else if (ret < 0) {
+ return ret;
+ }
+ }
+ }
+ return 0;
+}
+
+static int acpi_scan_attach_handler(struct acpi_device *device)
+{
+ struct acpi_hardware_id *hwid;
+ int ret = 0;
+
+ list_for_each_entry(hwid, &device->pnp.ids, list) {
+ ret = acpi_scan_do_attach_handler(device, hwid->id);
+ if (ret)
+ break;
+
+ }
+ return ret;
+}
+
static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **ret_not_used)
{
- const struct acpi_device_id *id;
- acpi_status status = AE_OK;
struct acpi_device *device;
unsigned long long sta_not_used;
- int type_not_used;
+ int ret;
/*
* Ignore errors ignored by acpi_bus_check_add() to avoid terminating
* namespace walks prematurely.
*/
- if (acpi_bus_type_and_status(handle, &type_not_used, &sta_not_used))
+ if (acpi_bus_type_and_status(handle, &ret, &sta_not_used))
return AE_OK;
if (acpi_bus_get_device(handle, &device))
return AE_CTRL_DEPTH;
- id = __acpi_match_device(device, acpi_platform_device_ids);
- if (id) {
- /* This is a known good platform device. */
- acpi_create_platform_device(device, id->driver_data);
- } else if (device_attach(&device->dev) < 0) {
- status = AE_CTRL_DEPTH;
- }
- return status;
+ ret = acpi_scan_attach_handler(device);
+ if (ret)
+ return ret > 0 ? AE_OK : AE_CTRL_DEPTH;
+
+ ret = device_attach(&device->dev);
+ return ret >= 0 ? AE_OK : AE_CTRL_DEPTH;
}
/**
@@ -1615,14 +1651,14 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used,
* there has been a real error. There just have been no suitable ACPI objects
* in the table trunk from which the kernel could create a device and add an
* appropriate driver.
+ *
+ * Must be called under acpi_scan_lock.
*/
int acpi_bus_scan(acpi_handle handle)
{
void *device = NULL;
int error = 0;
- mutex_lock(&acpi_scan_lock);
-
if (ACPI_SUCCESS(acpi_bus_check_add(handle, 0, NULL, &device)))
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_check_add, NULL, NULL, &device);
@@ -1633,7 +1669,6 @@ int acpi_bus_scan(acpi_handle handle)
acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX,
acpi_bus_device_attach, NULL, NULL, NULL);
- mutex_unlock(&acpi_scan_lock);
return error;
}
EXPORT_SYMBOL(acpi_bus_scan);
@@ -1644,8 +1679,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used,
struct acpi_device *device = NULL;
if (!acpi_bus_get_device(handle, &device)) {
+ struct acpi_scan_handler *dev_handler = device->handler;
+
device->removal_type = ACPI_BUS_REMOVAL_EJECT;
- device_release_driver(&device->dev);
+ if (dev_handler) {
+ if (dev_handler->detach)
+ dev_handler->detach(device);
+
+ device->handler = NULL;
+ } else {
+ device_release_driver(&device->dev);
+ }
}
return AE_OK;
}
@@ -1661,10 +1705,14 @@ static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used,
return AE_OK;
}
+/**
+ * acpi_bus_trim - Remove ACPI device node and all of its descendants
+ * @start: Root of the ACPI device nodes subtree to remove.
+ *
+ * Must be called under acpi_scan_lock.
+ */
void acpi_bus_trim(struct acpi_device *start)
{
- mutex_lock(&acpi_scan_lock);
-
/*
* Execute acpi_bus_device_detach() as a post-order callback to detach
* all ACPI drivers from the device nodes being removed.
@@ -1679,33 +1727,45 @@ void acpi_bus_trim(struct acpi_device *start)
acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL,
acpi_bus_remove, NULL, NULL);
acpi_bus_remove(start->handle, 0, NULL, NULL);
-
- mutex_unlock(&acpi_scan_lock);
}
EXPORT_SYMBOL_GPL(acpi_bus_trim);
static int acpi_bus_scan_fixed(void)
{
int result = 0;
- struct acpi_device *device = NULL;
/*
* Enumerate all fixed-feature devices.
*/
- if ((acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON) == 0) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_POWER_BUTTON)) {
+ struct acpi_device *device = NULL;
+
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_POWER_BUTTON,
- ACPI_STA_DEFAULT, true);
+ ACPI_STA_DEFAULT);
+ if (result)
+ return result;
+
+ result = device_attach(&device->dev);
+ if (result < 0)
+ return result;
+
device_init_wakeup(&device->dev, true);
}
- if ((acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON) == 0) {
+ if (!(acpi_gbl_FADT.flags & ACPI_FADT_SLEEP_BUTTON)) {
+ struct acpi_device *device = NULL;
+
result = acpi_add_single_object(&device, NULL,
ACPI_BUS_TYPE_SLEEP_BUTTON,
- ACPI_STA_DEFAULT, true);
+ ACPI_STA_DEFAULT);
+ if (result)
+ return result;
+
+ result = device_attach(&device->dev);
}
- return result;
+ return result < 0 ? result : 0;
}
int __init acpi_scan_init(void)
@@ -1719,25 +1779,32 @@ int __init acpi_scan_init(void)
}
acpi_pci_root_init();
+ acpi_pci_link_init();
+ acpi_platform_init();
acpi_csrt_init();
+ acpi_container_init();
+ mutex_lock(&acpi_scan_lock);
/*
* Enumerate devices in the ACPI namespace.
*/
result = acpi_bus_scan(ACPI_ROOT_OBJECT);
if (result)
- return result;
+ goto out;
result = acpi_bus_get_device(ACPI_ROOT_OBJECT, &acpi_root);
if (result)
- return result;
+ goto out;
result = acpi_bus_scan_fixed();
if (result) {
acpi_device_unregister(acpi_root);
- return result;
+ goto out;
}
acpi_update_all_gpes();
- return 0;
+
+ out:
+ mutex_unlock(&acpi_scan_lock);
+ return result;
}
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 506fbd4b5733..da079d4e0baa 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -97,7 +97,7 @@ module_param(psv, int, 0644);
MODULE_PARM_DESC(psv, "Disable or override all passive trip points.");
static int acpi_thermal_add(struct acpi_device *device);
-static int acpi_thermal_remove(struct acpi_device *device, int type);
+static int acpi_thermal_remove(struct acpi_device *device);
static void acpi_thermal_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id thermal_device_ids[] = {
@@ -1111,7 +1111,7 @@ end:
return result;
}
-static int acpi_thermal_remove(struct acpi_device *device, int type)
+static int acpi_thermal_remove(struct acpi_device *device)
{
struct acpi_thermal *tz = NULL;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index ac9a69cd45f5..5be60ad8381f 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -88,7 +88,7 @@ module_param(use_bios_initial_backlight, bool, 0644);
static int register_count = 0;
static int acpi_video_bus_add(struct acpi_device *device);
-static int acpi_video_bus_remove(struct acpi_device *device, int type);
+static int acpi_video_bus_remove(struct acpi_device *device);
static void acpi_video_bus_notify(struct acpi_device *device, u32 event);
static const struct acpi_device_id video_device_ids[] = {
@@ -1740,7 +1740,7 @@ static int acpi_video_bus_add(struct acpi_device *device)
return error;
}
-static int acpi_video_bus_remove(struct acpi_device *device, int type)
+static int acpi_video_bus_remove(struct acpi_device *device)
{
struct acpi_video_bus *video = NULL;