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 }