1212700Sjkim/******************************************************************************* 2212700Sjkim * 3212700Sjkim * Module Name: hwpci - Obtain PCI bus, device, and function numbers 4212700Sjkim * 5212700Sjkim ******************************************************************************/ 6212700Sjkim 7217365Sjkim/* 8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp. 9212700Sjkim * All rights reserved. 10212700Sjkim * 11217365Sjkim * Redistribution and use in source and binary forms, with or without 12217365Sjkim * modification, are permitted provided that the following conditions 13217365Sjkim * are met: 14217365Sjkim * 1. Redistributions of source code must retain the above copyright 15217365Sjkim * notice, this list of conditions, and the following disclaimer, 16217365Sjkim * without modification. 17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18217365Sjkim * substantially similar to the "NO WARRANTY" disclaimer below 19217365Sjkim * ("Disclaimer") and any redistribution must be conditioned upon 20217365Sjkim * including a substantially similar Disclaimer requirement for further 21217365Sjkim * binary redistribution. 22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names 23217365Sjkim * of any contributors may be used to endorse or promote products derived 24217365Sjkim * from this software without specific prior written permission. 25212700Sjkim * 26217365Sjkim * Alternatively, this software may be distributed under the terms of the 27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free 28217365Sjkim * Software Foundation. 29212700Sjkim * 30217365Sjkim * NO WARRANTY 31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR 34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41217365Sjkim * POSSIBILITY OF SUCH DAMAGES. 42217365Sjkim */ 43212700Sjkim 44212761Sjkim#include <contrib/dev/acpica/include/acpi.h> 45212761Sjkim#include <contrib/dev/acpica/include/accommon.h> 46212700Sjkim 47212700Sjkim 48212700Sjkim#define _COMPONENT ACPI_NAMESPACE 49212700Sjkim ACPI_MODULE_NAME ("hwpci") 50212700Sjkim 51212700Sjkim 52212700Sjkim/* PCI configuration space values */ 53212700Sjkim 54212700Sjkim#define PCI_CFG_HEADER_TYPE_REG 0x0E 55212700Sjkim#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 56212700Sjkim#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 57212700Sjkim 58212700Sjkim/* PCI header values */ 59212700Sjkim 60212700Sjkim#define PCI_HEADER_TYPE_MASK 0x7F 61212700Sjkim#define PCI_TYPE_BRIDGE 0x01 62212700Sjkim#define PCI_TYPE_CARDBUS_BRIDGE 0x02 63212700Sjkim 64212700Sjkimtypedef struct acpi_pci_device 65212700Sjkim{ 66212700Sjkim ACPI_HANDLE Device; 67212700Sjkim struct acpi_pci_device *Next; 68212700Sjkim 69212700Sjkim} ACPI_PCI_DEVICE; 70212700Sjkim 71212700Sjkim 72212700Sjkim/* Local prototypes */ 73212700Sjkim 74212700Sjkimstatic ACPI_STATUS 75212700SjkimAcpiHwBuildPciList ( 76212700Sjkim ACPI_HANDLE RootPciDevice, 77212700Sjkim ACPI_HANDLE PciRegion, 78212700Sjkim ACPI_PCI_DEVICE **ReturnListHead); 79212700Sjkim 80212700Sjkimstatic ACPI_STATUS 81212700SjkimAcpiHwProcessPciList ( 82212700Sjkim ACPI_PCI_ID *PciId, 83212700Sjkim ACPI_PCI_DEVICE *ListHead); 84212700Sjkim 85212700Sjkimstatic void 86212700SjkimAcpiHwDeletePciList ( 87212700Sjkim ACPI_PCI_DEVICE *ListHead); 88212700Sjkim 89212700Sjkimstatic ACPI_STATUS 90212700SjkimAcpiHwGetPciDeviceInfo ( 91212700Sjkim ACPI_PCI_ID *PciId, 92212700Sjkim ACPI_HANDLE PciDevice, 93212700Sjkim UINT16 *BusNumber, 94212700Sjkim BOOLEAN *IsBridge); 95212700Sjkim 96212700Sjkim 97212700Sjkim/******************************************************************************* 98212700Sjkim * 99212700Sjkim * FUNCTION: AcpiHwDerivePciId 100212700Sjkim * 101212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 102212700Sjkim * modified by this function. 103212700Sjkim * RootPciDevice - A handle to a PCI device object. This 104212700Sjkim * object must be a PCI Root Bridge having a 105212700Sjkim * _HID value of either PNP0A03 or PNP0A08 106212700Sjkim * PciRegion - A handle to a PCI configuration space 107212700Sjkim * Operation Region being initialized 108212700Sjkim * 109212700Sjkim * RETURN: Status 110212700Sjkim * 111212700Sjkim * DESCRIPTION: This function derives a full PCI ID for a PCI device, 112212700Sjkim * consisting of a Segment number, Bus number, Device number, 113212700Sjkim * and function code. 114212700Sjkim * 115212700Sjkim * The PCI hardware dynamically configures PCI bus numbers 116212700Sjkim * depending on the bus topology discovered during system 117212700Sjkim * initialization. This function is invoked during configuration 118212700Sjkim * of a PCI_Config Operation Region in order to (possibly) update 119212700Sjkim * the Bus/Device/Function numbers in the PciId with the actual 120212700Sjkim * values as determined by the hardware and operating system 121212700Sjkim * configuration. 122212700Sjkim * 123212700Sjkim * The PciId parameter is initially populated during the Operation 124212700Sjkim * Region initialization. This function is then called, and is 125212700Sjkim * will make any necessary modifications to the Bus, Device, or 126212700Sjkim * Function number PCI ID subfields as appropriate for the 127212700Sjkim * current hardware and OS configuration. 128212700Sjkim * 129212700Sjkim * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId 130212700Sjkim * interface since this feature is OS-independent. This module 131212700Sjkim * specifically avoids any use of recursion by building a local 132212700Sjkim * temporary device list. 133212700Sjkim * 134212700Sjkim ******************************************************************************/ 135212700Sjkim 136212700SjkimACPI_STATUS 137212700SjkimAcpiHwDerivePciId ( 138212700Sjkim ACPI_PCI_ID *PciId, 139212700Sjkim ACPI_HANDLE RootPciDevice, 140212700Sjkim ACPI_HANDLE PciRegion) 141212700Sjkim{ 142212700Sjkim ACPI_STATUS Status; 143284460Sjkim ACPI_PCI_DEVICE *ListHead; 144212700Sjkim 145212700Sjkim 146212700Sjkim ACPI_FUNCTION_TRACE (HwDerivePciId); 147212700Sjkim 148212700Sjkim 149212700Sjkim if (!PciId) 150212700Sjkim { 151212700Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 152212700Sjkim } 153212700Sjkim 154212700Sjkim /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ 155212700Sjkim 156212700Sjkim Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); 157212700Sjkim if (ACPI_SUCCESS (Status)) 158212700Sjkim { 159212700Sjkim /* Walk the list, updating the PCI device/function/bus numbers */ 160212700Sjkim 161212700Sjkim Status = AcpiHwProcessPciList (PciId, ListHead); 162281075Sdim 163281075Sdim /* Delete the list */ 164281075Sdim 165281075Sdim AcpiHwDeletePciList (ListHead); 166212700Sjkim } 167212700Sjkim 168212700Sjkim return_ACPI_STATUS (Status); 169212700Sjkim} 170212700Sjkim 171212700Sjkim 172212700Sjkim/******************************************************************************* 173212700Sjkim * 174212700Sjkim * FUNCTION: AcpiHwBuildPciList 175212700Sjkim * 176212700Sjkim * PARAMETERS: RootPciDevice - A handle to a PCI device object. This 177212700Sjkim * object is guaranteed to be a PCI Root 178212700Sjkim * Bridge having a _HID value of either 179212700Sjkim * PNP0A03 or PNP0A08 180212700Sjkim * PciRegion - A handle to the PCI configuration space 181212700Sjkim * Operation Region 182212700Sjkim * ReturnListHead - Where the PCI device list is returned 183212700Sjkim * 184212700Sjkim * RETURN: Status 185212700Sjkim * 186212700Sjkim * DESCRIPTION: Builds a list of devices from the input PCI region up to the 187212700Sjkim * Root PCI device for this namespace subtree. 188212700Sjkim * 189212700Sjkim ******************************************************************************/ 190212700Sjkim 191212700Sjkimstatic ACPI_STATUS 192212700SjkimAcpiHwBuildPciList ( 193212700Sjkim ACPI_HANDLE RootPciDevice, 194212700Sjkim ACPI_HANDLE PciRegion, 195212700Sjkim ACPI_PCI_DEVICE **ReturnListHead) 196212700Sjkim{ 197212700Sjkim ACPI_HANDLE CurrentDevice; 198212700Sjkim ACPI_HANDLE ParentDevice; 199212700Sjkim ACPI_STATUS Status; 200212700Sjkim ACPI_PCI_DEVICE *ListElement; 201212700Sjkim 202212700Sjkim 203212700Sjkim /* 204212700Sjkim * Ascend namespace branch until the RootPciDevice is reached, building 205212700Sjkim * a list of device nodes. Loop will exit when either the PCI device is 206212700Sjkim * found, or the root of the namespace is reached. 207212700Sjkim */ 208284460Sjkim *ReturnListHead = NULL; 209212700Sjkim CurrentDevice = PciRegion; 210212700Sjkim while (1) 211212700Sjkim { 212212700Sjkim Status = AcpiGetParent (CurrentDevice, &ParentDevice); 213212700Sjkim if (ACPI_FAILURE (Status)) 214212700Sjkim { 215281075Sdim /* Must delete the list before exit */ 216281075Sdim 217281075Sdim AcpiHwDeletePciList (*ReturnListHead); 218212700Sjkim return (Status); 219212700Sjkim } 220212700Sjkim 221212700Sjkim /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ 222212700Sjkim 223212700Sjkim if (ParentDevice == RootPciDevice) 224212700Sjkim { 225212700Sjkim return (AE_OK); 226212700Sjkim } 227212700Sjkim 228212700Sjkim ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); 229212700Sjkim if (!ListElement) 230212700Sjkim { 231281075Sdim /* Must delete the list before exit */ 232281075Sdim 233281075Sdim AcpiHwDeletePciList (*ReturnListHead); 234212700Sjkim return (AE_NO_MEMORY); 235212700Sjkim } 236212700Sjkim 237212700Sjkim /* Put new element at the head of the list */ 238212700Sjkim 239284460Sjkim ListElement->Next = *ReturnListHead; 240212700Sjkim ListElement->Device = ParentDevice; 241284460Sjkim *ReturnListHead = ListElement; 242212700Sjkim 243212700Sjkim CurrentDevice = ParentDevice; 244212700Sjkim } 245212700Sjkim} 246212700Sjkim 247212700Sjkim 248212700Sjkim/******************************************************************************* 249212700Sjkim * 250212700Sjkim * FUNCTION: AcpiHwProcessPciList 251212700Sjkim * 252212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 253212700Sjkim * modified by this function. 254212700Sjkim * ListHead - Device list created by 255212700Sjkim * AcpiHwBuildPciList 256212700Sjkim * 257212700Sjkim * RETURN: Status 258212700Sjkim * 259212700Sjkim * DESCRIPTION: Walk downward through the PCI device list, getting the device 260212700Sjkim * info for each, via the PCI configuration space and updating 261212700Sjkim * the PCI ID as necessary. Deletes the list during traversal. 262212700Sjkim * 263212700Sjkim ******************************************************************************/ 264212700Sjkim 265212700Sjkimstatic ACPI_STATUS 266212700SjkimAcpiHwProcessPciList ( 267212700Sjkim ACPI_PCI_ID *PciId, 268212700Sjkim ACPI_PCI_DEVICE *ListHead) 269212700Sjkim{ 270212700Sjkim ACPI_STATUS Status = AE_OK; 271212700Sjkim ACPI_PCI_DEVICE *Info; 272212700Sjkim UINT16 BusNumber; 273212700Sjkim BOOLEAN IsBridge = TRUE; 274212700Sjkim 275212700Sjkim 276212700Sjkim ACPI_FUNCTION_NAME (HwProcessPciList); 277212700Sjkim 278212700Sjkim 279212700Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 280212700Sjkim "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", 281212700Sjkim PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); 282212700Sjkim 283212700Sjkim BusNumber = PciId->Bus; 284212700Sjkim 285212700Sjkim /* 286212700Sjkim * Descend down the namespace tree, collecting PCI device, function, 287212700Sjkim * and bus numbers. BusNumber is only important for PCI bridges. 288212700Sjkim * Algorithm: As we descend the tree, use the last valid PCI device, 289212700Sjkim * function, and bus numbers that are discovered, and assign them 290212700Sjkim * to the PCI ID for the target device. 291212700Sjkim */ 292212700Sjkim Info = ListHead; 293212700Sjkim while (Info) 294212700Sjkim { 295212700Sjkim Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, 296212700Sjkim &BusNumber, &IsBridge); 297212700Sjkim if (ACPI_FAILURE (Status)) 298212700Sjkim { 299241973Sjkim return (Status); 300212700Sjkim } 301212700Sjkim 302212700Sjkim Info = Info->Next; 303212700Sjkim } 304212700Sjkim 305212700Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 306212700Sjkim "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " 307212700Sjkim "Status %X BusNumber %X IsBridge %X\n", 308212700Sjkim PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, 309212700Sjkim Status, BusNumber, IsBridge)); 310212700Sjkim 311241973Sjkim return (AE_OK); 312212700Sjkim} 313212700Sjkim 314212700Sjkim 315212700Sjkim/******************************************************************************* 316212700Sjkim * 317212700Sjkim * FUNCTION: AcpiHwDeletePciList 318212700Sjkim * 319212700Sjkim * PARAMETERS: ListHead - Device list created by 320212700Sjkim * AcpiHwBuildPciList 321212700Sjkim * 322212700Sjkim * RETURN: None 323212700Sjkim * 324212700Sjkim * DESCRIPTION: Free the entire PCI list. 325212700Sjkim * 326212700Sjkim ******************************************************************************/ 327212700Sjkim 328212700Sjkimstatic void 329212700SjkimAcpiHwDeletePciList ( 330212700Sjkim ACPI_PCI_DEVICE *ListHead) 331212700Sjkim{ 332212700Sjkim ACPI_PCI_DEVICE *Next; 333212700Sjkim ACPI_PCI_DEVICE *Previous; 334212700Sjkim 335212700Sjkim 336212700Sjkim Next = ListHead; 337212700Sjkim while (Next) 338212700Sjkim { 339212700Sjkim Previous = Next; 340212700Sjkim Next = Previous->Next; 341212700Sjkim ACPI_FREE (Previous); 342212700Sjkim } 343212700Sjkim} 344212700Sjkim 345212700Sjkim 346212700Sjkim/******************************************************************************* 347212700Sjkim * 348212700Sjkim * FUNCTION: AcpiHwGetPciDeviceInfo 349212700Sjkim * 350212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 351212700Sjkim * modified by this function. 352212700Sjkim * PciDevice - Handle for the PCI device object 353212700Sjkim * BusNumber - Where a PCI bridge bus number is returned 354212700Sjkim * IsBridge - Return value, indicates if this PCI 355212700Sjkim * device is a PCI bridge 356212700Sjkim * 357212700Sjkim * RETURN: Status 358212700Sjkim * 359212700Sjkim * DESCRIPTION: Get the device info for a single PCI device object. Get the 360212700Sjkim * _ADR (contains PCI device and function numbers), and for PCI 361212700Sjkim * bridge devices, get the bus number from PCI configuration 362212700Sjkim * space. 363212700Sjkim * 364212700Sjkim ******************************************************************************/ 365212700Sjkim 366212700Sjkimstatic ACPI_STATUS 367212700SjkimAcpiHwGetPciDeviceInfo ( 368212700Sjkim ACPI_PCI_ID *PciId, 369212700Sjkim ACPI_HANDLE PciDevice, 370212700Sjkim UINT16 *BusNumber, 371212700Sjkim BOOLEAN *IsBridge) 372212700Sjkim{ 373212700Sjkim ACPI_STATUS Status; 374212700Sjkim ACPI_OBJECT_TYPE ObjectType; 375212700Sjkim UINT64 ReturnValue; 376212700Sjkim UINT64 PciValue; 377212700Sjkim 378212700Sjkim 379212700Sjkim /* We only care about objects of type Device */ 380212700Sjkim 381212700Sjkim Status = AcpiGetType (PciDevice, &ObjectType); 382212700Sjkim if (ACPI_FAILURE (Status)) 383212700Sjkim { 384212700Sjkim return (Status); 385212700Sjkim } 386212700Sjkim 387212700Sjkim if (ObjectType != ACPI_TYPE_DEVICE) 388212700Sjkim { 389212700Sjkim return (AE_OK); 390212700Sjkim } 391212700Sjkim 392212700Sjkim /* We need an _ADR. Ignore device if not present */ 393212700Sjkim 394212700Sjkim Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, 395212700Sjkim PciDevice, &ReturnValue); 396212700Sjkim if (ACPI_FAILURE (Status)) 397212700Sjkim { 398212700Sjkim return (AE_OK); 399212700Sjkim } 400212700Sjkim 401212700Sjkim /* 402212700Sjkim * From _ADR, get the PCI Device and Function and 403212700Sjkim * update the PCI ID. 404212700Sjkim */ 405212700Sjkim PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); 406212700Sjkim PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); 407212700Sjkim 408212700Sjkim /* 409212700Sjkim * If the previous device was a bridge, use the previous 410212700Sjkim * device bus number 411212700Sjkim */ 412212700Sjkim if (*IsBridge) 413212700Sjkim { 414212700Sjkim PciId->Bus = *BusNumber; 415212700Sjkim } 416212700Sjkim 417212700Sjkim /* 418212700Sjkim * Get the bus numbers from PCI Config space: 419212700Sjkim * 420212700Sjkim * First, get the PCI HeaderType 421212700Sjkim */ 422212700Sjkim *IsBridge = FALSE; 423212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 424212700Sjkim PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); 425212700Sjkim if (ACPI_FAILURE (Status)) 426212700Sjkim { 427212700Sjkim return (Status); 428212700Sjkim } 429212700Sjkim 430212700Sjkim /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ 431212700Sjkim 432212700Sjkim PciValue &= PCI_HEADER_TYPE_MASK; 433212700Sjkim 434212700Sjkim if ((PciValue != PCI_TYPE_BRIDGE) && 435212700Sjkim (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) 436212700Sjkim { 437212700Sjkim return (AE_OK); 438212700Sjkim } 439212700Sjkim 440212700Sjkim /* Bridge: Get the Primary BusNumber */ 441212700Sjkim 442212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 443212700Sjkim PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); 444212700Sjkim if (ACPI_FAILURE (Status)) 445212700Sjkim { 446212700Sjkim return (Status); 447212700Sjkim } 448212700Sjkim 449212700Sjkim *IsBridge = TRUE; 450212700Sjkim PciId->Bus = (UINT16) PciValue; 451212700Sjkim 452212700Sjkim /* Bridge: Get the Secondary BusNumber */ 453212700Sjkim 454212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 455212700Sjkim PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); 456212700Sjkim if (ACPI_FAILURE (Status)) 457212700Sjkim { 458212700Sjkim return (Status); 459212700Sjkim } 460212700Sjkim 461212700Sjkim *BusNumber = (UINT16) PciValue; 462212700Sjkim return (AE_OK); 463212700Sjkim} 464