aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/acpica/exmutex.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/acpi/acpica/exmutex.c')
-rw-r--r--drivers/acpi/acpica/exmutex.c45
1 files changed, 35 insertions, 10 deletions
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index d301c1f363ef..2f0114202b05 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -83,6 +83,15 @@ void acpi_ex_unlink_mutex(union acpi_operand_object *obj_desc)
83 83
84 if (obj_desc->mutex.prev) { 84 if (obj_desc->mutex.prev) {
85 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next; 85 (obj_desc->mutex.prev)->mutex.next = obj_desc->mutex.next;
86
87 /*
88 * Migrate the previous sync level associated with this mutex to the
89 * previous mutex on the list so that it may be preserved. This handles
90 * the case where several mutexes have been acquired at the same level,
91 * but are not released in opposite order.
92 */
93 (obj_desc->mutex.prev)->mutex.original_sync_level =
94 obj_desc->mutex.original_sync_level;
86 } else { 95 } else {
87 thread->acquired_mutex_list = obj_desc->mutex.next; 96 thread->acquired_mutex_list = obj_desc->mutex.next;
88 } 97 }
@@ -349,6 +358,7 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
349 struct acpi_walk_state *walk_state) 358 struct acpi_walk_state *walk_state)
350{ 359{
351 acpi_status status = AE_OK; 360 acpi_status status = AE_OK;
361 u8 previous_sync_level;
352 362
353 ACPI_FUNCTION_TRACE(ex_release_mutex); 363 ACPI_FUNCTION_TRACE(ex_release_mutex);
354 364
@@ -373,11 +383,12 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
373 walk_state->thread->thread_id) 383 walk_state->thread->thread_id)
374 && (obj_desc != acpi_gbl_global_lock_mutex)) { 384 && (obj_desc != acpi_gbl_global_lock_mutex)) {
375 ACPI_ERROR((AE_INFO, 385 ACPI_ERROR((AE_INFO,
376 "Thread %lX cannot release Mutex [%4.4s] acquired by thread %lX", 386 "Thread %p cannot release Mutex [%4.4s] acquired by thread %p",
377 (unsigned long)walk_state->thread->thread_id, 387 ACPI_CAST_PTR(void, walk_state->thread->thread_id),
378 acpi_ut_get_node_name(obj_desc->mutex.node), 388 acpi_ut_get_node_name(obj_desc->mutex.node),
379 (unsigned long)obj_desc->mutex.owner_thread-> 389 ACPI_CAST_PTR(void,
380 thread_id)); 390 obj_desc->mutex.owner_thread->
391 thread_id)));
381 return_ACPI_STATUS(AE_AML_NOT_OWNER); 392 return_ACPI_STATUS(AE_AML_NOT_OWNER);
382 } 393 }
383 394
@@ -391,10 +402,14 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
391 } 402 }
392 403
393 /* 404 /*
394 * The sync level of the mutex must be less than or equal to the current 405 * The sync level of the mutex must be equal to the current sync level. In
395 * sync level 406 * other words, the current level means that at least one mutex at that
407 * level is currently being held. Attempting to release a mutex of a
408 * different level can only mean that the mutex ordering rule is being
409 * violated. This behavior is clarified in ACPI 4.0 specification.
396 */ 410 */
397 if (obj_desc->mutex.sync_level > walk_state->thread->current_sync_level) { 411 if (obj_desc->mutex.sync_level !=
412 walk_state->thread->current_sync_level) {
398 ACPI_ERROR((AE_INFO, 413 ACPI_ERROR((AE_INFO,
399 "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", 414 "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d",
400 acpi_ut_get_node_name(obj_desc->mutex.node), 415 acpi_ut_get_node_name(obj_desc->mutex.node),
@@ -403,14 +418,24 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
403 return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 418 return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
404 } 419 }
405 420
421 /*
422 * Get the previous sync_level from the head of the acquired mutex list.
423 * This handles the case where several mutexes at the same level have been
424 * acquired, but are not released in reverse order.
425 */
426 previous_sync_level =
427 walk_state->thread->acquired_mutex_list->mutex.original_sync_level;
428
406 status = acpi_ex_release_mutex_object(obj_desc); 429 status = acpi_ex_release_mutex_object(obj_desc);
430 if (ACPI_FAILURE(status)) {
431 return_ACPI_STATUS(status);
432 }
407 433
408 if (obj_desc->mutex.acquisition_depth == 0) { 434 if (obj_desc->mutex.acquisition_depth == 0) {
409 435
410 /* Restore the original sync_level */ 436 /* Restore the previous sync_level */
411 437
412 walk_state->thread->current_sync_level = 438 walk_state->thread->current_sync_level = previous_sync_level;
413 obj_desc->mutex.original_sync_level;
414 } 439 }
415 return_ACPI_STATUS(status); 440 return_ACPI_STATUS(status);
416} 441}