| /** @file | |
| Provide common utility functions to PciHostBridgeLib instances in | |
| ArmVirtPkg and OvmfPkg. | |
| Copyright (C) 2016, Red Hat, Inc. | |
| Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | |
| Copyright (c) 2020, Huawei Corporation. All rights reserved.<BR> | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <IndustryStandard/Acpi10.h> | |
| #include <IndustryStandard/Pci.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/DevicePathLib.h> | |
| #include <Library/HardwareInfoLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/PciHostBridgeUtilityLib.h> | |
| #include <Library/PciLib.h> | |
| #include <Library/QemuFwCfgLib.h> | |
| #include <Protocol/PciHostBridgeResourceAllocation.h> | |
| #pragma pack(1) | |
| typedef struct { | |
| ACPI_HID_DEVICE_PATH AcpiDevicePath; | |
| EFI_DEVICE_PATH_PROTOCOL EndDevicePath; | |
| } OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH; | |
| #pragma pack () | |
| GLOBAL_REMOVE_IF_UNREFERENCED | |
| CHAR16 *mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[] = { | |
| L"Mem", L"I/O", L"Bus" | |
| }; | |
| STATIC | |
| CONST | |
| OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH mRootBridgeDevicePathTemplate = { | |
| { | |
| { | |
| ACPI_DEVICE_PATH, | |
| ACPI_DP, | |
| { | |
| (UINT8)(sizeof (ACPI_HID_DEVICE_PATH)), | |
| (UINT8)((sizeof (ACPI_HID_DEVICE_PATH)) >> 8) | |
| } | |
| }, | |
| EISA_PNP_ID (0x0A03), // HID | |
| 0 // UID | |
| }, | |
| { | |
| END_DEVICE_PATH_TYPE, | |
| END_ENTIRE_DEVICE_PATH_SUBTYPE, | |
| { | |
| END_DEVICE_PATH_LENGTH, | |
| 0 | |
| } | |
| } | |
| }; | |
| /** | |
| Utility function to initialize a PCI_ROOT_BRIDGE structure. | |
| @param[in] Supports Supported attributes. | |
| @param[in] Attributes Initial attributes. | |
| @param[in] AllocAttributes Allocation attributes. | |
| @param[in] DmaAbove4G DMA above 4GB memory. | |
| @param[in] NoExtendedConfigSpace No Extended Config Space. | |
| @param[in] RootBusNumber The bus number to store in RootBus. | |
| @param[in] MaxSubBusNumber The inclusive maximum bus number that can | |
| be assigned to any subordinate bus found | |
| behind any PCI bridge hanging off this | |
| root bus. | |
| The caller is repsonsible for ensuring | |
| that RootBusNumber <= MaxSubBusNumber. If | |
| RootBusNumber equals MaxSubBusNumber, then | |
| the root bus has no room for subordinate | |
| buses. | |
| @param[in] Io IO aperture. | |
| @param[in] Mem MMIO aperture. | |
| @param[in] MemAbove4G MMIO aperture above 4G. | |
| @param[in] PMem Prefetchable MMIO aperture. | |
| @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. | |
| @param[out] RootBus The PCI_ROOT_BRIDGE structure (allocated | |
| by the caller) that should be filled in by | |
| this function. | |
| @retval EFI_SUCCESS Initialization successful. A device path | |
| consisting of an ACPI device path node, | |
| with UID = RootBusNumber, has been | |
| allocated and linked into RootBus. | |
| @retval EFI_OUT_OF_RESOURCES Memory allocation failed. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| PciHostBridgeUtilityInitRootBridge ( | |
| IN UINT64 Supports, | |
| IN UINT64 Attributes, | |
| IN UINT64 AllocAttributes, | |
| IN BOOLEAN DmaAbove4G, | |
| IN BOOLEAN NoExtendedConfigSpace, | |
| IN UINT8 RootBusNumber, | |
| IN UINT8 MaxSubBusNumber, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Io, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Mem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G, | |
| OUT PCI_ROOT_BRIDGE *RootBus | |
| ) | |
| { | |
| OVMF_PCI_ROOT_BRIDGE_DEVICE_PATH *DevicePath; | |
| // | |
| // Be safe if other fields are added to PCI_ROOT_BRIDGE later. | |
| // | |
| ZeroMem (RootBus, sizeof *RootBus); | |
| RootBus->Segment = 0; | |
| RootBus->Supports = Supports; | |
| RootBus->Attributes = Attributes; | |
| RootBus->DmaAbove4G = DmaAbove4G; | |
| RootBus->AllocationAttributes = AllocAttributes; | |
| RootBus->Bus.Base = RootBusNumber; | |
| RootBus->Bus.Limit = MaxSubBusNumber; | |
| CopyMem (&RootBus->Io, Io, sizeof (*Io)); | |
| CopyMem (&RootBus->Mem, Mem, sizeof (*Mem)); | |
| CopyMem (&RootBus->MemAbove4G, MemAbove4G, sizeof (*MemAbove4G)); | |
| CopyMem (&RootBus->PMem, PMem, sizeof (*PMem)); | |
| CopyMem (&RootBus->PMemAbove4G, PMemAbove4G, sizeof (*PMemAbove4G)); | |
| RootBus->NoExtendedConfigSpace = NoExtendedConfigSpace; | |
| DevicePath = AllocateCopyPool ( | |
| sizeof mRootBridgeDevicePathTemplate, | |
| &mRootBridgeDevicePathTemplate | |
| ); | |
| if (DevicePath == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| DevicePath->AcpiDevicePath.UID = RootBusNumber; | |
| RootBus->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)DevicePath; | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a: populated root bus %d, with room for %d subordinate bus(es)\n", | |
| __func__, | |
| RootBusNumber, | |
| MaxSubBusNumber - RootBusNumber | |
| )); | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Utility function to uninitialize a PCI_ROOT_BRIDGE structure set up with | |
| PciHostBridgeUtilityInitRootBridge(). | |
| @param[in] RootBus The PCI_ROOT_BRIDGE structure, allocated by the caller and | |
| initialized with PciHostBridgeUtilityInitRootBridge(), | |
| that should be uninitialized. This function doesn't free | |
| RootBus. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PciHostBridgeUtilityUninitRootBridge ( | |
| IN PCI_ROOT_BRIDGE *RootBus | |
| ) | |
| { | |
| FreePool (RootBus->DevicePath); | |
| } | |
| /** | |
| Utility function to scan PCI root bridges and create instances for those | |
| that are found not empty. Populate their resources from the default | |
| provided parameters and return all the root bridge instances in an array. | |
| @param[out] Count The number of root bridge instances. | |
| @param[in] Attributes Initial attributes. | |
| @param[in] AllocAttributes Allocation attributes. | |
| @param[in] DmaAbove4G DMA above 4GB memory. | |
| @param[in] NoExtendedConfigSpace No Extended Config Space. | |
| @param[in] BusMin Minimum Bus number, inclusive. | |
| @param[in] BusMax Maximum Bus number, inclusive. | |
| @param[in] Io IO aperture. | |
| @param[in] Mem MMIO aperture. | |
| @param[in] MemAbove4G MMIO aperture above 4G. | |
| @param[in] PMem Prefetchable MMIO aperture. | |
| @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. | |
| @return All the root bridge instances in an array. | |
| **/ | |
| STATIC | |
| PCI_ROOT_BRIDGE * | |
| PciHostBridgeUtilityGetRootBridgesBusScan ( | |
| OUT UINTN *Count, | |
| IN UINT64 Attributes, | |
| IN UINT64 AllocationAttributes, | |
| IN BOOLEAN DmaAbove4G, | |
| IN BOOLEAN NoExtendedConfigSpace, | |
| IN UINTN BusMin, | |
| IN UINTN BusMax, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Io, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Mem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FIRMWARE_CONFIG_ITEM FwCfgItem; | |
| UINTN FwCfgSize; | |
| UINT64 ExtraRootBridges; | |
| PCI_ROOT_BRIDGE *Bridges; | |
| UINTN Initialized; | |
| UINTN LastRootBridgeNumber; | |
| UINTN RootBridgeNumber; | |
| if ((BusMin > BusMax) || (BusMax > PCI_MAX_BUS)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: invalid bus range with BusMin %Lu and BusMax " | |
| "%Lu\n", | |
| __func__, | |
| (UINT64)BusMin, | |
| (UINT64)BusMax | |
| )); | |
| return NULL; | |
| } | |
| // | |
| // QEMU provides the number of extra root buses, shortening the exhaustive | |
| // search below. If there is no hint, the feature is missing. | |
| // | |
| Status = QemuFwCfgFindFile ("etc/extra-pci-roots", &FwCfgItem, &FwCfgSize); | |
| if (EFI_ERROR (Status) || (FwCfgSize != sizeof ExtraRootBridges)) { | |
| ExtraRootBridges = 0; | |
| } else { | |
| QemuFwCfgSelectItem (FwCfgItem); | |
| QemuFwCfgReadBytes (FwCfgSize, &ExtraRootBridges); | |
| // | |
| // Validate the number of extra root bridges. As BusMax is inclusive, the | |
| // max bus count is (BusMax - BusMin + 1). From that, the "main" root bus | |
| // is always a given, so the max count for the "extra" root bridges is one | |
| // less, i.e. (BusMax - BusMin). If the QEMU hint exceeds that, we have | |
| // invalid behavior. | |
| // | |
| if (ExtraRootBridges > BusMax - BusMin) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: invalid count of extra root buses (%Lu) " | |
| "reported by QEMU\n", | |
| __func__, | |
| ExtraRootBridges | |
| )); | |
| return NULL; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a: %Lu extra root buses reported by QEMU\n", | |
| __func__, | |
| ExtraRootBridges | |
| )); | |
| } | |
| // | |
| // Allocate the "main" root bridge, and any extra root bridges. | |
| // | |
| Bridges = AllocatePool ((1 + (UINTN)ExtraRootBridges) * sizeof *Bridges); | |
| if (Bridges == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES)); | |
| return NULL; | |
| } | |
| Initialized = 0; | |
| // | |
| // The "main" root bus is always there. | |
| // | |
| LastRootBridgeNumber = BusMin; | |
| // | |
| // Scan all other root buses. If function 0 of any device on a bus returns a | |
| // VendorId register value different from all-bits-one, then that bus is | |
| // alive. | |
| // | |
| for (RootBridgeNumber = BusMin + 1; | |
| RootBridgeNumber <= BusMax && Initialized < ExtraRootBridges; | |
| ++RootBridgeNumber) | |
| { | |
| UINTN Device; | |
| for (Device = 0; Device <= PCI_MAX_DEVICE; ++Device) { | |
| if (PciRead16 ( | |
| PCI_LIB_ADDRESS ( | |
| RootBridgeNumber, | |
| Device, | |
| 0, | |
| PCI_VENDOR_ID_OFFSET | |
| ) | |
| ) != MAX_UINT16) | |
| { | |
| break; | |
| } | |
| } | |
| if (Device <= PCI_MAX_DEVICE) { | |
| // | |
| // Found the next root bus. We can now install the *previous* one, | |
| // because now we know how big a bus number range *that* one has, for any | |
| // subordinate buses that might exist behind PCI bridges hanging off it. | |
| // | |
| Status = PciHostBridgeUtilityInitRootBridge ( | |
| Attributes, | |
| Attributes, | |
| AllocationAttributes, | |
| DmaAbove4G, | |
| NoExtendedConfigSpace, | |
| (UINT8)LastRootBridgeNumber, | |
| (UINT8)(RootBridgeNumber - 1), | |
| Io, | |
| Mem, | |
| MemAbove4G, | |
| PMem, | |
| PMemAbove4G, | |
| &Bridges[Initialized] | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeBridges; | |
| } | |
| ++Initialized; | |
| LastRootBridgeNumber = RootBridgeNumber; | |
| } | |
| } | |
| // | |
| // Install the last root bus (which might be the only, ie. main, root bus, if | |
| // we've found no extra root buses). | |
| // | |
| Status = PciHostBridgeUtilityInitRootBridge ( | |
| Attributes, | |
| Attributes, | |
| AllocationAttributes, | |
| DmaAbove4G, | |
| NoExtendedConfigSpace, | |
| (UINT8)LastRootBridgeNumber, | |
| (UINT8)BusMax, | |
| Io, | |
| Mem, | |
| MemAbove4G, | |
| PMem, | |
| PMemAbove4G, | |
| &Bridges[Initialized] | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeBridges; | |
| } | |
| ++Initialized; | |
| *Count = Initialized; | |
| return Bridges; | |
| FreeBridges: | |
| while (Initialized > 0) { | |
| --Initialized; | |
| PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]); | |
| } | |
| FreePool (Bridges); | |
| return NULL; | |
| } | |
| /** | |
| Utility function to read root bridges information from host-provided fw-cfg | |
| file and return them in an array. | |
| @param[out] Count The number of root bridge instances. | |
| @return All the root bridge instances in an array parsed from | |
| host-provided fw-cfg file (hardware-info). | |
| **/ | |
| STATIC | |
| PCI_ROOT_BRIDGE * | |
| PciHostBridgeUtilityGetRootBridgesHostProvided ( | |
| OUT UINTN *Count | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| FIRMWARE_CONFIG_ITEM FwCfgItem; | |
| UINTN FwCfgSize; | |
| PCI_ROOT_BRIDGE *Bridges; | |
| UINTN Initialized; | |
| UINTN LastRootBridgeNumber; | |
| UINTN RootBridgeNumber; | |
| UINTN PciHostBridgeCount; | |
| UINT8 *HardwareInfoBlob; | |
| LIST_ENTRY HwInfoList; | |
| LIST_ENTRY *HwLink; | |
| HARDWARE_INFO *HwInfo; | |
| UINT64 Attributes; | |
| UINT64 AllocationAttributes; | |
| BOOLEAN DmaAbove4G; | |
| BOOLEAN NoExtendedConfigSpace; | |
| BOOLEAN CombineMemPMem; | |
| PCI_ROOT_BRIDGE_APERTURE Io; | |
| PCI_ROOT_BRIDGE_APERTURE Mem; | |
| PCI_ROOT_BRIDGE_APERTURE MemAbove4G; | |
| PCI_ROOT_BRIDGE_APERTURE PMem; | |
| PCI_ROOT_BRIDGE_APERTURE PMemAbove4G; | |
| // | |
| // Initialize the Hardware Info list head to start with an empty but valid | |
| // list head. | |
| // | |
| InitializeListHead (&HwInfoList); | |
| HardwareInfoBlob = NULL; | |
| Initialized = 0; | |
| Bridges = NULL; | |
| PciHostBridgeCount = 0; | |
| // | |
| // Hypervisor can provide the specifications (resources) for one or more | |
| // PCI host bridges. Such information comes through fw-cfg as part of | |
| // the hardware-info file. | |
| // | |
| Status = QemuFwCfgFindFile ("etc/hardware-info", &FwCfgItem, &FwCfgSize); | |
| if (EFI_ERROR (Status)) { | |
| return NULL; | |
| } | |
| HardwareInfoBlob = AllocatePool (FwCfgSize); | |
| if (HardwareInfoBlob == NULL) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: Failed to allocate memory for hardware resources info\n", | |
| __func__ | |
| )); | |
| return NULL; | |
| } | |
| QemuFwCfgSelectItem (FwCfgItem); | |
| QemuFwCfgReadBytes (FwCfgSize, HardwareInfoBlob); | |
| // | |
| // Create the list of hardware info devices filtering for PCI host | |
| // bridges | |
| // | |
| Status = CreateHardwareInfoList ( | |
| HardwareInfoBlob, | |
| FwCfgSize, | |
| HardwareInfoTypeHostBridge, | |
| &HwInfoList | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: Failed to create hardware info list to retrieve host " | |
| "bridges information from fw-cfg\n", | |
| __func__ | |
| )); | |
| goto FreeBridges; | |
| } | |
| PciHostBridgeCount = GetHardwareInfoCountByType ( | |
| &HwInfoList, | |
| HardwareInfoTypeHostBridge, | |
| sizeof (HOST_BRIDGE_INFO) | |
| ); | |
| if (PciHostBridgeCount == 0) { | |
| goto FreeBridges; | |
| } | |
| DEBUG (( | |
| DEBUG_INFO, | |
| "%a: Host provided description for %Lu root bridges\n", | |
| __func__, | |
| PciHostBridgeCount | |
| )); | |
| // | |
| // Allocate the root bridges | |
| // | |
| Bridges = AllocatePool (((UINTN)PciHostBridgeCount) * sizeof *Bridges); | |
| if (Bridges == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a: %r\n", __func__, EFI_OUT_OF_RESOURCES)); | |
| goto FreeBridges; | |
| } | |
| // | |
| // If Host Bridges' specification was obtained from fw-cfg, the list | |
| // contains information to populate all root bridges in the system | |
| // including resources and attributes. | |
| // | |
| HwLink = GetFirstHardwareInfoByType ( | |
| &HwInfoList, | |
| HardwareInfoTypeHostBridge, | |
| sizeof (HOST_BRIDGE_INFO) | |
| ); | |
| while (!EndOfHardwareInfoList (&HwInfoList, HwLink)) { | |
| HwInfo = HARDWARE_INFO_FROM_LINK (HwLink); | |
| Status = HardwareInfoPciHostBridgeGet ( | |
| HwInfo->Data.PciHostBridge, | |
| (UINTN)HwInfo->Header.Size, | |
| &RootBridgeNumber, | |
| &LastRootBridgeNumber, | |
| &Attributes, | |
| &DmaAbove4G, | |
| &NoExtendedConfigSpace, | |
| &CombineMemPMem, | |
| &Io, | |
| &Mem, | |
| &MemAbove4G, | |
| &PMem, | |
| &PMemAbove4G, | |
| NULL | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeBridges; | |
| } | |
| if ((RootBridgeNumber > LastRootBridgeNumber) || (LastRootBridgeNumber > PCI_MAX_BUS)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "%a: invalid bus range with BusMin %Lu and BusMax " | |
| "%Lu\n", | |
| __func__, | |
| (UINT64)RootBridgeNumber, | |
| (UINT64)LastRootBridgeNumber | |
| )); | |
| goto FreeBridges; | |
| } | |
| AllocationAttributes = 0; | |
| if (CombineMemPMem) { | |
| AllocationAttributes |= EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM; | |
| } | |
| if ((MemAbove4G.Limit > MemAbove4G.Base) || | |
| (PMemAbove4G.Limit > PMemAbove4G.Base)) | |
| { | |
| AllocationAttributes |= EFI_PCI_HOST_BRIDGE_MEM64_DECODE; | |
| } | |
| Status = PciHostBridgeUtilityInitRootBridge ( | |
| Attributes, | |
| Attributes, | |
| AllocationAttributes, | |
| DmaAbove4G, | |
| NoExtendedConfigSpace, | |
| (UINT8)RootBridgeNumber, | |
| (UINT8)LastRootBridgeNumber, | |
| &Io, | |
| &Mem, | |
| &MemAbove4G, | |
| &PMem, | |
| &PMemAbove4G, | |
| &Bridges[Initialized] | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| goto FreeBridges; | |
| } | |
| ++Initialized; | |
| HwLink = GetNextHardwareInfoByType ( | |
| &HwInfoList, | |
| HwLink, | |
| HardwareInfoTypeHostBridge, | |
| sizeof (HOST_BRIDGE_INFO) | |
| ); | |
| } | |
| *Count = Initialized; | |
| // | |
| // If resources were allocated for host bridges info, release them | |
| // | |
| if (HardwareInfoBlob) { | |
| FreePool (HardwareInfoBlob); | |
| } | |
| FreeHardwareInfoList (&HwInfoList); | |
| return Bridges; | |
| FreeBridges: | |
| while (Initialized > 0) { | |
| --Initialized; | |
| PciHostBridgeUtilityUninitRootBridge (&Bridges[Initialized]); | |
| } | |
| if (Bridges) { | |
| FreePool (Bridges); | |
| } | |
| if (HardwareInfoBlob) { | |
| FreePool (HardwareInfoBlob); | |
| } | |
| FreeHardwareInfoList (&HwInfoList); | |
| return NULL; | |
| } | |
| /** | |
| Utility function to return all the root bridge instances in an array. | |
| @param[out] Count The number of root bridge instances. | |
| @param[in] Attributes Initial attributes. | |
| @param[in] AllocAttributes Allocation attributes. | |
| @param[in] DmaAbove4G DMA above 4GB memory. | |
| @param[in] NoExtendedConfigSpace No Extended Config Space. | |
| @param[in] BusMin Minimum Bus number, inclusive. | |
| @param[in] BusMax Maximum Bus number, inclusive. | |
| @param[in] Io IO aperture. | |
| @param[in] Mem MMIO aperture. | |
| @param[in] MemAbove4G MMIO aperture above 4G. | |
| @param[in] PMem Prefetchable MMIO aperture. | |
| @param[in] PMemAbove4G Prefetchable MMIO aperture above 4G. | |
| @return All the root bridge instances in an array. | |
| **/ | |
| PCI_ROOT_BRIDGE * | |
| EFIAPI | |
| PciHostBridgeUtilityGetRootBridges ( | |
| OUT UINTN *Count, | |
| IN UINT64 Attributes, | |
| IN UINT64 AllocationAttributes, | |
| IN BOOLEAN DmaAbove4G, | |
| IN BOOLEAN NoExtendedConfigSpace, | |
| IN UINTN BusMin, | |
| IN UINTN BusMax, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Io, | |
| IN PCI_ROOT_BRIDGE_APERTURE *Mem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *MemAbove4G, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMem, | |
| IN PCI_ROOT_BRIDGE_APERTURE *PMemAbove4G | |
| ) | |
| { | |
| PCI_ROOT_BRIDGE *Bridges; | |
| *Count = 0; | |
| // | |
| // First attempt to get the host provided descriptions of the Root Bridges | |
| // if available. | |
| // | |
| Bridges = PciHostBridgeUtilityGetRootBridgesHostProvided (Count); | |
| // | |
| // If host did not provide Root Bridge information, scan the buses and | |
| // auto populate them with default resources. | |
| // | |
| if (Bridges == NULL) { | |
| Bridges = PciHostBridgeUtilityGetRootBridgesBusScan ( | |
| Count, | |
| Attributes, | |
| AllocationAttributes, | |
| DmaAbove4G, | |
| NoExtendedConfigSpace, | |
| BusMin, | |
| BusMax, | |
| Io, | |
| Mem, | |
| MemAbove4G, | |
| PMem, | |
| PMemAbove4G | |
| ); | |
| } | |
| return Bridges; | |
| } | |
| /** | |
| Utility function to free root bridge instances array from | |
| PciHostBridgeUtilityGetRootBridges(). | |
| @param[in] Bridges The root bridge instances array. | |
| @param[in] Count The count of the array. | |
| **/ | |
| VOID | |
| EFIAPI | |
| PciHostBridgeUtilityFreeRootBridges ( | |
| IN PCI_ROOT_BRIDGE *Bridges, | |
| IN UINTN Count | |
| ) | |
| { | |
| if ((Bridges == NULL) && (Count == 0)) { | |
| return; | |
| } | |
| ASSERT (Bridges != NULL && Count > 0); | |
| do { | |
| --Count; | |
| PciHostBridgeUtilityUninitRootBridge (&Bridges[Count]); | |
| } while (Count > 0); | |
| FreePool (Bridges); | |
| } | |
| /** | |
| Utility function to inform the platform that the resource conflict happens. | |
| @param[in] Configuration Pointer to PCI I/O and PCI memory resource | |
| descriptors. The Configuration contains the | |
| resources for all the root bridges. The resource | |
| for each root bridge is terminated with END | |
| descriptor and an additional END is appended | |
| indicating the end of the entire resources. The | |
| resource descriptor field values follow the | |
| description in | |
| EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL | |
| .SubmitResources(). | |
| **/ | |
| VOID | |
| EFIAPI | |
| PciHostBridgeUtilityResourceConflict ( | |
| IN VOID *Configuration | |
| ) | |
| { | |
| EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor; | |
| UINTN RootBridgeIndex; | |
| DEBUG ((DEBUG_ERROR, "PciHostBridge: Resource conflict happens!\n")); | |
| RootBridgeIndex = 0; | |
| Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)Configuration; | |
| while (Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR) { | |
| DEBUG ((DEBUG_ERROR, "RootBridge[%d]:\n", RootBridgeIndex++)); | |
| for ( ; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) { | |
| ASSERT ( | |
| Descriptor->ResType < | |
| ARRAY_SIZE (mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr) | |
| ); | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| " %s: Length/Alignment = 0x%lx / 0x%lx\n", | |
| mPciHostBridgeUtilityLibAcpiAddressSpaceTypeStr[Descriptor->ResType], | |
| Descriptor->AddrLen, | |
| Descriptor->AddrRangeMax | |
| )); | |
| if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| " Granularity/SpecificFlag = %ld / %02x%s\n", | |
| Descriptor->AddrSpaceGranularity, | |
| Descriptor->SpecificFlag, | |
| ((Descriptor->SpecificFlag & | |
| EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE | |
| ) != 0) ? L" (Prefetchable)" : L"" | |
| )); | |
| } | |
| } | |
| // | |
| // Skip the END descriptor for root bridge | |
| // | |
| ASSERT (Descriptor->Desc == ACPI_END_TAG_DESCRIPTOR); | |
| Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *)( | |
| (EFI_ACPI_END_TAG_DESCRIPTOR *)Descriptor + 1 | |
| ); | |
| } | |
| } |