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