1 /******************************************************************************* 2 * 3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers 4 * 5 ******************************************************************************/ 6 7 /****************************************************************************** 8 * 9 * 1. Copyright Notice 10 * 11 * Some or all of this work - Copyright (c) 1999 - 2022, Intel Corp. 12 * All rights reserved. 13 * 14 * 2. License 15 * 16 * 2.1. This is your license from Intel Corp. under its intellectual property 17 * rights. You may have additional license terms from the party that provided 18 * you this software, covering your right to use that party's intellectual 19 * property rights. 20 * 21 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 22 * copy of the source code appearing in this file ("Covered Code") an 23 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 24 * base code distributed originally by Intel ("Original Intel Code") to copy, 25 * make derivatives, distribute, use and display any portion of the Covered 26 * Code in any form, with the right to sublicense such rights; and 27 * 28 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 29 * license (with the right to sublicense), under only those claims of Intel 30 * patents that are infringed by the Original Intel Code, to make, use, sell, 31 * offer to sell, and import the Covered Code and derivative works thereof 32 * solely to the minimum extent necessary to exercise the above copyright 33 * license, and in no event shall the patent license extend to any additions 34 * to or modifications of the Original Intel Code. No other license or right 35 * is granted directly or by implication, estoppel or otherwise; 36 * 37 * The above copyright and patent license is granted only if the following 38 * conditions are met: 39 * 40 * 3. Conditions 41 * 42 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 43 * Redistribution of source code of any substantial portion of the Covered 44 * Code or modification with rights to further distribute source must include 45 * the above Copyright Notice, the above License, this list of Conditions, 46 * and the following Disclaimer and Export Compliance provision. In addition, 47 * Licensee must cause all Covered Code to which Licensee contributes to 48 * contain a file documenting the changes Licensee made to create that Covered 49 * Code and the date of any change. Licensee must include in that file the 50 * documentation of any changes made by any predecessor Licensee. Licensee 51 * must include a prominent statement that the modification is derived, 52 * directly or indirectly, from Original Intel Code. 53 * 54 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 55 * Redistribution of source code of any substantial portion of the Covered 56 * Code or modification without rights to further distribute source must 57 * include the following Disclaimer and Export Compliance provision in the 58 * documentation and/or other materials provided with distribution. In 59 * addition, Licensee may not authorize further sublicense of source of any 60 * portion of the Covered Code, and must include terms to the effect that the 61 * license from Licensee to its licensee is limited to the intellectual 62 * property embodied in the software Licensee provides to its licensee, and 63 * not to intellectual property embodied in modifications its licensee may 64 * make. 65 * 66 * 3.3. Redistribution of Executable. Redistribution in executable form of any 67 * substantial portion of the Covered Code or modification must reproduce the 68 * above Copyright Notice, and the following Disclaimer and Export Compliance 69 * provision in the documentation and/or other materials provided with the 70 * distribution. 71 * 72 * 3.4. Intel retains all right, title, and interest in and to the Original 73 * Intel Code. 74 * 75 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 76 * Intel shall be used in advertising or otherwise to promote the sale, use or 77 * other dealings in products derived from or relating to the Covered Code 78 * without prior written authorization from Intel. 79 * 80 * 4. Disclaimer and Export Compliance 81 * 82 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 83 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 84 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 85 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 86 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 87 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 88 * PARTICULAR PURPOSE. 89 * 90 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 91 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 92 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 93 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 94 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 95 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 96 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 97 * LIMITED REMEDY. 98 * 99 * 4.3. Licensee shall not export, either directly or indirectly, any of this 100 * software or system incorporating such software without first obtaining any 101 * required license or other approval from the U. S. Department of Commerce or 102 * any other agency or department of the United States Government. In the 103 * event Licensee exports any such software from the United States or 104 * re-exports any such software from a foreign destination, Licensee shall 105 * ensure that the distribution and export/re-export of the software is in 106 * compliance with all laws, regulations, orders, or other restrictions of the 107 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 108 * any of its subsidiaries will export/re-export any technical data, process, 109 * software, or service, directly or indirectly, to any country for which the 110 * United States government or any agency thereof requires an export license, 111 * other governmental approval, or letter of assurance, without first obtaining 112 * such license, approval or letter. 113 * 114 ***************************************************************************** 115 * 116 * Alternatively, you may choose to be licensed under the terms of the 117 * following license: 118 * 119 * Redistribution and use in source and binary forms, with or without 120 * modification, are permitted provided that the following conditions 121 * are met: 122 * 1. Redistributions of source code must retain the above copyright 123 * notice, this list of conditions, and the following disclaimer, 124 * without modification. 125 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 126 * substantially similar to the "NO WARRANTY" disclaimer below 127 * ("Disclaimer") and any redistribution must be conditioned upon 128 * including a substantially similar Disclaimer requirement for further 129 * binary redistribution. 130 * 3. Neither the names of the above-listed copyright holders nor the names 131 * of any contributors may be used to endorse or promote products derived 132 * from this software without specific prior written permission. 133 * 134 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 135 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 136 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 137 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 138 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 139 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 140 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 141 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 142 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 143 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 144 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 145 * 146 * Alternatively, you may choose to be licensed under the terms of the 147 * GNU General Public License ("GPL") version 2 as published by the Free 148 * Software Foundation. 149 * 150 *****************************************************************************/ 151 152 #include <contrib/dev/acpica/include/acpi.h> 153 #include <contrib/dev/acpica/include/accommon.h> 154 155 156 #define _COMPONENT ACPI_NAMESPACE 157 ACPI_MODULE_NAME ("hwpci") 158 159 160 /* PCI configuration space values */ 161 162 #define PCI_CFG_HEADER_TYPE_REG 0x0E 163 #define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 164 #define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 165 166 /* PCI header values */ 167 168 #define PCI_HEADER_TYPE_MASK 0x7F 169 #define PCI_TYPE_BRIDGE 0x01 170 #define PCI_TYPE_CARDBUS_BRIDGE 0x02 171 172 typedef struct acpi_pci_device 173 { 174 ACPI_HANDLE Device; 175 struct acpi_pci_device *Next; 176 177 } ACPI_PCI_DEVICE; 178 179 180 /* Local prototypes */ 181 182 static ACPI_STATUS 183 AcpiHwBuildPciList ( 184 ACPI_HANDLE RootPciDevice, 185 ACPI_HANDLE PciRegion, 186 ACPI_PCI_DEVICE **ReturnListHead); 187 188 static ACPI_STATUS 189 AcpiHwProcessPciList ( 190 ACPI_PCI_ID *PciId, 191 ACPI_PCI_DEVICE *ListHead); 192 193 static void 194 AcpiHwDeletePciList ( 195 ACPI_PCI_DEVICE *ListHead); 196 197 static ACPI_STATUS 198 AcpiHwGetPciDeviceInfo ( 199 ACPI_PCI_ID *PciId, 200 ACPI_HANDLE PciDevice, 201 UINT16 *BusNumber, 202 BOOLEAN *IsBridge); 203 204 205 /******************************************************************************* 206 * 207 * FUNCTION: AcpiHwDerivePciId 208 * 209 * PARAMETERS: PciId - Initial values for the PCI ID. May be 210 * modified by this function. 211 * RootPciDevice - A handle to a PCI device object. This 212 * object must be a PCI Root Bridge having a 213 * _HID value of either PNP0A03 or PNP0A08 214 * PciRegion - A handle to a PCI configuration space 215 * Operation Region being initialized 216 * 217 * RETURN: Status 218 * 219 * DESCRIPTION: This function derives a full PCI ID for a PCI device, 220 * consisting of a Segment number, Bus number, Device number, 221 * and function code. 222 * 223 * The PCI hardware dynamically configures PCI bus numbers 224 * depending on the bus topology discovered during system 225 * initialization. This function is invoked during configuration 226 * of a PCI_Config Operation Region in order to (possibly) update 227 * the Bus/Device/Function numbers in the PciId with the actual 228 * values as determined by the hardware and operating system 229 * configuration. 230 * 231 * The PciId parameter is initially populated during the Operation 232 * Region initialization. This function is then called, and is 233 * will make any necessary modifications to the Bus, Device, or 234 * Function number PCI ID subfields as appropriate for the 235 * current hardware and OS configuration. 236 * 237 * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId 238 * interface since this feature is OS-independent. This module 239 * specifically avoids any use of recursion by building a local 240 * temporary device list. 241 * 242 ******************************************************************************/ 243 244 ACPI_STATUS 245 AcpiHwDerivePciId ( 246 ACPI_PCI_ID *PciId, 247 ACPI_HANDLE RootPciDevice, 248 ACPI_HANDLE PciRegion) 249 { 250 ACPI_STATUS Status; 251 ACPI_PCI_DEVICE *ListHead; 252 253 254 ACPI_FUNCTION_TRACE (HwDerivePciId); 255 256 257 if (!PciId) 258 { 259 return_ACPI_STATUS (AE_BAD_PARAMETER); 260 } 261 262 /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ 263 264 Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); 265 if (ACPI_SUCCESS (Status)) 266 { 267 /* Walk the list, updating the PCI device/function/bus numbers */ 268 269 Status = AcpiHwProcessPciList (PciId, ListHead); 270 271 /* Delete the list */ 272 273 AcpiHwDeletePciList (ListHead); 274 } 275 276 return_ACPI_STATUS (Status); 277 } 278 279 280 /******************************************************************************* 281 * 282 * FUNCTION: AcpiHwBuildPciList 283 * 284 * PARAMETERS: RootPciDevice - A handle to a PCI device object. This 285 * object is guaranteed to be a PCI Root 286 * Bridge having a _HID value of either 287 * PNP0A03 or PNP0A08 288 * PciRegion - A handle to the PCI configuration space 289 * Operation Region 290 * ReturnListHead - Where the PCI device list is returned 291 * 292 * RETURN: Status 293 * 294 * DESCRIPTION: Builds a list of devices from the input PCI region up to the 295 * Root PCI device for this namespace subtree. 296 * 297 ******************************************************************************/ 298 299 static ACPI_STATUS 300 AcpiHwBuildPciList ( 301 ACPI_HANDLE RootPciDevice, 302 ACPI_HANDLE PciRegion, 303 ACPI_PCI_DEVICE **ReturnListHead) 304 { 305 ACPI_HANDLE CurrentDevice; 306 ACPI_HANDLE ParentDevice; 307 ACPI_STATUS Status; 308 ACPI_PCI_DEVICE *ListElement; 309 310 311 /* 312 * Ascend namespace branch until the RootPciDevice is reached, building 313 * a list of device nodes. Loop will exit when either the PCI device is 314 * found, or the root of the namespace is reached. 315 */ 316 *ReturnListHead = NULL; 317 CurrentDevice = PciRegion; 318 while (1) 319 { 320 Status = AcpiGetParent (CurrentDevice, &ParentDevice); 321 if (ACPI_FAILURE (Status)) 322 { 323 /* Must delete the list before exit */ 324 325 AcpiHwDeletePciList (*ReturnListHead); 326 return (Status); 327 } 328 329 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ 330 331 if (ParentDevice == RootPciDevice) 332 { 333 return (AE_OK); 334 } 335 336 ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); 337 if (!ListElement) 338 { 339 /* Must delete the list before exit */ 340 341 AcpiHwDeletePciList (*ReturnListHead); 342 return (AE_NO_MEMORY); 343 } 344 345 /* Put new element at the head of the list */ 346 347 ListElement->Next = *ReturnListHead; 348 ListElement->Device = ParentDevice; 349 *ReturnListHead = ListElement; 350 351 CurrentDevice = ParentDevice; 352 } 353 } 354 355 356 /******************************************************************************* 357 * 358 * FUNCTION: AcpiHwProcessPciList 359 * 360 * PARAMETERS: PciId - Initial values for the PCI ID. May be 361 * modified by this function. 362 * ListHead - Device list created by 363 * AcpiHwBuildPciList 364 * 365 * RETURN: Status 366 * 367 * DESCRIPTION: Walk downward through the PCI device list, getting the device 368 * info for each, via the PCI configuration space and updating 369 * the PCI ID as necessary. Deletes the list during traversal. 370 * 371 ******************************************************************************/ 372 373 static ACPI_STATUS 374 AcpiHwProcessPciList ( 375 ACPI_PCI_ID *PciId, 376 ACPI_PCI_DEVICE *ListHead) 377 { 378 ACPI_STATUS Status = AE_OK; 379 ACPI_PCI_DEVICE *Info; 380 UINT16 BusNumber; 381 BOOLEAN IsBridge = TRUE; 382 383 384 ACPI_FUNCTION_NAME (HwProcessPciList); 385 386 387 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 388 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", 389 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); 390 391 BusNumber = PciId->Bus; 392 393 /* 394 * Descend down the namespace tree, collecting PCI device, function, 395 * and bus numbers. BusNumber is only important for PCI bridges. 396 * Algorithm: As we descend the tree, use the last valid PCI device, 397 * function, and bus numbers that are discovered, and assign them 398 * to the PCI ID for the target device. 399 */ 400 Info = ListHead; 401 while (Info) 402 { 403 Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, 404 &BusNumber, &IsBridge); 405 if (ACPI_FAILURE (Status)) 406 { 407 return (Status); 408 } 409 410 Info = Info->Next; 411 } 412 413 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 414 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " 415 "Status %X BusNumber %X IsBridge %X\n", 416 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, 417 Status, BusNumber, IsBridge)); 418 419 return (AE_OK); 420 } 421 422 423 /******************************************************************************* 424 * 425 * FUNCTION: AcpiHwDeletePciList 426 * 427 * PARAMETERS: ListHead - Device list created by 428 * AcpiHwBuildPciList 429 * 430 * RETURN: None 431 * 432 * DESCRIPTION: Free the entire PCI list. 433 * 434 ******************************************************************************/ 435 436 static void 437 AcpiHwDeletePciList ( 438 ACPI_PCI_DEVICE *ListHead) 439 { 440 ACPI_PCI_DEVICE *Next; 441 ACPI_PCI_DEVICE *Previous; 442 443 444 Next = ListHead; 445 while (Next) 446 { 447 Previous = Next; 448 Next = Previous->Next; 449 ACPI_FREE (Previous); 450 } 451 } 452 453 454 /******************************************************************************* 455 * 456 * FUNCTION: AcpiHwGetPciDeviceInfo 457 * 458 * PARAMETERS: PciId - Initial values for the PCI ID. May be 459 * modified by this function. 460 * PciDevice - Handle for the PCI device object 461 * BusNumber - Where a PCI bridge bus number is returned 462 * IsBridge - Return value, indicates if this PCI 463 * device is a PCI bridge 464 * 465 * RETURN: Status 466 * 467 * DESCRIPTION: Get the device info for a single PCI device object. Get the 468 * _ADR (contains PCI device and function numbers), and for PCI 469 * bridge devices, get the bus number from PCI configuration 470 * space. 471 * 472 ******************************************************************************/ 473 474 static ACPI_STATUS 475 AcpiHwGetPciDeviceInfo ( 476 ACPI_PCI_ID *PciId, 477 ACPI_HANDLE PciDevice, 478 UINT16 *BusNumber, 479 BOOLEAN *IsBridge) 480 { 481 ACPI_STATUS Status; 482 ACPI_OBJECT_TYPE ObjectType; 483 UINT64 ReturnValue; 484 UINT64 PciValue; 485 486 487 /* We only care about objects of type Device */ 488 489 Status = AcpiGetType (PciDevice, &ObjectType); 490 if (ACPI_FAILURE (Status)) 491 { 492 return (Status); 493 } 494 495 if (ObjectType != ACPI_TYPE_DEVICE) 496 { 497 return (AE_OK); 498 } 499 500 /* We need an _ADR. Ignore device if not present */ 501 502 Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, 503 PciDevice, &ReturnValue); 504 if (ACPI_FAILURE (Status)) 505 { 506 return (AE_OK); 507 } 508 509 /* 510 * From _ADR, get the PCI Device and Function and 511 * update the PCI ID. 512 */ 513 PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); 514 PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); 515 516 /* 517 * If the previous device was a bridge, use the previous 518 * device bus number 519 */ 520 if (*IsBridge) 521 { 522 PciId->Bus = *BusNumber; 523 } 524 525 /* 526 * Get the bus numbers from PCI Config space: 527 * 528 * First, get the PCI HeaderType 529 */ 530 *IsBridge = FALSE; 531 Status = AcpiOsReadPciConfiguration (PciId, 532 PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); 533 if (ACPI_FAILURE (Status)) 534 { 535 return (Status); 536 } 537 538 /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ 539 540 PciValue &= PCI_HEADER_TYPE_MASK; 541 542 if ((PciValue != PCI_TYPE_BRIDGE) && 543 (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) 544 { 545 return (AE_OK); 546 } 547 548 /* Bridge: Get the Primary BusNumber */ 549 550 Status = AcpiOsReadPciConfiguration (PciId, 551 PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); 552 if (ACPI_FAILURE (Status)) 553 { 554 return (Status); 555 } 556 557 *IsBridge = TRUE; 558 PciId->Bus = (UINT16) PciValue; 559 560 /* Bridge: Get the Secondary BusNumber */ 561 562 Status = AcpiOsReadPciConfiguration (PciId, 563 PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); 564 if (ACPI_FAILURE (Status)) 565 { 566 return (Status); 567 } 568 569 *BusNumber = (UINT16) PciValue; 570 return (AE_OK); 571 } 572