1 /****************************************************************************** 2 * 3 * Module Name: evregion - ACPI AddressSpace (OpRegion) handler dispatch 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2012, 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 45 #define __EVREGION_C__ 46 47 #include <contrib/dev/acpica/include/acpi.h> 48 #include <contrib/dev/acpica/include/accommon.h> 49 #include <contrib/dev/acpica/include/acevents.h> 50 #include <contrib/dev/acpica/include/acnamesp.h> 51 #include <contrib/dev/acpica/include/acinterp.h> 52 53 #define _COMPONENT ACPI_EVENTS 54 ACPI_MODULE_NAME ("evregion") 55 56 57 /* Local prototypes */ 58 59 static BOOLEAN 60 AcpiEvHasDefaultHandler ( 61 ACPI_NAMESPACE_NODE *Node, 62 ACPI_ADR_SPACE_TYPE SpaceId); 63 64 static void 65 AcpiEvOrphanEcRegMethod ( 66 void); 67 68 static ACPI_STATUS 69 AcpiEvRegRun ( 70 ACPI_HANDLE ObjHandle, 71 UINT32 Level, 72 void *Context, 73 void **ReturnValue); 74 75 static ACPI_STATUS 76 AcpiEvInstallHandler ( 77 ACPI_HANDLE ObjHandle, 78 UINT32 Level, 79 void *Context, 80 void **ReturnValue); 81 82 /* These are the address spaces that will get default handlers */ 83 84 #define ACPI_NUM_DEFAULT_SPACES 4 85 86 static UINT8 AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] = 87 { 88 ACPI_ADR_SPACE_SYSTEM_MEMORY, 89 ACPI_ADR_SPACE_SYSTEM_IO, 90 ACPI_ADR_SPACE_PCI_CONFIG, 91 ACPI_ADR_SPACE_DATA_TABLE 92 }; 93 94 95 /******************************************************************************* 96 * 97 * FUNCTION: AcpiEvInstallRegionHandlers 98 * 99 * PARAMETERS: None 100 * 101 * RETURN: Status 102 * 103 * DESCRIPTION: Installs the core subsystem default address space handlers. 104 * 105 ******************************************************************************/ 106 107 ACPI_STATUS 108 AcpiEvInstallRegionHandlers ( 109 void) 110 { 111 ACPI_STATUS Status; 112 UINT32 i; 113 114 115 ACPI_FUNCTION_TRACE (EvInstallRegionHandlers); 116 117 118 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 119 if (ACPI_FAILURE (Status)) 120 { 121 return_ACPI_STATUS (Status); 122 } 123 124 /* 125 * All address spaces (PCI Config, EC, SMBus) are scope dependent and 126 * registration must occur for a specific device. 127 * 128 * In the case of the system memory and IO address spaces there is 129 * currently no device associated with the address space. For these we 130 * use the root. 131 * 132 * We install the default PCI config space handler at the root so that 133 * this space is immediately available even though the we have not 134 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI 135 * specification which states that the PCI config space must be always 136 * available -- even though we are nowhere near ready to find the PCI root 137 * buses at this point. 138 * 139 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler 140 * has already been installed (via AcpiInstallAddressSpaceHandler). 141 * Similar for AE_SAME_HANDLER. 142 */ 143 for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) 144 { 145 Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode, 146 AcpiGbl_DefaultAddressSpaces[i], 147 ACPI_DEFAULT_HANDLER, NULL, NULL); 148 switch (Status) 149 { 150 case AE_OK: 151 case AE_SAME_HANDLER: 152 case AE_ALREADY_EXISTS: 153 154 /* These exceptions are all OK */ 155 156 Status = AE_OK; 157 break; 158 159 default: 160 161 goto UnlockAndExit; 162 } 163 } 164 165 UnlockAndExit: 166 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 167 return_ACPI_STATUS (Status); 168 } 169 170 171 /******************************************************************************* 172 * 173 * FUNCTION: AcpiEvHasDefaultHandler 174 * 175 * PARAMETERS: Node - Namespace node for the device 176 * SpaceId - The address space ID 177 * 178 * RETURN: TRUE if default handler is installed, FALSE otherwise 179 * 180 * DESCRIPTION: Check if the default handler is installed for the requested 181 * space ID. 182 * 183 ******************************************************************************/ 184 185 static BOOLEAN 186 AcpiEvHasDefaultHandler ( 187 ACPI_NAMESPACE_NODE *Node, 188 ACPI_ADR_SPACE_TYPE SpaceId) 189 { 190 ACPI_OPERAND_OBJECT *ObjDesc; 191 ACPI_OPERAND_OBJECT *HandlerObj; 192 193 194 /* Must have an existing internal object */ 195 196 ObjDesc = AcpiNsGetAttachedObject (Node); 197 if (ObjDesc) 198 { 199 HandlerObj = ObjDesc->Device.Handler; 200 201 /* Walk the linked list of handlers for this object */ 202 203 while (HandlerObj) 204 { 205 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 206 { 207 if (HandlerObj->AddressSpace.HandlerFlags & 208 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) 209 { 210 return (TRUE); 211 } 212 } 213 214 HandlerObj = HandlerObj->AddressSpace.Next; 215 } 216 } 217 218 return (FALSE); 219 } 220 221 222 /******************************************************************************* 223 * 224 * FUNCTION: AcpiEvInitializeOpRegions 225 * 226 * PARAMETERS: None 227 * 228 * RETURN: Status 229 * 230 * DESCRIPTION: Execute _REG methods for all Operation Regions that have 231 * an installed default region handler. 232 * 233 ******************************************************************************/ 234 235 ACPI_STATUS 236 AcpiEvInitializeOpRegions ( 237 void) 238 { 239 ACPI_STATUS Status; 240 UINT32 i; 241 242 243 ACPI_FUNCTION_TRACE (EvInitializeOpRegions); 244 245 246 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 247 if (ACPI_FAILURE (Status)) 248 { 249 return_ACPI_STATUS (Status); 250 } 251 252 /* Run the _REG methods for OpRegions in each default address space */ 253 254 for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) 255 { 256 /* 257 * Make sure the installed handler is the DEFAULT handler. If not the 258 * default, the _REG methods will have already been run (when the 259 * handler was installed) 260 */ 261 if (AcpiEvHasDefaultHandler (AcpiGbl_RootNode, 262 AcpiGbl_DefaultAddressSpaces[i])) 263 { 264 Status = AcpiEvExecuteRegMethods (AcpiGbl_RootNode, 265 AcpiGbl_DefaultAddressSpaces[i]); 266 } 267 } 268 269 AcpiGbl_RegMethodsExecuted = TRUE; 270 271 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 272 return_ACPI_STATUS (Status); 273 } 274 275 276 /******************************************************************************* 277 * 278 * FUNCTION: AcpiEvExecuteRegMethod 279 * 280 * PARAMETERS: RegionObj - Region object 281 * Function - Passed to _REG: On (1) or Off (0) 282 * 283 * RETURN: Status 284 * 285 * DESCRIPTION: Execute _REG method for a region 286 * 287 ******************************************************************************/ 288 289 ACPI_STATUS 290 AcpiEvExecuteRegMethod ( 291 ACPI_OPERAND_OBJECT *RegionObj, 292 UINT32 Function) 293 { 294 ACPI_EVALUATE_INFO *Info; 295 ACPI_OPERAND_OBJECT *Args[3]; 296 ACPI_OPERAND_OBJECT *RegionObj2; 297 ACPI_STATUS Status; 298 299 300 ACPI_FUNCTION_TRACE (EvExecuteRegMethod); 301 302 303 RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); 304 if (!RegionObj2) 305 { 306 return_ACPI_STATUS (AE_NOT_EXIST); 307 } 308 309 if (RegionObj2->Extra.Method_REG == NULL) 310 { 311 return_ACPI_STATUS (AE_OK); 312 } 313 314 /* Allocate and initialize the evaluation information block */ 315 316 Info = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EVALUATE_INFO)); 317 if (!Info) 318 { 319 return_ACPI_STATUS (AE_NO_MEMORY); 320 } 321 322 Info->PrefixNode = RegionObj2->Extra.Method_REG; 323 Info->Pathname = NULL; 324 Info->Parameters = Args; 325 Info->Flags = ACPI_IGNORE_RETURN_VALUE; 326 327 /* 328 * The _REG method has two arguments: 329 * 330 * Arg0 - Integer: 331 * Operation region space ID Same value as RegionObj->Region.SpaceId 332 * 333 * Arg1 - Integer: 334 * connection status 1 for connecting the handler, 0 for disconnecting 335 * the handler (Passed as a parameter) 336 */ 337 Args[0] = AcpiUtCreateIntegerObject ((UINT64) RegionObj->Region.SpaceId); 338 if (!Args[0]) 339 { 340 Status = AE_NO_MEMORY; 341 goto Cleanup1; 342 } 343 344 Args[1] = AcpiUtCreateIntegerObject ((UINT64) Function); 345 if (!Args[1]) 346 { 347 Status = AE_NO_MEMORY; 348 goto Cleanup2; 349 } 350 351 Args[2] = NULL; /* Terminate list */ 352 353 /* Execute the method, no return value */ 354 355 ACPI_DEBUG_EXEC ( 356 AcpiUtDisplayInitPathname (ACPI_TYPE_METHOD, Info->PrefixNode, NULL)); 357 358 Status = AcpiNsEvaluate (Info); 359 AcpiUtRemoveReference (Args[1]); 360 361 Cleanup2: 362 AcpiUtRemoveReference (Args[0]); 363 364 Cleanup1: 365 ACPI_FREE (Info); 366 return_ACPI_STATUS (Status); 367 } 368 369 370 /******************************************************************************* 371 * 372 * FUNCTION: AcpiEvAddressSpaceDispatch 373 * 374 * PARAMETERS: RegionObj - Internal region object 375 * FieldObj - Corresponding field. Can be NULL. 376 * Function - Read or Write operation 377 * RegionOffset - Where in the region to read or write 378 * BitWidth - Field width in bits (8, 16, 32, or 64) 379 * Value - Pointer to in or out value, must be 380 * a full 64-bit integer 381 * 382 * RETURN: Status 383 * 384 * DESCRIPTION: Dispatch an address space or operation region access to 385 * a previously installed handler. 386 * 387 ******************************************************************************/ 388 389 ACPI_STATUS 390 AcpiEvAddressSpaceDispatch ( 391 ACPI_OPERAND_OBJECT *RegionObj, 392 ACPI_OPERAND_OBJECT *FieldObj, 393 UINT32 Function, 394 UINT32 RegionOffset, 395 UINT32 BitWidth, 396 UINT64 *Value) 397 { 398 ACPI_STATUS Status; 399 ACPI_ADR_SPACE_HANDLER Handler; 400 ACPI_ADR_SPACE_SETUP RegionSetup; 401 ACPI_OPERAND_OBJECT *HandlerDesc; 402 ACPI_OPERAND_OBJECT *RegionObj2; 403 void *RegionContext = NULL; 404 ACPI_CONNECTION_INFO *Context; 405 406 407 ACPI_FUNCTION_TRACE (EvAddressSpaceDispatch); 408 409 410 RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); 411 if (!RegionObj2) 412 { 413 return_ACPI_STATUS (AE_NOT_EXIST); 414 } 415 416 /* Ensure that there is a handler associated with this region */ 417 418 HandlerDesc = RegionObj->Region.Handler; 419 if (!HandlerDesc) 420 { 421 ACPI_ERROR ((AE_INFO, 422 "No handler for Region [%4.4s] (%p) [%s]", 423 AcpiUtGetNodeName (RegionObj->Region.Node), 424 RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 425 426 return_ACPI_STATUS (AE_NOT_EXIST); 427 } 428 429 Context = HandlerDesc->AddressSpace.Context; 430 431 /* 432 * It may be the case that the region has never been initialized. 433 * Some types of regions require special init code 434 */ 435 if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) 436 { 437 /* This region has not been initialized yet, do it */ 438 439 RegionSetup = HandlerDesc->AddressSpace.Setup; 440 if (!RegionSetup) 441 { 442 /* No initialization routine, exit with error */ 443 444 ACPI_ERROR ((AE_INFO, 445 "No init routine for region(%p) [%s]", 446 RegionObj, AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 447 return_ACPI_STATUS (AE_NOT_EXIST); 448 } 449 450 /* 451 * We must exit the interpreter because the region setup will 452 * potentially execute control methods (for example, the _REG method 453 * for this region) 454 */ 455 AcpiExExitInterpreter (); 456 457 Status = RegionSetup (RegionObj, ACPI_REGION_ACTIVATE, 458 Context, &RegionContext); 459 460 /* Re-enter the interpreter */ 461 462 AcpiExEnterInterpreter (); 463 464 /* Check for failure of the Region Setup */ 465 466 if (ACPI_FAILURE (Status)) 467 { 468 ACPI_EXCEPTION ((AE_INFO, Status, 469 "During region initialization: [%s]", 470 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 471 return_ACPI_STATUS (Status); 472 } 473 474 /* Region initialization may have been completed by RegionSetup */ 475 476 if (!(RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE)) 477 { 478 RegionObj->Region.Flags |= AOPOBJ_SETUP_COMPLETE; 479 480 if (RegionObj2->Extra.RegionContext) 481 { 482 /* The handler for this region was already installed */ 483 484 ACPI_FREE (RegionContext); 485 } 486 else 487 { 488 /* 489 * Save the returned context for use in all accesses to 490 * this particular region 491 */ 492 RegionObj2->Extra.RegionContext = RegionContext; 493 } 494 } 495 } 496 497 /* We have everything we need, we can invoke the address space handler */ 498 499 Handler = HandlerDesc->AddressSpace.Handler; 500 501 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 502 "Handler %p (@%p) Address %8.8X%8.8X [%s]\n", 503 &RegionObj->Region.Handler->AddressSpace, Handler, 504 ACPI_FORMAT_NATIVE_UINT (RegionObj->Region.Address + RegionOffset), 505 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 506 507 508 /* 509 * Special handling for GenericSerialBus and GeneralPurposeIo: 510 * There are three extra parameters that must be passed to the 511 * handler via the context: 512 * 1) Connection buffer, a resource template from Connection() op. 513 * 2) Length of the above buffer. 514 * 3) Actual access length from the AccessAs() op. 515 */ 516 if (((RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) || 517 (RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GPIO)) && 518 Context && 519 FieldObj) 520 { 521 /* Get the Connection (ResourceTemplate) buffer */ 522 523 Context->Connection = FieldObj->Field.ResourceBuffer; 524 Context->Length = FieldObj->Field.ResourceLength; 525 Context->AccessLength = FieldObj->Field.AccessLength; 526 } 527 528 if (!(HandlerDesc->AddressSpace.HandlerFlags & 529 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) 530 { 531 /* 532 * For handlers other than the default (supplied) handlers, we must 533 * exit the interpreter because the handler *might* block -- we don't 534 * know what it will do, so we can't hold the lock on the intepreter. 535 */ 536 AcpiExExitInterpreter(); 537 } 538 539 /* Call the handler */ 540 541 Status = Handler (Function, 542 (RegionObj->Region.Address + RegionOffset), BitWidth, Value, 543 Context, RegionObj2->Extra.RegionContext); 544 545 if (ACPI_FAILURE (Status)) 546 { 547 ACPI_EXCEPTION ((AE_INFO, Status, "Returned by Handler for [%s]", 548 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 549 } 550 551 if (!(HandlerDesc->AddressSpace.HandlerFlags & 552 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED)) 553 { 554 /* 555 * We just returned from a non-default handler, we must re-enter the 556 * interpreter 557 */ 558 AcpiExEnterInterpreter (); 559 } 560 561 return_ACPI_STATUS (Status); 562 } 563 564 565 /******************************************************************************* 566 * 567 * FUNCTION: AcpiEvDetachRegion 568 * 569 * PARAMETERS: RegionObj - Region Object 570 * AcpiNsIsLocked - Namespace Region Already Locked? 571 * 572 * RETURN: None 573 * 574 * DESCRIPTION: Break the association between the handler and the region 575 * this is a two way association. 576 * 577 ******************************************************************************/ 578 579 void 580 AcpiEvDetachRegion( 581 ACPI_OPERAND_OBJECT *RegionObj, 582 BOOLEAN AcpiNsIsLocked) 583 { 584 ACPI_OPERAND_OBJECT *HandlerObj; 585 ACPI_OPERAND_OBJECT *ObjDesc; 586 ACPI_OPERAND_OBJECT **LastObjPtr; 587 ACPI_ADR_SPACE_SETUP RegionSetup; 588 void **RegionContext; 589 ACPI_OPERAND_OBJECT *RegionObj2; 590 ACPI_STATUS Status; 591 592 593 ACPI_FUNCTION_TRACE (EvDetachRegion); 594 595 596 RegionObj2 = AcpiNsGetSecondaryObject (RegionObj); 597 if (!RegionObj2) 598 { 599 return_VOID; 600 } 601 RegionContext = &RegionObj2->Extra.RegionContext; 602 603 /* Get the address handler from the region object */ 604 605 HandlerObj = RegionObj->Region.Handler; 606 if (!HandlerObj) 607 { 608 /* This region has no handler, all done */ 609 610 return_VOID; 611 } 612 613 /* Find this region in the handler's list */ 614 615 ObjDesc = HandlerObj->AddressSpace.RegionList; 616 LastObjPtr = &HandlerObj->AddressSpace.RegionList; 617 618 while (ObjDesc) 619 { 620 /* Is this the correct Region? */ 621 622 if (ObjDesc == RegionObj) 623 { 624 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 625 "Removing Region %p from address handler %p\n", 626 RegionObj, HandlerObj)); 627 628 /* This is it, remove it from the handler's list */ 629 630 *LastObjPtr = ObjDesc->Region.Next; 631 ObjDesc->Region.Next = NULL; /* Must clear field */ 632 633 if (AcpiNsIsLocked) 634 { 635 Status = AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 636 if (ACPI_FAILURE (Status)) 637 { 638 return_VOID; 639 } 640 } 641 642 /* Now stop region accesses by executing the _REG method */ 643 644 Status = AcpiEvExecuteRegMethod (RegionObj, ACPI_REG_DISCONNECT); 645 if (ACPI_FAILURE (Status)) 646 { 647 ACPI_EXCEPTION ((AE_INFO, Status, "from region _REG, [%s]", 648 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 649 } 650 651 if (AcpiNsIsLocked) 652 { 653 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 654 if (ACPI_FAILURE (Status)) 655 { 656 return_VOID; 657 } 658 } 659 660 /* 661 * If the region has been activated, call the setup handler with 662 * the deactivate notification 663 */ 664 if (RegionObj->Region.Flags & AOPOBJ_SETUP_COMPLETE) 665 { 666 RegionSetup = HandlerObj->AddressSpace.Setup; 667 Status = RegionSetup (RegionObj, ACPI_REGION_DEACTIVATE, 668 HandlerObj->AddressSpace.Context, RegionContext); 669 670 /* Init routine may fail, Just ignore errors */ 671 672 if (ACPI_FAILURE (Status)) 673 { 674 ACPI_EXCEPTION ((AE_INFO, Status, 675 "from region handler - deactivate, [%s]", 676 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 677 } 678 679 RegionObj->Region.Flags &= ~(AOPOBJ_SETUP_COMPLETE); 680 } 681 682 /* 683 * Remove handler reference in the region 684 * 685 * NOTE: this doesn't mean that the region goes away, the region 686 * is just inaccessible as indicated to the _REG method 687 * 688 * If the region is on the handler's list, this must be the 689 * region's handler 690 */ 691 RegionObj->Region.Handler = NULL; 692 AcpiUtRemoveReference (HandlerObj); 693 694 return_VOID; 695 } 696 697 /* Walk the linked list of handlers */ 698 699 LastObjPtr = &ObjDesc->Region.Next; 700 ObjDesc = ObjDesc->Region.Next; 701 } 702 703 /* If we get here, the region was not in the handler's region list */ 704 705 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 706 "Cannot remove region %p from address handler %p\n", 707 RegionObj, HandlerObj)); 708 709 return_VOID; 710 } 711 712 713 /******************************************************************************* 714 * 715 * FUNCTION: AcpiEvAttachRegion 716 * 717 * PARAMETERS: HandlerObj - Handler Object 718 * RegionObj - Region Object 719 * AcpiNsIsLocked - Namespace Region Already Locked? 720 * 721 * RETURN: None 722 * 723 * DESCRIPTION: Create the association between the handler and the region 724 * this is a two way association. 725 * 726 ******************************************************************************/ 727 728 ACPI_STATUS 729 AcpiEvAttachRegion ( 730 ACPI_OPERAND_OBJECT *HandlerObj, 731 ACPI_OPERAND_OBJECT *RegionObj, 732 BOOLEAN AcpiNsIsLocked) 733 { 734 735 ACPI_FUNCTION_TRACE (EvAttachRegion); 736 737 738 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 739 "Adding Region [%4.4s] %p to address handler %p [%s]\n", 740 AcpiUtGetNodeName (RegionObj->Region.Node), 741 RegionObj, HandlerObj, 742 AcpiUtGetRegionName (RegionObj->Region.SpaceId))); 743 744 /* Link this region to the front of the handler's list */ 745 746 RegionObj->Region.Next = HandlerObj->AddressSpace.RegionList; 747 HandlerObj->AddressSpace.RegionList = RegionObj; 748 749 /* Install the region's handler */ 750 751 if (RegionObj->Region.Handler) 752 { 753 return_ACPI_STATUS (AE_ALREADY_EXISTS); 754 } 755 756 RegionObj->Region.Handler = HandlerObj; 757 AcpiUtAddReference (HandlerObj); 758 759 return_ACPI_STATUS (AE_OK); 760 } 761 762 763 /******************************************************************************* 764 * 765 * FUNCTION: AcpiEvInstallHandler 766 * 767 * PARAMETERS: WalkNamespace callback 768 * 769 * DESCRIPTION: This routine installs an address handler into objects that are 770 * of type Region or Device. 771 * 772 * If the Object is a Device, and the device has a handler of 773 * the same type then the search is terminated in that branch. 774 * 775 * This is because the existing handler is closer in proximity 776 * to any more regions than the one we are trying to install. 777 * 778 ******************************************************************************/ 779 780 static ACPI_STATUS 781 AcpiEvInstallHandler ( 782 ACPI_HANDLE ObjHandle, 783 UINT32 Level, 784 void *Context, 785 void **ReturnValue) 786 { 787 ACPI_OPERAND_OBJECT *HandlerObj; 788 ACPI_OPERAND_OBJECT *NextHandlerObj; 789 ACPI_OPERAND_OBJECT *ObjDesc; 790 ACPI_NAMESPACE_NODE *Node; 791 ACPI_STATUS Status; 792 793 794 ACPI_FUNCTION_NAME (EvInstallHandler); 795 796 797 HandlerObj = (ACPI_OPERAND_OBJECT *) Context; 798 799 /* Parameter validation */ 800 801 if (!HandlerObj) 802 { 803 return (AE_OK); 804 } 805 806 /* Convert and validate the device handle */ 807 808 Node = AcpiNsValidateHandle (ObjHandle); 809 if (!Node) 810 { 811 return (AE_BAD_PARAMETER); 812 } 813 814 /* 815 * We only care about regions and objects that are allowed to have 816 * address space handlers 817 */ 818 if ((Node->Type != ACPI_TYPE_DEVICE) && 819 (Node->Type != ACPI_TYPE_REGION) && 820 (Node != AcpiGbl_RootNode)) 821 { 822 return (AE_OK); 823 } 824 825 /* Check for an existing internal object */ 826 827 ObjDesc = AcpiNsGetAttachedObject (Node); 828 if (!ObjDesc) 829 { 830 /* No object, just exit */ 831 832 return (AE_OK); 833 } 834 835 /* Devices are handled different than regions */ 836 837 if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE) 838 { 839 /* Check if this Device already has a handler for this address space */ 840 841 NextHandlerObj = ObjDesc->Device.Handler; 842 while (NextHandlerObj) 843 { 844 /* Found a handler, is it for the same address space? */ 845 846 if (NextHandlerObj->AddressSpace.SpaceId == 847 HandlerObj->AddressSpace.SpaceId) 848 { 849 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 850 "Found handler for region [%s] in device %p(%p) " 851 "handler %p\n", 852 AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId), 853 ObjDesc, NextHandlerObj, HandlerObj)); 854 855 /* 856 * Since the object we found it on was a device, then it 857 * means that someone has already installed a handler for 858 * the branch of the namespace from this device on. Just 859 * bail out telling the walk routine to not traverse this 860 * branch. This preserves the scoping rule for handlers. 861 */ 862 return (AE_CTRL_DEPTH); 863 } 864 865 /* Walk the linked list of handlers attached to this device */ 866 867 NextHandlerObj = NextHandlerObj->AddressSpace.Next; 868 } 869 870 /* 871 * As long as the device didn't have a handler for this space we 872 * don't care about it. We just ignore it and proceed. 873 */ 874 return (AE_OK); 875 } 876 877 /* Object is a Region */ 878 879 if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId) 880 { 881 /* This region is for a different address space, just ignore it */ 882 883 return (AE_OK); 884 } 885 886 /* 887 * Now we have a region and it is for the handler's address space type. 888 * 889 * First disconnect region for any previous handler (if any) 890 */ 891 AcpiEvDetachRegion (ObjDesc, FALSE); 892 893 /* Connect the region to the new handler */ 894 895 Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE); 896 return (Status); 897 } 898 899 900 /******************************************************************************* 901 * 902 * FUNCTION: AcpiEvInstallSpaceHandler 903 * 904 * PARAMETERS: Node - Namespace node for the device 905 * SpaceId - The address space ID 906 * Handler - Address of the handler 907 * Setup - Address of the setup function 908 * Context - Value passed to the handler on each access 909 * 910 * RETURN: Status 911 * 912 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. 913 * Assumes namespace is locked 914 * 915 ******************************************************************************/ 916 917 ACPI_STATUS 918 AcpiEvInstallSpaceHandler ( 919 ACPI_NAMESPACE_NODE *Node, 920 ACPI_ADR_SPACE_TYPE SpaceId, 921 ACPI_ADR_SPACE_HANDLER Handler, 922 ACPI_ADR_SPACE_SETUP Setup, 923 void *Context) 924 { 925 ACPI_OPERAND_OBJECT *ObjDesc; 926 ACPI_OPERAND_OBJECT *HandlerObj; 927 ACPI_STATUS Status; 928 ACPI_OBJECT_TYPE Type; 929 UINT8 Flags = 0; 930 931 932 ACPI_FUNCTION_TRACE (EvInstallSpaceHandler); 933 934 935 /* 936 * This registration is valid for only the types below and the root. This 937 * is where the default handlers get placed. 938 */ 939 if ((Node->Type != ACPI_TYPE_DEVICE) && 940 (Node->Type != ACPI_TYPE_PROCESSOR) && 941 (Node->Type != ACPI_TYPE_THERMAL) && 942 (Node != AcpiGbl_RootNode)) 943 { 944 Status = AE_BAD_PARAMETER; 945 goto UnlockAndExit; 946 } 947 948 if (Handler == ACPI_DEFAULT_HANDLER) 949 { 950 Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; 951 952 switch (SpaceId) 953 { 954 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 955 Handler = AcpiExSystemMemorySpaceHandler; 956 Setup = AcpiEvSystemMemoryRegionSetup; 957 break; 958 959 case ACPI_ADR_SPACE_SYSTEM_IO: 960 Handler = AcpiExSystemIoSpaceHandler; 961 Setup = AcpiEvIoSpaceRegionSetup; 962 break; 963 964 case ACPI_ADR_SPACE_PCI_CONFIG: 965 Handler = AcpiExPciConfigSpaceHandler; 966 Setup = AcpiEvPciConfigRegionSetup; 967 break; 968 969 case ACPI_ADR_SPACE_CMOS: 970 Handler = AcpiExCmosSpaceHandler; 971 Setup = AcpiEvCmosRegionSetup; 972 break; 973 974 case ACPI_ADR_SPACE_PCI_BAR_TARGET: 975 Handler = AcpiExPciBarSpaceHandler; 976 Setup = AcpiEvPciBarRegionSetup; 977 break; 978 979 case ACPI_ADR_SPACE_DATA_TABLE: 980 Handler = AcpiExDataTableSpaceHandler; 981 Setup = NULL; 982 break; 983 984 default: 985 Status = AE_BAD_PARAMETER; 986 goto UnlockAndExit; 987 } 988 } 989 990 /* If the caller hasn't specified a setup routine, use the default */ 991 992 if (!Setup) 993 { 994 Setup = AcpiEvDefaultRegionSetup; 995 } 996 997 /* Check for an existing internal object */ 998 999 ObjDesc = AcpiNsGetAttachedObject (Node); 1000 if (ObjDesc) 1001 { 1002 /* 1003 * The attached device object already exists. Make sure the handler 1004 * is not already installed. 1005 */ 1006 HandlerObj = ObjDesc->Device.Handler; 1007 1008 /* Walk the handler list for this device */ 1009 1010 while (HandlerObj) 1011 { 1012 /* Same SpaceId indicates a handler already installed */ 1013 1014 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 1015 { 1016 if (HandlerObj->AddressSpace.Handler == Handler) 1017 { 1018 /* 1019 * It is (relatively) OK to attempt to install the SAME 1020 * handler twice. This can easily happen with the 1021 * PCI_Config space. 1022 */ 1023 Status = AE_SAME_HANDLER; 1024 goto UnlockAndExit; 1025 } 1026 else 1027 { 1028 /* A handler is already installed */ 1029 1030 Status = AE_ALREADY_EXISTS; 1031 } 1032 goto UnlockAndExit; 1033 } 1034 1035 /* Walk the linked list of handlers */ 1036 1037 HandlerObj = HandlerObj->AddressSpace.Next; 1038 } 1039 } 1040 else 1041 { 1042 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 1043 "Creating object on Device %p while installing handler\n", Node)); 1044 1045 /* ObjDesc does not exist, create one */ 1046 1047 if (Node->Type == ACPI_TYPE_ANY) 1048 { 1049 Type = ACPI_TYPE_DEVICE; 1050 } 1051 else 1052 { 1053 Type = Node->Type; 1054 } 1055 1056 ObjDesc = AcpiUtCreateInternalObject (Type); 1057 if (!ObjDesc) 1058 { 1059 Status = AE_NO_MEMORY; 1060 goto UnlockAndExit; 1061 } 1062 1063 /* Init new descriptor */ 1064 1065 ObjDesc->Common.Type = (UINT8) Type; 1066 1067 /* Attach the new object to the Node */ 1068 1069 Status = AcpiNsAttachObject (Node, ObjDesc, Type); 1070 1071 /* Remove local reference to the object */ 1072 1073 AcpiUtRemoveReference (ObjDesc); 1074 1075 if (ACPI_FAILURE (Status)) 1076 { 1077 goto UnlockAndExit; 1078 } 1079 } 1080 1081 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 1082 "Installing address handler for region %s(%X) on Device %4.4s %p(%p)\n", 1083 AcpiUtGetRegionName (SpaceId), SpaceId, 1084 AcpiUtGetNodeName (Node), Node, ObjDesc)); 1085 1086 /* 1087 * Install the handler 1088 * 1089 * At this point there is no existing handler. Just allocate the object 1090 * for the handler and link it into the list. 1091 */ 1092 HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); 1093 if (!HandlerObj) 1094 { 1095 Status = AE_NO_MEMORY; 1096 goto UnlockAndExit; 1097 } 1098 1099 /* Init handler obj */ 1100 1101 HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId; 1102 HandlerObj->AddressSpace.HandlerFlags = Flags; 1103 HandlerObj->AddressSpace.RegionList = NULL; 1104 HandlerObj->AddressSpace.Node = Node; 1105 HandlerObj->AddressSpace.Handler = Handler; 1106 HandlerObj->AddressSpace.Context = Context; 1107 HandlerObj->AddressSpace.Setup = Setup; 1108 1109 /* Install at head of Device.AddressSpace list */ 1110 1111 HandlerObj->AddressSpace.Next = ObjDesc->Device.Handler; 1112 1113 /* 1114 * The Device object is the first reference on the HandlerObj. 1115 * Each region that uses the handler adds a reference. 1116 */ 1117 ObjDesc->Device.Handler = HandlerObj; 1118 1119 /* 1120 * Walk the namespace finding all of the regions this 1121 * handler will manage. 1122 * 1123 * Start at the device and search the branch toward 1124 * the leaf nodes until either the leaf is encountered or 1125 * a device is detected that has an address handler of the 1126 * same type. 1127 * 1128 * In either case, back up and search down the remainder 1129 * of the branch 1130 */ 1131 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX, 1132 ACPI_NS_WALK_UNLOCK, AcpiEvInstallHandler, NULL, 1133 HandlerObj, NULL); 1134 1135 UnlockAndExit: 1136 return_ACPI_STATUS (Status); 1137 } 1138 1139 1140 /******************************************************************************* 1141 * 1142 * FUNCTION: AcpiEvExecuteRegMethods 1143 * 1144 * PARAMETERS: Node - Namespace node for the device 1145 * SpaceId - The address space ID 1146 * 1147 * RETURN: Status 1148 * 1149 * DESCRIPTION: Run all _REG methods for the input Space ID; 1150 * Note: assumes namespace is locked, or system init time. 1151 * 1152 ******************************************************************************/ 1153 1154 ACPI_STATUS 1155 AcpiEvExecuteRegMethods ( 1156 ACPI_NAMESPACE_NODE *Node, 1157 ACPI_ADR_SPACE_TYPE SpaceId) 1158 { 1159 ACPI_STATUS Status; 1160 1161 1162 ACPI_FUNCTION_TRACE (EvExecuteRegMethods); 1163 1164 1165 /* 1166 * Run all _REG methods for all Operation Regions for this space ID. This 1167 * is a separate walk in order to handle any interdependencies between 1168 * regions and _REG methods. (i.e. handlers must be installed for all 1169 * regions of this Space ID before we can run any _REG methods) 1170 */ 1171 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, ACPI_UINT32_MAX, 1172 ACPI_NS_WALK_UNLOCK, AcpiEvRegRun, NULL, 1173 &SpaceId, NULL); 1174 1175 /* Special case for EC: handle "orphan" _REG methods with no region */ 1176 1177 if (SpaceId == ACPI_ADR_SPACE_EC) 1178 { 1179 AcpiEvOrphanEcRegMethod (); 1180 } 1181 1182 return_ACPI_STATUS (Status); 1183 } 1184 1185 1186 /******************************************************************************* 1187 * 1188 * FUNCTION: AcpiEvRegRun 1189 * 1190 * PARAMETERS: WalkNamespace callback 1191 * 1192 * DESCRIPTION: Run _REG method for region objects of the requested spaceID 1193 * 1194 ******************************************************************************/ 1195 1196 static ACPI_STATUS 1197 AcpiEvRegRun ( 1198 ACPI_HANDLE ObjHandle, 1199 UINT32 Level, 1200 void *Context, 1201 void **ReturnValue) 1202 { 1203 ACPI_OPERAND_OBJECT *ObjDesc; 1204 ACPI_NAMESPACE_NODE *Node; 1205 ACPI_ADR_SPACE_TYPE SpaceId; 1206 ACPI_STATUS Status; 1207 1208 1209 SpaceId = *ACPI_CAST_PTR (ACPI_ADR_SPACE_TYPE, Context); 1210 1211 /* Convert and validate the device handle */ 1212 1213 Node = AcpiNsValidateHandle (ObjHandle); 1214 if (!Node) 1215 { 1216 return (AE_BAD_PARAMETER); 1217 } 1218 1219 /* 1220 * We only care about regions.and objects that are allowed to have address 1221 * space handlers 1222 */ 1223 if ((Node->Type != ACPI_TYPE_REGION) && 1224 (Node != AcpiGbl_RootNode)) 1225 { 1226 return (AE_OK); 1227 } 1228 1229 /* Check for an existing internal object */ 1230 1231 ObjDesc = AcpiNsGetAttachedObject (Node); 1232 if (!ObjDesc) 1233 { 1234 /* No object, just exit */ 1235 1236 return (AE_OK); 1237 } 1238 1239 /* Object is a Region */ 1240 1241 if (ObjDesc->Region.SpaceId != SpaceId) 1242 { 1243 /* This region is for a different address space, just ignore it */ 1244 1245 return (AE_OK); 1246 } 1247 1248 Status = AcpiEvExecuteRegMethod (ObjDesc, ACPI_REG_CONNECT); 1249 return (Status); 1250 } 1251 1252 1253 /******************************************************************************* 1254 * 1255 * FUNCTION: AcpiEvOrphanEcRegMethod 1256 * 1257 * PARAMETERS: None 1258 * 1259 * RETURN: None 1260 * 1261 * DESCRIPTION: Execute an "orphan" _REG method that appears under the EC 1262 * device. This is a _REG method that has no corresponding region 1263 * within the EC device scope. The orphan _REG method appears to 1264 * have been enabled by the description of the ECDT in the ACPI 1265 * specification: "The availability of the region space can be 1266 * detected by providing a _REG method object underneath the 1267 * Embedded Controller device." 1268 * 1269 * To quickly access the EC device, we use the EC_ID that appears 1270 * within the ECDT. Otherwise, we would need to perform a time- 1271 * consuming namespace walk, executing _HID methods to find the 1272 * EC device. 1273 * 1274 ******************************************************************************/ 1275 1276 static void 1277 AcpiEvOrphanEcRegMethod ( 1278 void) 1279 { 1280 ACPI_TABLE_ECDT *Table; 1281 ACPI_STATUS Status; 1282 ACPI_OBJECT_LIST Args; 1283 ACPI_OBJECT Objects[2]; 1284 ACPI_NAMESPACE_NODE *EcDeviceNode; 1285 ACPI_NAMESPACE_NODE *RegMethod; 1286 ACPI_NAMESPACE_NODE *NextNode; 1287 1288 1289 ACPI_FUNCTION_TRACE (EvOrphanEcRegMethod); 1290 1291 1292 /* Get the ECDT (if present in system) */ 1293 1294 Status = AcpiGetTable (ACPI_SIG_ECDT, 0, 1295 ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Table)); 1296 if (ACPI_FAILURE (Status)) 1297 { 1298 return_VOID; 1299 } 1300 1301 /* We need a valid EC_ID string */ 1302 1303 if (!(*Table->Id)) 1304 { 1305 return_VOID; 1306 } 1307 1308 /* Namespace is currently locked, must release */ 1309 1310 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 1311 1312 /* Get a handle to the EC device referenced in the ECDT */ 1313 1314 Status = AcpiGetHandle (NULL, 1315 ACPI_CAST_PTR (char, Table->Id), 1316 ACPI_CAST_PTR (ACPI_HANDLE, &EcDeviceNode)); 1317 if (ACPI_FAILURE (Status)) 1318 { 1319 goto Exit; 1320 } 1321 1322 /* Get a handle to a _REG method immediately under the EC device */ 1323 1324 Status = AcpiGetHandle (EcDeviceNode, 1325 METHOD_NAME__REG, ACPI_CAST_PTR (ACPI_HANDLE, &RegMethod)); 1326 if (ACPI_FAILURE (Status)) 1327 { 1328 goto Exit; 1329 } 1330 1331 /* 1332 * Execute the _REG method only if there is no Operation Region in 1333 * this scope with the Embedded Controller space ID. Otherwise, it 1334 * will already have been executed. Note, this allows for Regions 1335 * with other space IDs to be present; but the code below will then 1336 * execute the _REG method with the EC space ID argument. 1337 */ 1338 NextNode = AcpiNsGetNextNode (EcDeviceNode, NULL); 1339 while (NextNode) 1340 { 1341 if ((NextNode->Type == ACPI_TYPE_REGION) && 1342 (NextNode->Object) && 1343 (NextNode->Object->Region.SpaceId == ACPI_ADR_SPACE_EC)) 1344 { 1345 goto Exit; /* Do not execute _REG */ 1346 } 1347 NextNode = AcpiNsGetNextNode (EcDeviceNode, NextNode); 1348 } 1349 1350 /* Evaluate the _REG(EC,Connect) method */ 1351 1352 Args.Count = 2; 1353 Args.Pointer = Objects; 1354 Objects[0].Type = ACPI_TYPE_INTEGER; 1355 Objects[0].Integer.Value = ACPI_ADR_SPACE_EC; 1356 Objects[1].Type = ACPI_TYPE_INTEGER; 1357 Objects[1].Integer.Value = ACPI_REG_CONNECT; 1358 1359 Status = AcpiEvaluateObject (RegMethod, NULL, &Args, NULL); 1360 1361 Exit: 1362 /* We ignore all errors from above, don't care */ 1363 1364 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 1365 return_VOID; 1366 } 1367