diff options
Diffstat (limited to 'sys/contrib/dev/acpica/exmutex.c')
-rw-r--r-- | sys/contrib/dev/acpica/exmutex.c | 311 |
1 files changed, 219 insertions, 92 deletions
diff --git a/sys/contrib/dev/acpica/exmutex.c b/sys/contrib/dev/acpica/exmutex.c index 06f1972..e1925ec 100644 --- a/sys/contrib/dev/acpica/exmutex.c +++ b/sys/contrib/dev/acpica/exmutex.c @@ -2,7 +2,7 @@ /****************************************************************************** * * Module Name: exmutex - ASL Mutex Acquire/Release functions - * $Revision: 1.28 $ + * $Revision: 1.40 $ * *****************************************************************************/ @@ -10,7 +10,7 @@ * * 1. Copyright Notice * - * Some or all of this work - Copyright (c) 1999 - 2005, Intel Corp. + * Some or all of this work - Copyright (c) 1999 - 2007, Intel Corp. * All rights reserved. * * 2. License @@ -119,6 +119,7 @@ #include <contrib/dev/acpica/acpi.h> #include <contrib/dev/acpica/acinterp.h> +#include <contrib/dev/acpica/acevents.h> #define _COMPONENT ACPI_EXECUTER ACPI_MODULE_NAME ("exmutex") @@ -216,6 +217,88 @@ AcpiExLinkMutex ( /******************************************************************************* * + * FUNCTION: AcpiExAcquireMutexObject + * + * PARAMETERS: TimeDesc - Timeout in milliseconds + * ObjDesc - Mutex object + * Thread - Current thread state + * + * RETURN: Status + * + * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common + * path that supports multiple acquires by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From AcpiExAcquireMutex, via an AML Acquire() operator + * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the + * global lock + * 3) From the external interface, AcpiAcquireGlobalLock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExAcquireMutexObject ( + UINT16 Timeout, + ACPI_OPERAND_OBJECT *ObjDesc, + ACPI_THREAD_ID ThreadId) +{ + ACPI_STATUS Status; + + + ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc); + + + if (!ObjDesc) + { + return_ACPI_STATUS (AE_BAD_PARAMETER); + } + + /* Support for multiple acquires by the owning thread */ + + if (ObjDesc->Mutex.ThreadId == ThreadId) + { + /* + * The mutex is already owned by this thread, just increment the + * acquisition depth + */ + ObjDesc->Mutex.AcquisitionDepth++; + return_ACPI_STATUS (AE_OK); + } + + /* Acquire the mutex, wait if necessary. Special case for Global Lock */ + + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + Status = AcpiEvAcquireGlobalLock (Timeout); + } + else + { + Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, + Timeout); + } + + if (ACPI_FAILURE (Status)) + { + /* Includes failure from a timeout on TimeDesc */ + + return_ACPI_STATUS (Status); + } + + /* Acquired the mutex: update mutex object */ + + ObjDesc->Mutex.ThreadId = ThreadId; + ObjDesc->Mutex.AcquisitionDepth = 1; + ObjDesc->Mutex.OriginalSyncLevel = 0; + ObjDesc->Mutex.OwnerThread = NULL; /* Used only for AML Acquire() */ + + return_ACPI_STATUS (AE_OK); +} + + +/******************************************************************************* + * * FUNCTION: AcpiExAcquireMutex * * PARAMETERS: TimeDesc - Timeout integer @@ -237,7 +320,7 @@ AcpiExAcquireMutex ( ACPI_STATUS Status; - ACPI_FUNCTION_TRACE_PTR ("ExAcquireMutex", ObjDesc); + ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc); if (!ObjDesc) @@ -245,70 +328,117 @@ AcpiExAcquireMutex ( return_ACPI_STATUS (AE_BAD_PARAMETER); } - /* Sanity check -- we must have a valid thread ID */ + /* Must have a valid thread ID */ if (!WalkState->Thread) { - ACPI_REPORT_ERROR (("Cannot acquire Mutex [%4.4s], null thread info\n", + ACPI_ERROR ((AE_INFO, "Cannot acquire Mutex [%4.4s], null thread info", AcpiUtGetNodeName (ObjDesc->Mutex.Node))); return_ACPI_STATUS (AE_AML_INTERNAL); } /* - * Current Sync must be less than or equal to the sync level of the - * mutex. This mechanism provides some deadlock prevention + * Current sync level must be less than or equal to the sync level of the + * mutex. This mechanism provides some deadlock prevention */ if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel) { - ACPI_REPORT_ERROR (( - "Cannot acquire Mutex [%4.4s], incorrect SyncLevel\n", - AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + ACPI_ERROR ((AE_INFO, + "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%d)", + AcpiUtGetNodeName (ObjDesc->Mutex.Node), + WalkState->Thread->CurrentSyncLevel)); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* Support for multiple acquires by the owning thread */ - - if (ObjDesc->Mutex.OwnerThread) + Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value, + ObjDesc, WalkState->Thread->ThreadId); + if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1) { - /* Special case for Global Lock, allow all threads */ + /* Save Thread object, original/current sync levels */ - if ((ObjDesc->Mutex.OwnerThread->ThreadId == - WalkState->Thread->ThreadId) || - (ObjDesc->Mutex.Semaphore == - AcpiGbl_GlobalLockSemaphore)) - { - /* - * The mutex is already owned by this thread, - * just increment the acquisition depth - */ - ObjDesc->Mutex.AcquisitionDepth++; - return_ACPI_STATUS (AE_OK); - } + ObjDesc->Mutex.OwnerThread = WalkState->Thread; + ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel; + WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel; + + /* Link the mutex to the current thread for force-unlock at method exit */ + + AcpiExLinkMutex (ObjDesc, WalkState->Thread); } - /* Acquire the mutex, wait if necessary */ + return_ACPI_STATUS (Status); +} - Status = AcpiExSystemAcquireMutex (TimeDesc, ObjDesc); - if (ACPI_FAILURE (Status)) + +/******************************************************************************* + * + * FUNCTION: AcpiExReleaseMutexObject + * + * PARAMETERS: ObjDesc - The object descriptor for this op + * + * RETURN: Status + * + * DESCRIPTION: Release a previously acquired Mutex, low level interface. + * Provides a common path that supports multiple releases (after + * previous multiple acquires) by the same thread. + * + * MUTEX: Interpreter must be locked + * + * NOTE: This interface is called from three places: + * 1) From AcpiExReleaseMutex, via an AML Acquire() operator + * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the + * global lock + * 3) From the external interface, AcpiReleaseGlobalLock + * + ******************************************************************************/ + +ACPI_STATUS +AcpiExReleaseMutexObject ( + ACPI_OPERAND_OBJECT *ObjDesc) +{ + ACPI_STATUS Status = AE_OK; + + + ACPI_FUNCTION_TRACE (ExReleaseMutexObject); + + + if (ObjDesc->Mutex.AcquisitionDepth == 0) { - /* Includes failure from a timeout on TimeDesc */ + return (AE_NOT_ACQUIRED); + } - return_ACPI_STATUS (Status); + /* Match multiple Acquires with multiple Releases */ + + ObjDesc->Mutex.AcquisitionDepth--; + if (ObjDesc->Mutex.AcquisitionDepth != 0) + { + /* Just decrement the depth and return */ + + return_ACPI_STATUS (AE_OK); } - /* Have the mutex: update mutex and walk info and save the SyncLevel */ + if (ObjDesc->Mutex.OwnerThread) + { + /* Unlink the mutex from the owner's list */ - ObjDesc->Mutex.OwnerThread = WalkState->Thread; - ObjDesc->Mutex.AcquisitionDepth = 1; - ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel; + AcpiExUnlinkMutex (ObjDesc); + ObjDesc->Mutex.OwnerThread = NULL; + } - WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel; + /* Release the mutex, special case for Global Lock */ - /* Link the mutex to the current thread for force-unlock at method exit */ + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + Status = AcpiEvReleaseGlobalLock (); + } + else + { + AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); + } - AcpiExLinkMutex (ObjDesc, WalkState->Thread); + /* Clear mutex info */ - return_ACPI_STATUS (AE_OK); + ObjDesc->Mutex.ThreadId = 0; + return_ACPI_STATUS (Status); } @@ -330,10 +460,10 @@ AcpiExReleaseMutex ( ACPI_OPERAND_OBJECT *ObjDesc, ACPI_WALK_STATE *WalkState) { - ACPI_STATUS Status; + ACPI_STATUS Status = AE_OK; - ACPI_FUNCTION_TRACE ("ExReleaseMutex"); + ACPI_FUNCTION_TRACE (ExReleaseMutex); if (!ObjDesc) @@ -345,70 +475,56 @@ AcpiExReleaseMutex ( if (!ObjDesc->Mutex.OwnerThread) { - ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], not acquired\n", - AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], not acquired", + AcpiUtGetNodeName (ObjDesc->Mutex.Node))); return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); } - /* Sanity check -- we must have a valid thread ID */ - - if (!WalkState->Thread) - { - ACPI_REPORT_ERROR (("Cannot release Mutex [%4.4s], null thread info\n", - AcpiUtGetNodeName (ObjDesc->Mutex.Node))); - return_ACPI_STATUS (AE_AML_INTERNAL); - } - /* * The Mutex is owned, but this thread must be the owner. * Special case for Global Lock, any thread can release */ if ((ObjDesc->Mutex.OwnerThread->ThreadId != WalkState->Thread->ThreadId) && - (ObjDesc->Mutex.Semaphore != AcpiGbl_GlobalLockSemaphore)) + (ObjDesc != AcpiGbl_GlobalLockMutex)) { - ACPI_REPORT_ERROR (( - "Thread %X cannot release Mutex [%4.4s] acquired by thread %X\n", + ACPI_ERROR ((AE_INFO, + "Thread %X cannot release Mutex [%4.4s] acquired by thread %X", WalkState->Thread->ThreadId, AcpiUtGetNodeName (ObjDesc->Mutex.Node), ObjDesc->Mutex.OwnerThread->ThreadId)); return_ACPI_STATUS (AE_AML_NOT_OWNER); } + /* Must have a valid thread ID */ + + if (!WalkState->Thread) + { + ACPI_ERROR ((AE_INFO, "Cannot release Mutex [%4.4s], null thread info", + AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + return_ACPI_STATUS (AE_AML_INTERNAL); + } + /* - * The sync level of the mutex must be less than or - * equal to the current sync level + * The sync level of the mutex must be less than or equal to the current + * sync level */ if (ObjDesc->Mutex.SyncLevel > WalkState->Thread->CurrentSyncLevel) { - ACPI_REPORT_ERROR (( - "Cannot release Mutex [%4.4s], incorrect SyncLevel\n", - AcpiUtGetNodeName (ObjDesc->Mutex.Node))); + ACPI_ERROR ((AE_INFO, + "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %d current %d", + AcpiUtGetNodeName (ObjDesc->Mutex.Node), + ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel)); return_ACPI_STATUS (AE_AML_MUTEX_ORDER); } - /* Match multiple Acquires with multiple Releases */ + Status = AcpiExReleaseMutexObject (ObjDesc); - ObjDesc->Mutex.AcquisitionDepth--; - if (ObjDesc->Mutex.AcquisitionDepth != 0) + if (ObjDesc->Mutex.AcquisitionDepth == 0) { - /* Just decrement the depth and return */ + /* Restore the original SyncLevel */ - return_ACPI_STATUS (AE_OK); + WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel; } - - /* Unlink the mutex from the owner's list */ - - AcpiExUnlinkMutex (ObjDesc); - - /* Release the mutex */ - - Status = AcpiExSystemReleaseMutex (ObjDesc); - - /* Update the mutex and walk state, restore SyncLevel before acquire */ - - ObjDesc->Mutex.OwnerThread = NULL; - WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel; - return_ACPI_STATUS (Status); } @@ -423,6 +539,12 @@ AcpiExReleaseMutex ( * * DESCRIPTION: Release all mutexes held by this thread * + * NOTE: This function is called as the thread is exiting the interpreter. + * Mutexes are not released when an individual control method is exited, but + * only when the parent thread actually exits the interpreter. This allows one + * method to acquire a mutex, and a different method to release it, as long as + * this is performed underneath a single parent control method. + * ******************************************************************************/ void @@ -430,8 +552,7 @@ AcpiExReleaseAllMutexes ( ACPI_THREAD_STATE *Thread) { ACPI_OPERAND_OBJECT *Next = Thread->AcquiredMutexList; - ACPI_OPERAND_OBJECT *This; - ACPI_STATUS Status; + ACPI_OPERAND_OBJECT *ObjDesc; ACPI_FUNCTION_ENTRY (); @@ -441,28 +562,34 @@ AcpiExReleaseAllMutexes ( while (Next) { - This = Next; - Next = This->Mutex.Next; + ObjDesc = Next; + Next = ObjDesc->Mutex.Next; + + ObjDesc->Mutex.Prev = NULL; + ObjDesc->Mutex.Next = NULL; + ObjDesc->Mutex.AcquisitionDepth = 0; - This->Mutex.AcquisitionDepth = 1; - This->Mutex.Prev = NULL; - This->Mutex.Next = NULL; + /* Release the mutex, special case for Global Lock */ - /* Release the mutex */ + if (ObjDesc == AcpiGbl_GlobalLockMutex) + { + /* Ignore errors */ - Status = AcpiExSystemReleaseMutex (This); - if (ACPI_FAILURE (Status)) + (void) AcpiEvReleaseGlobalLock (); + } + else { - continue; + AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); } /* Mark mutex unowned */ - This->Mutex.OwnerThread = NULL; + ObjDesc->Mutex.OwnerThread = NULL; + ObjDesc->Mutex.ThreadId = 0; /* Update Thread SyncLevel (Last mutex is the important one) */ - Thread->CurrentSyncLevel = This->Mutex.OriginalSyncLevel; + Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel; } } |