1 /******************************************************************************* 2 * 3 * Module Name: hwpci - Obtain PCI bus, device, and function numbers 4 * 5 ******************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 = NULL; 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 ACPI_PCI_DEVICE *ListHead = NULL; 202 203 204 /* 205 * Ascend namespace branch until the RootPciDevice is reached, building 206 * a list of device nodes. Loop will exit when either the PCI device is 207 * found, or the root of the namespace is reached. 208 */ 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 *ReturnListHead = ListHead; 226 return (AE_OK); 227 } 228 229 ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); 230 if (!ListElement) 231 { 232 /* Must delete the list before exit */ 233 234 AcpiHwDeletePciList (*ReturnListHead); 235 return (AE_NO_MEMORY); 236 } 237 238 /* Put new element at the head of the list */ 239 240 ListElement->Next = ListHead; 241 ListElement->Device = ParentDevice; 242 ListHead = ListElement; 243 244 CurrentDevice = ParentDevice; 245 } 246 } 247 248 249 /******************************************************************************* 250 * 251 * FUNCTION: AcpiHwProcessPciList 252 * 253 * PARAMETERS: PciId - Initial values for the PCI ID. May be 254 * modified by this function. 255 * ListHead - Device list created by 256 * AcpiHwBuildPciList 257 * 258 * RETURN: Status 259 * 260 * DESCRIPTION: Walk downward through the PCI device list, getting the device 261 * info for each, via the PCI configuration space and updating 262 * the PCI ID as necessary. Deletes the list during traversal. 263 * 264 ******************************************************************************/ 265 266 static ACPI_STATUS 267 AcpiHwProcessPciList ( 268 ACPI_PCI_ID *PciId, 269 ACPI_PCI_DEVICE *ListHead) 270 { 271 ACPI_STATUS Status = AE_OK; 272 ACPI_PCI_DEVICE *Info; 273 UINT16 BusNumber; 274 BOOLEAN IsBridge = TRUE; 275 276 277 ACPI_FUNCTION_NAME (HwProcessPciList); 278 279 280 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 281 "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", 282 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); 283 284 BusNumber = PciId->Bus; 285 286 /* 287 * Descend down the namespace tree, collecting PCI device, function, 288 * and bus numbers. BusNumber is only important for PCI bridges. 289 * Algorithm: As we descend the tree, use the last valid PCI device, 290 * function, and bus numbers that are discovered, and assign them 291 * to the PCI ID for the target device. 292 */ 293 Info = ListHead; 294 while (Info) 295 { 296 Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, 297 &BusNumber, &IsBridge); 298 if (ACPI_FAILURE (Status)) 299 { 300 return (Status); 301 } 302 303 Info = Info->Next; 304 } 305 306 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 307 "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " 308 "Status %X BusNumber %X IsBridge %X\n", 309 PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, 310 Status, BusNumber, IsBridge)); 311 312 return (AE_OK); 313 } 314 315 316 /******************************************************************************* 317 * 318 * FUNCTION: AcpiHwDeletePciList 319 * 320 * PARAMETERS: ListHead - Device list created by 321 * AcpiHwBuildPciList 322 * 323 * RETURN: None 324 * 325 * DESCRIPTION: Free the entire PCI list. 326 * 327 ******************************************************************************/ 328 329 static void 330 AcpiHwDeletePciList ( 331 ACPI_PCI_DEVICE *ListHead) 332 { 333 ACPI_PCI_DEVICE *Next; 334 ACPI_PCI_DEVICE *Previous; 335 336 337 Next = ListHead; 338 while (Next) 339 { 340 Previous = Next; 341 Next = Previous->Next; 342 ACPI_FREE (Previous); 343 } 344 } 345 346 347 /******************************************************************************* 348 * 349 * FUNCTION: AcpiHwGetPciDeviceInfo 350 * 351 * PARAMETERS: PciId - Initial values for the PCI ID. May be 352 * modified by this function. 353 * PciDevice - Handle for the PCI device object 354 * BusNumber - Where a PCI bridge bus number is returned 355 * IsBridge - Return value, indicates if this PCI 356 * device is a PCI bridge 357 * 358 * RETURN: Status 359 * 360 * DESCRIPTION: Get the device info for a single PCI device object. Get the 361 * _ADR (contains PCI device and function numbers), and for PCI 362 * bridge devices, get the bus number from PCI configuration 363 * space. 364 * 365 ******************************************************************************/ 366 367 static ACPI_STATUS 368 AcpiHwGetPciDeviceInfo ( 369 ACPI_PCI_ID *PciId, 370 ACPI_HANDLE PciDevice, 371 UINT16 *BusNumber, 372 BOOLEAN *IsBridge) 373 { 374 ACPI_STATUS Status; 375 ACPI_OBJECT_TYPE ObjectType; 376 UINT64 ReturnValue; 377 UINT64 PciValue; 378 379 380 /* We only care about objects of type Device */ 381 382 Status = AcpiGetType (PciDevice, &ObjectType); 383 if (ACPI_FAILURE (Status)) 384 { 385 return (Status); 386 } 387 388 if (ObjectType != ACPI_TYPE_DEVICE) 389 { 390 return (AE_OK); 391 } 392 393 /* We need an _ADR. Ignore device if not present */ 394 395 Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, 396 PciDevice, &ReturnValue); 397 if (ACPI_FAILURE (Status)) 398 { 399 return (AE_OK); 400 } 401 402 /* 403 * From _ADR, get the PCI Device and Function and 404 * update the PCI ID. 405 */ 406 PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); 407 PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); 408 409 /* 410 * If the previous device was a bridge, use the previous 411 * device bus number 412 */ 413 if (*IsBridge) 414 { 415 PciId->Bus = *BusNumber; 416 } 417 418 /* 419 * Get the bus numbers from PCI Config space: 420 * 421 * First, get the PCI HeaderType 422 */ 423 *IsBridge = FALSE; 424 Status = AcpiOsReadPciConfiguration (PciId, 425 PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); 426 if (ACPI_FAILURE (Status)) 427 { 428 return (Status); 429 } 430 431 /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ 432 433 PciValue &= PCI_HEADER_TYPE_MASK; 434 435 if ((PciValue != PCI_TYPE_BRIDGE) && 436 (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) 437 { 438 return (AE_OK); 439 } 440 441 /* Bridge: Get the Primary BusNumber */ 442 443 Status = AcpiOsReadPciConfiguration (PciId, 444 PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); 445 if (ACPI_FAILURE (Status)) 446 { 447 return (Status); 448 } 449 450 *IsBridge = TRUE; 451 PciId->Bus = (UINT16) PciValue; 452 453 /* Bridge: Get the Secondary BusNumber */ 454 455 Status = AcpiOsReadPciConfiguration (PciId, 456 PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); 457 if (ACPI_FAILURE (Status)) 458 { 459 return (Status); 460 } 461 462 *BusNumber = (UINT16) PciValue; 463 return (AE_OK); 464 } 465