1 /****************************************************************************** 2 * 3 * Module Name: evhandler - Support for Address Space handlers 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2026, 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 MERCHANTABILITY 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 "acpi.h" 45 #include "accommon.h" 46 #include "acevents.h" 47 #include "acnamesp.h" 48 #include "acinterp.h" 49 50 #define _COMPONENT ACPI_EVENTS 51 ACPI_MODULE_NAME ("evhandler") 52 53 54 /* Local prototypes */ 55 56 static ACPI_STATUS 57 AcpiEvInstallHandler ( 58 ACPI_HANDLE ObjHandle, 59 UINT32 Level, 60 void *Context, 61 void **ReturnValue); 62 63 64 /* These are the address spaces that will get default handlers */ 65 66 UINT8 AcpiGbl_DefaultAddressSpaces[ACPI_NUM_DEFAULT_SPACES] = 67 { 68 ACPI_ADR_SPACE_SYSTEM_MEMORY, 69 ACPI_ADR_SPACE_SYSTEM_IO, 70 ACPI_ADR_SPACE_PCI_CONFIG, 71 ACPI_ADR_SPACE_DATA_TABLE 72 }; 73 74 75 /******************************************************************************* 76 * 77 * FUNCTION: AcpiEvInstallRegionHandlers 78 * 79 * PARAMETERS: None 80 * 81 * RETURN: Status 82 * 83 * DESCRIPTION: Installs the core subsystem default address space handlers. 84 * 85 ******************************************************************************/ 86 87 ACPI_STATUS 88 AcpiEvInstallRegionHandlers ( 89 void) 90 { 91 ACPI_STATUS Status; 92 UINT32 i; 93 94 95 ACPI_FUNCTION_TRACE (EvInstallRegionHandlers); 96 97 98 Status = AcpiUtAcquireMutex (ACPI_MTX_NAMESPACE); 99 if (ACPI_FAILURE (Status)) 100 { 101 return_ACPI_STATUS (Status); 102 } 103 104 /* 105 * All address spaces (PCI Config, EC, SMBus) are scope dependent and 106 * registration must occur for a specific device. 107 * 108 * In the case of the system memory and IO address spaces there is 109 * currently no device associated with the address space. For these we 110 * use the root. 111 * 112 * We install the default PCI config space handler at the root so that 113 * this space is immediately available even though the we have not 114 * enumerated all the PCI Root Buses yet. This is to conform to the ACPI 115 * specification which states that the PCI config space must be always 116 * available -- even though we are nowhere near ready to find the PCI root 117 * buses at this point. 118 * 119 * NOTE: We ignore AE_ALREADY_EXISTS because this means that a handler 120 * has already been installed (via AcpiInstallAddressSpaceHandler). 121 * Similar for AE_SAME_HANDLER. 122 */ 123 for (i = 0; i < ACPI_NUM_DEFAULT_SPACES; i++) 124 { 125 Status = AcpiEvInstallSpaceHandler (AcpiGbl_RootNode, 126 AcpiGbl_DefaultAddressSpaces[i], 127 ACPI_DEFAULT_HANDLER, NULL, NULL); 128 switch (Status) 129 { 130 case AE_OK: 131 case AE_SAME_HANDLER: 132 case AE_ALREADY_EXISTS: 133 134 /* These exceptions are all OK */ 135 136 Status = AE_OK; 137 break; 138 139 default: 140 141 goto UnlockAndExit; 142 } 143 } 144 145 UnlockAndExit: 146 (void) AcpiUtReleaseMutex (ACPI_MTX_NAMESPACE); 147 return_ACPI_STATUS (Status); 148 } 149 150 151 /******************************************************************************* 152 * 153 * FUNCTION: AcpiEvHasDefaultHandler 154 * 155 * PARAMETERS: Node - Namespace node for the device 156 * SpaceId - The address space ID 157 * 158 * RETURN: TRUE if default handler is installed, FALSE otherwise 159 * 160 * DESCRIPTION: Check if the default handler is installed for the requested 161 * space ID. 162 * 163 ******************************************************************************/ 164 165 BOOLEAN 166 AcpiEvHasDefaultHandler ( 167 ACPI_NAMESPACE_NODE *Node, 168 ACPI_ADR_SPACE_TYPE SpaceId) 169 { 170 ACPI_OPERAND_OBJECT *ObjDesc; 171 ACPI_OPERAND_OBJECT *HandlerObj; 172 173 174 /* Must have an existing internal object */ 175 176 ObjDesc = AcpiNsGetAttachedObject (Node); 177 if (ObjDesc) 178 { 179 HandlerObj = ObjDesc->CommonNotify.Handler; 180 181 /* Walk the linked list of handlers for this object */ 182 183 while (HandlerObj) 184 { 185 /* Validate handler object type before accessing fields */ 186 187 if (HandlerObj->Common.Type != ACPI_TYPE_LOCAL_ADDRESS_HANDLER) 188 { 189 break; 190 } 191 192 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 193 { 194 if (HandlerObj->AddressSpace.HandlerFlags & 195 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) 196 { 197 return (TRUE); 198 } 199 } 200 201 HandlerObj = HandlerObj->AddressSpace.Next; 202 } 203 } 204 205 return (FALSE); 206 } 207 208 209 /******************************************************************************* 210 * 211 * FUNCTION: AcpiEvInstallHandler 212 * 213 * PARAMETERS: WalkNamespace callback 214 * 215 * DESCRIPTION: This routine installs an address handler into objects that are 216 * of type Region or Device. 217 * 218 * If the Object is a Device, and the device has a handler of 219 * the same type then the search is terminated in that branch. 220 * 221 * This is because the existing handler is closer in proximity 222 * to any more regions than the one we are trying to install. 223 * 224 ******************************************************************************/ 225 226 static ACPI_STATUS 227 AcpiEvInstallHandler ( 228 ACPI_HANDLE ObjHandle, 229 UINT32 Level, 230 void *Context, 231 void **ReturnValue) 232 { 233 ACPI_OPERAND_OBJECT *HandlerObj; 234 ACPI_OPERAND_OBJECT *NextHandlerObj; 235 ACPI_OPERAND_OBJECT *ObjDesc; 236 ACPI_NAMESPACE_NODE *Node; 237 ACPI_STATUS Status; 238 239 240 ACPI_FUNCTION_NAME (EvInstallHandler); 241 242 243 HandlerObj = (ACPI_OPERAND_OBJECT *) Context; 244 245 /* Parameter validation */ 246 247 if (!HandlerObj) 248 { 249 return (AE_OK); 250 } 251 252 /* Convert and validate the device handle */ 253 254 Node = AcpiNsValidateHandle (ObjHandle); 255 if (!Node) 256 { 257 return (AE_BAD_PARAMETER); 258 } 259 260 /* 261 * We only care about regions and objects that are allowed to have 262 * address space handlers 263 */ 264 if ((Node->Type != ACPI_TYPE_DEVICE) && 265 (Node->Type != ACPI_TYPE_REGION) && 266 (Node != AcpiGbl_RootNode)) 267 { 268 return (AE_OK); 269 } 270 271 /* Check for an existing internal object */ 272 273 ObjDesc = AcpiNsGetAttachedObject (Node); 274 if (!ObjDesc) 275 { 276 /* No object, just exit */ 277 278 return (AE_OK); 279 } 280 281 /* Devices are handled different than regions */ 282 283 if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE) 284 { 285 /* Check if this Device already has a handler for this address space */ 286 287 NextHandlerObj = AcpiEvFindRegionHandler ( 288 HandlerObj->AddressSpace.SpaceId, ObjDesc->CommonNotify.Handler); 289 if (NextHandlerObj) 290 { 291 /* Found a handler, is it for the same address space? */ 292 293 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 294 "Found handler for region [%s] in device %p(%p) handler %p\n", 295 AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId), 296 ObjDesc, NextHandlerObj, HandlerObj)); 297 298 /* 299 * Since the object we found it on was a device, then it means 300 * that someone has already installed a handler for the branch 301 * of the namespace from this device on. Just bail out telling 302 * the walk routine to not traverse this branch. This preserves 303 * the scoping rule for handlers. 304 */ 305 return (AE_CTRL_DEPTH); 306 } 307 308 /* 309 * As long as the device didn't have a handler for this space we 310 * don't care about it. We just ignore it and proceed. 311 */ 312 return (AE_OK); 313 } 314 315 /* Object is a Region */ 316 317 if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId) 318 { 319 /* This region is for a different address space, just ignore it */ 320 321 return (AE_OK); 322 } 323 324 /* 325 * Now we have a region and it is for the handler's address space type. 326 * 327 * First disconnect region for any previous handler (if any) 328 */ 329 AcpiEvDetachRegion (ObjDesc, FALSE); 330 331 /* Connect the region to the new handler */ 332 333 Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE); 334 return (Status); 335 } 336 337 338 /******************************************************************************* 339 * 340 * FUNCTION: AcpiEvFindRegionHandler 341 * 342 * PARAMETERS: SpaceId - The address space ID 343 * HandlerObj - Head of the handler object list 344 * 345 * RETURN: Matching handler object. NULL if space ID not matched 346 * 347 * DESCRIPTION: Search a handler object list for a match on the address 348 * space ID. 349 * 350 ******************************************************************************/ 351 352 ACPI_OPERAND_OBJECT * 353 AcpiEvFindRegionHandler ( 354 ACPI_ADR_SPACE_TYPE SpaceId, 355 ACPI_OPERAND_OBJECT *HandlerObj) 356 { 357 358 /* Walk the handler list for this device */ 359 360 while (HandlerObj) 361 { 362 if (HandlerObj->Common.Type != ACPI_TYPE_LOCAL_ADDRESS_HANDLER) 363 { 364 break; 365 } 366 367 /* Same SpaceId indicates a handler is installed */ 368 369 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 370 { 371 return (HandlerObj); 372 } 373 374 /* Next handler object */ 375 376 HandlerObj = HandlerObj->AddressSpace.Next; 377 } 378 379 return (NULL); 380 } 381 382 383 /******************************************************************************* 384 * 385 * FUNCTION: AcpiEvInstallSpaceHandler 386 * 387 * PARAMETERS: Node - Namespace node for the device 388 * SpaceId - The address space ID 389 * Handler - Address of the handler 390 * Setup - Address of the setup function 391 * Context - Value passed to the handler on each access 392 * 393 * RETURN: Status 394 * 395 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. 396 * Assumes namespace is locked 397 * 398 ******************************************************************************/ 399 400 ACPI_STATUS 401 AcpiEvInstallSpaceHandler ( 402 ACPI_NAMESPACE_NODE *Node, 403 ACPI_ADR_SPACE_TYPE SpaceId, 404 ACPI_ADR_SPACE_HANDLER Handler, 405 ACPI_ADR_SPACE_SETUP Setup, 406 void *Context) 407 { 408 ACPI_OPERAND_OBJECT *ObjDesc; 409 ACPI_OPERAND_OBJECT *HandlerObj; 410 ACPI_STATUS Status = AE_OK; 411 ACPI_OBJECT_TYPE Type; 412 UINT8 Flags = 0; 413 414 415 ACPI_FUNCTION_TRACE (EvInstallSpaceHandler); 416 417 418 /* 419 * This registration is valid for only the types below and the root. 420 * The root node is where the default handlers get installed. 421 */ 422 if ((Node->Type != ACPI_TYPE_DEVICE) && 423 (Node->Type != ACPI_TYPE_PROCESSOR) && 424 (Node->Type != ACPI_TYPE_THERMAL) && 425 (Node != AcpiGbl_RootNode)) 426 { 427 Status = AE_BAD_PARAMETER; 428 goto UnlockAndExit; 429 } 430 431 if (Handler == ACPI_DEFAULT_HANDLER) 432 { 433 Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; 434 435 switch (SpaceId) 436 { 437 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 438 439 Handler = AcpiExSystemMemorySpaceHandler; 440 Setup = AcpiEvSystemMemoryRegionSetup; 441 break; 442 443 case ACPI_ADR_SPACE_SYSTEM_IO: 444 445 Handler = AcpiExSystemIoSpaceHandler; 446 Setup = AcpiEvIoSpaceRegionSetup; 447 break; 448 449 case ACPI_ADR_SPACE_PCI_CONFIG: 450 451 Handler = AcpiExPciConfigSpaceHandler; 452 Setup = AcpiEvPciConfigRegionSetup; 453 break; 454 455 case ACPI_ADR_SPACE_CMOS: 456 457 Handler = AcpiExCmosSpaceHandler; 458 Setup = AcpiEvCmosRegionSetup; 459 break; 460 461 case ACPI_ADR_SPACE_PCI_BAR_TARGET: 462 463 Handler = AcpiExPciBarSpaceHandler; 464 Setup = AcpiEvPciBarRegionSetup; 465 break; 466 467 case ACPI_ADR_SPACE_DATA_TABLE: 468 469 Handler = AcpiExDataTableSpaceHandler; 470 Setup = AcpiEvDataTableRegionSetup; 471 break; 472 473 default: 474 475 Status = AE_BAD_PARAMETER; 476 goto UnlockAndExit; 477 } 478 } 479 480 /* If the caller hasn't specified a setup routine, use the default */ 481 482 if (!Setup) 483 { 484 Setup = AcpiEvDefaultRegionSetup; 485 } 486 487 /* Check for an existing internal object */ 488 489 ObjDesc = AcpiNsGetAttachedObject (Node); 490 if (ObjDesc) 491 { 492 /* 493 * The attached device object already exists. Now make sure 494 * the handler is not already installed. 495 */ 496 HandlerObj = AcpiEvFindRegionHandler (SpaceId, 497 ObjDesc->CommonNotify.Handler); 498 499 if (HandlerObj) 500 { 501 if (HandlerObj->AddressSpace.Handler == Handler) 502 { 503 /* 504 * It is (relatively) OK to attempt to install the SAME 505 * handler twice. This can easily happen with the 506 * PCI_Config space. 507 */ 508 Status = AE_SAME_HANDLER; 509 goto UnlockAndExit; 510 } 511 else 512 { 513 /* A handler is already installed */ 514 515 Status = AE_ALREADY_EXISTS; 516 } 517 518 goto UnlockAndExit; 519 } 520 } 521 else 522 { 523 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 524 "Creating object on Device %p while installing handler\n", 525 Node)); 526 527 /* ObjDesc does not exist, create one */ 528 529 if (Node->Type == ACPI_TYPE_ANY) 530 { 531 Type = ACPI_TYPE_DEVICE; 532 } 533 else 534 { 535 Type = Node->Type; 536 } 537 538 ObjDesc = AcpiUtCreateInternalObject (Type); 539 if (!ObjDesc) 540 { 541 Status = AE_NO_MEMORY; 542 goto UnlockAndExit; 543 } 544 545 /* Init new descriptor */ 546 547 ObjDesc->Common.Type = (UINT8) Type; 548 549 /* Attach the new object to the Node */ 550 551 Status = AcpiNsAttachObject (Node, ObjDesc, Type); 552 553 /* Remove local reference to the object */ 554 555 AcpiUtRemoveReference (ObjDesc); 556 557 if (ACPI_FAILURE (Status)) 558 { 559 goto UnlockAndExit; 560 } 561 } 562 563 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 564 "Installing address handler for region %s(%X) " 565 "on Device %4.4s %p(%p)\n", 566 AcpiUtGetRegionName (SpaceId), SpaceId, 567 AcpiUtGetNodeName (Node), Node, ObjDesc)); 568 569 /* 570 * Install the handler 571 * 572 * At this point there is no existing handler. Just allocate the object 573 * for the handler and link it into the list. 574 */ 575 HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); 576 if (!HandlerObj) 577 { 578 Status = AE_NO_MEMORY; 579 goto UnlockAndExit; 580 } 581 582 /* Init handler obj */ 583 584 Status = AcpiOsCreateMutex (&HandlerObj->AddressSpace.ContextMutex); 585 if (ACPI_FAILURE (Status)) 586 { 587 AcpiUtRemoveReference (HandlerObj); 588 goto UnlockAndExit; 589 } 590 591 HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId; 592 HandlerObj->AddressSpace.HandlerFlags = Flags; 593 HandlerObj->AddressSpace.RegionList = NULL; 594 HandlerObj->AddressSpace.Node = Node; 595 HandlerObj->AddressSpace.Handler = Handler; 596 HandlerObj->AddressSpace.Context = Context; 597 HandlerObj->AddressSpace.Setup = Setup; 598 599 /* Install at head of Device.AddressSpace list */ 600 601 HandlerObj->AddressSpace.Next = ObjDesc->CommonNotify.Handler; 602 603 /* 604 * The Device object is the first reference on the HandlerObj. 605 * Each region that uses the handler adds a reference. 606 */ 607 ObjDesc->CommonNotify.Handler = HandlerObj; 608 609 /* 610 * Walk the namespace finding all of the regions this handler will 611 * manage. 612 * 613 * Start at the device and search the branch toward the leaf nodes 614 * until either the leaf is encountered or a device is detected that 615 * has an address handler of the same type. 616 * 617 * In either case, back up and search down the remainder of the branch 618 */ 619 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, 620 ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, 621 AcpiEvInstallHandler, NULL, HandlerObj, NULL); 622 623 UnlockAndExit: 624 return_ACPI_STATUS (Status); 625 } 626