aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLv Zheng <lv.zheng@intel.com>2014-04-04 00:37:51 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2014-04-20 16:59:37 -0400
commit69c841b6dd8313c9a673246cc0e2535174272cab (patch)
tree6311ddfe34636003a140c40d10d58d9687772d6c
parent06a63e33f32fd6b68cc78fd88f294d0fee6b889a (diff)
ACPICA: Update use of acpi_os_wait_events_complete interface.
This patch cleans up all of the acpi_os_wait_events_complete() invocations to make it to be invoked inside of ACPICA in the way to accommodate Linux's work queue implementation. According to the report, current Linux kernel code is facing a boot time race issue in the acpi_remove_notify_handler(). This is because: Linux is using work queues to implement a deferred handler call environment while ACPICA expects OSPM to implement acpi_os_wait_events_complete() using wait queues. The position to invoke a "waiter" is not suitable for a "flusher" as new invocations can be scheduled after this position and before the deletion of the handler from its management container. Since the following commit has deleted acpi_os_wait_events_complete() parameters, it thus might not be possible for OSPM to achieve a safe removal using wait queues. This requires ACPICA to be changed accordingly to "flush" handlers rather than "wait" them to be drain up: Commit: 5ff986a2a9db11858247b71fe242fe17617229aa Date: Wed, 16 May 2012 13:36:07 -0700 Subject: Introduce acpi_os_wait_events_complete interface. This interface will block until asynchronous events like notifies and GPEs are complete. Within ACPICA, it is called before a notify or GPE handler is removed. ACPICA BZ 868. This patch fixes this issue by invoking acpi_os_wait_events_complete() in the way to "flush" things - it thus should be put to the position after handler is removed from its management container but before it is destructed. The technical concerns are: 1. MTX_NAMESPACE is used to protect things that acpi_os_wait_events_complete() might be waiting for, thus MTX_NAMESPACE must be unlocked before invoking acpi_os_wait_events_complete(). 2. MTX_NAMESPACE is also used to implement the serialization of acpi_install_notify_handler() and acpi_remove_notify_handler(). This patch changes this logic, thus if there are many acpi_install/remove_notify_handler() invoked in parallel, the acpi_os_wait_events_complete() might face the races which could cause it never running to an end. Normally this will require additional code to implement a separate locking facility which is not implemented due to 3. 3. Given ACPICA users will always invoke acpi_install_notify_handler() once during Linux module/device initialization and invoke acpi_remove_notify_handler() once during module/device finalization, problem stated in 2 will not happen in Linux environment due to the mutual exclusive module/device existence, this fix thus is sufficient. Same concerns can apply to acpi_install/remove_gpe_handler(). Reported and tested: Ronald Vink. Fixed: Lv Zheng. References: https://bugzilla.kernel.org/show_bug.cgi?id=60583 Signed-off-by: Lv Zheng <lv.zheng@intel.com> Reported-and-Tested-by: Ronald Vink <ronald.vink@boskalis.com> Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r--drivers/acpi/acpica/evxface.c55
1 files changed, 36 insertions, 19 deletions
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index a41a0e75b1b6..11e5803b8b41 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -239,7 +239,7 @@ acpi_remove_notify_handler(acpi_handle device,
239 union acpi_operand_object *obj_desc; 239 union acpi_operand_object *obj_desc;
240 union acpi_operand_object *handler_obj; 240 union acpi_operand_object *handler_obj;
241 union acpi_operand_object *previous_handler_obj; 241 union acpi_operand_object *previous_handler_obj;
242 acpi_status status; 242 acpi_status status = AE_OK;
243 u32 i; 243 u32 i;
244 244
245 ACPI_FUNCTION_TRACE(acpi_remove_notify_handler); 245 ACPI_FUNCTION_TRACE(acpi_remove_notify_handler);
@@ -251,20 +251,17 @@ acpi_remove_notify_handler(acpi_handle device,
251 return_ACPI_STATUS(AE_BAD_PARAMETER); 251 return_ACPI_STATUS(AE_BAD_PARAMETER);
252 } 252 }
253 253
254 /* Make sure all deferred notify tasks are completed */
255
256 acpi_os_wait_events_complete();
257
258 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
259 if (ACPI_FAILURE(status)) {
260 return_ACPI_STATUS(status);
261 }
262
263 /* Root Object. Global handlers are removed here */ 254 /* Root Object. Global handlers are removed here */
264 255
265 if (device == ACPI_ROOT_OBJECT) { 256 if (device == ACPI_ROOT_OBJECT) {
266 for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { 257 for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
267 if (handler_type & (i + 1)) { 258 if (handler_type & (i + 1)) {
259 status =
260 acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
261 if (ACPI_FAILURE(status)) {
262 return_ACPI_STATUS(status);
263 }
264
268 if (!acpi_gbl_global_notify[i].handler || 265 if (!acpi_gbl_global_notify[i].handler ||
269 (acpi_gbl_global_notify[i].handler != 266 (acpi_gbl_global_notify[i].handler !=
270 handler)) { 267 handler)) {
@@ -277,31 +274,40 @@ acpi_remove_notify_handler(acpi_handle device,
277 274
278 acpi_gbl_global_notify[i].handler = NULL; 275 acpi_gbl_global_notify[i].handler = NULL;
279 acpi_gbl_global_notify[i].context = NULL; 276 acpi_gbl_global_notify[i].context = NULL;
277
278 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
279
280 /* Make sure all deferred notify tasks are completed */
281
282 acpi_os_wait_events_complete();
280 } 283 }
281 } 284 }
282 285
283 goto unlock_and_exit; 286 return_ACPI_STATUS(AE_OK);
284 } 287 }
285 288
286 /* All other objects: Are Notifies allowed on this object? */ 289 /* All other objects: Are Notifies allowed on this object? */
287 290
288 if (!acpi_ev_is_notify_object(node)) { 291 if (!acpi_ev_is_notify_object(node)) {
289 status = AE_TYPE; 292 return_ACPI_STATUS(AE_TYPE);
290 goto unlock_and_exit;
291 } 293 }
292 294
293 /* Must have an existing internal object */ 295 /* Must have an existing internal object */
294 296
295 obj_desc = acpi_ns_get_attached_object(node); 297 obj_desc = acpi_ns_get_attached_object(node);
296 if (!obj_desc) { 298 if (!obj_desc) {
297 status = AE_NOT_EXIST; 299 return_ACPI_STATUS(AE_NOT_EXIST);
298 goto unlock_and_exit;
299 } 300 }
300 301
301 /* Internal object exists. Find the handler and remove it */ 302 /* Internal object exists. Find the handler and remove it */
302 303
303 for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) { 304 for (i = 0; i < ACPI_NUM_NOTIFY_TYPES; i++) {
304 if (handler_type & (i + 1)) { 305 if (handler_type & (i + 1)) {
306 status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
307 if (ACPI_FAILURE(status)) {
308 return_ACPI_STATUS(status);
309 }
310
305 handler_obj = obj_desc->common_notify.notify_list[i]; 311 handler_obj = obj_desc->common_notify.notify_list[i];
306 previous_handler_obj = NULL; 312 previous_handler_obj = NULL;
307 313
@@ -329,10 +335,17 @@ acpi_remove_notify_handler(acpi_handle device,
329 handler_obj->notify.next[i]; 335 handler_obj->notify.next[i];
330 } 336 }
331 337
338 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
339
340 /* Make sure all deferred notify tasks are completed */
341
342 acpi_os_wait_events_complete();
332 acpi_ut_remove_reference(handler_obj); 343 acpi_ut_remove_reference(handler_obj);
333 } 344 }
334 } 345 }
335 346
347 return_ACPI_STATUS(status);
348
336unlock_and_exit: 349unlock_and_exit:
337 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE); 350 (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
338 return_ACPI_STATUS(status); 351 return_ACPI_STATUS(status);
@@ -842,10 +855,6 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
842 return_ACPI_STATUS(AE_BAD_PARAMETER); 855 return_ACPI_STATUS(AE_BAD_PARAMETER);
843 } 856 }
844 857
845 /* Make sure all deferred GPE tasks are completed */
846
847 acpi_os_wait_events_complete();
848
849 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS); 858 status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
850 if (ACPI_FAILURE(status)) { 859 if (ACPI_FAILURE(status)) {
851 return_ACPI_STATUS(status); 860 return_ACPI_STATUS(status);
@@ -897,9 +906,17 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
897 (void)acpi_ev_add_gpe_reference(gpe_event_info); 906 (void)acpi_ev_add_gpe_reference(gpe_event_info);
898 } 907 }
899 908
909 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
910 (void)acpi_ut_release_mutex(ACPI_MTX_EVENTS);
911
912 /* Make sure all deferred GPE tasks are completed */
913
914 acpi_os_wait_events_complete();
915
900 /* Now we can free the handler object */ 916 /* Now we can free the handler object */
901 917
902 ACPI_FREE(handler); 918 ACPI_FREE(handler);
919 return_ACPI_STATUS(status);
903 920
904unlock_and_exit: 921unlock_and_exit:
905 acpi_os_release_lock(acpi_gbl_gpe_lock, flags); 922 acpi_os_release_lock(acpi_gbl_gpe_lock, flags);