1 /****************************************************************************** 2 * 3 * Module Name: dsmethod - Parser/Interpreter interface - control method parsing 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 __DSMETHOD_C__ 45 46 #include "acpi.h" 47 #include "accommon.h" 48 #include "acdispat.h" 49 #include "acinterp.h" 50 #include "acnamesp.h" 51 #include "acdisasm.h" 52 53 54 #define _COMPONENT ACPI_DISPATCHER 55 ACPI_MODULE_NAME ("dsmethod") 56 57 /* Local prototypes */ 58 59 static ACPI_STATUS 60 AcpiDsCreateMethodMutex ( 61 ACPI_OPERAND_OBJECT *MethodDesc); 62 63 64 /******************************************************************************* 65 * 66 * FUNCTION: AcpiDsMethodError 67 * 68 * PARAMETERS: Status - Execution status 69 * WalkState - Current state 70 * 71 * RETURN: Status 72 * 73 * DESCRIPTION: Called on method error. Invoke the global exception handler if 74 * present, dump the method data if the disassembler is configured 75 * 76 * Note: Allows the exception handler to change the status code 77 * 78 ******************************************************************************/ 79 80 ACPI_STATUS 81 AcpiDsMethodError ( 82 ACPI_STATUS Status, 83 ACPI_WALK_STATE *WalkState) 84 { 85 ACPI_FUNCTION_ENTRY (); 86 87 88 /* Ignore AE_OK and control exception codes */ 89 90 if (ACPI_SUCCESS (Status) || 91 (Status & AE_CODE_CONTROL)) 92 { 93 return (Status); 94 } 95 96 /* Invoke the global exception handler */ 97 98 if (AcpiGbl_ExceptionHandler) 99 { 100 /* Exit the interpreter, allow handler to execute methods */ 101 102 AcpiExExitInterpreter (); 103 104 /* 105 * Handler can map the exception code to anything it wants, including 106 * AE_OK, in which case the executing method will not be aborted. 107 */ 108 Status = AcpiGbl_ExceptionHandler (Status, 109 WalkState->MethodNode ? 110 WalkState->MethodNode->Name.Integer : 0, 111 WalkState->Opcode, WalkState->AmlOffset, NULL); 112 AcpiExEnterInterpreter (); 113 } 114 115 AcpiDsClearImplicitReturn (WalkState); 116 117 #ifdef ACPI_DISASSEMBLER 118 if (ACPI_FAILURE (Status)) 119 { 120 /* Display method locals/args if disassembler is present */ 121 122 AcpiDmDumpMethodInfo (Status, WalkState, WalkState->Op); 123 } 124 #endif 125 126 return (Status); 127 } 128 129 130 /******************************************************************************* 131 * 132 * FUNCTION: AcpiDsCreateMethodMutex 133 * 134 * PARAMETERS: ObjDesc - The method object 135 * 136 * RETURN: Status 137 * 138 * DESCRIPTION: Create a mutex object for a serialized control method 139 * 140 ******************************************************************************/ 141 142 static ACPI_STATUS 143 AcpiDsCreateMethodMutex ( 144 ACPI_OPERAND_OBJECT *MethodDesc) 145 { 146 ACPI_OPERAND_OBJECT *MutexDesc; 147 ACPI_STATUS Status; 148 149 150 ACPI_FUNCTION_TRACE (DsCreateMethodMutex); 151 152 153 /* Create the new mutex object */ 154 155 MutexDesc = AcpiUtCreateInternalObject (ACPI_TYPE_MUTEX); 156 if (!MutexDesc) 157 { 158 return_ACPI_STATUS (AE_NO_MEMORY); 159 } 160 161 /* Create the actual OS Mutex */ 162 163 Status = AcpiOsCreateMutex (&MutexDesc->Mutex.OsMutex); 164 if (ACPI_FAILURE (Status)) 165 { 166 AcpiUtDeleteObjectDesc (MutexDesc); 167 return_ACPI_STATUS (Status); 168 } 169 170 MutexDesc->Mutex.SyncLevel = MethodDesc->Method.SyncLevel; 171 MethodDesc->Method.Mutex = MutexDesc; 172 return_ACPI_STATUS (AE_OK); 173 } 174 175 176 /******************************************************************************* 177 * 178 * FUNCTION: AcpiDsBeginMethodExecution 179 * 180 * PARAMETERS: MethodNode - Node of the method 181 * ObjDesc - The method object 182 * WalkState - current state, NULL if not yet executing 183 * a method. 184 * 185 * RETURN: Status 186 * 187 * DESCRIPTION: Prepare a method for execution. Parses the method if necessary, 188 * increments the thread count, and waits at the method semaphore 189 * for clearance to execute. 190 * 191 ******************************************************************************/ 192 193 ACPI_STATUS 194 AcpiDsBeginMethodExecution ( 195 ACPI_NAMESPACE_NODE *MethodNode, 196 ACPI_OPERAND_OBJECT *ObjDesc, 197 ACPI_WALK_STATE *WalkState) 198 { 199 ACPI_STATUS Status = AE_OK; 200 201 202 ACPI_FUNCTION_TRACE_PTR (DsBeginMethodExecution, MethodNode); 203 204 205 if (!MethodNode) 206 { 207 return_ACPI_STATUS (AE_NULL_ENTRY); 208 } 209 210 /* Prevent wraparound of thread count */ 211 212 if (ObjDesc->Method.ThreadCount == ACPI_UINT8_MAX) 213 { 214 ACPI_ERROR ((AE_INFO, 215 "Method reached maximum reentrancy limit (255)")); 216 return_ACPI_STATUS (AE_AML_METHOD_LIMIT); 217 } 218 219 /* 220 * If this method is serialized, we need to acquire the method mutex. 221 */ 222 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED) 223 { 224 /* 225 * Create a mutex for the method if it is defined to be Serialized 226 * and a mutex has not already been created. We defer the mutex creation 227 * until a method is actually executed, to minimize the object count 228 */ 229 if (!ObjDesc->Method.Mutex) 230 { 231 Status = AcpiDsCreateMethodMutex (ObjDesc); 232 if (ACPI_FAILURE (Status)) 233 { 234 return_ACPI_STATUS (Status); 235 } 236 } 237 238 /* 239 * The CurrentSyncLevel (per-thread) must be less than or equal to 240 * the sync level of the method. This mechanism provides some 241 * deadlock prevention 242 * 243 * Top-level method invocation has no walk state at this point 244 */ 245 if (WalkState && 246 (WalkState->Thread->CurrentSyncLevel > ObjDesc->Method.Mutex->Mutex.SyncLevel)) 247 { 248 ACPI_ERROR ((AE_INFO, 249 "Cannot acquire Mutex for method [%4.4s], current SyncLevel is too large (%u)", 250 AcpiUtGetNodeName (MethodNode), 251 WalkState->Thread->CurrentSyncLevel)); 252 253 return_ACPI_STATUS (AE_AML_MUTEX_ORDER); 254 } 255 256 /* 257 * Obtain the method mutex if necessary. Do not acquire mutex for a 258 * recursive call. 259 */ 260 if (!WalkState || 261 !ObjDesc->Method.Mutex->Mutex.ThreadId || 262 (WalkState->Thread->ThreadId != ObjDesc->Method.Mutex->Mutex.ThreadId)) 263 { 264 /* 265 * Acquire the method mutex. This releases the interpreter if we 266 * block (and reacquires it before it returns) 267 */ 268 Status = AcpiExSystemWaitMutex (ObjDesc->Method.Mutex->Mutex.OsMutex, 269 ACPI_WAIT_FOREVER); 270 if (ACPI_FAILURE (Status)) 271 { 272 return_ACPI_STATUS (Status); 273 } 274 275 /* Update the mutex and walk info and save the original SyncLevel */ 276 277 if (WalkState) 278 { 279 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 280 WalkState->Thread->CurrentSyncLevel; 281 282 ObjDesc->Method.Mutex->Mutex.ThreadId = WalkState->Thread->ThreadId; 283 WalkState->Thread->CurrentSyncLevel = ObjDesc->Method.SyncLevel; 284 } 285 else 286 { 287 ObjDesc->Method.Mutex->Mutex.OriginalSyncLevel = 288 ObjDesc->Method.Mutex->Mutex.SyncLevel; 289 } 290 } 291 292 /* Always increase acquisition depth */ 293 294 ObjDesc->Method.Mutex->Mutex.AcquisitionDepth++; 295 } 296 297 /* 298 * Allocate an Owner ID for this method, only if this is the first thread 299 * to begin concurrent execution. We only need one OwnerId, even if the 300 * method is invoked recursively. 301 */ 302 if (!ObjDesc->Method.OwnerId) 303 { 304 Status = AcpiUtAllocateOwnerId (&ObjDesc->Method.OwnerId); 305 if (ACPI_FAILURE (Status)) 306 { 307 goto Cleanup; 308 } 309 } 310 311 /* 312 * Increment the method parse tree thread count since it has been 313 * reentered one more time (even if it is the same thread) 314 */ 315 ObjDesc->Method.ThreadCount++; 316 AcpiMethodCount++; 317 return_ACPI_STATUS (Status); 318 319 320 Cleanup: 321 /* On error, must release the method mutex (if present) */ 322 323 if (ObjDesc->Method.Mutex) 324 { 325 AcpiOsReleaseMutex (ObjDesc->Method.Mutex->Mutex.OsMutex); 326 } 327 return_ACPI_STATUS (Status); 328 } 329 330 331 /******************************************************************************* 332 * 333 * FUNCTION: AcpiDsCallControlMethod 334 * 335 * PARAMETERS: Thread - Info for this thread 336 * ThisWalkState - Current walk state 337 * Op - Current Op to be walked 338 * 339 * RETURN: Status 340 * 341 * DESCRIPTION: Transfer execution to a called control method 342 * 343 ******************************************************************************/ 344 345 ACPI_STATUS 346 AcpiDsCallControlMethod ( 347 ACPI_THREAD_STATE *Thread, 348 ACPI_WALK_STATE *ThisWalkState, 349 ACPI_PARSE_OBJECT *Op) 350 { 351 ACPI_STATUS Status; 352 ACPI_NAMESPACE_NODE *MethodNode; 353 ACPI_WALK_STATE *NextWalkState = NULL; 354 ACPI_OPERAND_OBJECT *ObjDesc; 355 ACPI_EVALUATE_INFO *Info; 356 UINT32 i; 357 358 359 ACPI_FUNCTION_TRACE_PTR (DsCallControlMethod, ThisWalkState); 360 361 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, "Calling method %p, currentstate=%p\n", 362 ThisWalkState->PrevOp, ThisWalkState)); 363 364 /* 365 * Get the namespace entry for the control method we are about to call 366 */ 367 MethodNode = ThisWalkState->MethodCallNode; 368 if (!MethodNode) 369 { 370 return_ACPI_STATUS (AE_NULL_ENTRY); 371 } 372 373 ObjDesc = AcpiNsGetAttachedObject (MethodNode); 374 if (!ObjDesc) 375 { 376 return_ACPI_STATUS (AE_NULL_OBJECT); 377 } 378 379 /* Init for new method, possibly wait on method mutex */ 380 381 Status = AcpiDsBeginMethodExecution (MethodNode, ObjDesc, 382 ThisWalkState); 383 if (ACPI_FAILURE (Status)) 384 { 385 return_ACPI_STATUS (Status); 386 } 387 388 /* Begin method parse/execution. Create a new walk state */ 389 390 NextWalkState = AcpiDsCreateWalkState (ObjDesc->Method.OwnerId, 391 NULL, ObjDesc, Thread); 392 if (!NextWalkState) 393 { 394 Status = AE_NO_MEMORY; 395 goto Cleanup; 396 } 397 398 /* 399 * The resolved arguments were put on the previous walk state's operand 400 * stack. Operands on the previous walk state stack always 401 * start at index 0. Also, null terminate the list of arguments 402 */ 403 ThisWalkState->Operands [ThisWalkState->NumOperands] = NULL; 404 405 /* 406 * Allocate and initialize the evaluation information block 407 * TBD: this is somewhat inefficient, should change interface to 408 * DsInitAmlWalk. For now, keeps this struct off the CPU stack 409 */ 410 Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 411 if (!Info) 412 { 413 Status = AE_NO_MEMORY; 414 goto Cleanup; 415 } 416 417 Info->Parameters = &ThisWalkState->Operands[0]; 418 419 Status = AcpiDsInitAmlWalk (NextWalkState, NULL, MethodNode, 420 ObjDesc->Method.AmlStart, ObjDesc->Method.AmlLength, 421 Info, ACPI_IMODE_EXECUTE); 422 423 ACPI_FREE (Info); 424 if (ACPI_FAILURE (Status)) 425 { 426 goto Cleanup; 427 } 428 429 /* 430 * Delete the operands on the previous walkstate operand stack 431 * (they were copied to new objects) 432 */ 433 for (i = 0; i < ObjDesc->Method.ParamCount; i++) 434 { 435 AcpiUtRemoveReference (ThisWalkState->Operands [i]); 436 ThisWalkState->Operands [i] = NULL; 437 } 438 439 /* Clear the operand stack */ 440 441 ThisWalkState->NumOperands = 0; 442 443 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 444 "**** Begin nested execution of [%4.4s] **** WalkState=%p\n", 445 MethodNode->Name.Ascii, NextWalkState)); 446 447 /* Invoke an internal method if necessary */ 448 449 if (ObjDesc->Method.InfoFlags & ACPI_METHOD_INTERNAL_ONLY) 450 { 451 Status = ObjDesc->Method.Dispatch.Implementation (NextWalkState); 452 if (Status == AE_OK) 453 { 454 Status = AE_CTRL_TERMINATE; 455 } 456 } 457 458 return_ACPI_STATUS (Status); 459 460 461 Cleanup: 462 463 /* On error, we must terminate the method properly */ 464 465 AcpiDsTerminateControlMethod (ObjDesc, NextWalkState); 466 if (NextWalkState) 467 { 468 AcpiDsDeleteWalkState (NextWalkState); 469 } 470 471 return_ACPI_STATUS (Status); 472 } 473 474 475 /******************************************************************************* 476 * 477 * FUNCTION: AcpiDsRestartControlMethod 478 * 479 * PARAMETERS: WalkState - State for preempted method (caller) 480 * ReturnDesc - Return value from the called method 481 * 482 * RETURN: Status 483 * 484 * DESCRIPTION: Restart a method that was preempted by another (nested) method 485 * invocation. Handle the return value (if any) from the callee. 486 * 487 ******************************************************************************/ 488 489 ACPI_STATUS 490 AcpiDsRestartControlMethod ( 491 ACPI_WALK_STATE *WalkState, 492 ACPI_OPERAND_OBJECT *ReturnDesc) 493 { 494 ACPI_STATUS Status; 495 int SameAsImplicitReturn; 496 497 498 ACPI_FUNCTION_TRACE_PTR (DsRestartControlMethod, WalkState); 499 500 501 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 502 "****Restart [%4.4s] Op %p ReturnValueFromCallee %p\n", 503 AcpiUtGetNodeName (WalkState->MethodNode), 504 WalkState->MethodCallOp, ReturnDesc)); 505 506 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 507 " ReturnFromThisMethodUsed?=%X ResStack %p Walk %p\n", 508 WalkState->ReturnUsed, 509 WalkState->Results, WalkState)); 510 511 /* Did the called method return a value? */ 512 513 if (ReturnDesc) 514 { 515 /* Is the implicit return object the same as the return desc? */ 516 517 SameAsImplicitReturn = (WalkState->ImplicitReturnObj == ReturnDesc); 518 519 /* Are we actually going to use the return value? */ 520 521 if (WalkState->ReturnUsed) 522 { 523 /* Save the return value from the previous method */ 524 525 Status = AcpiDsResultPush (ReturnDesc, WalkState); 526 if (ACPI_FAILURE (Status)) 527 { 528 AcpiUtRemoveReference (ReturnDesc); 529 return_ACPI_STATUS (Status); 530 } 531 532 /* 533 * Save as THIS method's return value in case it is returned 534 * immediately to yet another method 535 */ 536 WalkState->ReturnDesc = ReturnDesc; 537 } 538 539 /* 540 * The following code is the optional support for the so-called 541 * "implicit return". Some AML code assumes that the last value of the 542 * method is "implicitly" returned to the caller, in the absence of an 543 * explicit return value. 544 * 545 * Just save the last result of the method as the return value. 546 * 547 * NOTE: this is optional because the ASL language does not actually 548 * support this behavior. 549 */ 550 else if (!AcpiDsDoImplicitReturn (ReturnDesc, WalkState, FALSE) || 551 SameAsImplicitReturn) 552 { 553 /* 554 * Delete the return value if it will not be used by the 555 * calling method or remove one reference if the explicit return 556 * is the same as the implicit return value. 557 */ 558 AcpiUtRemoveReference (ReturnDesc); 559 } 560 } 561 562 return_ACPI_STATUS (AE_OK); 563 } 564 565 566 /******************************************************************************* 567 * 568 * FUNCTION: AcpiDsTerminateControlMethod 569 * 570 * PARAMETERS: MethodDesc - Method object 571 * WalkState - State associated with the method 572 * 573 * RETURN: None 574 * 575 * DESCRIPTION: Terminate a control method. Delete everything that the method 576 * created, delete all locals and arguments, and delete the parse 577 * tree if requested. 578 * 579 * MUTEX: Interpreter is locked 580 * 581 ******************************************************************************/ 582 583 void 584 AcpiDsTerminateControlMethod ( 585 ACPI_OPERAND_OBJECT *MethodDesc, 586 ACPI_WALK_STATE *WalkState) 587 { 588 589 ACPI_FUNCTION_TRACE_PTR (DsTerminateControlMethod, WalkState); 590 591 592 /* MethodDesc is required, WalkState is optional */ 593 594 if (!MethodDesc) 595 { 596 return_VOID; 597 } 598 599 if (WalkState) 600 { 601 /* Delete all arguments and locals */ 602 603 AcpiDsMethodDataDeleteAll (WalkState); 604 605 /* 606 * If method is serialized, release the mutex and restore the 607 * current sync level for this thread 608 */ 609 if (MethodDesc->Method.Mutex) 610 { 611 /* Acquisition Depth handles recursive calls */ 612 613 MethodDesc->Method.Mutex->Mutex.AcquisitionDepth--; 614 if (!MethodDesc->Method.Mutex->Mutex.AcquisitionDepth) 615 { 616 WalkState->Thread->CurrentSyncLevel = 617 MethodDesc->Method.Mutex->Mutex.OriginalSyncLevel; 618 619 AcpiOsReleaseMutex (MethodDesc->Method.Mutex->Mutex.OsMutex); 620 MethodDesc->Method.Mutex->Mutex.ThreadId = 0; 621 } 622 } 623 624 /* 625 * Delete any namespace objects created anywhere within the 626 * namespace by the execution of this method. Unless: 627 * 1) This method is a module-level executable code method, in which 628 * case we want make the objects permanent. 629 * 2) There are other threads executing the method, in which case we 630 * will wait until the last thread has completed. 631 */ 632 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL) && 633 (MethodDesc->Method.ThreadCount == 1)) 634 { 635 /* Delete any direct children of (created by) this method */ 636 637 AcpiNsDeleteNamespaceSubtree (WalkState->MethodNode); 638 639 /* 640 * Delete any objects that were created by this method 641 * elsewhere in the namespace (if any were created). 642 * Use of the ACPI_METHOD_MODIFIED_NAMESPACE optimizes the 643 * deletion such that we don't have to perform an entire 644 * namespace walk for every control method execution. 645 */ 646 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_MODIFIED_NAMESPACE) 647 { 648 AcpiNsDeleteNamespaceByOwner (MethodDesc->Method.OwnerId); 649 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_MODIFIED_NAMESPACE; 650 } 651 } 652 } 653 654 /* Decrement the thread count on the method */ 655 656 if (MethodDesc->Method.ThreadCount) 657 { 658 MethodDesc->Method.ThreadCount--; 659 } 660 else 661 { 662 ACPI_ERROR ((AE_INFO, 663 "Invalid zero thread count in method")); 664 } 665 666 /* Are there any other threads currently executing this method? */ 667 668 if (MethodDesc->Method.ThreadCount) 669 { 670 /* 671 * Additional threads. Do not release the OwnerId in this case, 672 * we immediately reuse it for the next thread executing this method 673 */ 674 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH, 675 "*** Completed execution of one thread, %u threads remaining\n", 676 MethodDesc->Method.ThreadCount)); 677 } 678 else 679 { 680 /* This is the only executing thread for this method */ 681 682 /* 683 * Support to dynamically change a method from NotSerialized to 684 * Serialized if it appears that the method is incorrectly written and 685 * does not support multiple thread execution. The best example of this 686 * is if such a method creates namespace objects and blocks. A second 687 * thread will fail with an AE_ALREADY_EXISTS exception. 688 * 689 * This code is here because we must wait until the last thread exits 690 * before marking the method as serialized. 691 */ 692 if (MethodDesc->Method.InfoFlags & ACPI_METHOD_SERIALIZED_PENDING) 693 { 694 if (WalkState) 695 { 696 ACPI_INFO ((AE_INFO, 697 "Marking method %4.4s as Serialized because of AE_ALREADY_EXISTS error", 698 WalkState->MethodNode->Name.Ascii)); 699 } 700 701 /* 702 * Method tried to create an object twice and was marked as 703 * "pending serialized". The probable cause is that the method 704 * cannot handle reentrancy. 705 * 706 * The method was created as NotSerialized, but it tried to create 707 * a named object and then blocked, causing the second thread 708 * entrance to begin and then fail. Workaround this problem by 709 * marking the method permanently as Serialized when the last 710 * thread exits here. 711 */ 712 MethodDesc->Method.InfoFlags &= ~ACPI_METHOD_SERIALIZED_PENDING; 713 MethodDesc->Method.InfoFlags |= ACPI_METHOD_SERIALIZED; 714 MethodDesc->Method.SyncLevel = 0; 715 } 716 717 /* No more threads, we can free the OwnerId */ 718 719 if (!(MethodDesc->Method.InfoFlags & ACPI_METHOD_MODULE_LEVEL)) 720 { 721 AcpiUtReleaseOwnerId (&MethodDesc->Method.OwnerId); 722 } 723 } 724 725 return_VOID; 726 }