Path: blob/main/sys/contrib/dev/acpica/components/hardware/hwpci.c
48521 views
/*******************************************************************************1*2* Module Name: hwpci - Obtain PCI bus, device, and function numbers3*4******************************************************************************/56/******************************************************************************7*8* 1. Copyright Notice9*10* Some or all of this work - Copyright (c) 1999 - 2025, Intel Corp.11* All rights reserved.12*13* 2. License14*15* 2.1. This is your license from Intel Corp. under its intellectual property16* rights. You may have additional license terms from the party that provided17* you this software, covering your right to use that party's intellectual18* property rights.19*20* 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a21* copy of the source code appearing in this file ("Covered Code") an22* irrevocable, perpetual, worldwide license under Intel's copyrights in the23* base code distributed originally by Intel ("Original Intel Code") to copy,24* make derivatives, distribute, use and display any portion of the Covered25* Code in any form, with the right to sublicense such rights; and26*27* 2.3. Intel grants Licensee a non-exclusive and non-transferable patent28* license (with the right to sublicense), under only those claims of Intel29* patents that are infringed by the Original Intel Code, to make, use, sell,30* offer to sell, and import the Covered Code and derivative works thereof31* solely to the minimum extent necessary to exercise the above copyright32* license, and in no event shall the patent license extend to any additions33* to or modifications of the Original Intel Code. No other license or right34* is granted directly or by implication, estoppel or otherwise;35*36* The above copyright and patent license is granted only if the following37* conditions are met:38*39* 3. Conditions40*41* 3.1. Redistribution of Source with Rights to Further Distribute Source.42* Redistribution of source code of any substantial portion of the Covered43* Code or modification with rights to further distribute source must include44* the above Copyright Notice, the above License, this list of Conditions,45* and the following Disclaimer and Export Compliance provision. In addition,46* Licensee must cause all Covered Code to which Licensee contributes to47* contain a file documenting the changes Licensee made to create that Covered48* Code and the date of any change. Licensee must include in that file the49* documentation of any changes made by any predecessor Licensee. Licensee50* must include a prominent statement that the modification is derived,51* directly or indirectly, from Original Intel Code.52*53* 3.2. Redistribution of Source with no Rights to Further Distribute Source.54* Redistribution of source code of any substantial portion of the Covered55* Code or modification without rights to further distribute source must56* include the following Disclaimer and Export Compliance provision in the57* documentation and/or other materials provided with distribution. In58* addition, Licensee may not authorize further sublicense of source of any59* portion of the Covered Code, and must include terms to the effect that the60* license from Licensee to its licensee is limited to the intellectual61* property embodied in the software Licensee provides to its licensee, and62* not to intellectual property embodied in modifications its licensee may63* make.64*65* 3.3. Redistribution of Executable. Redistribution in executable form of any66* substantial portion of the Covered Code or modification must reproduce the67* above Copyright Notice, and the following Disclaimer and Export Compliance68* provision in the documentation and/or other materials provided with the69* distribution.70*71* 3.4. Intel retains all right, title, and interest in and to the Original72* Intel Code.73*74* 3.5. Neither the name Intel nor any other trademark owned or controlled by75* Intel shall be used in advertising or otherwise to promote the sale, use or76* other dealings in products derived from or relating to the Covered Code77* without prior written authorization from Intel.78*79* 4. Disclaimer and Export Compliance80*81* 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED82* HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE83* IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,84* INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY85* UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY86* IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A87* PARTICULAR PURPOSE.88*89* 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES90* OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR91* COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,92* SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY93* CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL94* HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS95* SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY96* LIMITED REMEDY.97*98* 4.3. Licensee shall not export, either directly or indirectly, any of this99* software or system incorporating such software without first obtaining any100* required license or other approval from the U. S. Department of Commerce or101* any other agency or department of the United States Government. In the102* event Licensee exports any such software from the United States or103* re-exports any such software from a foreign destination, Licensee shall104* ensure that the distribution and export/re-export of the software is in105* compliance with all laws, regulations, orders, or other restrictions of the106* U.S. Export Administration Regulations. Licensee agrees that neither it nor107* any of its subsidiaries will export/re-export any technical data, process,108* software, or service, directly or indirectly, to any country for which the109* United States government or any agency thereof requires an export license,110* other governmental approval, or letter of assurance, without first obtaining111* such license, approval or letter.112*113*****************************************************************************114*115* Alternatively, you may choose to be licensed under the terms of the116* following license:117*118* Redistribution and use in source and binary forms, with or without119* modification, are permitted provided that the following conditions120* are met:121* 1. Redistributions of source code must retain the above copyright122* notice, this list of conditions, and the following disclaimer,123* without modification.124* 2. Redistributions in binary form must reproduce at minimum a disclaimer125* substantially similar to the "NO WARRANTY" disclaimer below126* ("Disclaimer") and any redistribution must be conditioned upon127* including a substantially similar Disclaimer requirement for further128* binary redistribution.129* 3. Neither the names of the above-listed copyright holders nor the names130* of any contributors may be used to endorse or promote products derived131* from this software without specific prior written permission.132*133* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS134* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT135* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR136* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT137* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,138* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT139* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,140* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY141* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT142* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE143* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.144*145* Alternatively, you may choose to be licensed under the terms of the146* GNU General Public License ("GPL") version 2 as published by the Free147* Software Foundation.148*149*****************************************************************************/150151#include <contrib/dev/acpica/include/acpi.h>152#include <contrib/dev/acpica/include/accommon.h>153154155#define _COMPONENT ACPI_NAMESPACE156ACPI_MODULE_NAME ("hwpci")157158159/* PCI configuration space values */160161#define PCI_CFG_HEADER_TYPE_REG 0x0E162#define PCI_CFG_PRIMARY_BUS_NUMBER_REG 0x18163#define PCI_CFG_SECONDARY_BUS_NUMBER_REG 0x19164165/* PCI header values */166167#define PCI_HEADER_TYPE_MASK 0x7F168#define PCI_TYPE_BRIDGE 0x01169#define PCI_TYPE_CARDBUS_BRIDGE 0x02170171typedef struct acpi_pci_device172{173ACPI_HANDLE Device;174struct acpi_pci_device *Next;175176} ACPI_PCI_DEVICE;177178179/* Local prototypes */180181static ACPI_STATUS182AcpiHwBuildPciList (183ACPI_HANDLE RootPciDevice,184ACPI_HANDLE PciRegion,185ACPI_PCI_DEVICE **ReturnListHead);186187static ACPI_STATUS188AcpiHwProcessPciList (189ACPI_PCI_ID *PciId,190ACPI_PCI_DEVICE *ListHead);191192static void193AcpiHwDeletePciList (194ACPI_PCI_DEVICE *ListHead);195196static ACPI_STATUS197AcpiHwGetPciDeviceInfo (198ACPI_PCI_ID *PciId,199ACPI_HANDLE PciDevice,200UINT16 *BusNumber,201BOOLEAN *IsBridge);202203204/*******************************************************************************205*206* FUNCTION: AcpiHwDerivePciId207*208* PARAMETERS: PciId - Initial values for the PCI ID. May be209* modified by this function.210* RootPciDevice - A handle to a PCI device object. This211* object must be a PCI Root Bridge having a212* _HID value of either PNP0A03 or PNP0A08213* PciRegion - A handle to a PCI configuration space214* Operation Region being initialized215*216* RETURN: Status217*218* DESCRIPTION: This function derives a full PCI ID for a PCI device,219* consisting of a Segment number, Bus number, Device number,220* and function code.221*222* The PCI hardware dynamically configures PCI bus numbers223* depending on the bus topology discovered during system224* initialization. This function is invoked during configuration225* of a PCI_Config Operation Region in order to (possibly) update226* the Bus/Device/Function numbers in the PciId with the actual227* values as determined by the hardware and operating system228* configuration.229*230* The PciId parameter is initially populated during the Operation231* Region initialization. This function is then called, and is232* will make any necessary modifications to the Bus, Device, or233* Function number PCI ID subfields as appropriate for the234* current hardware and OS configuration.235*236* NOTE: Created 08/2010. Replaces the previous OSL AcpiOsDerivePciId237* interface since this feature is OS-independent. This module238* specifically avoids any use of recursion by building a local239* temporary device list.240*241******************************************************************************/242243ACPI_STATUS244AcpiHwDerivePciId (245ACPI_PCI_ID *PciId,246ACPI_HANDLE RootPciDevice,247ACPI_HANDLE PciRegion)248{249ACPI_STATUS Status;250ACPI_PCI_DEVICE *ListHead;251252253ACPI_FUNCTION_TRACE (HwDerivePciId);254255256if (!PciId)257{258return_ACPI_STATUS (AE_BAD_PARAMETER);259}260261/* Build a list of PCI devices, from PciRegion up to RootPciDevice */262263Status = AcpiHwBuildPciList (RootPciDevice, PciRegion, &ListHead);264if (ACPI_SUCCESS (Status))265{266/* Walk the list, updating the PCI device/function/bus numbers */267268Status = AcpiHwProcessPciList (PciId, ListHead);269270/* Delete the list */271272AcpiHwDeletePciList (ListHead);273}274275return_ACPI_STATUS (Status);276}277278279/*******************************************************************************280*281* FUNCTION: AcpiHwBuildPciList282*283* PARAMETERS: RootPciDevice - A handle to a PCI device object. This284* object is guaranteed to be a PCI Root285* Bridge having a _HID value of either286* PNP0A03 or PNP0A08287* PciRegion - A handle to the PCI configuration space288* Operation Region289* ReturnListHead - Where the PCI device list is returned290*291* RETURN: Status292*293* DESCRIPTION: Builds a list of devices from the input PCI region up to the294* Root PCI device for this namespace subtree.295*296******************************************************************************/297298static ACPI_STATUS299AcpiHwBuildPciList (300ACPI_HANDLE RootPciDevice,301ACPI_HANDLE PciRegion,302ACPI_PCI_DEVICE **ReturnListHead)303{304ACPI_HANDLE CurrentDevice;305ACPI_HANDLE ParentDevice;306ACPI_STATUS Status;307ACPI_PCI_DEVICE *ListElement;308309310/*311* Ascend namespace branch until the RootPciDevice is reached, building312* a list of device nodes. Loop will exit when either the PCI device is313* found, or the root of the namespace is reached.314*/315*ReturnListHead = NULL;316CurrentDevice = PciRegion;317while (1)318{319Status = AcpiGetParent (CurrentDevice, &ParentDevice);320if (ACPI_FAILURE (Status))321{322/* Must delete the list before exit */323324AcpiHwDeletePciList (*ReturnListHead);325return (Status);326}327328/* Finished when we reach the PCI root device (PNP0A03 or PNP0A08) */329330if (ParentDevice == RootPciDevice)331{332return (AE_OK);333}334335ListElement = ACPI_ALLOCATE (sizeof (ACPI_PCI_DEVICE));336if (!ListElement)337{338/* Must delete the list before exit */339340AcpiHwDeletePciList (*ReturnListHead);341return (AE_NO_MEMORY);342}343344/* Put new element at the head of the list */345346ListElement->Next = *ReturnListHead;347ListElement->Device = ParentDevice;348*ReturnListHead = ListElement;349350CurrentDevice = ParentDevice;351}352}353354355/*******************************************************************************356*357* FUNCTION: AcpiHwProcessPciList358*359* PARAMETERS: PciId - Initial values for the PCI ID. May be360* modified by this function.361* ListHead - Device list created by362* AcpiHwBuildPciList363*364* RETURN: Status365*366* DESCRIPTION: Walk downward through the PCI device list, getting the device367* info for each, via the PCI configuration space and updating368* the PCI ID as necessary. Deletes the list during traversal.369*370******************************************************************************/371372static ACPI_STATUS373AcpiHwProcessPciList (374ACPI_PCI_ID *PciId,375ACPI_PCI_DEVICE *ListHead)376{377ACPI_STATUS Status = AE_OK;378ACPI_PCI_DEVICE *Info;379UINT16 BusNumber;380BOOLEAN IsBridge = TRUE;381382383ACPI_FUNCTION_NAME (HwProcessPciList);384385386ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,387"Input PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X\n",388PciId->Segment, PciId->Bus, PciId->Device, PciId->Function));389390BusNumber = PciId->Bus;391392/*393* Descend down the namespace tree, collecting PCI device, function,394* and bus numbers. BusNumber is only important for PCI bridges.395* Algorithm: As we descend the tree, use the last valid PCI device,396* function, and bus numbers that are discovered, and assign them397* to the PCI ID for the target device.398*/399Info = ListHead;400while (Info)401{402Status = AcpiHwGetPciDeviceInfo (PciId, Info->Device,403&BusNumber, &IsBridge);404if (ACPI_FAILURE (Status))405{406return (Status);407}408409Info = Info->Next;410}411412ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,413"Output PciId: Seg %4.4X Bus %4.4X Dev %4.4X Func %4.4X "414"Status %X BusNumber %X IsBridge %X\n",415PciId->Segment, PciId->Bus, PciId->Device, PciId->Function,416Status, BusNumber, IsBridge));417418return (AE_OK);419}420421422/*******************************************************************************423*424* FUNCTION: AcpiHwDeletePciList425*426* PARAMETERS: ListHead - Device list created by427* AcpiHwBuildPciList428*429* RETURN: None430*431* DESCRIPTION: Free the entire PCI list.432*433******************************************************************************/434435static void436AcpiHwDeletePciList (437ACPI_PCI_DEVICE *ListHead)438{439ACPI_PCI_DEVICE *Next;440ACPI_PCI_DEVICE *Previous;441442443Next = ListHead;444while (Next)445{446Previous = Next;447Next = Previous->Next;448ACPI_FREE (Previous);449}450}451452453/*******************************************************************************454*455* FUNCTION: AcpiHwGetPciDeviceInfo456*457* PARAMETERS: PciId - Initial values for the PCI ID. May be458* modified by this function.459* PciDevice - Handle for the PCI device object460* BusNumber - Where a PCI bridge bus number is returned461* IsBridge - Return value, indicates if this PCI462* device is a PCI bridge463*464* RETURN: Status465*466* DESCRIPTION: Get the device info for a single PCI device object. Get the467* _ADR (contains PCI device and function numbers), and for PCI468* bridge devices, get the bus number from PCI configuration469* space.470*471******************************************************************************/472473static ACPI_STATUS474AcpiHwGetPciDeviceInfo (475ACPI_PCI_ID *PciId,476ACPI_HANDLE PciDevice,477UINT16 *BusNumber,478BOOLEAN *IsBridge)479{480ACPI_STATUS Status;481ACPI_OBJECT_TYPE ObjectType;482UINT64 ReturnValue;483UINT64 PciValue;484485486/* We only care about objects of type Device */487488Status = AcpiGetType (PciDevice, &ObjectType);489if (ACPI_FAILURE (Status))490{491return (Status);492}493494if (ObjectType != ACPI_TYPE_DEVICE)495{496return (AE_OK);497}498499/* We need an _ADR. Ignore device if not present */500501Status = AcpiUtEvaluateNumericObject (METHOD_NAME__ADR,502PciDevice, &ReturnValue);503if (ACPI_FAILURE (Status))504{505return (AE_OK);506}507508/*509* From _ADR, get the PCI Device and Function and510* update the PCI ID.511*/512PciId->Device = ACPI_HIWORD (ACPI_LODWORD (ReturnValue));513PciId->Function = ACPI_LOWORD (ACPI_LODWORD (ReturnValue));514515/*516* If the previous device was a bridge, use the previous517* device bus number518*/519if (*IsBridge)520{521PciId->Bus = *BusNumber;522}523524/*525* Get the bus numbers from PCI Config space:526*527* First, get the PCI HeaderType528*/529*IsBridge = FALSE;530Status = AcpiOsReadPciConfiguration (PciId,531PCI_CFG_HEADER_TYPE_REG, &PciValue, 8);532if (ACPI_FAILURE (Status))533{534return (Status);535}536537/* We only care about bridges (1=PciBridge, 2=CardBusBridge) */538539PciValue &= PCI_HEADER_TYPE_MASK;540541if ((PciValue != PCI_TYPE_BRIDGE) &&542(PciValue != PCI_TYPE_CARDBUS_BRIDGE))543{544return (AE_OK);545}546547/* Bridge: Get the Primary BusNumber */548549Status = AcpiOsReadPciConfiguration (PciId,550PCI_CFG_PRIMARY_BUS_NUMBER_REG, &PciValue, 8);551if (ACPI_FAILURE (Status))552{553return (Status);554}555556*IsBridge = TRUE;557PciId->Bus = (UINT16) PciValue;558559/* Bridge: Get the Secondary BusNumber */560561Status = AcpiOsReadPciConfiguration (PciId,562PCI_CFG_SECONDARY_BUS_NUMBER_REG, &PciValue, 8);563if (ACPI_FAILURE (Status))564{565return (Status);566}567568*BusNumber = (UINT16) PciValue;569return (AE_OK);570}571572573