From d783156ea38431b20af0d4f910a6f9f9054d33b9 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:52:12 +0100 Subject: ACPI / scan: Define non-empty device removal handler If an ACPI namespace node is removed (usually, as a result of a table unload), and there is a data object attached to that node, acpi_ns_delete_node() executes the removal handler submitted to acpi_attach_data() for that object. That handler is currently empty for struct acpi_device objects, so it is necessary to detach those objects from the corresponding ACPI namespace nodes in advance every time a table unload may happen. That is cumbersome and inefficient and leads to some design constraints that turn out to be quite inconvenient (in particular, struct acpi_device objects cannot be registered for namespace nodes representing devices that are not reported as present or functional by _STA). For this reason, introduce a non-empty removal handler for ACPI device objects that will unregister them when their ACPI namespace nodes go away. This code modification alone should not change functionality except for the ordering of the ACPI hotplug workqueue which should not matter (without subsequent code changes). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- include/acpi/acpi_bus.h | 1 + 1 file changed, 1 insertion(+) (limited to 'include/acpi') diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index c602c7718421..9fe5f63155ed 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -299,6 +299,7 @@ struct acpi_device { struct list_head children; struct list_head node; struct list_head wakeup_list; + struct list_head del_list; struct acpi_device_status status; struct acpi_device_flags flags; struct acpi_device_pnp pnp; -- cgit v1.2.3 From 202317a573b20d77a9abb7c16a3fd5b40cef3d9d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:54:37 +0100 Subject: ACPI / scan: Add acpi_device objects for all device nodes in the namespace Modify the ACPI namespace scanning code to register a struct acpi_device object for every namespace node representing a device, processor and so on, even if the device represented by that namespace node is reported to be not present and not functional by _STA. There are multiple reasons to do that. First of all, it avoids quite a lot of overhead when struct acpi_device objects are deleted every time acpi_bus_trim() is run and then added again by a subsequent acpi_bus_scan() for the same scope, although the namespace objects they correspond to stay in memory all the time (which always is the case on a vast majority of systems). Second, it will allow user space to see that there are namespace nodes representing devices that are not present at the moment and may be added to the system. It will also allow user space to evaluate _SUN for those nodes to check what physical slots the "missing" devices may be put into and it will make sense to add a sysfs attribute for _STA evaluation after this change (that will be useful for thermal management on some systems). Next, it will help to consolidate the ACPI hotplug handling among subsystems by making it possible to store hotplug-related information in struct acpi_device objects in a standard common way. Finally, it will help to avoid a race condition related to the deletion of ACPI namespace nodes. Namely, namespace nodes may be deleted as a result of a table unload triggered by _EJ0 or _DCK. If a hotplug notification for one of those nodes is triggered right before the deletion and it executes a hotplug callback via acpi_hotplug_execute(), the ACPI handle passed to that callback may be stale when the callback actually runs. One way to work around that is to always pass struct acpi_device pointers to hotplug callbacks after doing a get_device() on the objects in question which eliminates the use-after-free possibility (the ACPI handles in those objects are invalidated by acpi_scan_drop_device(), so they will trigger ACPICA errors on attempts to use them). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- Documentation/acpi/namespace.txt | 9 +--- drivers/acpi/device_pm.c | 22 ++++++-- drivers/acpi/dock.c | 9 ++-- drivers/acpi/internal.h | 3 ++ drivers/acpi/pci_root.c | 5 +- drivers/acpi/scan.c | 107 ++++++++++++++++++------------------- drivers/pci/hotplug/acpiphp_glue.c | 2 +- drivers/xen/xen-acpi-cpuhotplug.c | 8 +-- drivers/xen/xen-acpi-memhotplug.c | 7 +-- include/acpi/acpi_bus.h | 9 +++- 10 files changed, 97 insertions(+), 84 deletions(-) (limited to 'include/acpi') diff --git a/Documentation/acpi/namespace.txt b/Documentation/acpi/namespace.txt index 260f6a3661fa..1860cb3865c6 100644 --- a/Documentation/acpi/namespace.txt +++ b/Documentation/acpi/namespace.txt @@ -235,10 +235,6 @@ Wysocki . named object's type in the second column). In that case the object's directory in sysfs will contain the 'path' attribute whose value is the full path to the node from the namespace root. - struct acpi_device objects are created for the ACPI namespace nodes - whose _STA control methods return PRESENT or FUNCTIONING. The power - resource nodes or nodes without _STA are assumed to be both PRESENT - and FUNCTIONING. F: The struct acpi_device object is created for a fixed hardware feature (as indicated by the fixed feature flag's name in the second @@ -340,7 +336,7 @@ Wysocki . | +-------------+-------+----------------+ | | | | +- - - - - - - +- - - - - - +- - - - - - - -+ - | +-| * PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | + | +-| PNP0C0D:00 | \_SB_.LID0 | acpi:PNP0C0D: | | | +- - - - - - - +- - - - - - +- - - - - - - -+ | | | | +------------+------------+-----------------------+ @@ -390,6 +386,3 @@ Wysocki . attribute (as described earlier in this document). NOTE: N/A indicates the device object does not have the 'path' or the 'modalias' attribute. - NOTE: The PNP0C0D device listed above is highlighted (marked by "*") - to indicate it will be created only when its _STA methods return - PRESENT or FUNCTIONING. diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c index b3480cf7db1a..d49f1e464703 100644 --- a/drivers/acpi/device_pm.c +++ b/drivers/acpi/device_pm.c @@ -256,6 +256,8 @@ int acpi_bus_init_power(struct acpi_device *device) return -EINVAL; device->power.state = ACPI_STATE_UNKNOWN; + if (!acpi_device_is_present(device)) + return 0; result = acpi_device_get_power(device, &state); if (result) @@ -302,15 +304,18 @@ int acpi_device_fix_up_power(struct acpi_device *device) return ret; } -int acpi_bus_update_power(acpi_handle handle, int *state_p) +int acpi_device_update_power(struct acpi_device *device, int *state_p) { - struct acpi_device *device; int state; int result; - result = acpi_bus_get_device(handle, &device); - if (result) + if (device->power.state == ACPI_STATE_UNKNOWN) { + result = acpi_bus_init_power(device); + if (!result && state_p) + *state_p = device->power.state; + return result; + } result = acpi_device_get_power(device, &state); if (result) @@ -338,6 +343,15 @@ int acpi_bus_update_power(acpi_handle handle, int *state_p) return 0; } + +int acpi_bus_update_power(acpi_handle handle, int *state_p) +{ + struct acpi_device *device; + int result; + + result = acpi_bus_get_device(handle, &device); + return result ? result : acpi_device_update_power(device, state_p); +} EXPORT_SYMBOL_GPL(acpi_bus_update_power); bool acpi_bus_power_manageable(acpi_handle handle) diff --git a/drivers/acpi/dock.c b/drivers/acpi/dock.c index dcd73ccb514c..de032010da3c 100644 --- a/drivers/acpi/dock.c +++ b/drivers/acpi/dock.c @@ -323,14 +323,11 @@ static int dock_present(struct dock_station *ds) */ static void dock_create_acpi_device(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; int ret; - if (acpi_bus_get_device(handle, &device)) { - /* - * no device created for this object, - * so we should create one. - */ + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { ret = acpi_bus_scan(handle); if (ret) pr_debug("error adding bus, %x\n", -ret); diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index d8606498bf6f..809b8082c134 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -90,6 +90,7 @@ void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); void acpi_bus_device_eject(void *data, u32 ost_src); +bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- Power Resource @@ -107,6 +108,8 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state); int acpi_power_on_resources(struct acpi_device *device, int state); int acpi_power_transition(struct acpi_device *device, int state); +int acpi_device_update_power(struct acpi_device *device, int *state_p); + int acpi_wakeup_device_init(void); void acpi_early_processor_set_pdc(void); diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 20360e480bd8..4076491c6ded 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -634,9 +634,10 @@ void __init acpi_pci_root_init(void) static void handle_root_bridge_insertion(acpi_handle handle) { - struct acpi_device *device; + struct acpi_device *device = NULL; - if (!acpi_bus_get_device(handle, &device)) { + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) { dev_printk(KERN_DEBUG, &device->dev, "acpi device already exists; ignoring notify\n"); return; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index ad2522015e5e..bc52192785f1 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -259,7 +259,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_bus_trim(device); - /* Device node has been unregistered. */ put_device(&device->dev); device = NULL; @@ -328,7 +327,7 @@ void acpi_bus_device_eject(void *data, u32 ost_src) static void acpi_scan_bus_device_check(void *data, u32 ost_source) { acpi_handle handle = data; - struct acpi_device *device = NULL; + struct acpi_device *device; u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; int error; @@ -336,8 +335,9 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) mutex_lock(&acpi_scan_lock); if (ost_source != ACPI_NOTIFY_BUS_CHECK) { + device = NULL; acpi_bus_get_device(handle, &device); - if (device) { + if (acpi_device_enumerated(device)) { dev_warn(&device->dev, "Attempt to re-insert\n"); goto out; } @@ -347,9 +347,10 @@ static void acpi_scan_bus_device_check(void *data, u32 ost_source) acpi_handle_warn(handle, "Namespace scan failure\n"); goto out; } - error = acpi_bus_get_device(handle, &device); - if (error) { - acpi_handle_warn(handle, "Missing device node object\n"); + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { + acpi_handle_warn(handle, "Device not enumerated\n"); goto out; } ost_code = ACPI_OST_SC_SUCCESS; @@ -1111,20 +1112,6 @@ int acpi_device_add(struct acpi_device *device, return result; } -static void acpi_device_unregister(struct acpi_device *device) -{ - acpi_detach_data(device->handle, acpi_scan_drop_device); - acpi_device_del(device); - /* - * 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_device_set_power(device, ACPI_STATE_D3_COLD); - device->handle = NULL; - put_device(&device->dev); -} - /* -------------------------------------------------------------------------- Driver Management -------------------------------------------------------------------------- */ @@ -1703,6 +1690,8 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); device->flags.match_driver = false; + device->flags.initialized = true; + device->flags.visited = false; device_initialize(&device->dev); dev_set_uevent_suppress(&device->dev, true); } @@ -1787,6 +1776,15 @@ static int acpi_bus_type_and_status(acpi_handle handle, int *type, return 0; } +bool acpi_device_is_present(struct acpi_device *adev) +{ + if (adev->status.present || adev->status.functional) + return true; + + adev->flags.initialized = false; + return false; +} + static bool acpi_scan_handler_matching(struct acpi_scan_handler *handler, char *idstr, const struct acpi_device_id **matchid) @@ -1880,18 +1878,6 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used, acpi_scan_init_hotplug(handle, type); - if (!(sta & ACPI_STA_DEVICE_PRESENT) && - !(sta & ACPI_STA_DEVICE_FUNCTIONING)) { - struct acpi_device_wakeup wakeup; - - if (acpi_has_method(handle, "_PRW")) { - acpi_bus_extract_wakeup_device_power_package(handle, - &wakeup); - acpi_power_resources_list_free(&wakeup.resources); - } - return AE_CTRL_DEPTH; - } - acpi_add_single_object(&device, handle, type, sta); if (!device) return AE_CTRL_DEPTH; @@ -1930,32 +1916,50 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, void *not_used, void **ret_not_used) { struct acpi_device *device; - unsigned long long sta_not_used; + unsigned long long sta; int ret; /* * Ignore errors ignored by acpi_bus_check_add() to avoid terminating * namespace walks prematurely. */ - if (acpi_bus_type_and_status(handle, &ret, &sta_not_used)) + if (acpi_bus_type_and_status(handle, &ret, &sta)) return AE_OK; if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; + STRUCT_TO_INT(device->status) = sta; + /* Skip devices that are not present. */ + if (!acpi_device_is_present(device)) + goto err; + if (device->handler) return AE_OK; + if (!device->flags.initialized) { + acpi_bus_update_power(device, NULL); + device->flags.initialized = true; + } ret = acpi_scan_attach_handler(device); if (ret < 0) - return AE_CTRL_DEPTH; + goto err; device->flags.match_driver = true; if (ret > 0) - return AE_OK; + goto ok; ret = device_attach(&device->dev); - return ret >= 0 ? AE_OK : AE_CTRL_DEPTH; + if (ret < 0) + goto err; + + ok: + device->flags.visited = true; + return AE_OK; + + err: + device->flags.visited = false; + return AE_CTRL_DEPTH; } /** @@ -2007,21 +2011,17 @@ static acpi_status acpi_bus_device_detach(acpi_handle handle, u32 lvl_not_used, } else { device_release_driver(&device->dev); } + /* + * Most likely, the device is going away, so put it into D3cold + * before that. + */ + acpi_device_set_power(device, ACPI_STATE_D3_COLD); + device->flags.initialized = false; + device->flags.visited = false; } return AE_OK; } -static acpi_status acpi_bus_remove(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_not_used) -{ - struct acpi_device *device = NULL; - - if (!acpi_bus_get_device(handle, &device)) - acpi_device_unregister(device); - - return AE_OK; -} - /** * acpi_bus_trim - Remove ACPI device node and all of its descendants * @start: Root of the ACPI device nodes subtree to remove. @@ -2037,13 +2037,6 @@ void acpi_bus_trim(struct acpi_device *start) acpi_walk_namespace(ACPI_TYPE_ANY, start->handle, ACPI_UINT32_MAX, NULL, acpi_bus_device_detach, NULL, NULL); acpi_bus_device_detach(start->handle, 0, NULL, NULL); - /* - * Execute acpi_bus_remove() as a post-order callback to remove device - * nodes in the given namespace scope. - */ - 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); } EXPORT_SYMBOL_GPL(acpi_bus_trim); @@ -2121,7 +2114,9 @@ int __init acpi_scan_init(void) result = acpi_bus_scan_fixed(); if (result) { - acpi_device_unregister(acpi_root); + acpi_detach_data(acpi_root->handle, acpi_scan_drop_device); + acpi_device_del(acpi_root); + put_device(&acpi_root->dev); goto out; } diff --git a/drivers/pci/hotplug/acpiphp_glue.c b/drivers/pci/hotplug/acpiphp_glue.c index 1cf605f67673..67be6bab7535 100644 --- a/drivers/pci/hotplug/acpiphp_glue.c +++ b/drivers/pci/hotplug/acpiphp_glue.c @@ -489,7 +489,7 @@ static void acpiphp_bus_add(acpi_handle handle) acpi_bus_scan(handle); acpi_bus_get_device(handle, &adev); - if (adev) + if (acpi_device_enumerated(adev)) acpi_device_set_power(adev, ACPI_STATE_D0); } diff --git a/drivers/xen/xen-acpi-cpuhotplug.c b/drivers/xen/xen-acpi-cpuhotplug.c index 8dae6c13063a..73496c3d18ae 100644 --- a/drivers/xen/xen-acpi-cpuhotplug.c +++ b/drivers/xen/xen-acpi-cpuhotplug.c @@ -269,7 +269,8 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, if (!is_processor_present(handle)) break; - if (!acpi_bus_get_device(handle, &device)) + acpi_bus_get_device(handle, &device); + if (acpi_device_enumerated(device)) break; result = acpi_bus_scan(handle); @@ -277,8 +278,9 @@ static void acpi_processor_hotplug_notify(acpi_handle handle, pr_err(PREFIX "Unable to add the device\n"); break; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_err(PREFIX "Missing device object\n"); break; } diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c index 9083f1e474f8..9b056f06691f 100644 --- a/drivers/xen/xen-acpi-memhotplug.c +++ b/drivers/xen/xen-acpi-memhotplug.c @@ -169,7 +169,7 @@ static int acpi_memory_get_device(acpi_handle handle, acpi_scan_lock_acquire(); acpi_bus_get_device(handle, &device); - if (device) + if (acpi_device_enumerated(device)) goto end; /* @@ -182,8 +182,9 @@ static int acpi_memory_get_device(acpi_handle handle, result = -EINVAL; goto out; } - result = acpi_bus_get_device(handle, &device); - if (result) { + device = NULL; + acpi_bus_get_device(handle, &device); + if (!acpi_device_enumerated(device)) { pr_warn(PREFIX "Missing device object\n"); result = -EINVAL; goto out; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 9fe5f63155ed..e748dbfca9d5 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -169,7 +169,9 @@ struct acpi_device_flags { u32 ejectable:1; u32 power_manageable:1; u32 match_driver:1; - u32 reserved:27; + u32 initialized:1; + u32 visited:1; + u32 reserved:25; }; /* File System */ @@ -386,6 +388,11 @@ int acpi_match_device_ids(struct acpi_device *device, int acpi_create_dir(struct acpi_device *); void acpi_remove_dir(struct acpi_device *); +static inline bool acpi_device_enumerated(struct acpi_device *adev) +{ + return adev && adev->flags.initialized && adev->flags.visited; +} + typedef void (*acpi_hp_callback)(void *data, u32 src); acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src); -- cgit v1.2.3 From 3338db0057ed9f554050bd06863731c515d79672 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:20 +0100 Subject: ACPI / hotplug: Make ACPI PCI root hotplug use common hotplug code Rework the common ACPI device hotplug code so that it is suitable for PCI host bridge hotplug and switch the PCI host bridge scan handler to using the common hotplug code. This allows quite a few lines of code that are not necessary any more to be dropped from the PCI host bridge scan handler and removes arbitrary differences in behavior between PCI host bridge hotplug and ACPI-based hotplug of other components, like CPUs and memory. Also acpi_device_hotplug() can be static now. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/internal.h | 2 - drivers/acpi/pci_root.c | 125 +++++------------------------------------------- drivers/acpi/scan.c | 42 +++++++++------- include/acpi/acpi_bus.h | 2 +- 4 files changed, 37 insertions(+), 134 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h index a0d42cf5b0c5..f4aa467c407e 100644 --- a/drivers/acpi/internal.h +++ b/drivers/acpi/internal.h @@ -28,7 +28,6 @@ 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_pci_root_hp_init(void); void acpi_processor_init(void); void acpi_platform_init(void); int acpi_sysfs_init(void); @@ -89,7 +88,6 @@ void acpi_device_add_finalize(struct acpi_device *device); void acpi_free_pnp_ids(struct acpi_device_pnp *pnp); int acpi_bind_one(struct device *dev, acpi_handle handle); int acpi_unbind_one(struct device *dev); -void acpi_device_hotplug(void *data, u32 ost_src); bool acpi_device_is_present(struct acpi_device *adev); /* -------------------------------------------------------------------------- diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index ca05064f3ff7..2dd11e0bac24 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -51,6 +51,12 @@ 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); +static int acpi_pci_root_scan_dependent(struct acpi_device *adev) +{ + acpiphp_check_host_bridge(adev->handle); + return 0; +} + #define ACPI_PCIE_REQ_SUPPORT (OSC_PCI_EXT_CONFIG_SUPPORT \ | OSC_PCI_ASPM_SUPPORT \ | OSC_PCI_CLOCK_PM_SUPPORT \ @@ -66,7 +72,8 @@ static struct acpi_scan_handler pci_root_handler = { .attach = acpi_pci_root_add, .detach = acpi_pci_root_remove, .hotplug = { - .ignore = true, + .enabled = true, + .scan_dependent = acpi_pci_root_scan_dependent, }, }; @@ -624,119 +631,9 @@ static void acpi_pci_root_remove(struct acpi_device *device) void __init acpi_pci_root_init(void) { acpi_hest_init(); - - if (!acpi_pci_disabled) { - pci_acpi_crs_quirks(); - acpi_scan_add_handler(&pci_root_handler); - } -} -/* Support root bridge hotplug */ - -static void handle_root_bridge_insertion(acpi_handle handle) -{ - struct acpi_device *device = NULL; - - acpi_bus_get_device(handle, &device); - if (acpi_device_enumerated(device)) { - dev_printk(KERN_DEBUG, &device->dev, - "acpi device already exists; ignoring notify\n"); - return; - } - - if (acpi_bus_scan(handle)) - acpi_handle_err(handle, "cannot add bridge to acpi list\n"); -} - -static void hotplug_event_root(void *data, u32 type) -{ - acpi_handle handle = data; - struct acpi_pci_root *root; - - acpi_scan_lock_acquire(); - - root = acpi_pci_find_root(handle); - - switch (type) { - case ACPI_NOTIFY_BUS_CHECK: - /* bus enumerate */ - acpi_handle_printk(KERN_DEBUG, handle, - "Bus check notify on %s\n", __func__); - if (root) - acpiphp_check_host_bridge(handle); - else - handle_root_bridge_insertion(handle); - - break; - - case ACPI_NOTIFY_DEVICE_CHECK: - /* device check */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device check notify on %s\n", __func__); - if (!root) - handle_root_bridge_insertion(handle); - break; - - case ACPI_NOTIFY_EJECT_REQUEST: - /* request device eject */ - acpi_handle_printk(KERN_DEBUG, handle, - "Device eject notify on %s\n", __func__); - if (!root) - break; - - acpi_evaluate_hotplug_ost(handle, ACPI_NOTIFY_EJECT_REQUEST, - ACPI_OST_SC_EJECT_IN_PROGRESS, NULL); - get_device(&root->device->dev); - - acpi_scan_lock_release(); - - acpi_device_hotplug(root->device, ACPI_NOTIFY_EJECT_REQUEST); + if (acpi_pci_disabled) return; - default: - acpi_handle_warn(handle, - "notify_handler: unknown event type 0x%x\n", - type); - break; - } - - acpi_scan_lock_release(); -} - -static void handle_hotplug_event_root(acpi_handle handle, u32 type, - void *context) -{ - acpi_hotplug_execute(hotplug_event_root, handle, type); -} - -static acpi_status __init -find_root_bridges(acpi_handle handle, u32 lvl, void *context, void **rv) -{ - acpi_status status; - int *count = (int *)context; - - if (!acpi_is_root_bridge(handle)) - return AE_OK; - - (*count)++; - - status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, - handle_hotplug_event_root, NULL); - if (ACPI_FAILURE(status)) - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is not installed, exit status: %u\n", - (unsigned int)status); - else - acpi_handle_printk(KERN_DEBUG, handle, - "notify handler is installed\n"); - - return AE_OK; -} - -void __init acpi_pci_root_hp_init(void) -{ - int num = 0; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, - ACPI_UINT32_MAX, find_root_bridges, NULL, &num, NULL); - printk(KERN_DEBUG "Found %d acpi root devices\n", num); + pci_acpi_crs_quirks(); + acpi_scan_add_handler_with_hotplug(&pci_root_handler, "pci_root"); } diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index dd0ff9de9277..18865c86c463 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -283,17 +283,6 @@ static int acpi_scan_device_check(struct acpi_device *adev) { int error; - /* - * This function is only called for device objects for which matching - * scan handlers exist. The only situation in which the scan handler is - * not attached to this device object yet is when the device has just - * appeared (either it wasn't present at all before or it was removed - * and then added again). - */ - if (adev->handler) { - dev_warn(&adev->dev, "Already enumerated\n"); - return -EBUSY; - } error = acpi_bus_scan(adev->handle); if (error) { dev_warn(&adev->dev, "Namespace scan failure\n"); @@ -309,10 +298,11 @@ static int acpi_scan_device_check(struct acpi_device *adev) return 0; } -void acpi_device_hotplug(void *data, u32 src) +static void acpi_device_hotplug(void *data, u32 src) { u32 ost_code = ACPI_OST_SC_NON_SPECIFIC_FAILURE; struct acpi_device *adev = data; + struct acpi_scan_handler *handler; int error; lock_device_hotplug(); @@ -326,12 +316,32 @@ void acpi_device_hotplug(void *data, u32 src) if (adev->handle == INVALID_ACPI_HANDLE) goto out; + handler = adev->handler; + switch (src) { case ACPI_NOTIFY_BUS_CHECK: - error = acpi_bus_scan(adev->handle); + if (handler) { + error = handler->hotplug.scan_dependent ? + handler->hotplug.scan_dependent(adev) : + acpi_bus_scan(adev->handle); + } else { + error = acpi_scan_device_check(adev); + } break; case ACPI_NOTIFY_DEVICE_CHECK: - error = acpi_scan_device_check(adev); + /* + * This code is only run for device objects for which matching + * scan handlers exist. The only situation in which the scan + * handler is not attached to this device object yet is when the + * device has just appeared (either it wasn't present at all + * before or it was removed and then added again). + */ + if (adev->handler) { + dev_warn(&adev->dev, "Already enumerated\n"); + error = -EBUSY; + } else { + error = acpi_scan_device_check(adev); + } break; case ACPI_NOTIFY_EJECT_REQUEST: case ACPI_OST_EC_OSPM_EJECT: @@ -1805,7 +1815,7 @@ static void acpi_scan_init_hotplug(acpi_handle handle, int type) */ list_for_each_entry(hwid, &pnp.ids, list) { handler = acpi_scan_match_handler(hwid->id, NULL); - if (handler && !handler->hotplug.ignore) { + if (handler) { acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY, acpi_hotplug_notify_cb, handler); break; @@ -2083,8 +2093,6 @@ int __init acpi_scan_init(void) acpi_update_all_gpes(); - acpi_pci_root_hp_init(); - out: mutex_unlock(&acpi_scan_lock); return result; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index e748dbfca9d5..2359c69f1680 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -100,8 +100,8 @@ enum acpi_hotplug_mode { struct acpi_hotplug_profile { struct kobject kobj; bool enabled:1; - bool ignore:1; enum acpi_hotplug_mode mode; + int (*scan_dependent)(struct acpi_device *adev); }; static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( -- cgit v1.2.3 From 46394fd017c0615982a3d29d45ced14bea9c526d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:55:32 +0100 Subject: ACPI / hotplug: Move container-specific code out of the core Move container-specific uevents from the core hotplug code to the container scan handler's .attach() and .detach() callbacks. This way the core will not have to special-case containers and the uevents will be guaranteed to happen every time a container is either scanned or trimmed as appropriate. Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/container.c | 11 ++++++++--- drivers/acpi/scan.c | 8 +------- include/acpi/acpi_bus.h | 7 ------- 3 files changed, 9 insertions(+), 17 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/container.c b/drivers/acpi/container.c index e23151667655..83d232c10f13 100644 --- a/drivers/acpi/container.c +++ b/drivers/acpi/container.c @@ -44,19 +44,24 @@ static const struct acpi_device_id container_device_ids[] = { {"", 0}, }; -static int container_device_attach(struct acpi_device *device, +static int container_device_attach(struct acpi_device *adev, const struct acpi_device_id *not_used) { - /* This is necessary for container hotplug to work. */ + kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); return 1; } +static void container_device_detach(struct acpi_device *adev) +{ + kobject_uevent(&adev->dev.kobj, KOBJ_OFFLINE); +} + static struct acpi_scan_handler container_handler = { .ids = container_device_ids, .attach = container_device_attach, + .detach = container_device_detach, .hotplug = { .enabled = true, - .mode = AHM_CONTAINER, }, }; diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 18865c86c463..b1b8f4304597 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -206,9 +206,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) acpi_status status; unsigned long long sta; - if (device->handler && device->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&device->dev.kobj, KOBJ_OFFLINE); - /* * Carry out two passes here and ignore errors in the first pass, * because if the devices in question are memory blocks and @@ -288,10 +285,7 @@ static int acpi_scan_device_check(struct acpi_device *adev) dev_warn(&adev->dev, "Namespace scan failure\n"); return error; } - if (adev->handler) { - if (adev->handler->hotplug.mode == AHM_CONTAINER) - kobject_uevent(&adev->dev.kobj, KOBJ_ONLINE); - } else { + if (!adev->handler) { dev_warn(&adev->dev, "Enumeration failure\n"); return -ENODEV; } diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 2359c69f1680..3e4150b6d71a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,16 +91,9 @@ struct acpi_device; * ----------------- */ -enum acpi_hotplug_mode { - AHM_GENERIC = 0, - AHM_CONTAINER, - AHM_COUNT -}; - struct acpi_hotplug_profile { struct kobject kobj; bool enabled:1; - enum acpi_hotplug_mode mode; int (*scan_dependent)(struct acpi_device *adev); }; -- cgit v1.2.3 From 25db115b0bf72acfdf8a339fa8e37d8b895214d6 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 22 Nov 2013 21:56:06 +0100 Subject: ACPI: Introduce acpi_set_device_status() Introduce a static inline function for setting the status field of struct acpi_device on the basis of a supplied u32 number, acpi_set_device_status(), and use it instead of the horrible horrible STRUCT_TO_INT() macro wherever applicable. Having done that, drop STRUCT_TO_INT() (and pretend that it has never existed). Signed-off-by: Rafael J. Wysocki Tested-by: Mika Westerberg --- drivers/acpi/bus.c | 11 +++-------- drivers/acpi/scan.c | 5 ++--- include/acpi/acpi_bus.h | 5 +++++ 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c index 8b09a75f6579..f509019ee2c7 100644 --- a/drivers/acpi/bus.c +++ b/drivers/acpi/bus.c @@ -52,9 +52,6 @@ struct acpi_device *acpi_root; struct proc_dir_entry *acpi_root_dir; EXPORT_SYMBOL(acpi_root_dir); -#define STRUCT_TO_INT(s) (*((int*)&s)) - - #ifdef CONFIG_X86 static int set_copy_dsdt(const struct dmi_system_id *id) { @@ -115,18 +112,16 @@ int acpi_bus_get_status(struct acpi_device *device) if (ACPI_FAILURE(status)) return -ENODEV; - STRUCT_TO_INT(device->status) = (int) sta; + acpi_set_device_status(device, sta); if (device->status.functional && !device->status.present) { ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]: " "functional but not present;\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); + device->pnp.bus_id, (u32)sta)); } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] status [%08x]\n", - device->pnp.bus_id, - (u32) STRUCT_TO_INT(device->status))); + device->pnp.bus_id, (u32)sta)); return 0; } EXPORT_SYMBOL(acpi_bus_get_status); diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 06db2c036085..cf773c918102 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -20,7 +20,6 @@ #define _COMPONENT ACPI_BUS_COMPONENT ACPI_MODULE_NAME("scan"); -#define STRUCT_TO_INT(s) (*((int*)&s)) extern struct acpi_device *acpi_root; #define ACPI_BUS_CLASS "system_bus" @@ -1683,7 +1682,7 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle, device->device_type = type; device->handle = handle; device->parent = acpi_bus_get_parent(handle); - STRUCT_TO_INT(device->status) = sta; + acpi_set_device_status(device, sta); acpi_device_get_busid(device); acpi_set_pnp_ids(handle, &device->pnp, type); acpi_bus_get_flags(device); @@ -1927,7 +1926,7 @@ static acpi_status acpi_bus_device_attach(acpi_handle handle, u32 lvl_not_used, if (acpi_bus_get_device(handle, &device)) return AE_CTRL_DEPTH; - STRUCT_TO_INT(device->status) = sta; + acpi_set_device_status(device, sta); /* Skip devices that are not present. */ if (!acpi_device_is_present(device)) goto err; diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 3e4150b6d71a..95831e7b70be 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -320,6 +320,11 @@ static inline void *acpi_driver_data(struct acpi_device *d) #define to_acpi_device(d) container_of(d, struct acpi_device, dev) #define to_acpi_driver(d) container_of(d, struct acpi_driver, drv) +static inline void acpi_set_device_status(struct acpi_device *adev, u32 sta) +{ + *((u32 *)&adev->status) = sta; +} + /* acpi_device.dev.bus == &acpi_bus_type */ extern struct bus_type acpi_bus_type; -- cgit v1.2.3 From d9fef0c4d2e08c3888add77f1dc54fb12afb3928 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:57:58 +0100 Subject: ACPI / bind: Simplify child device lookups Now that we create a struct acpi_device object for every ACPI namespace node representing a device, it is not necessary to use acpi_walk_namespace() for child device lookup in acpi_find_child() any more. Instead, we can simply walk the list of children of the given struct acpi_device object and return the matching one (or the one which is the best match if there are more of them). The checks done during the matching loop can be simplified too so that the secondary namespace walks in find_child_checks() are not necessary any more. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu --- drivers/acpi/glue.c | 137 +++++++++++++++++++----------------------------- include/acpi/acpi_bus.h | 3 ++ 2 files changed, 58 insertions(+), 82 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index a22a295edb69..ea77512ad70c 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -82,107 +82,80 @@ static struct acpi_bus_type *acpi_get_bus_type(struct device *dev) #define FIND_CHILD_MIN_SCORE 1 #define FIND_CHILD_MAX_SCORE 2 -static acpi_status acpi_dev_present(acpi_handle handle, u32 lvl_not_used, - void *not_used, void **ret_p) -{ - struct acpi_device *adev = NULL; - - acpi_bus_get_device(handle, &adev); - if (adev) { - *ret_p = handle; - return AE_CTRL_TERMINATE; - } - return AE_OK; -} - -static int do_find_child_checks(acpi_handle handle, bool is_bridge) +static int find_child_checks(struct acpi_device *adev, bool check_children) { bool sta_present = true; unsigned long long sta; acpi_status status; - status = acpi_evaluate_integer(handle, "_STA", NULL, &sta); + status = acpi_evaluate_integer(adev->handle, "_STA", NULL, &sta); if (status == AE_NOT_FOUND) sta_present = false; else if (ACPI_FAILURE(status) || !(sta & ACPI_STA_DEVICE_ENABLED)) return -ENODEV; - if (is_bridge) { - void *test = NULL; + if (check_children && list_empty(&adev->children)) + return -ENODEV; - /* Check if this object has at least one child device. */ - acpi_walk_namespace(ACPI_TYPE_DEVICE, handle, 1, - acpi_dev_present, NULL, NULL, &test); - if (!test) - return -ENODEV; - } return sta_present ? FIND_CHILD_MAX_SCORE : FIND_CHILD_MIN_SCORE; } -struct find_child_context { - u64 addr; - bool is_bridge; - acpi_handle ret; - int ret_score; -}; - -static acpi_status do_find_child(acpi_handle handle, u32 lvl_not_used, - void *data, void **not_used) +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children) { - struct find_child_context *context = data; - unsigned long long addr; - acpi_status status; - int score; - - status = acpi_evaluate_integer(handle, METHOD_NAME__ADR, NULL, &addr); - if (ACPI_FAILURE(status) || addr != context->addr) - return AE_OK; - - if (!context->ret) { - /* This is the first matching object. Save its handle. */ - context->ret = handle; - return AE_OK; - } - /* - * There is more than one matching object with the same _ADR value. - * That really is unexpected, so we are kind of beyond the scope of the - * spec here. We have to choose which one to return, though. - * - * First, check if the previously found object is good enough and return - * its handle if so. Second, check the same for the object that we've - * just found. - */ - if (!context->ret_score) { - score = do_find_child_checks(context->ret, context->is_bridge); - if (score == FIND_CHILD_MAX_SCORE) - return AE_CTRL_TERMINATE; - else - context->ret_score = score; - } - score = do_find_child_checks(handle, context->is_bridge); - if (score == FIND_CHILD_MAX_SCORE) { - context->ret = handle; - return AE_CTRL_TERMINATE; - } else if (score > context->ret_score) { - context->ret = handle; - context->ret_score = score; + struct acpi_device *adev, *ret = NULL; + int ret_score = 0; + + list_for_each_entry(adev, &parent->children, node) { + unsigned long long addr; + acpi_status status; + int score; + + status = acpi_evaluate_integer(adev->handle, METHOD_NAME__ADR, + NULL, &addr); + if (ACPI_FAILURE(status) || addr != address) + continue; + + if (!ret) { + /* This is the first matching object. Save it. */ + ret = adev; + continue; + } + /* + * There is more than one matching device object with the same + * _ADR value. That really is unexpected, so we are kind of + * beyond the scope of the spec here. We have to choose which + * one to return, though. + * + * First, check if the previously found object is good enough + * and return it if so. Second, do the same for the object that + * we've just found. + */ + if (!ret_score) { + ret_score = find_child_checks(ret, check_children); + if (ret_score == FIND_CHILD_MAX_SCORE) + return ret; + } + score = find_child_checks(adev, check_children); + if (score == FIND_CHILD_MAX_SCORE) { + return adev; + } else if (score > ret_score) { + ret = adev; + ret_score = score; + } } - return AE_OK; + return ret; } -acpi_handle acpi_find_child(acpi_handle parent, u64 addr, bool is_bridge) +acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge) { - if (parent) { - struct find_child_context context = { - .addr = addr, - .is_bridge = is_bridge, - }; - - acpi_walk_namespace(ACPI_TYPE_DEVICE, parent, 1, do_find_child, - NULL, &context, NULL); - return context.ret; - } - return NULL; + struct acpi_device *adev; + + if (!handle || acpi_bus_get_device(handle, &adev)) + return NULL; + + adev = acpi_find_child_device(adev, addr, is_bridge); + return adev ? adev->handle : NULL; } EXPORT_SYMBOL_GPL(acpi_find_child); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index b241b733052e..6d82c5c14c0f 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -431,6 +431,9 @@ struct acpi_pci_root { }; /* helper */ + +struct acpi_device *acpi_find_child_device(struct acpi_device *parent, + u64 address, bool check_children); acpi_handle acpi_find_child(acpi_handle, u64, bool); static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { -- cgit v1.2.3 From 11dcc75dba5bf8b69c4612de10e366c4e04cb123 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:18 +0100 Subject: ACPI / bind: Redefine acpi_get_child() Since acpi_get_child() is the only user of acpi_find_child() now, drop the static inline definition of the former and redefine the latter as new acpi_get_child(). Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Tested-by: Aaron Lu # for ATA binding --- drivers/acpi/glue.c | 6 +++--- include/acpi/acpi_bus.h | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 9d200d5029ca..12b2acbaa116 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -150,17 +150,17 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, return ret; } -acpi_handle acpi_find_child(acpi_handle handle, u64 addr, bool is_bridge) +acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { struct acpi_device *adev; if (!handle || acpi_bus_get_device(handle, &adev)) return NULL; - adev = acpi_find_child_device(adev, addr, is_bridge); + adev = acpi_find_child_device(adev, addr, false); return adev ? adev->handle : NULL; } -EXPORT_SYMBOL_GPL(acpi_find_child); +EXPORT_SYMBOL_GPL(acpi_get_child); static void acpi_physnode_link_name(char *buf, unsigned int node_id) { diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 6d82c5c14c0f..a1a48f27933a 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -434,11 +434,7 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); -acpi_handle acpi_find_child(acpi_handle, u64, bool); -static inline acpi_handle acpi_get_child(acpi_handle handle, u64 addr) -{ - return acpi_find_child(handle, addr, false); -} +acpi_handle acpi_get_child(acpi_handle handle, u64 addr); void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From 9c5ad36d987a1b06f6b0b9dc7bc61a45d277455d Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Thu, 28 Nov 2013 23:58:28 +0100 Subject: ACPI / bind: Redefine acpi_preset_companion() Modify acpi_preset_companion() to take a struct acpi_device pointer instead of an ACPI handle as its second argument and redefine it as a static inline wrapper around ACPI_COMPANION_SET() passing the return value of acpi_find_child_device() directly as the second argument to it. Update its users to pass struct acpi_device pointers instead of ACPI handles to it. This allows some unnecessary acpi_bus_get_device() calls to be avoided. Signed-off-by: Rafael J. Wysocki Reviewed-by: Aaron Lu Tested-by: Aaron Lu # for ATA binding --- drivers/acpi/glue.c | 10 +--------- drivers/ata/libata-acpi.c | 26 +++++++++++++------------- drivers/mmc/core/sdio_bus.c | 2 +- include/acpi/acpi_bus.h | 1 - include/linux/acpi.h | 6 ++++++ 5 files changed, 21 insertions(+), 24 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 12b2acbaa116..c0d18b2145c1 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -149,6 +149,7 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, } return ret; } +EXPORT_SYMBOL_GPL(acpi_find_child_device); acpi_handle acpi_get_child(acpi_handle handle, u64 addr) { @@ -298,15 +299,6 @@ int acpi_unbind_one(struct device *dev) } EXPORT_SYMBOL_GPL(acpi_unbind_one); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr) -{ - struct acpi_device *adev; - - if (!acpi_bus_get_device(acpi_get_child(parent, addr), &adev)) - ACPI_COMPANION_SET(dev, adev); -} -EXPORT_SYMBOL_GPL(acpi_preset_companion); - static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c index 8e22d9762328..9e69a5308693 100644 --- a/drivers/ata/libata-acpi.c +++ b/drivers/ata/libata-acpi.c @@ -178,12 +178,12 @@ static const struct acpi_dock_ops ata_acpi_ap_dock_ops = { /* bind acpi handle to pata port */ void ata_acpi_bind_port(struct ata_port *ap) { - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); - if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_handle) + if (libata_noacpi || ap->flags & ATA_FLAG_ACPI_SATA || !host_companion) return; - acpi_preset_companion(&ap->tdev, host_handle, ap->port_no); + acpi_preset_companion(&ap->tdev, host_companion, ap->port_no); if (ata_acpi_gtm(ap, &ap->__acpi_init_gtm) == 0) ap->pflags |= ATA_PFLAG_INIT_GTM_VALID; @@ -196,17 +196,17 @@ void ata_acpi_bind_port(struct ata_port *ap) void ata_acpi_bind_dev(struct ata_device *dev) { struct ata_port *ap = dev->link->ap; - acpi_handle port_handle = ACPI_HANDLE(&ap->tdev); - acpi_handle host_handle = ACPI_HANDLE(ap->host->dev); - acpi_handle parent_handle; + struct acpi_device *port_companion = ACPI_COMPANION(&ap->tdev); + struct acpi_device *host_companion = ACPI_COMPANION(ap->host->dev); + struct acpi_device *parent; u64 adr; /* - * For both sata/pata devices, host handle is required. - * For pata device, port handle is also required. + * For both sata/pata devices, host companion device is required. + * For pata device, port companion device is also required. */ - if (libata_noacpi || !host_handle || - (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_handle)) + if (libata_noacpi || !host_companion || + (!(ap->flags & ATA_FLAG_ACPI_SATA) && !port_companion)) return; if (ap->flags & ATA_FLAG_ACPI_SATA) { @@ -214,13 +214,13 @@ void ata_acpi_bind_dev(struct ata_device *dev) adr = SATA_ADR(ap->port_no, NO_PORT_MULT); else adr = SATA_ADR(ap->port_no, dev->link->pmp); - parent_handle = host_handle; + parent = host_companion; } else { adr = dev->devno; - parent_handle = port_handle; + parent = port_companion; } - acpi_preset_companion(&dev->tdev, parent_handle, adr); + acpi_preset_companion(&dev->tdev, parent, adr); register_hotplug_dock_device(ata_dev_acpi_handle(dev), &ata_acpi_dev_dock_ops, dev, NULL, NULL); diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c index 157b570ba343..92d1ba8e8153 100644 --- a/drivers/mmc/core/sdio_bus.c +++ b/drivers/mmc/core/sdio_bus.c @@ -308,7 +308,7 @@ static void sdio_acpi_set_handle(struct sdio_func *func) struct mmc_host *host = func->card->host; u64 addr = (host->slotno << 16) | func->num; - acpi_preset_companion(&func->dev, ACPI_HANDLE(host->parent), addr); + acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr); } #else static inline void sdio_acpi_set_handle(struct sdio_func *func) {} diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a1a48f27933a..918eaab892e1 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -435,7 +435,6 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); acpi_handle acpi_get_child(acpi_handle handle, u64 addr); -void acpi_preset_companion(struct device *dev, acpi_handle parent, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); diff --git a/include/linux/acpi.h b/include/linux/acpi.h index d9099b15b472..115c610324d1 100644 --- a/include/linux/acpi.h +++ b/include/linux/acpi.h @@ -53,6 +53,12 @@ static inline acpi_handle acpi_device_handle(struct acpi_device *adev) #define ACPI_COMPANION_SET(dev, adev) ACPI_COMPANION(dev) = (adev) #define ACPI_HANDLE(dev) acpi_device_handle(ACPI_COMPANION(dev)) +static inline void acpi_preset_companion(struct device *dev, + struct acpi_device *parent, u64 addr) +{ + ACPI_COMPANION_SET(dev, acpi_find_child_device(parent, addr, NULL)); +} + static inline const char *acpi_dev_name(struct acpi_device *adev) { return dev_name(&adev->dev); -- cgit v1.2.3 From e3f02c5228c4b600abf6ca243301176f25553bd5 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Nov 2013 16:27:34 +0100 Subject: ACPI / bind: Rework struct acpi_bus_type Replace the .find_device function pointer in struct acpi_bus_type with a new one, .find_companion, that is supposed to point to a function returning struct acpi_device pointer (instead of an int) and takes one argument (instead of two). This way the role of this callback is more clear and the implementation of it can be more straightforward. Update all of the users of struct acpi_bus_type (PCI, PNP/ACPI and USB) to reflect the structure change. Signed-off-by: Rafael J. Wysocki Tested-by: Lan Tianyu # for USB/ACPI --- drivers/acpi/glue.c | 12 +++++++----- drivers/pci/pci-acpi.c | 12 +++--------- drivers/pnp/pnpacpi/core.c | 21 ++++++++------------- drivers/usb/core/usb-acpi.c | 40 ++++++++++++++++++++-------------------- include/acpi/acpi_bus.h | 2 +- 5 files changed, 39 insertions(+), 48 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index c0d18b2145c1..7608d66f289b 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -37,7 +37,7 @@ int register_acpi_bus_type(struct acpi_bus_type *type) { if (acpi_disabled) return -ENODEV; - if (type && type->match && type->find_device) { + if (type && type->match && type->find_companion) { down_write(&bus_type_sem); list_add_tail(&type->list, &bus_type_list); up_write(&bus_type_sem); @@ -302,17 +302,19 @@ EXPORT_SYMBOL_GPL(acpi_unbind_one); static int acpi_platform_notify(struct device *dev) { struct acpi_bus_type *type = acpi_get_bus_type(dev); - acpi_handle handle; int ret; ret = acpi_bind_one(dev, NULL); if (ret && type) { - ret = type->find_device(dev, &handle); - if (ret) { + struct acpi_device *adev; + + adev = type->find_companion(dev); + if (!adev) { DBG("Unable to get handle for %s\n", dev_name(dev)); + ret = -ENODEV; goto out; } - ret = acpi_bind_one(dev, handle); + ret = acpi_bind_one(dev, adev->handle); if (ret) goto out; } diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index adbf34003995..ce31eb0cdca7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -303,10 +303,9 @@ void acpi_pci_remove_bus(struct pci_bus *bus) } /* ACPI bus type */ -static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) +static struct acpi_device *acpi_pci_find_companion(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); - struct acpi_device *adev; bool check_children; u64 addr; @@ -319,13 +318,8 @@ static int acpi_pci_find_device(struct device *dev, acpi_handle *handle) || pci_dev->hdr_type == PCI_HEADER_TYPE_CARDBUS; /* Please ref to ACPI spec for the syntax of _ADR */ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn); - adev = acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, + return acpi_find_child_device(ACPI_COMPANION(dev->parent), addr, check_children); - if (adev) { - *handle = adev->handle; - return 0; - } - return -ENODEV; } static void pci_acpi_setup(struct device *dev) @@ -365,7 +359,7 @@ static bool pci_acpi_bus_match(struct device *dev) static struct acpi_bus_type acpi_pci_bus = { .name = "PCI", .match = pci_acpi_bus_match, - .find_device = acpi_pci_find_device, + .find_companion = acpi_pci_find_companion, .setup = pci_acpi_setup, .cleanup = pci_acpi_cleanup, }; diff --git a/drivers/pnp/pnpacpi/core.c b/drivers/pnp/pnpacpi/core.c index e869ba698ac0..156d14e2587e 100644 --- a/drivers/pnp/pnpacpi/core.c +++ b/drivers/pnp/pnpacpi/core.c @@ -328,20 +328,15 @@ static int __init acpi_pnp_match(struct device *dev, void *_pnp) && compare_pnp_id(pnp->id, acpi_device_hid(acpi)); } -static int __init acpi_pnp_find_device(struct device *dev, acpi_handle * handle) +static struct acpi_device * __init acpi_pnp_find_companion(struct device *dev) { - struct device *adev; - struct acpi_device *acpi; - - adev = bus_find_device(&acpi_bus_type, NULL, - to_pnp_dev(dev), acpi_pnp_match); - if (!adev) - return -ENODEV; + dev = bus_find_device(&acpi_bus_type, NULL, to_pnp_dev(dev), + acpi_pnp_match); + if (!dev) + return NULL; - acpi = to_acpi_device(adev); - *handle = acpi->handle; - put_device(adev); - return 0; + put_device(dev); + return to_acpi_device(dev); } /* complete initialization of a PNPACPI device includes having @@ -355,7 +350,7 @@ static bool acpi_pnp_bus_match(struct device *dev) static struct acpi_bus_type __initdata acpi_pnp_bus = { .name = "PNP", .match = acpi_pnp_bus_match, - .find_device = acpi_pnp_find_device, + .find_companion = acpi_pnp_find_companion, }; int pnpacpi_disabled __initdata; diff --git a/drivers/usb/core/usb-acpi.c b/drivers/usb/core/usb-acpi.c index 11c656976cb5..f0155a39aaa3 100644 --- a/drivers/usb/core/usb-acpi.c +++ b/drivers/usb/core/usb-acpi.c @@ -126,7 +126,7 @@ out: return ret; } -static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) +static struct acpi_device *usb_acpi_find_companion(struct device *dev) { struct usb_device *udev; acpi_handle *parent_handle; @@ -168,16 +168,15 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) break; } - return -ENODEV; + return NULL; } /* root hub's parent is the usb hcd. */ - parent_handle = ACPI_HANDLE(dev->parent); - *handle = acpi_get_child(parent_handle, udev->portnum); - if (!*handle) - return -ENODEV; - return 0; + return acpi_find_child_device(ACPI_COMPANION(dev->parent), + udev->portnum, false); } else if (is_usb_port(dev)) { + struct acpi_device *adev = NULL; + sscanf(dev_name(dev), "port%d", &port_num); /* Get the struct usb_device point of port's hub */ udev = to_usb_device(dev->parent->parent); @@ -193,26 +192,27 @@ static int usb_acpi_find_device(struct device *dev, acpi_handle *handle) raw_port_num = usb_hcd_find_raw_port_number(hcd, port_num); - *handle = acpi_get_child(ACPI_HANDLE(&udev->dev), - raw_port_num); - if (!*handle) - return -ENODEV; + adev = acpi_find_child_device(ACPI_COMPANION(&udev->dev), + raw_port_num, false); + if (!adev) + return NULL; } else { parent_handle = usb_get_hub_port_acpi_handle(udev->parent, udev->portnum); if (!parent_handle) - return -ENODEV; + return NULL; - *handle = acpi_get_child(parent_handle, port_num); - if (!*handle) - return -ENODEV; + acpi_bus_get_device(parent_handle, &adev); + adev = acpi_find_child_device(adev, port_num, false); + if (!adev) + return NULL; } - usb_acpi_check_port_connect_type(udev, *handle, port_num); - } else - return -ENODEV; + usb_acpi_check_port_connect_type(udev, adev->handle, port_num); + return adev; + } - return 0; + return NULL; } static bool usb_acpi_bus_match(struct device *dev) @@ -223,7 +223,7 @@ static bool usb_acpi_bus_match(struct device *dev) static struct acpi_bus_type usb_acpi_bus = { .name = "USB", .match = usb_acpi_bus_match, - .find_device = usb_acpi_find_device, + .find_companion = usb_acpi_find_companion, }; int usb_acpi_register(void) diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 918eaab892e1..a50898e67a68 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -412,7 +412,7 @@ struct acpi_bus_type { struct list_head list; const char *name; bool (*match)(struct device *dev); - int (*find_device) (struct device *, acpi_handle *); + struct acpi_device * (*find_companion)(struct device *); void (*setup)(struct device *); void (*cleanup)(struct device *); }; -- cgit v1.2.3 From bfecc2b3e34c6751343bacd317c4dfd1d695142c Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Fri, 29 Nov 2013 16:27:53 +0100 Subject: ACPI / bind: Move acpi_get_child() to drivers/ide/ide-acpi.c Since drivers/ide/ide-acpi.c is the only remaining user of acpi_get_child(), move that function into that file as a static routine. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/glue.c | 12 ------------ drivers/ide/ide-acpi.c | 11 +++++++++++ include/acpi/acpi_bus.h | 1 - 3 files changed, 11 insertions(+), 13 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/glue.c b/drivers/acpi/glue.c index 896351b9d483..0c789224d40d 100644 --- a/drivers/acpi/glue.c +++ b/drivers/acpi/glue.c @@ -151,18 +151,6 @@ struct acpi_device *acpi_find_child_device(struct acpi_device *parent, } EXPORT_SYMBOL_GPL(acpi_find_child_device); -acpi_handle acpi_get_child(acpi_handle handle, u64 addr) -{ - struct acpi_device *adev; - - if (!handle || acpi_bus_get_device(handle, &adev)) - return NULL; - - adev = acpi_find_child_device(adev, addr, false); - return adev ? adev->handle : NULL; -} -EXPORT_SYMBOL_GPL(acpi_get_child); - static void acpi_physnode_link_name(char *buf, unsigned int node_id) { if (node_id > 0) diff --git a/drivers/ide/ide-acpi.c b/drivers/ide/ide-acpi.c index 333d4053e727..b6940992a6ff 100644 --- a/drivers/ide/ide-acpi.c +++ b/drivers/ide/ide-acpi.c @@ -97,6 +97,17 @@ bool ide_port_acpi(ide_hwif_t *hwif) return ide_noacpi == 0 && hwif->acpidata; } +static acpi_handle acpi_get_child(acpi_handle handle, u64 addr) +{ + struct acpi_device *adev; + + if (!handle || acpi_bus_get_device(handle, &adev)) + return NULL; + + adev = acpi_find_child_device(adev, addr, false); + return adev ? adev->handle : NULL; +} + /** * ide_get_dev_handle - finds acpi_handle and PCI device.function * @dev: device to locate diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index a50898e67a68..7135fe3d6daa 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -434,7 +434,6 @@ struct acpi_pci_root { struct acpi_device *acpi_find_child_device(struct acpi_device *parent, u64 address, bool check_children); -acpi_handle acpi_get_child(acpi_handle handle, u64 addr); int acpi_is_root_bridge(acpi_handle); struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle); -- cgit v1.2.3 From d22ddcbc4fb7a483d0721eddfda3f0558821d372 Mon Sep 17 00:00:00 2001 From: "Rafael J. Wysocki" Date: Sun, 29 Dec 2013 15:25:35 +0100 Subject: ACPI / hotplug: Add demand_offline hotplug profile flag Add a new ACPI hotplug profile flag, demand_offline, such that if set for the given ACPI device object's scan handler, it will cause acpi_scan_hot_remove() to check if that device object's physical companions are offline upfront and fail the hot removal if that is not the case. That flag will be useful to overcome a problem with containers on some system where they can only be hot-removed after some cleanup operations carried out by user space, which needs to be notified of the container hot-removal before the kernel attempts to offline devices in the container. In those cases the current implementation of acpi_scan_hot_remove() is not sufficient, because it first tries to offline the devices in the container and only if that is suffcessful it tries to offline the container itself. As a result, the container hot-removal notification is not delivered to user space at the right time. Signed-off-by: Rafael J. Wysocki --- drivers/acpi/scan.c | 41 +++++++++++++++++++++++++++++++++++++---- include/acpi/acpi_bus.h | 3 ++- 2 files changed, 39 insertions(+), 5 deletions(-) (limited to 'include/acpi') diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c index 5383c81a8a1b..65243b9dd868 100644 --- a/drivers/acpi/scan.c +++ b/drivers/acpi/scan.c @@ -126,6 +126,24 @@ acpi_device_modalias_show(struct device *dev, struct device_attribute *attr, cha } static DEVICE_ATTR(modalias, 0444, acpi_device_modalias_show, NULL); +static bool acpi_scan_is_offline(struct acpi_device *adev) +{ + struct acpi_device_physical_node *pn; + bool offline = true; + + mutex_lock(&adev->physical_node_lock); + + list_for_each_entry(pn, &adev->physical_node_list, node) + if (device_supports_offline(pn->dev) && !pn->dev->offline) { + kobject_uevent(&pn->dev->kobj, KOBJ_CHANGE); + offline = false; + break; + } + + mutex_unlock(&adev->physical_node_lock); + return offline; +} + static acpi_status acpi_bus_offline(acpi_handle handle, u32 lvl, void *data, void **ret_p) { @@ -196,12 +214,11 @@ static acpi_status acpi_bus_online(acpi_handle handle, u32 lvl, void *data, return AE_OK; } -static int acpi_scan_hot_remove(struct acpi_device *device) +static int acpi_scan_try_to_offline(struct acpi_device *device) { acpi_handle handle = device->handle; - struct device *errdev; + struct device *errdev = NULL; acpi_status status; - unsigned long long sta; /* * Carry out two passes here and ignore errors in the first pass, @@ -212,7 +229,6 @@ static int acpi_scan_hot_remove(struct acpi_device *device) * * If the first pass is successful, the second one isn't needed, though. */ - errdev = NULL; status = acpi_walk_namespace(ACPI_TYPE_ANY, handle, ACPI_UINT32_MAX, NULL, acpi_bus_offline, (void *)false, (void **)&errdev); @@ -241,6 +257,23 @@ static int acpi_scan_hot_remove(struct acpi_device *device) return -EBUSY; } } + return 0; +} + +static int acpi_scan_hot_remove(struct acpi_device *device) +{ + acpi_handle handle = device->handle; + unsigned long long sta; + acpi_status status; + + if (device->handler->hotplug.demand_offline && !acpi_force_hot_remove) { + if (!acpi_scan_is_offline(device)) + return -EBUSY; + } else { + int error = acpi_scan_try_to_offline(device); + if (error) + return error; + } ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Hot-removing device %s...\n", dev_name(&device->dev))); diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h index 7135fe3d6daa..48d302501539 100644 --- a/include/acpi/acpi_bus.h +++ b/include/acpi/acpi_bus.h @@ -91,8 +91,9 @@ struct acpi_device; struct acpi_hotplug_profile { struct kobject kobj; - bool enabled:1; int (*scan_dependent)(struct acpi_device *adev); + bool enabled:1; + bool demand_offline:1; }; static inline struct acpi_hotplug_profile *to_acpi_hotplug_profile( -- cgit v1.2.3