1 
   2 /******************************************************************************
   3  *
   4  * Module Name: exmutex - ASL Mutex Acquire/Release functions
   5  *
   6  *****************************************************************************/
   7 
   8 /*
   9  * Copyright (C) 2000 - 2011, Intel Corp.
  10  * All rights reserved.
  11  *
  12  * Redistribution and use in source and binary forms, with or without
  13  * modification, are permitted provided that the following conditions
  14  * are met:
  15  * 1. Redistributions of source code must retain the above copyright
  16  *    notice, this list of conditions, and the following disclaimer,
  17  *    without modification.
  18  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  19  *    substantially similar to the "NO WARRANTY" disclaimer below
  20  *    ("Disclaimer") and any redistribution must be conditioned upon
  21  *    including a substantially similar Disclaimer requirement for further
  22  *    binary redistribution.
  23  * 3. Neither the names of the above-listed copyright holders nor the names
  24  *    of any contributors may be used to endorse or promote products derived
  25  *    from this software without specific prior written permission.
  26  *
  27  * Alternatively, this software may be distributed under the terms of the
  28  * GNU General Public License ("GPL") version 2 as published by the Free
  29  * Software Foundation.
  30  *
  31  * NO WARRANTY
  32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  33  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  34  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  35  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  36  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  37  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  38  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  39  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  40  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  41  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  42  * POSSIBILITY OF SUCH DAMAGES.
  43  */
  44 
  45 #define __EXMUTEX_C__
  46 
  47 #include "acpi.h"
  48 #include "accommon.h"
  49 #include "acinterp.h"
  50 #include "acevents.h"
  51 
  52 #define _COMPONENT          ACPI_EXECUTER
  53         ACPI_MODULE_NAME    ("exmutex")
  54 
  55 /* Local prototypes */
  56 
  57 static void
  58 AcpiExLinkMutex (
  59     ACPI_OPERAND_OBJECT     *ObjDesc,
  60     ACPI_THREAD_STATE       *Thread);
  61 
  62 
  63 /*******************************************************************************
  64  *
  65  * FUNCTION:    AcpiExUnlinkMutex
  66  *
  67  * PARAMETERS:  ObjDesc             - The mutex to be unlinked
  68  *
  69  * RETURN:      None
  70  *
  71  * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list
  72  *
  73  ******************************************************************************/
  74 
  75 void
  76 AcpiExUnlinkMutex (
  77     ACPI_OPERAND_OBJECT     *ObjDesc)
  78 {
  79     ACPI_THREAD_STATE       *Thread = ObjDesc->Mutex.OwnerThread;
  80 
  81 
  82     if (!Thread)
  83     {
  84         return;
  85     }
  86 
  87     /* Doubly linked list */
  88 
  89     if (ObjDesc->Mutex.Next)
  90     {
  91         (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev;
  92     }
  93 
  94     if (ObjDesc->Mutex.Prev)
  95     {
  96         (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next;
  97 
  98         /*
  99          * Migrate the previous sync level associated with this mutex to
 100          * the previous mutex on the list so that it may be preserved.
 101          * This handles the case where several mutexes have been acquired
 102          * at the same level, but are not released in opposite order.
 103          */
 104         (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel =
 105             ObjDesc->Mutex.OriginalSyncLevel;
 106     }
 107     else
 108     {
 109         Thread->AcquiredMutexList = ObjDesc->Mutex.Next;
 110     }
 111 }
 112 
 113 
 114 /*******************************************************************************
 115  *
 116  * FUNCTION:    AcpiExLinkMutex
 117  *
 118  * PARAMETERS:  ObjDesc             - The mutex to be linked
 119  *              Thread              - Current executing thread object
 120  *
 121  * RETURN:      None
 122  *
 123  * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk
 124  *
 125  ******************************************************************************/
 126 
 127 static void
 128 AcpiExLinkMutex (
 129     ACPI_OPERAND_OBJECT     *ObjDesc,
 130     ACPI_THREAD_STATE       *Thread)
 131 {
 132     ACPI_OPERAND_OBJECT     *ListHead;
 133 
 134 
 135     ListHead = Thread->AcquiredMutexList;
 136 
 137     /* This object will be the first object in the list */
 138 
 139     ObjDesc->Mutex.Prev = NULL;
 140     ObjDesc->Mutex.Next = ListHead;
 141 
 142     /* Update old first object to point back to this object */
 143 
 144     if (ListHead)
 145     {
 146         ListHead->Mutex.Prev = ObjDesc;
 147     }
 148 
 149     /* Update list head */
 150 
 151     Thread->AcquiredMutexList = ObjDesc;
 152 }
 153 
 154 
 155 /*******************************************************************************
 156  *
 157  * FUNCTION:    AcpiExAcquireMutexObject
 158  *
 159  * PARAMETERS:  Timeout             - Timeout in milliseconds
 160  *              ObjDesc             - Mutex object
 161  *              ThreadId            - Current thread state
 162  *
 163  * RETURN:      Status
 164  *
 165  * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common
 166  *              path that supports multiple acquires by the same thread.
 167  *
 168  * MUTEX:       Interpreter must be locked
 169  *
 170  * NOTE: This interface is called from three places:
 171  * 1) From AcpiExAcquireMutex, via an AML Acquire() operator
 172  * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the
 173  *    global lock
 174  * 3) From the external interface, AcpiAcquireGlobalLock
 175  *
 176  ******************************************************************************/
 177 
 178 ACPI_STATUS
 179 AcpiExAcquireMutexObject (
 180     UINT16                  Timeout,
 181     ACPI_OPERAND_OBJECT     *ObjDesc,
 182     ACPI_THREAD_ID          ThreadId)
 183 {
 184     ACPI_STATUS             Status;
 185 
 186 
 187     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc);
 188 
 189 
 190     if (!ObjDesc)
 191     {
 192         return_ACPI_STATUS (AE_BAD_PARAMETER);
 193     }
 194 
 195     /* Support for multiple acquires by the owning thread */
 196 
 197     if (ObjDesc->Mutex.ThreadId == ThreadId)
 198     {
 199         /*
 200          * The mutex is already owned by this thread, just increment the
 201          * acquisition depth
 202          */
 203         ObjDesc->Mutex.AcquisitionDepth++;
 204         return_ACPI_STATUS (AE_OK);
 205     }
 206 
 207     /* Acquire the mutex, wait if necessary. Special case for Global Lock */
 208 
 209     if (ObjDesc == AcpiGbl_GlobalLockMutex)
 210     {
 211         Status = AcpiEvAcquireGlobalLock (Timeout);
 212     }
 213     else
 214     {
 215         Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex,
 216                     Timeout);
 217     }
 218 
 219     if (ACPI_FAILURE (Status))
 220     {
 221         /* Includes failure from a timeout on TimeDesc */
 222 
 223         return_ACPI_STATUS (Status);
 224     }
 225 
 226     /* Acquired the mutex: update mutex object */
 227 
 228     ObjDesc->Mutex.ThreadId = ThreadId;
 229     ObjDesc->Mutex.AcquisitionDepth = 1;
 230     ObjDesc->Mutex.OriginalSyncLevel = 0;
 231     ObjDesc->Mutex.OwnerThread = NULL;      /* Used only for AML Acquire() */
 232 
 233     return_ACPI_STATUS (AE_OK);
 234 }
 235 
 236 
 237 /*******************************************************************************
 238  *
 239  * FUNCTION:    AcpiExAcquireMutex
 240  *
 241  * PARAMETERS:  TimeDesc            - Timeout integer
 242  *              ObjDesc             - Mutex object
 243  *              WalkState           - Current method execution state
 244  *
 245  * RETURN:      Status
 246  *
 247  * DESCRIPTION: Acquire an AML mutex
 248  *
 249  ******************************************************************************/
 250 
 251 ACPI_STATUS
 252 AcpiExAcquireMutex (
 253     ACPI_OPERAND_OBJECT     *TimeDesc,
 254     ACPI_OPERAND_OBJECT     *ObjDesc,
 255     ACPI_WALK_STATE         *WalkState)
 256 {
 257     ACPI_STATUS             Status;
 258 
 259 
 260     ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc);
 261 
 262 
 263     if (!ObjDesc)
 264     {
 265         return_ACPI_STATUS (AE_BAD_PARAMETER);
 266     }
 267 
 268     /* Must have a valid thread state struct */
 269 
 270     if (!WalkState->Thread)
 271     {
 272         ACPI_ERROR ((AE_INFO,
 273             "Cannot acquire Mutex [%4.4s], null thread info",
 274             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 275         return_ACPI_STATUS (AE_AML_INTERNAL);
 276     }
 277 
 278     /*
 279      * Current sync level must be less than or equal to the sync level of the
 280      * mutex. This mechanism provides some deadlock prevention
 281      */
 282     if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel)
 283     {
 284         ACPI_ERROR ((AE_INFO,
 285             "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)",
 286             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 287             WalkState->Thread->CurrentSyncLevel));
 288         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 289     }
 290 
 291     Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value,
 292                 ObjDesc, WalkState->Thread->ThreadId);
 293     if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1)
 294     {
 295         /* Save Thread object, original/current sync levels */
 296 
 297         ObjDesc->Mutex.OwnerThread = WalkState->Thread;
 298         ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel;
 299         WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel;
 300 
 301         /* Link the mutex to the current thread for force-unlock at method exit */
 302 
 303         AcpiExLinkMutex (ObjDesc, WalkState->Thread);
 304     }
 305 
 306     return_ACPI_STATUS (Status);
 307 }
 308 
 309 
 310 /*******************************************************************************
 311  *
 312  * FUNCTION:    AcpiExReleaseMutexObject
 313  *
 314  * PARAMETERS:  ObjDesc             - The object descriptor for this op
 315  *
 316  * RETURN:      Status
 317  *
 318  * DESCRIPTION: Release a previously acquired Mutex, low level interface.
 319  *              Provides a common path that supports multiple releases (after
 320  *              previous multiple acquires) by the same thread.
 321  *
 322  * MUTEX:       Interpreter must be locked
 323  *
 324  * NOTE: This interface is called from three places:
 325  * 1) From AcpiExReleaseMutex, via an AML Acquire() operator
 326  * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the
 327  *    global lock
 328  * 3) From the external interface, AcpiReleaseGlobalLock
 329  *
 330  ******************************************************************************/
 331 
 332 ACPI_STATUS
 333 AcpiExReleaseMutexObject (
 334     ACPI_OPERAND_OBJECT     *ObjDesc)
 335 {
 336     ACPI_STATUS             Status = AE_OK;
 337 
 338 
 339     ACPI_FUNCTION_TRACE (ExReleaseMutexObject);
 340 
 341 
 342     if (ObjDesc->Mutex.AcquisitionDepth == 0)
 343     {
 344         return (AE_NOT_ACQUIRED);
 345     }
 346 
 347     /* Match multiple Acquires with multiple Releases */
 348 
 349     ObjDesc->Mutex.AcquisitionDepth--;
 350     if (ObjDesc->Mutex.AcquisitionDepth != 0)
 351     {
 352         /* Just decrement the depth and return */
 353 
 354         return_ACPI_STATUS (AE_OK);
 355     }
 356 
 357     if (ObjDesc->Mutex.OwnerThread)
 358     {
 359         /* Unlink the mutex from the owner's list */
 360 
 361         AcpiExUnlinkMutex (ObjDesc);
 362         ObjDesc->Mutex.OwnerThread = NULL;
 363     }
 364 
 365     /* Release the mutex, special case for Global Lock */
 366 
 367     if (ObjDesc == AcpiGbl_GlobalLockMutex)
 368     {
 369         Status = AcpiEvReleaseGlobalLock ();
 370     }
 371     else
 372     {
 373         AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 374     }
 375 
 376     /* Clear mutex info */
 377 
 378     ObjDesc->Mutex.ThreadId = 0;
 379     return_ACPI_STATUS (Status);
 380 }
 381 
 382 
 383 /*******************************************************************************
 384  *
 385  * FUNCTION:    AcpiExReleaseMutex
 386  *
 387  * PARAMETERS:  ObjDesc             - The object descriptor for this op
 388  *              WalkState           - Current method execution state
 389  *
 390  * RETURN:      Status
 391  *
 392  * DESCRIPTION: Release a previously acquired Mutex.
 393  *
 394  ******************************************************************************/
 395 
 396 ACPI_STATUS
 397 AcpiExReleaseMutex (
 398     ACPI_OPERAND_OBJECT     *ObjDesc,
 399     ACPI_WALK_STATE         *WalkState)
 400 {
 401     ACPI_STATUS             Status = AE_OK;
 402     UINT8                   PreviousSyncLevel;
 403     ACPI_THREAD_STATE       *OwnerThread;
 404 
 405 
 406     ACPI_FUNCTION_TRACE (ExReleaseMutex);
 407 
 408 
 409     if (!ObjDesc)
 410     {
 411         return_ACPI_STATUS (AE_BAD_PARAMETER);
 412     }
 413 
 414     OwnerThread = ObjDesc->Mutex.OwnerThread;
 415 
 416     /* The mutex must have been previously acquired in order to release it */
 417 
 418     if (!OwnerThread)
 419     {
 420         ACPI_ERROR ((AE_INFO,
 421             "Cannot release Mutex [%4.4s], not acquired",
 422             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 423         return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED);
 424     }
 425 
 426     /* Must have a valid thread ID */
 427 
 428     if (!WalkState->Thread)
 429     {
 430         ACPI_ERROR ((AE_INFO,
 431             "Cannot release Mutex [%4.4s], null thread info",
 432             AcpiUtGetNodeName (ObjDesc->Mutex.Node)));
 433         return_ACPI_STATUS (AE_AML_INTERNAL);
 434     }
 435 
 436     /*
 437      * The Mutex is owned, but this thread must be the owner.
 438      * Special case for Global Lock, any thread can release
 439      */
 440     if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) &&
 441         (ObjDesc != AcpiGbl_GlobalLockMutex))
 442     {
 443         ACPI_ERROR ((AE_INFO,
 444             "Thread %u cannot release Mutex [%4.4s] acquired by thread %u",
 445             (UINT32) WalkState->Thread->ThreadId,
 446             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 447             (UINT32) OwnerThread->ThreadId));
 448         return_ACPI_STATUS (AE_AML_NOT_OWNER);
 449     }
 450 
 451     /*
 452      * The sync level of the mutex must be equal to the current sync level. In
 453      * other words, the current level means that at least one mutex at that
 454      * level is currently being held. Attempting to release a mutex of a
 455      * different level can only mean that the mutex ordering rule is being
 456      * violated. This behavior is clarified in ACPI 4.0 specification.
 457      */
 458     if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel)
 459     {
 460         ACPI_ERROR ((AE_INFO,
 461             "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u",
 462             AcpiUtGetNodeName (ObjDesc->Mutex.Node),
 463             ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel));
 464         return_ACPI_STATUS (AE_AML_MUTEX_ORDER);
 465     }
 466 
 467     /*
 468      * Get the previous SyncLevel from the head of the acquired mutex list.
 469      * This handles the case where several mutexes at the same level have been
 470      * acquired, but are not released in reverse order.
 471      */
 472     PreviousSyncLevel =
 473         OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel;
 474 
 475     Status = AcpiExReleaseMutexObject (ObjDesc);
 476     if (ACPI_FAILURE (Status))
 477     {
 478         return_ACPI_STATUS (Status);
 479     }
 480 
 481     if (ObjDesc->Mutex.AcquisitionDepth == 0)
 482     {
 483         /* Restore the previous SyncLevel */
 484 
 485         OwnerThread->CurrentSyncLevel = PreviousSyncLevel;
 486     }
 487 
 488     return_ACPI_STATUS (Status);
 489 }
 490 
 491 
 492 /*******************************************************************************
 493  *
 494  * FUNCTION:    AcpiExReleaseAllMutexes
 495  *
 496  * PARAMETERS:  Thread              - Current executing thread object
 497  *
 498  * RETURN:      Status
 499  *
 500  * DESCRIPTION: Release all mutexes held by this thread
 501  *
 502  * NOTE: This function is called as the thread is exiting the interpreter.
 503  * Mutexes are not released when an individual control method is exited, but
 504  * only when the parent thread actually exits the interpreter. This allows one
 505  * method to acquire a mutex, and a different method to release it, as long as
 506  * this is performed underneath a single parent control method.
 507  *
 508  ******************************************************************************/
 509 
 510 void
 511 AcpiExReleaseAllMutexes (
 512     ACPI_THREAD_STATE       *Thread)
 513 {
 514     ACPI_OPERAND_OBJECT     *Next = Thread->AcquiredMutexList;
 515     ACPI_OPERAND_OBJECT     *ObjDesc;
 516 
 517 
 518     ACPI_FUNCTION_ENTRY ();
 519 
 520 
 521     /* Traverse the list of owned mutexes, releasing each one */
 522 
 523     while (Next)
 524     {
 525         ObjDesc = Next;
 526         Next = ObjDesc->Mutex.Next;
 527 
 528         ObjDesc->Mutex.Prev = NULL;
 529         ObjDesc->Mutex.Next = NULL;
 530         ObjDesc->Mutex.AcquisitionDepth = 0;
 531 
 532         /* Release the mutex, special case for Global Lock */
 533 
 534         if (ObjDesc == AcpiGbl_GlobalLockMutex)
 535         {
 536             /* Ignore errors */
 537 
 538             (void) AcpiEvReleaseGlobalLock ();
 539         }
 540         else
 541         {
 542             AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex);
 543         }
 544 
 545         /* Mark mutex unowned */
 546 
 547         ObjDesc->Mutex.OwnerThread = NULL;
 548         ObjDesc->Mutex.ThreadId = 0;
 549 
 550         /* Update Thread SyncLevel (Last mutex is the important one) */
 551 
 552         Thread->CurrentSyncLevel = ObjDesc->Mutex.OriginalSyncLevel;
 553     }
 554 }