aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorBob Moore <robert.moore@intel.com>2009-05-20 22:02:34 -0400
committerLen Brown <len.brown@intel.com>2009-05-27 00:32:24 -0400
commit10a3b461a258f52b17fb8e35edf3625726eca9a8 (patch)
tree9fa487b04ecb9007f6eac30ee9a6ecb4c179090e /drivers/acpi
parentba9e2ae443feb7231d9631ea0f62b63e26cfb9b1 (diff)
ACPICA: Mutex support: Fix release ordering issue and current sync level
Fixes a problem where if multiple mutexes of the same sync level are acquired but then not released in strict opposite order, the current sync level becomes confused and can cause errors. ACPICA BZ 471. http://acpica.org/bugzilla/show_bug.cgi?id=471 Signed-off-by: Bob Moore <robert.moore@intel.com> Signed-off-by: Lin Ming <ming.m.lin@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi')
-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 d7cb030a21f..77a592aa53c 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}