1212700Sjkim/******************************************************************************* 2212700Sjkim * 3212700Sjkim * Module Name: hwpci - Obtain PCI bus, device, and function numbers 4212700Sjkim * 5212700Sjkim ******************************************************************************/ 6212700Sjkim 7217365Sjkim/* 8245582Sjkim * Copyright (C) 2000 - 2013, 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 44212700Sjkim#define __HWPCI_C__ 45212700Sjkim 46212761Sjkim#include <contrib/dev/acpica/include/acpi.h> 47212761Sjkim#include <contrib/dev/acpica/include/accommon.h> 48212700Sjkim 49212700Sjkim 50212700Sjkim#define _COMPONENT ACPI_NAMESPACE 51212700Sjkim ACPI_MODULE_NAME ("hwpci") 52212700Sjkim 53212700Sjkim 54212700Sjkim/* PCI configuration space values */ 55212700Sjkim 56212700Sjkim#define PCI_CFG_HEADER_TYPE_REG 0x0E 57212700Sjkim#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18 58212700Sjkim#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19 59212700Sjkim 60212700Sjkim/* PCI header values */ 61212700Sjkim 62212700Sjkim#define PCI_HEADER_TYPE_MASK 0x7F 63212700Sjkim#define PCI_TYPE_BRIDGE 0x01 64212700Sjkim#define PCI_TYPE_CARDBUS_BRIDGE 0x02 65212700Sjkim 66212700Sjkimtypedef struct acpi_pci_device 67212700Sjkim{ 68212700Sjkim ACPI_HANDLE Device; 69212700Sjkim struct acpi_pci_device *Next; 70212700Sjkim 71212700Sjkim} ACPI_PCI_DEVICE; 72212700Sjkim 73212700Sjkim 74212700Sjkim/* Local prototypes */ 75212700Sjkim 76212700Sjkimstatic ACPI_STATUS 77212700SjkimAcpiHwBuildPciList ( 78212700Sjkim ACPI_HANDLE RootPciDevice, 79212700Sjkim ACPI_HANDLE PciRegion, 80212700Sjkim ACPI_PCI_DEVICE **ReturnListHead); 81212700Sjkim 82212700Sjkimstatic ACPI_STATUS 83212700SjkimAcpiHwProcessPciList ( 84212700Sjkim ACPI_PCI_ID *PciId, 85212700Sjkim ACPI_PCI_DEVICE *ListHead); 86212700Sjkim 87212700Sjkimstatic void 88212700SjkimAcpiHwDeletePciList ( 89212700Sjkim ACPI_PCI_DEVICE *ListHead); 90212700Sjkim 91212700Sjkimstatic ACPI_STATUS 92212700SjkimAcpiHwGetPciDeviceInfo ( 93212700Sjkim ACPI_PCI_ID *PciId, 94212700Sjkim ACPI_HANDLE PciDevice, 95212700Sjkim UINT16 *BusNumber, 96212700Sjkim BOOLEAN *IsBridge); 97212700Sjkim 98212700Sjkim 99212700Sjkim/******************************************************************************* 100212700Sjkim * 101212700Sjkim * FUNCTION: AcpiHwDerivePciId 102212700Sjkim * 103212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 104212700Sjkim * modified by this function. 105212700Sjkim * RootPciDevice - A handle to a PCI device object. This 106212700Sjkim * object must be a PCI Root Bridge having a 107212700Sjkim * _HID value of either PNP0A03 or PNP0A08 108212700Sjkim * PciRegion - A handle to a PCI configuration space 109212700Sjkim * Operation Region being initialized 110212700Sjkim * 111212700Sjkim * RETURN: Status 112212700Sjkim * 113212700Sjkim * DESCRIPTION: This function derives a full PCI ID for a PCI device, 114212700Sjkim * consisting of a Segment number, Bus number, Device number, 115212700Sjkim * and function code. 116212700Sjkim * 117212700Sjkim * The PCI hardware dynamically configures PCI bus numbers 118212700Sjkim * depending on the bus topology discovered during system 119212700Sjkim * initialization. This function is invoked during configuration 120212700Sjkim * of a PCI_Config Operation Region in order to (possibly) update 121212700Sjkim * the Bus/Device/Function numbers in the PciId with the actual 122212700Sjkim * values as determined by the hardware and operating system 123212700Sjkim * configuration. 124212700Sjkim * 125212700Sjkim * The PciId parameter is initially populated during the Operation 126212700Sjkim * Region initialization. This function is then called, and is 127212700Sjkim * will make any necessary modifications to the Bus, Device, or 128212700Sjkim * Function number PCI ID subfields as appropriate for the 129212700Sjkim * current hardware and OS configuration. 130212700Sjkim * 131212700Sjkim * NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId 132212700Sjkim * interface since this feature is OS-independent. This module 133212700Sjkim * specifically avoids any use of recursion by building a local 134212700Sjkim * temporary device list. 135212700Sjkim * 136212700Sjkim ******************************************************************************/ 137212700Sjkim 138212700SjkimACPI_STATUS 139212700SjkimAcpiHwDerivePciId ( 140212700Sjkim ACPI_PCI_ID *PciId, 141212700Sjkim ACPI_HANDLE RootPciDevice, 142212700Sjkim ACPI_HANDLE PciRegion) 143212700Sjkim{ 144212700Sjkim ACPI_STATUS Status; 145212700Sjkim ACPI_PCI_DEVICE *ListHead = NULL; 146212700Sjkim 147212700Sjkim 148212700Sjkim ACPI_FUNCTION_TRACE (HwDerivePciId); 149212700Sjkim 150212700Sjkim 151212700Sjkim if (!PciId) 152212700Sjkim { 153212700Sjkim return_ACPI_STATUS (AE_BAD_PARAMETER); 154212700Sjkim } 155212700Sjkim 156212700Sjkim /* Build a list of PCI devices, from PciRegion up to RootPciDevice */ 157212700Sjkim 158212700Sjkim Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead); 159212700Sjkim if (ACPI_SUCCESS (Status)) 160212700Sjkim { 161212700Sjkim /* Walk the list, updating the PCI device/function/bus numbers */ 162212700Sjkim 163212700Sjkim Status = AcpiHwProcessPciList (PciId, ListHead); 164212700Sjkim } 165212700Sjkim 166212700Sjkim /* Always delete the list */ 167212700Sjkim 168212700Sjkim AcpiHwDeletePciList (ListHead); 169212700Sjkim return_ACPI_STATUS (Status); 170212700Sjkim} 171212700Sjkim 172212700Sjkim 173212700Sjkim/******************************************************************************* 174212700Sjkim * 175212700Sjkim * FUNCTION: AcpiHwBuildPciList 176212700Sjkim * 177212700Sjkim * PARAMETERS: RootPciDevice - A handle to a PCI device object. This 178212700Sjkim * object is guaranteed to be a PCI Root 179212700Sjkim * Bridge having a _HID value of either 180212700Sjkim * PNP0A03 or PNP0A08 181212700Sjkim * PciRegion - A handle to the PCI configuration space 182212700Sjkim * Operation Region 183212700Sjkim * ReturnListHead - Where the PCI device list is returned 184212700Sjkim * 185212700Sjkim * RETURN: Status 186212700Sjkim * 187212700Sjkim * DESCRIPTION: Builds a list of devices from the input PCI region up to the 188212700Sjkim * Root PCI device for this namespace subtree. 189212700Sjkim * 190212700Sjkim ******************************************************************************/ 191212700Sjkim 192212700Sjkimstatic ACPI_STATUS 193212700SjkimAcpiHwBuildPciList ( 194212700Sjkim ACPI_HANDLE RootPciDevice, 195212700Sjkim ACPI_HANDLE PciRegion, 196212700Sjkim ACPI_PCI_DEVICE **ReturnListHead) 197212700Sjkim{ 198212700Sjkim ACPI_HANDLE CurrentDevice; 199212700Sjkim ACPI_HANDLE ParentDevice; 200212700Sjkim ACPI_STATUS Status; 201212700Sjkim ACPI_PCI_DEVICE *ListElement; 202212700Sjkim ACPI_PCI_DEVICE *ListHead = NULL; 203212700Sjkim 204212700Sjkim 205212700Sjkim /* 206212700Sjkim * Ascend namespace branch until the RootPciDevice is reached, building 207212700Sjkim * a list of device nodes. Loop will exit when either the PCI device is 208212700Sjkim * found, or the root of the namespace is reached. 209212700Sjkim */ 210212700Sjkim CurrentDevice = PciRegion; 211212700Sjkim while (1) 212212700Sjkim { 213212700Sjkim Status = AcpiGetParent (CurrentDevice, &ParentDevice); 214212700Sjkim if (ACPI_FAILURE (Status)) 215212700Sjkim { 216212700Sjkim return (Status); 217212700Sjkim } 218212700Sjkim 219212700Sjkim /* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */ 220212700Sjkim 221212700Sjkim if (ParentDevice == RootPciDevice) 222212700Sjkim { 223212700Sjkim *ReturnListHead = ListHead; 224212700Sjkim return (AE_OK); 225212700Sjkim } 226212700Sjkim 227212700Sjkim ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE)); 228212700Sjkim if (!ListElement) 229212700Sjkim { 230212700Sjkim return (AE_NO_MEMORY); 231212700Sjkim } 232212700Sjkim 233212700Sjkim /* Put new element at the head of the list */ 234212700Sjkim 235212700Sjkim ListElement->Next = ListHead; 236212700Sjkim ListElement->Device = ParentDevice; 237212700Sjkim ListHead = ListElement; 238212700Sjkim 239212700Sjkim CurrentDevice = ParentDevice; 240212700Sjkim } 241212700Sjkim} 242212700Sjkim 243212700Sjkim 244212700Sjkim/******************************************************************************* 245212700Sjkim * 246212700Sjkim * FUNCTION: AcpiHwProcessPciList 247212700Sjkim * 248212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 249212700Sjkim * modified by this function. 250212700Sjkim * ListHead - Device list created by 251212700Sjkim * AcpiHwBuildPciList 252212700Sjkim * 253212700Sjkim * RETURN: Status 254212700Sjkim * 255212700Sjkim * DESCRIPTION: Walk downward through the PCI device list, getting the device 256212700Sjkim * info for each, via the PCI configuration space and updating 257212700Sjkim * the PCI ID as necessary. Deletes the list during traversal. 258212700Sjkim * 259212700Sjkim ******************************************************************************/ 260212700Sjkim 261212700Sjkimstatic ACPI_STATUS 262212700SjkimAcpiHwProcessPciList ( 263212700Sjkim ACPI_PCI_ID *PciId, 264212700Sjkim ACPI_PCI_DEVICE *ListHead) 265212700Sjkim{ 266212700Sjkim ACPI_STATUS Status = AE_OK; 267212700Sjkim ACPI_PCI_DEVICE *Info; 268212700Sjkim UINT16 BusNumber; 269212700Sjkim BOOLEAN IsBridge = TRUE; 270212700Sjkim 271212700Sjkim 272212700Sjkim ACPI_FUNCTION_NAME (HwProcessPciList); 273212700Sjkim 274212700Sjkim 275212700Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 276212700Sjkim "Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n", 277212700Sjkim PciId->Segment, PciId->Bus, PciId->Device, PciId->Function)); 278212700Sjkim 279212700Sjkim BusNumber = PciId->Bus; 280212700Sjkim 281212700Sjkim /* 282212700Sjkim * Descend down the namespace tree, collecting PCI device, function, 283212700Sjkim * and bus numbers. BusNumber is only important for PCI bridges. 284212700Sjkim * Algorithm: As we descend the tree, use the last valid PCI device, 285212700Sjkim * function, and bus numbers that are discovered, and assign them 286212700Sjkim * to the PCI ID for the target device. 287212700Sjkim */ 288212700Sjkim Info = ListHead; 289212700Sjkim while (Info) 290212700Sjkim { 291212700Sjkim Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device, 292212700Sjkim &BusNumber, &IsBridge); 293212700Sjkim if (ACPI_FAILURE (Status)) 294212700Sjkim { 295241973Sjkim return (Status); 296212700Sjkim } 297212700Sjkim 298212700Sjkim Info = Info->Next; 299212700Sjkim } 300212700Sjkim 301212700Sjkim ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 302212700Sjkim "Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X " 303212700Sjkim "Status %X BusNumber %X IsBridge %X\n", 304212700Sjkim PciId->Segment, PciId->Bus, PciId->Device, PciId->Function, 305212700Sjkim Status, BusNumber, IsBridge)); 306212700Sjkim 307241973Sjkim return (AE_OK); 308212700Sjkim} 309212700Sjkim 310212700Sjkim 311212700Sjkim/******************************************************************************* 312212700Sjkim * 313212700Sjkim * FUNCTION: AcpiHwDeletePciList 314212700Sjkim * 315212700Sjkim * PARAMETERS: ListHead - Device list created by 316212700Sjkim * AcpiHwBuildPciList 317212700Sjkim * 318212700Sjkim * RETURN: None 319212700Sjkim * 320212700Sjkim * DESCRIPTION: Free the entire PCI list. 321212700Sjkim * 322212700Sjkim ******************************************************************************/ 323212700Sjkim 324212700Sjkimstatic void 325212700SjkimAcpiHwDeletePciList ( 326212700Sjkim ACPI_PCI_DEVICE *ListHead) 327212700Sjkim{ 328212700Sjkim ACPI_PCI_DEVICE *Next; 329212700Sjkim ACPI_PCI_DEVICE *Previous; 330212700Sjkim 331212700Sjkim 332212700Sjkim Next = ListHead; 333212700Sjkim while (Next) 334212700Sjkim { 335212700Sjkim Previous = Next; 336212700Sjkim Next = Previous->Next; 337212700Sjkim ACPI_FREE (Previous); 338212700Sjkim } 339212700Sjkim} 340212700Sjkim 341212700Sjkim 342212700Sjkim/******************************************************************************* 343212700Sjkim * 344212700Sjkim * FUNCTION: AcpiHwGetPciDeviceInfo 345212700Sjkim * 346212700Sjkim * PARAMETERS: PciId - Initial values for the PCI ID. May be 347212700Sjkim * modified by this function. 348212700Sjkim * PciDevice - Handle for the PCI device object 349212700Sjkim * BusNumber - Where a PCI bridge bus number is returned 350212700Sjkim * IsBridge - Return value, indicates if this PCI 351212700Sjkim * device is a PCI bridge 352212700Sjkim * 353212700Sjkim * RETURN: Status 354212700Sjkim * 355212700Sjkim * DESCRIPTION: Get the device info for a single PCI device object. Get the 356212700Sjkim * _ADR (contains PCI device and function numbers), and for PCI 357212700Sjkim * bridge devices, get the bus number from PCI configuration 358212700Sjkim * space. 359212700Sjkim * 360212700Sjkim ******************************************************************************/ 361212700Sjkim 362212700Sjkimstatic ACPI_STATUS 363212700SjkimAcpiHwGetPciDeviceInfo ( 364212700Sjkim ACPI_PCI_ID *PciId, 365212700Sjkim ACPI_HANDLE PciDevice, 366212700Sjkim UINT16 *BusNumber, 367212700Sjkim BOOLEAN *IsBridge) 368212700Sjkim{ 369212700Sjkim ACPI_STATUS Status; 370212700Sjkim ACPI_OBJECT_TYPE ObjectType; 371212700Sjkim UINT64 ReturnValue; 372212700Sjkim UINT64 PciValue; 373212700Sjkim 374212700Sjkim 375212700Sjkim /* We only care about objects of type Device */ 376212700Sjkim 377212700Sjkim Status = AcpiGetType (PciDevice, &ObjectType); 378212700Sjkim if (ACPI_FAILURE (Status)) 379212700Sjkim { 380212700Sjkim return (Status); 381212700Sjkim } 382212700Sjkim 383212700Sjkim if (ObjectType != ACPI_TYPE_DEVICE) 384212700Sjkim { 385212700Sjkim return (AE_OK); 386212700Sjkim } 387212700Sjkim 388212700Sjkim /* We need an _ADR. Ignore device if not present */ 389212700Sjkim 390212700Sjkim Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR, 391212700Sjkim PciDevice, &ReturnValue); 392212700Sjkim if (ACPI_FAILURE (Status)) 393212700Sjkim { 394212700Sjkim return (AE_OK); 395212700Sjkim } 396212700Sjkim 397212700Sjkim /* 398212700Sjkim * From _ADR, get the PCI Device and Function and 399212700Sjkim * update the PCI ID. 400212700Sjkim */ 401212700Sjkim PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue)); 402212700Sjkim PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue)); 403212700Sjkim 404212700Sjkim /* 405212700Sjkim * If the previous device was a bridge, use the previous 406212700Sjkim * device bus number 407212700Sjkim */ 408212700Sjkim if (*IsBridge) 409212700Sjkim { 410212700Sjkim PciId->Bus = *BusNumber; 411212700Sjkim } 412212700Sjkim 413212700Sjkim /* 414212700Sjkim * Get the bus numbers from PCI Config space: 415212700Sjkim * 416212700Sjkim * First, get the PCI HeaderType 417212700Sjkim */ 418212700Sjkim *IsBridge = FALSE; 419212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 420212700Sjkim PCI_CFG_HEADER_TYPE_REG, &PciValue, 8); 421212700Sjkim if (ACPI_FAILURE (Status)) 422212700Sjkim { 423212700Sjkim return (Status); 424212700Sjkim } 425212700Sjkim 426212700Sjkim /* We only care about bridges (1=PciBridge, 2=CardBusBridge) */ 427212700Sjkim 428212700Sjkim PciValue &= PCI_HEADER_TYPE_MASK; 429212700Sjkim 430212700Sjkim if ((PciValue != PCI_TYPE_BRIDGE) && 431212700Sjkim (PciValue != PCI_TYPE_CARDBUS_BRIDGE)) 432212700Sjkim { 433212700Sjkim return (AE_OK); 434212700Sjkim } 435212700Sjkim 436212700Sjkim /* Bridge: Get the Primary BusNumber */ 437212700Sjkim 438212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 439212700Sjkim PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8); 440212700Sjkim if (ACPI_FAILURE (Status)) 441212700Sjkim { 442212700Sjkim return (Status); 443212700Sjkim } 444212700Sjkim 445212700Sjkim *IsBridge = TRUE; 446212700Sjkim PciId->Bus = (UINT16) PciValue; 447212700Sjkim 448212700Sjkim /* Bridge: Get the Secondary BusNumber */ 449212700Sjkim 450212700Sjkim Status = AcpiOsReadPciConfiguration (PciId, 451212700Sjkim PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8); 452212700Sjkim if (ACPI_FAILURE (Status)) 453212700Sjkim { 454212700Sjkim return (Status); 455212700Sjkim } 456212700Sjkim 457212700Sjkim *BusNumber = (UINT16) PciValue; 458212700Sjkim return (AE_OK); 459212700Sjkim} 460