diff options
Diffstat (limited to 'drivers/acpi/acpica/exmutex.c')
-rw-r--r-- | drivers/acpi/acpica/exmutex.c | 45 |
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 | } |