aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/acpica/exmutex.c21
1 files changed, 19 insertions, 2 deletions
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index d7cb030a21f8..77a592aa53c0 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
@@ -404,14 +414,21 @@ acpi_ex_release_mutex(union acpi_operand_object *obj_desc,
404 return_ACPI_STATUS(AE_AML_MUTEX_ORDER); 414 return_ACPI_STATUS(AE_AML_MUTEX_ORDER);
405 } 415 }
406 416
417 /*
418 * Get the previous sync_level from the head of the acquired mutex list.
419 * This handles the case where several mutexes at the same level have been
420 * acquired, but are not released in reverse order.
421 */
422 previous_sync_level =
423 walk_state->thread->acquired_mutex_list->mutex.original_sync_level;
424
407 status = acpi_ex_release_mutex_object(obj_desc); 425 status = acpi_ex_release_mutex_object(obj_desc);
408 426
409 if (obj_desc->mutex.acquisition_depth == 0) { 427 if (obj_desc->mutex.acquisition_depth == 0) {
410 428
411 /* Restore the original sync_level */ 429 /* Restore the original sync_level */
412 430
413 walk_state->thread->current_sync_level = 431 walk_state->thread->current_sync_level = previous_sync_level;
414 obj_desc->mutex.original_sync_level;
415 } 432 }
416 return_ACPI_STATUS(status); 433 return_ACPI_STATUS(status);
417} 434}