diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-15 12:58:30 (GMT) |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-02-15 12:58:30 (GMT) |
commit | e8f71df723339b6d3861886f58c245812d1994f8 (patch) | |
tree | 77264d37afeff152816afa1fea7b960dc8cbbd1e /drivers/acpi | |
parent | b34bf8e3cd5039ccba7f478601188427b1a8cd0b (diff) | |
parent | 3757b94802fb65d8f696597a74053cf21738da0b (diff) | |
download | linux-e8f71df723339b6d3861886f58c245812d1994f8.tar.xz |
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/Kconfig | 2 | ||||
-rw-r--r-- | drivers/acpi/ac.c | 4 | ||||
-rw-r--r-- | drivers/acpi/acpi_memhotplug.c | 60 | ||||
-rw-r--r-- | drivers/acpi/acpi_pad.c | 3 | ||||
-rw-r--r-- | drivers/acpi/acpi_platform.c | 59 | ||||
-rw-r--r-- | drivers/acpi/battery.c | 2 | ||||
-rw-r--r-- | drivers/acpi/button.c | 4 | ||||
-rw-r--r-- | drivers/acpi/container.c | 180 | ||||
-rw-r--r-- | drivers/acpi/dock.c | 21 | ||||
-rw-r--r-- | drivers/acpi/ec.c | 2 | ||||
-rw-r--r-- | drivers/acpi/fan.c | 4 | ||||
-rw-r--r-- | drivers/acpi/hed.c | 2 | ||||
-rw-r--r-- | drivers/acpi/internal.h | 15 | ||||
-rw-r--r-- | drivers/acpi/pci_link.c | 47 | ||||
-rw-r--r-- | drivers/acpi/pci_root.c | 38 | ||||
-rw-r--r-- | drivers/acpi/pci_slot.c | 7 | ||||
-rw-r--r-- | drivers/acpi/processor_driver.c | 30 | ||||
-rw-r--r-- | drivers/acpi/sbs.c | 6 | ||||
-rw-r--r-- | drivers/acpi/sbshc.c | 4 | ||||
-rw-r--r-- | drivers/acpi/scan.c | 257 | ||||
-rw-r--r-- | drivers/acpi/thermal.c | 4 | ||||
-rw-r--r-- | drivers/acpi/video.c | 4 |
22 files changed, 390 insertions, 365 deletions
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig index 38c5078..78105b3 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 d5fdd36..6d5bf64 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 03d18f2..034d3e7 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 16fa979..31de104 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 2d1fb4c..26fce4b 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 7efaeaa..c5cd5b5 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 f0d936b..86c7d54 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 cc79d3e..5523ba7 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 78648f8..4fdea38 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 354007d..d45b287 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 3bd6a54..f815da8 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 a0cc796..13b1d39 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 da23347..7909232 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 a128082..ab764ed 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 22a8458..b3cc69c 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 d22585f..2c630c0 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 9c5929a..cbf1f12 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 ff0740e..e523245 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 cf6129a..b78bc60 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 c435871..daee749 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 506fbd4..da079d4 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 ac9a69c..5be60ad 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; |