aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-22 15:52:12 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2013-11-22 15:52:12 -0500
commitd783156ea38431b20af0d4f910a6f9f9054d33b9 (patch)
tree495556a88a8c2f1e080bafdd1d55fab4bbf114fe
parent74fc9cb2b950e3017e9df04a02a29e7cc92dc5a1 (diff)
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 <rafael.j.wysocki@intel.com> Tested-by: Mika Westerberg <mika.westerberg@linux.intel.com>
-rw-r--r--drivers/acpi/internal.h2
-rw-r--r--drivers/acpi/osl.c6
-rw-r--r--drivers/acpi/scan.c114
-rw-r--r--include/acpi/acpi_bus.h1
4 files changed, 102 insertions, 21 deletions
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index a29739c0ba79..d8606498bf6f 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -73,6 +73,8 @@ void acpi_lpss_init(void);
73static inline void acpi_lpss_init(void) {} 73static inline void acpi_lpss_init(void) {}
74#endif 74#endif
75 75
76bool acpi_queue_hotplug_work(struct work_struct *work);
77
76/* -------------------------------------------------------------------------- 78/* --------------------------------------------------------------------------
77 Device Node Initialization / Removal 79 Device Node Initialization / Removal
78 -------------------------------------------------------------------------- */ 80 -------------------------------------------------------------------------- */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 54a20ff4b864..5b9a785e2155 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -1215,6 +1215,10 @@ acpi_status acpi_hotplug_execute(acpi_hp_callback func, void *data, u32 src)
1215 return AE_OK; 1215 return AE_OK;
1216} 1216}
1217 1217
1218bool acpi_queue_hotplug_work(struct work_struct *work)
1219{
1220 return queue_work(kacpi_hotplug_wq, work);
1221}
1218 1222
1219acpi_status 1223acpi_status
1220acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle) 1224acpi_os_create_semaphore(u32 max_units, u32 initial_units, acpi_handle * handle)
@@ -1794,7 +1798,7 @@ acpi_status __init acpi_os_initialize1(void)
1794{ 1798{
1795 kacpid_wq = alloc_workqueue("kacpid", 0, 1); 1799 kacpid_wq = alloc_workqueue("kacpid", 0, 1);
1796 kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1); 1800 kacpi_notify_wq = alloc_workqueue("kacpi_notify", 0, 1);
1797 kacpi_hotplug_wq = alloc_workqueue("kacpi_hotplug", 0, 1); 1801 kacpi_hotplug_wq = alloc_ordered_workqueue("kacpi_hotplug", 0);
1798 BUG_ON(!kacpid_wq); 1802 BUG_ON(!kacpid_wq);
1799 BUG_ON(!kacpi_notify_wq); 1803 BUG_ON(!kacpi_notify_wq);
1800 BUG_ON(!kacpi_hotplug_wq); 1804 BUG_ON(!kacpi_hotplug_wq);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index fd39459926b1..ad2522015e5e 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -14,6 +14,8 @@
14 14
15#include <acpi/acpi_drivers.h> 15#include <acpi/acpi_drivers.h>
16 16
17#include <asm/pgtable.h>
18
17#include "internal.h" 19#include "internal.h"
18 20
19#define _COMPONENT ACPI_BUS_COMPONENT 21#define _COMPONENT ACPI_BUS_COMPONENT
@@ -27,6 +29,8 @@ extern struct acpi_device *acpi_root;
27 29
28#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent) 30#define ACPI_IS_ROOT_DEVICE(device) (!(device)->parent)
29 31
32#define INVALID_ACPI_HANDLE ((acpi_handle)empty_zero_page)
33
30/* 34/*
31 * If set, devices will be hot-removed even if they cannot be put offline 35 * If set, devices will be hot-removed even if they cannot be put offline
32 * gracefully (from the kernel's standpoint). 36 * gracefully (from the kernel's standpoint).
@@ -907,9 +911,91 @@ struct bus_type acpi_bus_type = {
907 .uevent = acpi_device_uevent, 911 .uevent = acpi_device_uevent,
908}; 912};
909 913
910static void acpi_bus_data_handler(acpi_handle handle, void *context) 914static void acpi_device_del(struct acpi_device *device)
915{
916 mutex_lock(&acpi_device_lock);
917 if (device->parent)
918 list_del(&device->node);
919
920 list_del(&device->wakeup_list);
921 mutex_unlock(&acpi_device_lock);
922
923 acpi_power_add_remove_device(device, false);
924 acpi_device_remove_files(device);
925 if (device->remove)
926 device->remove(device);
927
928 device_del(&device->dev);
929}
930
931static LIST_HEAD(acpi_device_del_list);
932static DEFINE_MUTEX(acpi_device_del_lock);
933
934static void acpi_device_del_work_fn(struct work_struct *work_not_used)
935{
936 for (;;) {
937 struct acpi_device *adev;
938
939 mutex_lock(&acpi_device_del_lock);
940
941 if (list_empty(&acpi_device_del_list)) {
942 mutex_unlock(&acpi_device_del_lock);
943 break;
944 }
945 adev = list_first_entry(&acpi_device_del_list,
946 struct acpi_device, del_list);
947 list_del(&adev->del_list);
948
949 mutex_unlock(&acpi_device_del_lock);
950
951 acpi_device_del(adev);
952 /*
953 * Drop references to all power resources that might have been
954 * used by the device.
955 */
956 acpi_power_transition(adev, ACPI_STATE_D3_COLD);
957 put_device(&adev->dev);
958 }
959}
960
961/**
962 * acpi_scan_drop_device - Drop an ACPI device object.
963 * @handle: Handle of an ACPI namespace node, not used.
964 * @context: Address of the ACPI device object to drop.
965 *
966 * This is invoked by acpi_ns_delete_node() during the removal of the ACPI
967 * namespace node the device object pointed to by @context is attached to.
968 *
969 * The unregistration is carried out asynchronously to avoid running
970 * acpi_device_del() under the ACPICA's namespace mutex and the list is used to
971 * ensure the correct ordering (the device objects must be unregistered in the
972 * same order in which the corresponding namespace nodes are deleted).
973 */
974static void acpi_scan_drop_device(acpi_handle handle, void *context)
911{ 975{
912 /* Intentionally empty. */ 976 static DECLARE_WORK(work, acpi_device_del_work_fn);
977 struct acpi_device *adev = context;
978
979 mutex_lock(&acpi_device_del_lock);
980
981 /*
982 * Use the ACPI hotplug workqueue which is ordered, so this work item
983 * won't run after any hotplug work items submitted subsequently. That
984 * prevents attempts to register device objects identical to those being
985 * deleted from happening concurrently (such attempts result from
986 * hotplug events handled via the ACPI hotplug workqueue). It also will
987 * run after all of the work items submitted previosuly, which helps
988 * those work items to ensure that they are not accessing stale device
989 * objects.
990 */
991 if (list_empty(&acpi_device_del_list))
992 acpi_queue_hotplug_work(&work);
993
994 list_add_tail(&adev->del_list, &acpi_device_del_list);
995 /* Make acpi_ns_validate_handle() return NULL for this handle. */
996 adev->handle = INVALID_ACPI_HANDLE;
997
998 mutex_unlock(&acpi_device_del_lock);
913} 999}
914 1000
915int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device) 1001int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
@@ -919,7 +1005,7 @@ int acpi_bus_get_device(acpi_handle handle, struct acpi_device **device)
919 if (!device) 1005 if (!device)
920 return -EINVAL; 1006 return -EINVAL;
921 1007
922 status = acpi_get_data(handle, acpi_bus_data_handler, (void **)device); 1008 status = acpi_get_data(handle, acpi_scan_drop_device, (void **)device);
923 if (ACPI_FAILURE(status) || !*device) { 1009 if (ACPI_FAILURE(status) || !*device) {
924 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n", 1010 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No context for object [%p]\n",
925 handle)); 1011 handle));
@@ -939,7 +1025,7 @@ int acpi_device_add(struct acpi_device *device,
939 if (device->handle) { 1025 if (device->handle) {
940 acpi_status status; 1026 acpi_status status;
941 1027
942 status = acpi_attach_data(device->handle, acpi_bus_data_handler, 1028 status = acpi_attach_data(device->handle, acpi_scan_drop_device,
943 device); 1029 device);
944 if (ACPI_FAILURE(status)) { 1030 if (ACPI_FAILURE(status)) {
945 acpi_handle_err(device->handle, 1031 acpi_handle_err(device->handle,
@@ -957,6 +1043,7 @@ int acpi_device_add(struct acpi_device *device,
957 INIT_LIST_HEAD(&device->node); 1043 INIT_LIST_HEAD(&device->node);
958 INIT_LIST_HEAD(&device->wakeup_list); 1044 INIT_LIST_HEAD(&device->wakeup_list);
959 INIT_LIST_HEAD(&device->physical_node_list); 1045 INIT_LIST_HEAD(&device->physical_node_list);
1046 INIT_LIST_HEAD(&device->del_list);
960 mutex_init(&device->physical_node_lock); 1047 mutex_init(&device->physical_node_lock);
961 1048
962 new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL); 1049 new_bus_id = kzalloc(sizeof(struct acpi_device_bus_id), GFP_KERNEL);
@@ -1020,27 +1107,14 @@ int acpi_device_add(struct acpi_device *device,
1020 mutex_unlock(&acpi_device_lock); 1107 mutex_unlock(&acpi_device_lock);
1021 1108
1022 err_detach: 1109 err_detach:
1023 acpi_detach_data(device->handle, acpi_bus_data_handler); 1110 acpi_detach_data(device->handle, acpi_scan_drop_device);
1024 return result; 1111 return result;
1025} 1112}
1026 1113
1027static void acpi_device_unregister(struct acpi_device *device) 1114static void acpi_device_unregister(struct acpi_device *device)
1028{ 1115{
1029 mutex_lock(&acpi_device_lock); 1116 acpi_detach_data(device->handle, acpi_scan_drop_device);
1030 if (device->parent) 1117 acpi_device_del(device);
1031 list_del(&device->node);
1032
1033 list_del(&device->wakeup_list);
1034 mutex_unlock(&acpi_device_lock);
1035
1036 acpi_detach_data(device->handle, acpi_bus_data_handler);
1037
1038 acpi_power_add_remove_device(device, false);
1039 acpi_device_remove_files(device);
1040 if (device->remove)
1041 device->remove(device);
1042
1043 device_del(&device->dev);
1044 /* 1118 /*
1045 * Transition the device to D3cold to drop the reference counts of all 1119 * Transition the device to D3cold to drop the reference counts of all
1046 * power resources the device depends on and turn off the ones that have 1120 * power resources the device depends on and turn off the ones that have
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 {
299 struct list_head children; 299 struct list_head children;
300 struct list_head node; 300 struct list_head node;
301 struct list_head wakeup_list; 301 struct list_head wakeup_list;
302 struct list_head del_list;
302 struct acpi_device_status status; 303 struct acpi_device_status status;
303 struct acpi_device_flags flags; 304 struct acpi_device_flags flags;
304 struct acpi_device_pnp pnp; 305 struct acpi_device_pnp pnp;