1 /******************************************************************************* 2 * 3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers 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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 47 48 #define _COMPONENT ACPI_NAMESPACE 49 ACPI_MODULE_NAME ("hwpci") 50 51 52 /* PCI configuration space values */ 53 54 #define PCI_CFG_HEADER_TYPE_REG 0x0E 55 #define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 56 #define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 57 58 /* PCI header values */ 59 60 #define PCI_HEADER_TYPE_MASK 0x7F 61 #define PCI_TYPE_BRIDGE 0x01 62 #define PCI_TYPE_CARDBUS_BRIDGE 0x02 63 64 typedef struct acpi_pci_device 65 { 66 ACPI_HANDLE Device; 67 struct acpi_pci_device *Next; 68 69 } ACPI_PCI_DEVICE; 70 71 72 /* Local prototypes */ 73 74 static ACPI_STATUS 75 AcpiHwBuildPciList ( 76 ACPI_HANDLE RootPciDevice, 77 ACPI_HANDLE PciRegion, 78 ACPI_PCI_DEVICE **ReturnListHead); 79 80 static ACPI_STATUS 81 AcpiHwProcessPciList ( 82 ACPI_PCI_ID *PciId, 83 ACPI_PCI_DEVICE *ListHead); 84 85 static void 86 AcpiHwDeletePciList ( 87 ACPI_PCI_DEVICE *ListHead); 88 89 static ACPI_STATUS 90 AcpiHwGetPciDeviceInfo ( 91 ACPI_PCI_ID *PciId, 92 ACPI_HANDLE PciDevice, 93 UINT16 *BusNumber, 94 BOOLEAN *IsBridge); 95 96 97 /******************************************************************************* 98 * 99 * FUNCTION: AcpiHwDerivePciId 100 * 101 * PARAMETERS: PciId - Initial values for the PCI ID. May be 102 * modified by this function. 103 * RootPciDevice - A handle to a PCI device object. This 104 * object must be a PCI Root Bridge having a 105 * _HID value of either PNP0A03 or PNP0A08 106 * PciRegion - A handle to a PCI configuration space 107 * Operation Region being initialized 108 * 109 * RETURN: Status 110 * 111 * DESCRIPTION: This function derives a full PCI ID for a PCI device, 112 * consisting of a Segment number, Bus number, Device number, 113 * and function code. 114 * 115 * The PCI hardware dynamically configures PCI bus numbers 116 * depending on the bus topology discovered during system 117 * initialization. This function is invoked during configuration 118 * of a PCI_Config Operation Region in order to (possibly) update 119 * the Bus/Device/Function numbers in the PciId with the actual 120 * values as determined by the hardware and operating system 121 * configuration. 122 * 123 * The PciId parameter is initially populated during the Operation 124 * Region initialization. This function is then called, and is 125 * will make any necessary modifications to the Bus, Device, or 126 * Function number PCI ID subfields as appropriate for the 127 * current hardware and OS configuration. 128 * 129 * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId 130 * interface since this feature is OS-independent. This module 131 * specifically avoids any use of recursion by building a local 132 * temporary device list. 133 * 134 ******************************************************************************/ 135 136 ACPI_STATUS 137 AcpiHwDerivePciId ( 138 ACPI_PCI_ID *PciId, 139 ACPI_HANDLE RootPciDevice, 140 ACPI_HANDLE PciRegion) 141 { 142 ACPI_STATUS Status; 143 ACPI_PCI_DEVICE *ListHead; 144 145 146 ACPI_FUNCTION_TRACE (HwDerivePciId); 147 148 149 if (!PciId) 150 { 151 return_ACPI_STATUS (AE_BAD_PARAMETER); 152 } 153 154 /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ 155 156 Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); 157 if (ACPI_SUCCESS (Status)) 158 { 159 /* Walk the list, updating the PCI device/function/bus numbers */ 160 161 Status = AcpiHwProcessPciList (PciId, ListHead); 162 163 /* Delete the list */ 164 165 AcpiHwDeletePciList (ListHead); 166 } 167 168 return_ACPI_STATUS (Status); 169 } 170 171 172 /******************************************************************************* 173 * 174 * FUNCTION: AcpiHwBuildPciList 175 * 176 * PARAMETERS: RootPciDevice - A handle to a PCI device object. This 177 * object is guaranteed to be a PCI Root 178 * Bridge having a _HID value of either 179 * PNP0A03 or PNP0A08 180 * PciRegion - A handle to the PCI configuration space 181 * Operation Region 182 * ReturnListHead - Where the PCI device list is returned 183 * 184 * RETURN: Status 185 * 186 * DESCRIPTION: Builds a list of devices from the input PCI region up to the 187 * Root PCI device for this namespace subtree. 188 * 189 ******************************************************************************/ 190 191 static ACPI_STATUS 192 AcpiHwBuildPciList ( 193 ACPI_HANDLE RootPciDevice, 194 ACPI_HANDLE PciRegion, 195 ACPI_PCI_DEVICE **ReturnListHead) 196 { 197 ACPI_HANDLE CurrentDevice; 198 ACPI_HANDLE ParentDevice; 199 ACPI_STATUS Status; 200 ACPI_PCI_DEVICE *ListElement; 201 202 203 /* 204 * Ascend namespace branch until the RootPciDevice is reached, building 205 * a list of device nodes. Loop will exit when either the PCI device is 206 * found, or the root of the namespace is reached. 207 */ 208 *ReturnListHead = NULL; 209 CurrentDevice = PciRegion; 210 while (1) 211 { 212 Status = AcpiGetParent (CurrentDevice, &ParentDevice); 213 if (ACPI_FAILURE (Status)) 214 { 215 /* Must delete the list before exit */ 216 217 AcpiHwDeletePciList (*ReturnListHead); 218 return (Status); 219 } 220 221 /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ 222 223 if (ParentDevice == RootPciDevice) 224 { 225 return (AE_OK); 226 } 227 228 ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); 229 if (!ListElement) 230 { 231 /* Must delete the list before exit */ 232 233 AcpiHwDeletePciList (*ReturnListHead); 234 return (AE_NO_MEMORY); 235 } 236 237 /* Put new element at the head of the list */ 238 239 ListElement->Next = *ReturnListHead; 240 ListElement->Device = ParentDevice; 241 *ReturnListHead = ListElement; 242 243 CurrentDevice = ParentDevice; 244 } 245 } 246 247 248 /******************************************************************************* 249 * 250 * FUNCTION: AcpiHwProcessPciList 251 * 252 * PARAMETERS: PciId - Initial values for the PCI ID. May be 253 * modified by this function. 254 * ListHead - Device list created by 255 * AcpiHwBuildPciList 256 * 257 * RETURN: Status 258 * 259 * DESCRIPTION: Walk downward through the PCI device list, getting the device 260 * info for each, via the PCI configuration space and updating 261 * the PCI ID as necessary. Deletes the list during traversal. 262 * 263 ******************************************************************************/ 264 265 static ACPI_STATUS 266 AcpiHwProcessPciList ( 267 ACPI_PCI_ID *PciId, 268 ACPI_PCI_DEVICE *ListHead) 269 { 270 ACPI_STATUS Status = AE_OK; 271 ACPI_PCI_DEVICE *Info; 272 UINT16 BusNumber; 273 BOOLEAN IsBridge = TRUE; 274 275 276 ACPI_FUNCTION_NAME (HwProcessPciList); 277 278 279 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 280 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", 281 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); 282 283 BusNumber = PciId->Bus; 284 285 /* 286 * Descend down the namespace tree, collecting PCI device, function, 287 * and bus numbers. BusNumber is only important for PCI bridges. 288 * Algorithm: As we descend the tree, use the last valid PCI device, 289 * function, and bus numbers that are discovered, and assign them 290 * to the PCI ID for the target device. 291 */ 292 Info = ListHead; 293 while (Info) 294 { 295 Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, 296 &BusNumber, &IsBridge); 297 if (ACPI_FAILURE (Status)) 298 { 299 return (Status); 300 } 301 302 Info = Info->Next; 303 } 304 305 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 306 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " 307 "Status %X BusNumber %X IsBridge %X\n", 308 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, 309 Status, BusNumber, IsBridge)); 310 311 return (AE_OK); 312 } 313 314 315 /******************************************************************************* 316 * 317 * FUNCTION: AcpiHwDeletePciList 318 * 319 * PARAMETERS: ListHead - Device list created by 320 * AcpiHwBuildPciList 321 * 322 * RETURN: None 323 * 324 * DESCRIPTION: Free the entire PCI list. 325 * 326 ******************************************************************************/ 327 328 static void 329 AcpiHwDeletePciList ( 330 ACPI_PCI_DEVICE *ListHead) 331 { 332 ACPI_PCI_DEVICE *Next; 333 ACPI_PCI_DEVICE *Previous; 334 335 336 Next = ListHead; 337 while (Next) 338 { 339 Previous = Next; 340 Next = Previous->Next; 341 ACPI_FREE (Previous); 342 } 343 } 344 345 346 /******************************************************************************* 347 * 348 * FUNCTION: AcpiHwGetPciDeviceInfo 349 * 350 * PARAMETERS: PciId - Initial values for the PCI ID. May be 351 * modified by this function. 352 * PciDevice - Handle for the PCI device object 353 * BusNumber - Where a PCI bridge bus number is returned 354 * IsBridge - Return value, indicates if this PCI 355 * device is a PCI bridge 356 * 357 * RETURN: Status 358 * 359 * DESCRIPTION: Get the device info for a single PCI device object. Get the 360 * _ADR (contains PCI device and function numbers), and for PCI 361 * bridge devices, get the bus number from PCI configuration 362 * space. 363 * 364 ******************************************************************************/ 365 366 static ACPI_STATUS 367 AcpiHwGetPciDeviceInfo ( 368 ACPI_PCI_ID *PciId, 369 ACPI_HANDLE PciDevice, 370 UINT16 *BusNumber, 371 BOOLEAN *IsBridge) 372 { 373 ACPI_STATUS Status; 374 ACPI_OBJECT_TYPE ObjectType; 375 UINT64 ReturnValue; 376 UINT64 PciValue; 377 378 379 /* We only care about objects of type Device */ 380 381 Status = AcpiGetType (PciDevice, &ObjectType); 382 if (ACPI_FAILURE (Status)) 383 { 384 return (Status); 385 } 386 387 if (ObjectType != ACPI_TYPE_DEVICE) 388 { 389 return (AE_OK); 390 } 391 392 /* We need an _ADR. Ignore device if not present */ 393 394 Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, 395 PciDevice, &ReturnValue); 396 if (ACPI_FAILURE (Status)) 397 { 398 return (AE_OK); 399 } 400 401 /* 402 * From _ADR, get the PCI Device and Function and 403 * update the PCI ID. 404 */ 405 PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); 406 PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); 407 408 /* 409 * If the previous device was a bridge, use the previous 410 * device bus number 411 */ 412 if (*IsBridge) 413 { 414 PciId->Bus = *BusNumber; 415 } 416 417 /* 418 * Get the bus numbers from PCI Config space: 419 * 420 * First, get the PCI HeaderType 421 */ 422 *IsBridge = FALSE; 423 Status = AcpiOsReadPciConfiguration (PciId, 424 PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); 425 if (ACPI_FAILURE (Status)) 426 { 427 return (Status); 428 } 429 430 /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ 431 432 PciValue &= PCI_HEADER_TYPE_MASK; 433 434 if ((PciValue != PCI_TYPE_BRIDGE) && 435 (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) 436 { 437 return (AE_OK); 438 } 439 440 /* Bridge: Get the Primary BusNumber */ 441 442 Status = AcpiOsReadPciConfiguration (PciId, 443 PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); 444 if (ACPI_FAILURE (Status)) 445 { 446 return (Status); 447 } 448 449 *IsBridge = TRUE; 450 PciId->Bus = (UINT16) PciValue; 451 452 /* Bridge: Get the Secondary BusNumber */ 453 454 Status = AcpiOsReadPciConfiguration (PciId, 455 PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); 456 if (ACPI_FAILURE (Status)) 457 { 458 return (Status); 459 } 460 461 *BusNumber = (UINT16) PciValue; 462 return (AE_OK); 463 } 464