1 /****************************************************************************** 2 * 3 * Module Name: exmutex - ASL Mutex Acquire/Release functions 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 #include <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acinterp.h> 47 #include <contrib/dev/acpica/include/acevents.h> 48 49 #define _COMPONENT ACPI_EXECUTER 50 ACPI_MODULE_NAME ("exmutex") 51 52 /* Local prototypes */ 53 54 static void 55 AcpiExLinkMutex ( 56 ACPI_OPERAND_OBJECT *ObjDesc, 57 ACPI_THREAD_STATE *Thread); 58 59 60 /******************************************************************************* 61 * 62 * FUNCTION: AcpiExUnlinkMutex 63 * 64 * PARAMETERS: ObjDesc - The mutex to be unlinked 65 * 66 * RETURN: None 67 * 68 * DESCRIPTION: Remove a mutex from the "AcquiredMutex" list 69 * 70 ******************************************************************************/ 71 72 void 73 AcpiExUnlinkMutex ( 74 ACPI_OPERAND_OBJECT *ObjDesc) 75 { 76 ACPI_THREAD_STATE *Thread = ObjDesc->Mutex.OwnerThread; 77 78 79 if (!Thread) 80 { 81 return; 82 } 83 84 /* Doubly linked list */ 85 86 if (ObjDesc->Mutex.Next) 87 { 88 (ObjDesc->Mutex.Next)->Mutex.Prev = ObjDesc->Mutex.Prev; 89 } 90 91 if (ObjDesc->Mutex.Prev) 92 { 93 (ObjDesc->Mutex.Prev)->Mutex.Next = ObjDesc->Mutex.Next; 94 95 /* 96 * Migrate the previous sync level associated with this mutex to 97 * the previous mutex on the list so that it may be preserved. 98 * This handles the case where several mutexes have been acquired 99 * at the same level, but are not released in opposite order. 100 */ 101 (ObjDesc->Mutex.Prev)->Mutex.OriginalSyncLevel = 102 ObjDesc->Mutex.OriginalSyncLevel; 103 } 104 else 105 { 106 Thread->AcquiredMutexList = ObjDesc->Mutex.Next; 107 } 108 } 109 110 111 /******************************************************************************* 112 * 113 * FUNCTION: AcpiExLinkMutex 114 * 115 * PARAMETERS: ObjDesc - The mutex to be linked 116 * Thread - Current executing thread object 117 * 118 * RETURN: None 119 * 120 * DESCRIPTION: Add a mutex to the "AcquiredMutex" list for this walk 121 * 122 ******************************************************************************/ 123 124 static void 125 AcpiExLinkMutex ( 126 ACPI_OPERAND_OBJECT *ObjDesc, 127 ACPI_THREAD_STATE *Thread) 128 { 129 ACPI_OPERAND_OBJECT *ListHead; 130 131 132 ListHead = Thread->AcquiredMutexList; 133 134 /* This object will be the first object in the list */ 135 136 ObjDesc->Mutex.Prev = NULL; 137 ObjDesc->Mutex.Next = ListHead; 138 139 /* Update old first object to point back to this object */ 140 141 if (ListHead) 142 { 143 ListHead->Mutex.Prev = ObjDesc; 144 } 145 146 /* Update list head */ 147 148 Thread->AcquiredMutexList = ObjDesc; 149 } 150 151 152 /******************************************************************************* 153 * 154 * FUNCTION: AcpiExAcquireMutexObject 155 * 156 * PARAMETERS: Timeout - Timeout in milliseconds 157 * ObjDesc - Mutex object 158 * ThreadId - Current thread state 159 * 160 * RETURN: Status 161 * 162 * DESCRIPTION: Acquire an AML mutex, low-level interface. Provides a common 163 * path that supports multiple acquires by the same thread. 164 * 165 * MUTEX: Interpreter must be locked 166 * 167 * NOTE: This interface is called from three places: 168 * 1) From AcpiExAcquireMutex, via an AML Acquire() operator 169 * 2) From AcpiExAcquireGlobalLock when an AML Field access requires the 170 * global lock 171 * 3) From the external interface, AcpiAcquireGlobalLock 172 * 173 ******************************************************************************/ 174 175 ACPI_STATUS 176 AcpiExAcquireMutexObject ( 177 UINT16 Timeout, 178 ACPI_OPERAND_OBJECT *ObjDesc, 179 ACPI_THREAD_ID ThreadId) 180 { 181 ACPI_STATUS Status; 182 183 184 ACPI_FUNCTION_TRACE_PTR (ExAcquireMutexObject, ObjDesc); 185 186 187 if (!ObjDesc) 188 { 189 return_ACPI_STATUS (AE_BAD_PARAMETER); 190 } 191 192 /* Support for multiple acquires by the owning thread */ 193 194 if (ObjDesc->Mutex.ThreadId == ThreadId) 195 { 196 /* 197 * The mutex is already owned by this thread, just increment the 198 * acquisition depth 199 */ 200 ObjDesc->Mutex.AcquisitionDepth++; 201 return_ACPI_STATUS (AE_OK); 202 } 203 204 /* Acquire the mutex, wait if necessary. Special case for Global Lock */ 205 206 if (ObjDesc == AcpiGbl_GlobalLockMutex) 207 { 208 Status = AcpiEvAcquireGlobalLock (Timeout); 209 } 210 else 211 { 212 Status = AcpiExSystemWaitMutex (ObjDesc->Mutex.OsMutex, 213 Timeout); 214 } 215 216 if (ACPI_FAILURE (Status)) 217 { 218 /* Includes failure from a timeout on TimeDesc */ 219 220 return_ACPI_STATUS (Status); 221 } 222 223 /* Acquired the mutex: update mutex object */ 224 225 ObjDesc->Mutex.ThreadId = ThreadId; 226 ObjDesc->Mutex.AcquisitionDepth = 1; 227 ObjDesc->Mutex.OriginalSyncLevel = 0; 228 ObjDesc->Mutex.OwnerThread = NULL; /* Used only for AML Acquire() */ 229 230 return_ACPI_STATUS (AE_OK); 231 } 232 233 234 /******************************************************************************* 235 * 236 * FUNCTION: AcpiExAcquireMutex 237 * 238 * PARAMETERS: TimeDesc - Timeout integer 239 * ObjDesc - Mutex object 240 * WalkState - Current method execution state 241 * 242 * RETURN: Status 243 * 244 * DESCRIPTION: Acquire an AML mutex 245 * 246 ******************************************************************************/ 247 248 ACPI_STATUS 249 AcpiExAcquireMutex ( 250 ACPI_OPERAND_OBJECT *TimeDesc, 251 ACPI_OPERAND_OBJECT *ObjDesc, 252 ACPI_WALK_STATE *WalkState) 253 { 254 ACPI_STATUS Status; 255 256 257 ACPI_FUNCTION_TRACE_PTR (ExAcquireMutex, ObjDesc); 258 259 260 if (!ObjDesc) 261 { 262 return_ACPI_STATUS (AE_BAD_PARAMETER); 263 } 264 265 /* Must have a valid thread state struct */ 266 267 if (!WalkState->Thread) 268 { 269 ACPI_ERROR ((AE_INFO, 270 "Cannot acquire Mutex [%4.4s], null thread info", 271 AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 272 return_ACPI_STATUS (AE_AML_INTERNAL); 273 } 274 275 /* 276 * Current sync level must be less than or equal to the sync level of the 277 * mutex. This mechanism provides some deadlock prevention 278 */ 279 if (WalkState->Thread->CurrentSyncLevel > ObjDesc->Mutex.SyncLevel) 280 { 281 ACPI_ERROR ((AE_INFO, 282 "Cannot acquire Mutex [%4.4s], current SyncLevel is too large (%u)", 283 AcpiUtGetNodeName (ObjDesc->Mutex.Node), 284 WalkState->Thread->CurrentSyncLevel)); 285 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 286 } 287 288 Status = AcpiExAcquireMutexObject ((UINT16) TimeDesc->Integer.Value, 289 ObjDesc, WalkState->Thread->ThreadId); 290 if (ACPI_SUCCESS (Status) && ObjDesc->Mutex.AcquisitionDepth == 1) 291 { 292 /* Save Thread object, original/current sync levels */ 293 294 ObjDesc->Mutex.OwnerThread = WalkState->Thread; 295 ObjDesc->Mutex.OriginalSyncLevel = WalkState->Thread->CurrentSyncLevel; 296 WalkState->Thread->CurrentSyncLevel = ObjDesc->Mutex.SyncLevel; 297 298 /* Link the mutex to the current thread for force-unlock at method exit */ 299 300 AcpiExLinkMutex (ObjDesc, WalkState->Thread); 301 } 302 303 return_ACPI_STATUS (Status); 304 } 305 306 307 /******************************************************************************* 308 * 309 * FUNCTION: AcpiExReleaseMutexObject 310 * 311 * PARAMETERS: ObjDesc - The object descriptor for this op 312 * 313 * RETURN: Status 314 * 315 * DESCRIPTION: Release a previously acquired Mutex, low level interface. 316 * Provides a common path that supports multiple releases (after 317 * previous multiple acquires) by the same thread. 318 * 319 * MUTEX: Interpreter must be locked 320 * 321 * NOTE: This interface is called from three places: 322 * 1) From AcpiExReleaseMutex, via an AML Acquire() operator 323 * 2) From AcpiExReleaseGlobalLock when an AML Field access requires the 324 * global lock 325 * 3) From the external interface, AcpiReleaseGlobalLock 326 * 327 ******************************************************************************/ 328 329 ACPI_STATUS 330 AcpiExReleaseMutexObject ( 331 ACPI_OPERAND_OBJECT *ObjDesc) 332 { 333 ACPI_STATUS Status = AE_OK; 334 335 336 ACPI_FUNCTION_TRACE (ExReleaseMutexObject); 337 338 339 if (ObjDesc->Mutex.AcquisitionDepth == 0) 340 { 341 return_ACPI_STATUS (AE_NOT_ACQUIRED); 342 } 343 344 /* Match multiple Acquires with multiple Releases */ 345 346 ObjDesc->Mutex.AcquisitionDepth--; 347 if (ObjDesc->Mutex.AcquisitionDepth != 0) 348 { 349 /* Just decrement the depth and return */ 350 351 return_ACPI_STATUS (AE_OK); 352 } 353 354 if (ObjDesc->Mutex.OwnerThread) 355 { 356 /* Unlink the mutex from the owner's list */ 357 358 AcpiExUnlinkMutex (ObjDesc); 359 ObjDesc->Mutex.OwnerThread = NULL; 360 } 361 362 /* Release the mutex, special case for Global Lock */ 363 364 if (ObjDesc == AcpiGbl_GlobalLockMutex) 365 { 366 Status = AcpiEvReleaseGlobalLock (); 367 } 368 else 369 { 370 AcpiOsReleaseMutex (ObjDesc->Mutex.OsMutex); 371 } 372 373 /* Clear mutex info */ 374 375 ObjDesc->Mutex.ThreadId = 0; 376 return_ACPI_STATUS (Status); 377 } 378 379 380 /******************************************************************************* 381 * 382 * FUNCTION: AcpiExReleaseMutex 383 * 384 * PARAMETERS: ObjDesc - The object descriptor for this op 385 * WalkState - Current method execution state 386 * 387 * RETURN: Status 388 * 389 * DESCRIPTION: Release a previously acquired Mutex. 390 * 391 ******************************************************************************/ 392 393 ACPI_STATUS 394 AcpiExReleaseMutex ( 395 ACPI_OPERAND_OBJECT *ObjDesc, 396 ACPI_WALK_STATE *WalkState) 397 { 398 ACPI_STATUS Status = AE_OK; 399 UINT8 PreviousSyncLevel; 400 ACPI_THREAD_STATE *OwnerThread; 401 402 403 ACPI_FUNCTION_TRACE (ExReleaseMutex); 404 405 406 if (!ObjDesc) 407 { 408 return_ACPI_STATUS (AE_BAD_PARAMETER); 409 } 410 411 OwnerThread = ObjDesc->Mutex.OwnerThread; 412 413 /* The mutex must have been previously acquired in order to release it */ 414 415 if (!OwnerThread) 416 { 417 ACPI_ERROR ((AE_INFO, 418 "Cannot release Mutex [%4.4s], not acquired", 419 AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 420 return_ACPI_STATUS (AE_AML_MUTEX_NOT_ACQUIRED); 421 } 422 423 /* Must have a valid thread ID */ 424 425 if (!WalkState->Thread) 426 { 427 ACPI_ERROR ((AE_INFO, 428 "Cannot release Mutex [%4.4s], null thread info", 429 AcpiUtGetNodeName (ObjDesc->Mutex.Node))); 430 return_ACPI_STATUS (AE_AML_INTERNAL); 431 } 432 433 /* 434 * The Mutex is owned, but this thread must be the owner. 435 * Special case for Global Lock, any thread can release 436 */ 437 if ((OwnerThread->ThreadId != WalkState->Thread->ThreadId) && 438 (ObjDesc != AcpiGbl_GlobalLockMutex)) 439 { 440 ACPI_ERROR ((AE_INFO, 441 "Thread %u cannot release Mutex [%4.4s] acquired by thread %u", 442 (UINT32) WalkState->Thread->ThreadId, 443 AcpiUtGetNodeName (ObjDesc->Mutex.Node), 444 (UINT32) OwnerThread->ThreadId)); 445 return_ACPI_STATUS (AE_AML_NOT_OWNER); 446 } 447 448 /* 449 * The sync level of the mutex must be equal to the current sync level. In 450 * other words, the current level means that at least one mutex at that 451 * level is currently being held. Attempting to release a mutex of a 452 * different level can only mean that the mutex ordering rule is being 453 * violated. This behavior is clarified in ACPI 4.0 specification. 454 */ 455 if (ObjDesc->Mutex.SyncLevel != OwnerThread->CurrentSyncLevel) 456 { 457 ACPI_ERROR ((AE_INFO, 458 "Cannot release Mutex [%4.4s], SyncLevel mismatch: mutex %u current %u", 459 AcpiUtGetNodeName (ObjDesc->Mutex.Node), 460 ObjDesc->Mutex.SyncLevel, WalkState->Thread->CurrentSyncLevel)); 461 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 462 } 463 464 /* 465 * Get the previous SyncLevel from the head of the acquired mutex list. 466 * This handles the case where several mutexes at the same level have been 467 * acquired, but are not released in reverse order. 468 */ 469 PreviousSyncLevel = 470 OwnerThread->AcquiredMutexList->Mutex.OriginalSyncLevel; 471 472 Status = AcpiExReleaseMutexObject (ObjDesc); 473 if (ACPI_FAILURE (Status)) 474 { 475 return_ACPI_STATUS (Status); 476 } 477 478 if (ObjDesc->Mutex.AcquisitionDepth == 0) 479 { 480 /* Restore the previous SyncLevel */ 481 482 OwnerThread->CurrentSyncLevel = PreviousSyncLevel; 483 } 484 485 return_ACPI_STATUS (Status); 486 } 487 488 489 /******************************************************************************* 490 * 491 * FUNCTION: AcpiExReleaseAllMutexes 492 * 493 * PARAMETERS: Thread - Current executing thread object 494 * 495 * RETURN: Status 496 * 497 * DESCRIPTION: Release all mutexes held by this thread 498 * 499 * NOTE: This function is called as the thread is exiting the interpreter. 500 * Mutexes are not released when an individual control method is exited, but 501 * only when the parent thread actually exits the interpreter. This allows one 502 * method to acquire a mutex, and a different method to release it, as long as 503 * this is performed underneath a single parent control method. 504 * 505 ******************************************************************************/ 506 507 void 508 AcpiExReleaseAllMutexes ( 509 ACPI_THREAD_STATE *Thread) 510 { 511 ACPI_OPERAND_OBJECT *Next = Thread->AcquiredMutexList; 512 ACPI_OPERAND_OBJECT *ObjDesc; 513 514 515 ACPI_FUNCTION_NAME (ExReleaseAllMutexes); 516 517 518 /* Traverse the list of owned mutexes, releasing each one */ 519 520 while (Next) 521 { 522 ObjDesc = Next; 523 Next = ObjDesc->Mutex.Next; 524 525 ObjDesc->Mutex.Prev = NULL; 526 ObjDesc->Mutex.Next = NULL; 527 ObjDesc->Mutex.AcquisitionDepth = 0; 528 529 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 530 "Force-releasing held mutex: %p\n", ObjDesc)); 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 } 555