diff options
-rw-r--r-- | drivers/acpi/acpica/exmutex.c | 21 |
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 | } |