1 /****************************************************************************** 2 * 3 * Module Name: evhandler - Support for Address Space handlers 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2016, 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 "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 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 186 { 187 if (HandlerObj->AddressSpace.HandlerFlags & 188 ACPI_ADDR_HANDLER_DEFAULT_INSTALLED) 189 { 190 return (TRUE); 191 } 192 } 193 194 HandlerObj = HandlerObj->AddressSpace.Next; 195 } 196 } 197 198 return (FALSE); 199 } 200 201 202 /******************************************************************************* 203 * 204 * FUNCTION: AcpiEvInstallHandler 205 * 206 * PARAMETERS: WalkNamespace callback 207 * 208 * DESCRIPTION: This routine installs an address handler into objects that are 209 * of type Region or Device. 210 * 211 * If the Object is a Device, and the device has a handler of 212 * the same type then the search is terminated in that branch. 213 * 214 * This is because the existing handler is closer in proximity 215 * to any more regions than the one we are trying to install. 216 * 217 ******************************************************************************/ 218 219 static ACPI_STATUS 220 AcpiEvInstallHandler ( 221 ACPI_HANDLE ObjHandle, 222 UINT32 Level, 223 void *Context, 224 void **ReturnValue) 225 { 226 ACPI_OPERAND_OBJECT *HandlerObj; 227 ACPI_OPERAND_OBJECT *NextHandlerObj; 228 ACPI_OPERAND_OBJECT *ObjDesc; 229 ACPI_NAMESPACE_NODE *Node; 230 ACPI_STATUS Status; 231 232 233 ACPI_FUNCTION_NAME (EvInstallHandler); 234 235 236 HandlerObj = (ACPI_OPERAND_OBJECT *) Context; 237 238 /* Parameter validation */ 239 240 if (!HandlerObj) 241 { 242 return (AE_OK); 243 } 244 245 /* Convert and validate the device handle */ 246 247 Node = AcpiNsValidateHandle (ObjHandle); 248 if (!Node) 249 { 250 return (AE_BAD_PARAMETER); 251 } 252 253 /* 254 * We only care about regions and objects that are allowed to have 255 * address space handlers 256 */ 257 if ((Node->Type != ACPI_TYPE_DEVICE) && 258 (Node->Type != ACPI_TYPE_REGION) && 259 (Node != AcpiGbl_RootNode)) 260 { 261 return (AE_OK); 262 } 263 264 /* Check for an existing internal object */ 265 266 ObjDesc = AcpiNsGetAttachedObject (Node); 267 if (!ObjDesc) 268 { 269 /* No object, just exit */ 270 271 return (AE_OK); 272 } 273 274 /* Devices are handled different than regions */ 275 276 if (ObjDesc->Common.Type == ACPI_TYPE_DEVICE) 277 { 278 /* Check if this Device already has a handler for this address space */ 279 280 NextHandlerObj = AcpiEvFindRegionHandler ( 281 HandlerObj->AddressSpace.SpaceId, ObjDesc->CommonNotify.Handler); 282 if (NextHandlerObj) 283 { 284 /* Found a handler, is it for the same address space? */ 285 286 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 287 "Found handler for region [%s] in device %p(%p) handler %p\n", 288 AcpiUtGetRegionName (HandlerObj->AddressSpace.SpaceId), 289 ObjDesc, NextHandlerObj, HandlerObj)); 290 291 /* 292 * Since the object we found it on was a device, then it means 293 * that someone has already installed a handler for the branch 294 * of the namespace from this device on. Just bail out telling 295 * the walk routine to not traverse this branch. This preserves 296 * the scoping rule for handlers. 297 */ 298 return (AE_CTRL_DEPTH); 299 } 300 301 /* 302 * As long as the device didn't have a handler for this space we 303 * don't care about it. We just ignore it and proceed. 304 */ 305 return (AE_OK); 306 } 307 308 /* Object is a Region */ 309 310 if (ObjDesc->Region.SpaceId != HandlerObj->AddressSpace.SpaceId) 311 { 312 /* This region is for a different address space, just ignore it */ 313 314 return (AE_OK); 315 } 316 317 /* 318 * Now we have a region and it is for the handler's address space type. 319 * 320 * First disconnect region for any previous handler (if any) 321 */ 322 AcpiEvDetachRegion (ObjDesc, FALSE); 323 324 /* Connect the region to the new handler */ 325 326 Status = AcpiEvAttachRegion (HandlerObj, ObjDesc, FALSE); 327 return (Status); 328 } 329 330 331 /******************************************************************************* 332 * 333 * FUNCTION: AcpiEvFindRegionHandler 334 * 335 * PARAMETERS: SpaceId - The address space ID 336 * HandlerObj - Head of the handler object list 337 * 338 * RETURN: Matching handler object. NULL if space ID not matched 339 * 340 * DESCRIPTION: Search a handler object list for a match on the address 341 * space ID. 342 * 343 ******************************************************************************/ 344 345 ACPI_OPERAND_OBJECT * 346 AcpiEvFindRegionHandler ( 347 ACPI_ADR_SPACE_TYPE SpaceId, 348 ACPI_OPERAND_OBJECT *HandlerObj) 349 { 350 351 /* Walk the handler list for this device */ 352 353 while (HandlerObj) 354 { 355 /* Same SpaceId indicates a handler is installed */ 356 357 if (HandlerObj->AddressSpace.SpaceId == SpaceId) 358 { 359 return (HandlerObj); 360 } 361 362 /* Next handler object */ 363 364 HandlerObj = HandlerObj->AddressSpace.Next; 365 } 366 367 return (NULL); 368 } 369 370 371 /******************************************************************************* 372 * 373 * FUNCTION: AcpiEvInstallSpaceHandler 374 * 375 * PARAMETERS: Node - Namespace node for the device 376 * SpaceId - The address space ID 377 * Handler - Address of the handler 378 * Setup - Address of the setup function 379 * Context - Value passed to the handler on each access 380 * 381 * RETURN: Status 382 * 383 * DESCRIPTION: Install a handler for all OpRegions of a given SpaceId. 384 * Assumes namespace is locked 385 * 386 ******************************************************************************/ 387 388 ACPI_STATUS 389 AcpiEvInstallSpaceHandler ( 390 ACPI_NAMESPACE_NODE *Node, 391 ACPI_ADR_SPACE_TYPE SpaceId, 392 ACPI_ADR_SPACE_HANDLER Handler, 393 ACPI_ADR_SPACE_SETUP Setup, 394 void *Context) 395 { 396 ACPI_OPERAND_OBJECT *ObjDesc; 397 ACPI_OPERAND_OBJECT *HandlerObj; 398 ACPI_STATUS Status = AE_OK; 399 ACPI_OBJECT_TYPE Type; 400 UINT8 Flags = 0; 401 402 403 ACPI_FUNCTION_TRACE (EvInstallSpaceHandler); 404 405 406 /* 407 * This registration is valid for only the types below and the root. 408 * The root node is where the default handlers get installed. 409 */ 410 if ((Node->Type != ACPI_TYPE_DEVICE) && 411 (Node->Type != ACPI_TYPE_PROCESSOR) && 412 (Node->Type != ACPI_TYPE_THERMAL) && 413 (Node != AcpiGbl_RootNode)) 414 { 415 Status = AE_BAD_PARAMETER; 416 goto UnlockAndExit; 417 } 418 419 if (Handler == ACPI_DEFAULT_HANDLER) 420 { 421 Flags = ACPI_ADDR_HANDLER_DEFAULT_INSTALLED; 422 423 switch (SpaceId) 424 { 425 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 426 427 Handler = AcpiExSystemMemorySpaceHandler; 428 Setup = AcpiEvSystemMemoryRegionSetup; 429 break; 430 431 case ACPI_ADR_SPACE_SYSTEM_IO: 432 433 Handler = AcpiExSystemIoSpaceHandler; 434 Setup = AcpiEvIoSpaceRegionSetup; 435 break; 436 437 case ACPI_ADR_SPACE_PCI_CONFIG: 438 439 Handler = AcpiExPciConfigSpaceHandler; 440 Setup = AcpiEvPciConfigRegionSetup; 441 break; 442 443 case ACPI_ADR_SPACE_CMOS: 444 445 Handler = AcpiExCmosSpaceHandler; 446 Setup = AcpiEvCmosRegionSetup; 447 break; 448 449 case ACPI_ADR_SPACE_PCI_BAR_TARGET: 450 451 Handler = AcpiExPciBarSpaceHandler; 452 Setup = AcpiEvPciBarRegionSetup; 453 break; 454 455 case ACPI_ADR_SPACE_DATA_TABLE: 456 457 Handler = AcpiExDataTableSpaceHandler; 458 Setup = NULL; 459 break; 460 461 default: 462 463 Status = AE_BAD_PARAMETER; 464 goto UnlockAndExit; 465 } 466 } 467 468 /* If the caller hasn't specified a setup routine, use the default */ 469 470 if (!Setup) 471 { 472 Setup = AcpiEvDefaultRegionSetup; 473 } 474 475 /* Check for an existing internal object */ 476 477 ObjDesc = AcpiNsGetAttachedObject (Node); 478 if (ObjDesc) 479 { 480 /* 481 * The attached device object already exists. Now make sure 482 * the handler is not already installed. 483 */ 484 HandlerObj = AcpiEvFindRegionHandler (SpaceId, 485 ObjDesc->CommonNotify.Handler); 486 487 if (HandlerObj) 488 { 489 if (HandlerObj->AddressSpace.Handler == Handler) 490 { 491 /* 492 * It is (relatively) OK to attempt to install the SAME 493 * handler twice. This can easily happen with the 494 * PCI_Config space. 495 */ 496 Status = AE_SAME_HANDLER; 497 goto UnlockAndExit; 498 } 499 else 500 { 501 /* A handler is already installed */ 502 503 Status = AE_ALREADY_EXISTS; 504 } 505 506 goto UnlockAndExit; 507 } 508 } 509 else 510 { 511 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 512 "Creating object on Device %p while installing handler\n", 513 Node)); 514 515 /* ObjDesc does not exist, create one */ 516 517 if (Node->Type == ACPI_TYPE_ANY) 518 { 519 Type = ACPI_TYPE_DEVICE; 520 } 521 else 522 { 523 Type = Node->Type; 524 } 525 526 ObjDesc = AcpiUtCreateInternalObject (Type); 527 if (!ObjDesc) 528 { 529 Status = AE_NO_MEMORY; 530 goto UnlockAndExit; 531 } 532 533 /* Init new descriptor */ 534 535 ObjDesc->Common.Type = (UINT8) Type; 536 537 /* Attach the new object to the Node */ 538 539 Status = AcpiNsAttachObject (Node, ObjDesc, Type); 540 541 /* Remove local reference to the object */ 542 543 AcpiUtRemoveReference (ObjDesc); 544 545 if (ACPI_FAILURE (Status)) 546 { 547 goto UnlockAndExit; 548 } 549 } 550 551 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 552 "Installing address handler for region %s(%X) " 553 "on Device %4.4s %p(%p)\n", 554 AcpiUtGetRegionName (SpaceId), SpaceId, 555 AcpiUtGetNodeName (Node), Node, ObjDesc)); 556 557 /* 558 * Install the handler 559 * 560 * At this point there is no existing handler. Just allocate the object 561 * for the handler and link it into the list. 562 */ 563 HandlerObj = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_ADDRESS_HANDLER); 564 if (!HandlerObj) 565 { 566 Status = AE_NO_MEMORY; 567 goto UnlockAndExit; 568 } 569 570 /* Init handler obj */ 571 572 HandlerObj->AddressSpace.SpaceId = (UINT8) SpaceId; 573 HandlerObj->AddressSpace.HandlerFlags = Flags; 574 HandlerObj->AddressSpace.RegionList = NULL; 575 HandlerObj->AddressSpace.Node = Node; 576 HandlerObj->AddressSpace.Handler = Handler; 577 HandlerObj->AddressSpace.Context = Context; 578 HandlerObj->AddressSpace.Setup = Setup; 579 580 /* Install at head of Device.AddressSpace list */ 581 582 HandlerObj->AddressSpace.Next = ObjDesc->CommonNotify.Handler; 583 584 /* 585 * The Device object is the first reference on the HandlerObj. 586 * Each region that uses the handler adds a reference. 587 */ 588 ObjDesc->CommonNotify.Handler = HandlerObj; 589 590 /* 591 * Walk the namespace finding all of the regions this handler will 592 * manage. 593 * 594 * Start at the device and search the branch toward the leaf nodes 595 * until either the leaf is encountered or a device is detected that 596 * has an address handler of the same type. 597 * 598 * In either case, back up and search down the remainder of the branch 599 */ 600 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, Node, 601 ACPI_UINT32_MAX, ACPI_NS_WALK_UNLOCK, 602 AcpiEvInstallHandler, NULL, HandlerObj, NULL); 603 604 UnlockAndExit: 605 return_ACPI_STATUS (Status); 606 } 607