summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c')
-rw-r--r--src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c1809
1 files changed, 1809 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
new file mode 100644
index 00000000..2b761007
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/MdeModulePkg/Bus/Pci/PciBusDxe/PciLib.c
@@ -0,0 +1,1809 @@
+/** @file
+ Internal library implementation for PCI Bus module.
+
+Copyright (c) 2006 - 2021, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "PciBus.h"
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+CHAR16 *mBarTypeStr[] = {
+ L"Unknow",
+ L" Io16",
+ L" Io32",
+ L" Mem32",
+ L"PMem32",
+ L" Mem64",
+ L"PMem64",
+ L" OpRom",
+ L" Io",
+ L" Mem",
+ L"Unknow"
+ };
+
+/**
+ Retrieve the max bus number that is assigned to the Root Bridge hierarchy.
+ It can support the case that there are multiple bus ranges.
+
+ @param Bridge Bridge device instance.
+
+ @retval The max bus number that is assigned to this Root Bridge hierarchy.
+
+**/
+UINT16
+PciGetMaxBusNumber (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
+ UINT64 MaxNumberInRange;
+
+ //
+ // Get PCI Root Bridge device
+ //
+ RootBridge = Bridge;
+ while (RootBridge->Parent != NULL) {
+ RootBridge = RootBridge->Parent;
+ }
+ MaxNumberInRange = 0;
+ //
+ // Iterate the bus number ranges to get max PCI bus number
+ //
+ BusNumberRanges = RootBridge->BusNumberRanges;
+ while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ BusNumberRanges++;
+ }
+ return (UINT16) MaxNumberInRange;
+}
+
+/**
+ Retrieve the PCI Card device BAR information via PciIo interface.
+
+ @param PciIoDevice PCI Card device instance.
+
+**/
+VOID
+GetBackPcCardBar (
+ IN PCI_IO_DEVICE *PciIoDevice
+ )
+{
+ UINT32 Address;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ //
+ // Read PciBar information from the bar register
+ //
+ if (!gFullEnumeration) {
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_0,
+ 1,
+ &Address
+ );
+
+ (PciIoDevice->PciBar)[P2C_MEM_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_1].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_1].BarType = PciBarTypeMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_MEMORY_BASE_1,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_MEM_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_MEM_2].Length = 0x2000000;
+ (PciIoDevice->PciBar)[P2C_MEM_2].BarType = PciBarTypePMem32;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_0_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_1].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_1].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_1].BarType = PciBarTypeIo16;
+
+ Address = 0;
+ PciIoDevice->PciIo.Pci.Read (
+ &(PciIoDevice->PciIo),
+ EfiPciIoWidthUint32,
+ PCI_CARD_IO_BASE_1_LOWER,
+ 1,
+ &Address
+ );
+ (PciIoDevice->PciBar)[P2C_IO_2].BaseAddress = (UINT64) (Address);
+ (PciIoDevice->PciBar)[P2C_IO_2].Length = 0x100;
+ (PciIoDevice->PciBar)[P2C_IO_2].BarType = PciBarTypeIo16;
+
+ }
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ GetResourcePaddingForHpb (PciIoDevice);
+ }
+}
+
+/**
+ Remove rejected pci device from specific root bridge
+ handle.
+
+ @param RootBridgeHandle Specific parent root bridge handle.
+ @param Bridge Bridge device instance.
+
+**/
+VOID
+RemoveRejectedPciDevices (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ PCI_IO_DEVICE *Temp;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *LastLink;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return;
+ }
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&Temp->Pci)) {
+ //
+ // Remove rejected devices recusively
+ //
+ RemoveRejectedPciDevices (RootBridgeHandle, Temp);
+ } else {
+ //
+ // Skip rejection for all PPBs, while detect rejection for others
+ //
+ if (IsPciDeviceRejected (Temp)) {
+
+ //
+ // For P2C, remove all devices on it
+ //
+ if (!IsListEmpty (&Temp->ChildList)) {
+ RemoveAllPciDeviceOnBridge (RootBridgeHandle, Temp);
+ }
+
+ //
+ // Finally remove itself
+ //
+ LastLink = CurrentLink->BackLink;
+ RemoveEntryList (CurrentLink);
+ FreePciDevice (Temp);
+
+ CurrentLink = LastLink;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+}
+
+/**
+ Dump the resourc map of the bridge device.
+
+ @param[in] BridgeResource Resource descriptor of the bridge device.
+**/
+VOID
+DumpBridgeResource (
+ IN PCI_RESOURCE_NODE *BridgeResource
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_RESOURCE_NODE *Resource;
+ PCI_BAR *Bar;
+
+ if ((BridgeResource != NULL) && (BridgeResource->Length != 0)) {
+ DEBUG ((
+ EFI_D_INFO, "Type = %s; Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx\n",
+ mBarTypeStr[MIN (BridgeResource->ResType, PciBarTypeMaxType)],
+ BridgeResource->PciDev->PciBar[BridgeResource->Bar].BaseAddress,
+ BridgeResource->Length, BridgeResource->Alignment
+ ));
+ for ( Link = GetFirstNode (&BridgeResource->ChildList)
+ ; !IsNull (&BridgeResource->ChildList, Link)
+ ; Link = GetNextNode (&BridgeResource->ChildList, Link)
+ ) {
+ Resource = RESOURCE_NODE_FROM_LINK (Link);
+ if (Resource->ResourceUsage == PciResUsageTypical) {
+ Bar = Resource->Virtual ? Resource->PciDev->VfPciBar : Resource->PciDev->PciBar;
+ DEBUG ((
+ EFI_D_INFO, " Base = 0x%lx;\tLength = 0x%lx;\tAlignment = 0x%lx;\tOwner = %s [%02x|%02x|%02x:",
+ Bar[Resource->Bar].BaseAddress, Resource->Length, Resource->Alignment,
+ IS_PCI_BRIDGE (&Resource->PciDev->Pci) ? L"PPB" :
+ IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) ? L"P2C" :
+ L"PCI",
+ Resource->PciDev->BusNumber, Resource->PciDev->DeviceNumber,
+ Resource->PciDev->FunctionNumber
+ ));
+
+ if ((!IS_PCI_BRIDGE (&Resource->PciDev->Pci) && !IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci)) ||
+ (IS_PCI_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < PPB_IO_RANGE)) ||
+ (IS_CARDBUS_BRIDGE (&Resource->PciDev->Pci) && (Resource->Bar < P2C_MEM_1))
+ ) {
+ //
+ // The resource requirement comes from the device itself.
+ //
+ DEBUG ((EFI_D_INFO, "%02x]", Bar[Resource->Bar].Offset));
+ } else {
+ //
+ // The resource requirement comes from the subordinate devices.
+ //
+ DEBUG ((EFI_D_INFO, "**]"));
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, " Base = Padding;\tLength = 0x%lx;\tAlignment = 0x%lx", Resource->Length, Resource->Alignment));
+ }
+ if (BridgeResource->ResType != Resource->ResType) {
+ DEBUG ((EFI_D_INFO, "; Type = %s", mBarTypeStr[MIN (Resource->ResType, PciBarTypeMaxType)]));
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+ }
+ }
+}
+
+/**
+ Find the corresponding resource node for the Device in child list of BridgeResource.
+
+ @param[in] Device Pointer to PCI_IO_DEVICE.
+ @param[in] BridgeResource Pointer to PCI_RESOURCE_NODE.
+ @param[out] DeviceResources Pointer to a buffer to receive resources for the Device.
+
+ @return Count of the resource descriptors returned.
+**/
+UINTN
+FindResourceNode (
+ IN PCI_IO_DEVICE *Device,
+ IN PCI_RESOURCE_NODE *BridgeResource,
+ OUT PCI_RESOURCE_NODE **DeviceResources OPTIONAL
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_RESOURCE_NODE *Resource;
+ UINTN Count;
+
+ Count = 0;
+ for ( Link = BridgeResource->ChildList.ForwardLink
+ ; Link != &BridgeResource->ChildList
+ ; Link = Link->ForwardLink
+ ) {
+ Resource = RESOURCE_NODE_FROM_LINK (Link);
+ if (Resource->PciDev == Device) {
+ if (DeviceResources != NULL) {
+ DeviceResources[Count] = Resource;
+ }
+ Count++;
+ }
+ }
+
+ return Count;
+}
+
+/**
+ Dump the resource map of all the devices under Bridge.
+
+ @param[in] Bridge Bridge device instance.
+ @param[in] Resources Resource descriptors for the bridge device.
+ @param[in] ResourceCount Count of resource descriptors.
+**/
+VOID
+DumpResourceMap (
+ IN PCI_IO_DEVICE *Bridge,
+ IN PCI_RESOURCE_NODE **Resources,
+ IN UINTN ResourceCount
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ PCI_IO_DEVICE *Device;
+ UINTN Index;
+ CHAR16 *Str;
+ PCI_RESOURCE_NODE **ChildResources;
+ UINTN ChildResourceCount;
+
+ DEBUG ((EFI_D_INFO, "PciBus: Resource Map for "));
+
+ Status = gBS->OpenProtocol (
+ Bridge->Handle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((
+ EFI_D_INFO, "Bridge [%02x|%02x|%02x]\n",
+ Bridge->BusNumber, Bridge->DeviceNumber, Bridge->FunctionNumber
+ ));
+ } else {
+ Str = ConvertDevicePathToText (
+ DevicePathFromHandle (Bridge->Handle),
+ FALSE,
+ FALSE
+ );
+ DEBUG ((EFI_D_INFO, "Root Bridge %s\n", Str != NULL ? Str : L""));
+ if (Str != NULL) {
+ FreePool (Str);
+ }
+ }
+
+ for (Index = 0; Index < ResourceCount; Index++) {
+ DumpBridgeResource (Resources[Index]);
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ for ( Link = Bridge->ChildList.ForwardLink
+ ; Link != &Bridge->ChildList
+ ; Link = Link->ForwardLink
+ ) {
+ Device = PCI_IO_DEVICE_FROM_LINK (Link);
+ if (IS_PCI_BRIDGE (&Device->Pci)) {
+
+ ChildResourceCount = 0;
+ for (Index = 0; Index < ResourceCount; Index++) {
+ ChildResourceCount += FindResourceNode (Device, Resources[Index], NULL);
+ }
+ ChildResources = AllocatePool (sizeof (PCI_RESOURCE_NODE *) * ChildResourceCount);
+ ASSERT (ChildResources != NULL);
+ ChildResourceCount = 0;
+ for (Index = 0; Index < ResourceCount; Index++) {
+ ChildResourceCount += FindResourceNode (Device, Resources[Index], &ChildResources[ChildResourceCount]);
+ }
+
+ DumpResourceMap (Device, ChildResources, ChildResourceCount);
+ FreePool (ChildResources);
+ }
+ }
+}
+
+/**
+ Adjust the Devices' BAR size to minimum value if it support Resizeable BAR capability.
+
+ @param RootBridgeDev Pointer to instance of PCI_IO_DEVICE..
+
+ @return TRUE if BAR size is adjusted.
+
+**/
+BOOLEAN
+AdjustPciDeviceBarSize (
+ IN PCI_IO_DEVICE *RootBridgeDev
+ )
+{
+ PCI_IO_DEVICE *PciIoDevice;
+ LIST_ENTRY *CurrentLink;
+ BOOLEAN Adjusted;
+ UINTN Offset;
+ UINTN BarIndex;
+
+ Adjusted = FALSE;
+ CurrentLink = RootBridgeDev->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &RootBridgeDev->ChildList) {
+ PciIoDevice = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_PCI_BRIDGE (&PciIoDevice->Pci)) {
+ if (AdjustPciDeviceBarSize (PciIoDevice)) {
+ Adjusted = TRUE;
+ }
+ } else {
+ if (PciIoDevice->ResizableBarOffset != 0) {
+ DEBUG ((
+ DEBUG_ERROR,
+ "PciBus: [%02x|%02x|%02x] Adjust Pci Device Bar Size\n",
+ PciIoDevice->BusNumber, PciIoDevice->DeviceNumber, PciIoDevice->FunctionNumber
+ ));
+ PciProgramResizableBar (PciIoDevice, PciResizableBarMin);
+ //
+ // Start to parse the bars
+ //
+ for (Offset = 0x10, BarIndex = 0; Offset <= 0x24 && BarIndex < PCI_MAX_BAR; BarIndex++) {
+ Offset = PciParseBar (PciIoDevice, Offset, BarIndex);
+ }
+ Adjusted = TRUE;
+ DEBUG_CODE (DumpPciBars (PciIoDevice););
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return Adjusted;
+}
+
+/**
+ Submits the I/O and memory resource requirements for the specified PCI Host Bridge.
+
+ @param PciResAlloc Point to protocol instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Successfully finished resource allocation.
+ @retval EFI_NOT_FOUND Cannot get root bridge instance.
+ @retval EFI_OUT_OF_RESOURCES Platform failed to program the resources if no hot plug supported.
+ @retval other Some error occurred when allocating resources for the PCI Host Bridge.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciHostBridgeResourceAllocator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_HANDLE RootBridgeHandle;
+ VOID *AcpiConfig;
+ EFI_STATUS Status;
+ UINT64 IoBase;
+ UINT64 Mem32Base;
+ UINT64 PMem32Base;
+ UINT64 Mem64Base;
+ UINT64 PMem64Base;
+ UINT64 IoResStatus;
+ UINT64 Mem32ResStatus;
+ UINT64 PMem32ResStatus;
+ UINT64 Mem64ResStatus;
+ UINT64 PMem64ResStatus;
+ UINT32 MaxOptionRomSize;
+ PCI_RESOURCE_NODE *IoBridge;
+ PCI_RESOURCE_NODE *Mem32Bridge;
+ PCI_RESOURCE_NODE *PMem32Bridge;
+ PCI_RESOURCE_NODE *Mem64Bridge;
+ PCI_RESOURCE_NODE *PMem64Bridge;
+ PCI_RESOURCE_NODE IoPool;
+ PCI_RESOURCE_NODE Mem32Pool;
+ PCI_RESOURCE_NODE PMem32Pool;
+ PCI_RESOURCE_NODE Mem64Pool;
+ PCI_RESOURCE_NODE PMem64Pool;
+ EFI_DEVICE_HANDLE_EXTENDED_DATA_PAYLOAD HandleExtendedData;
+ EFI_RESOURCE_ALLOC_FAILURE_ERROR_DATA_PAYLOAD AllocFailExtendedData;
+ BOOLEAN ResizableBarNeedAdjust;
+ BOOLEAN ResizableBarAdjusted;
+
+ ResizableBarNeedAdjust = PcdGetBool (PcdPcieResizableBarSupport);
+
+ //
+ // It may try several times if the resource allocation fails
+ //
+ while (TRUE) {
+ //
+ // Initialize resource pool
+ //
+ InitializeResourcePool (&IoPool, PciBarTypeIo16);
+ InitializeResourcePool (&Mem32Pool, PciBarTypeMem32);
+ InitializeResourcePool (&PMem32Pool, PciBarTypePMem32);
+ InitializeResourcePool (&Mem64Pool, PciBarTypeMem64);
+ InitializeResourcePool (&PMem64Pool, PciBarTypePMem64);
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get Root Bridge Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+
+ //
+ // If non-standard PCI Bridge I/O window alignment is supported,
+ // set I/O aligment to minimum possible alignment for root bridge.
+ //
+ IoBridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ FeaturePcdGet (PcdPciBridgeIoAlignmentProbe) ? 0x1FF: 0xFFF,
+ RB_IO_RANGE,
+ PciBarTypeIo16,
+ PciResUsageTypical
+ );
+
+ Mem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_MEM32_RANGE,
+ PciBarTypeMem32,
+ PciResUsageTypical
+ );
+
+ PMem32Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_PMEM32_RANGE,
+ PciBarTypePMem32,
+ PciResUsageTypical
+ );
+
+ Mem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_MEM64_RANGE,
+ PciBarTypeMem64,
+ PciResUsageTypical
+ );
+
+ PMem64Bridge = CreateResourceNode (
+ RootBridgeDev,
+ 0,
+ 0xFFFFF,
+ RB_PMEM64_RANGE,
+ PciBarTypePMem64,
+ PciResUsageTypical
+ );
+
+ //
+ // Get the max ROM size that the root bridge can process
+ // Insert to resource map so that there will be dedicate MEM32 resource range for Option ROM.
+ // All devices' Option ROM share the same MEM32 resource.
+ //
+ MaxOptionRomSize = GetMaxOptionRomSize (RootBridgeDev);
+ if (MaxOptionRomSize != 0) {
+ RootBridgeDev->PciBar[0].BarType = PciBarTypeOpRom;
+ RootBridgeDev->PciBar[0].Length = MaxOptionRomSize;
+ RootBridgeDev->PciBar[0].Alignment = MaxOptionRomSize - 1;
+ GetResourceFromDevice (RootBridgeDev, IoBridge, Mem32Bridge, PMem32Bridge, Mem64Bridge, PMem64Bridge);
+ }
+
+ //
+ // Create resourcemap by going through all the devices subject to this root bridge
+ //
+ CreateResourceMap (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge
+ );
+
+ //
+ // Based on the all the resource tree, construct ACPI resource node to
+ // submit the resource aperture to pci host bridge protocol
+ //
+ Status = ConstructAcpiResourceRequestor (
+ RootBridgeDev,
+ IoBridge,
+ Mem32Bridge,
+ PMem32Bridge,
+ Mem64Bridge,
+ PMem64Bridge,
+ &AcpiConfig
+ );
+
+ //
+ // Insert these resource nodes into the database
+ //
+ InsertResourceNode (&IoPool, IoBridge);
+ InsertResourceNode (&Mem32Pool, Mem32Bridge);
+ InsertResourceNode (&PMem32Pool, PMem32Bridge);
+ InsertResourceNode (&Mem64Pool, Mem64Bridge);
+ InsertResourceNode (&PMem64Pool, PMem64Bridge);
+
+ if (Status == EFI_SUCCESS) {
+ //
+ // Submit the resource requirement
+ //
+ Status = PciResAlloc->SubmitResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ AcpiConfig
+ );
+ //
+ // If SubmitResources returns error, PciBus isn't able to start.
+ // It's a fatal error so assertion is added.
+ //
+ DEBUG ((EFI_D_INFO, "PciBus: HostBridge->SubmitResources() - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Free acpi resource node
+ //
+ if (AcpiConfig != NULL) {
+ FreePool (AcpiConfig);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+ return Status;
+ }
+ }
+ //
+ // End while, at least one Root Bridge should be found.
+ //
+ ASSERT (RootBridgeDev != NULL);
+
+ //
+ // Notify platform to start to program the resource
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeAllocateResources);
+ DEBUG ((EFI_D_INFO, "PciBus: HostBridge->NotifyPhase(AllocateResources) - %r\n", Status));
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is not supported
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // Allocation failed, then return
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Allocation succeed.
+ // Get host bridge handle for status report, and then skip the main while
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ break;
+
+ } else {
+ //
+ // If Hot Plug is supported
+ //
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocation succeed, then continue the following
+ //
+ break;
+ }
+
+ //
+ // If the resource allocation is unsuccessful, free resources on bridge
+ //
+
+ RootBridgeDev = NULL;
+ RootBridgeHandle = 0;
+
+ IoResStatus = EFI_RESOURCE_SATISFIED;
+ Mem32ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem32ResStatus = EFI_RESOURCE_SATISFIED;
+ Mem64ResStatus = EFI_RESOURCE_SATISFIED;
+ PMem64ResStatus = EFI_RESOURCE_SATISFIED;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get host bridge handle for status report
+ //
+ HandleExtendedData.Handle = RootBridgeDev->PciRootBridgeIo->ParentHandle;
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (AcpiConfig != NULL) {
+ //
+ // Adjust resource allocation policy for each RB
+ //
+ GetResourceAllocationStatus (
+ AcpiConfig,
+ &IoResStatus,
+ &Mem32ResStatus,
+ &PMem32ResStatus,
+ &Mem64ResStatus,
+ &PMem64ResStatus
+ );
+ FreePool (AcpiConfig);
+ }
+ }
+ //
+ // End while
+ //
+
+ //
+ // Raise the EFI_IOB_EC_RESOURCE_CONFLICT status code
+ //
+ //
+ // It is very difficult to follow the spec here
+ // Device path , Bar index can not be get here
+ //
+ ZeroMem (&AllocFailExtendedData, sizeof (AllocFailExtendedData));
+
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_EC_RESOURCE_CONFLICT,
+ (VOID *) &AllocFailExtendedData,
+ sizeof (AllocFailExtendedData)
+ );
+
+ //
+ // When resource conflict happens, adjust the BAR size first.
+ // Only when adjusting BAR size doesn't help or BAR size cannot be adjusted,
+ // reject the device who requests largest resource that causes conflict.
+ //
+ ResizableBarAdjusted = FALSE;
+ if (ResizableBarNeedAdjust) {
+ ResizableBarAdjusted = AdjustPciDeviceBarSize (RootBridgeDev);
+ ResizableBarNeedAdjust = FALSE;
+ }
+ if (!ResizableBarAdjusted) {
+ Status = PciHostBridgeAdjustAllocation (
+ &IoPool,
+ &Mem32Pool,
+ &PMem32Pool,
+ &Mem64Pool,
+ &PMem64Pool,
+ IoResStatus,
+ Mem32ResStatus,
+ PMem32ResStatus,
+ Mem64ResStatus,
+ PMem64ResStatus
+ );
+ }
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeFreeResources);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ //
+ // End main while
+ //
+
+ //
+ // Raise the EFI_IOB_PCI_RES_ALLOC status code
+ //
+ REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_RES_ALLOC,
+ (VOID *) &HandleExtendedData,
+ sizeof (HandleExtendedData)
+ );
+
+ //
+ // Notify pci bus driver starts to program the resource
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeSetResources);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridgeDev = NULL;
+
+ RootBridgeHandle = 0;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get acpi resource node for all the resource types
+ //
+ AcpiConfig = NULL;
+ Status = PciResAlloc->GetProposedResources (
+ PciResAlloc,
+ RootBridgeDev->Handle,
+ &AcpiConfig
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the resource base by interpreting acpi resource node
+ //
+ //
+ GetResourceBase (
+ AcpiConfig,
+ &IoBase,
+ &Mem32Base,
+ &PMem32Base,
+ &Mem64Base,
+ &PMem64Base
+ );
+
+ //
+ // Create the entire system resource map from the information collected by
+ // enumerator. Several resource tree was created
+ //
+ FindResourceNode (RootBridgeDev, &IoPool, &IoBridge);
+ FindResourceNode (RootBridgeDev, &Mem32Pool, &Mem32Bridge);
+ FindResourceNode (RootBridgeDev, &PMem32Pool, &PMem32Bridge);
+ FindResourceNode (RootBridgeDev, &Mem64Pool, &Mem64Bridge);
+ FindResourceNode (RootBridgeDev, &PMem64Pool, &PMem64Bridge);
+
+ ASSERT (IoBridge != NULL);
+ ASSERT (Mem32Bridge != NULL);
+ ASSERT (PMem32Bridge != NULL);
+ ASSERT (Mem64Bridge != NULL);
+ ASSERT (PMem64Bridge != NULL);
+
+ //
+ // Program IO resources
+ //
+ ProgramResource (
+ IoBase,
+ IoBridge
+ );
+
+ //
+ // Program Mem32 resources
+ //
+ ProgramResource (
+ Mem32Base,
+ Mem32Bridge
+ );
+
+ //
+ // Program PMem32 resources
+ //
+ ProgramResource (
+ PMem32Base,
+ PMem32Bridge
+ );
+
+ //
+ // Program Mem64 resources
+ //
+ ProgramResource (
+ Mem64Base,
+ Mem64Bridge
+ );
+
+ //
+ // Program PMem64 resources
+ //
+ ProgramResource (
+ PMem64Base,
+ PMem64Bridge
+ );
+
+ //
+ // Process Option ROM for this root bridge after all BARs are programmed.
+ // The PPB's MEM32 RANGE BAR is re-programmed to the Option ROM BAR Base in order to
+ // shadow the Option ROM of the devices under the PPB.
+ // After the shadow, Option ROM BAR decoding is turned off and the PPB's MEM32 RANGE
+ // BAR is restored back to the original value.
+ // The original value is programmed by ProgramResource() above.
+ //
+ DEBUG ((
+ DEBUG_INFO, "Process Option ROM: BAR Base/Length = %lx/%lx\n",
+ RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length
+ ));
+ ProcessOptionRom (RootBridgeDev, RootBridgeDev->PciBar[0].BaseAddress, RootBridgeDev->PciBar[0].Length);
+
+ IoBridge ->PciDev->PciBar[IoBridge ->Bar].BaseAddress = IoBase;
+ Mem32Bridge ->PciDev->PciBar[Mem32Bridge ->Bar].BaseAddress = Mem32Base;
+ PMem32Bridge->PciDev->PciBar[PMem32Bridge->Bar].BaseAddress = PMem32Base;
+ Mem64Bridge ->PciDev->PciBar[Mem64Bridge ->Bar].BaseAddress = Mem64Base;
+ PMem64Bridge->PciDev->PciBar[PMem64Bridge->Bar].BaseAddress = PMem64Base;
+
+ //
+ // Dump the resource map for current root bridge
+ //
+ DEBUG_CODE (
+ PCI_RESOURCE_NODE *Resources[5];
+ Resources[0] = IoBridge;
+ Resources[1] = Mem32Bridge;
+ Resources[2] = PMem32Bridge;
+ Resources[3] = Mem64Bridge;
+ Resources[4] = PMem64Bridge;
+ DumpResourceMap (RootBridgeDev, Resources, ARRAY_SIZE (Resources));
+ );
+
+ FreePool (AcpiConfig);
+ }
+
+ //
+ // Destroy all the resource tree
+ //
+ DestroyResourceTree (&IoPool);
+ DestroyResourceTree (&Mem32Pool);
+ DestroyResourceTree (&PMem32Pool);
+ DestroyResourceTree (&Mem64Pool);
+ DestroyResourceTree (&PMem64Pool);
+
+ //
+ // Notify the resource allocation phase is to end
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeEndResourceAllocation);
+
+ return Status;
+}
+
+/**
+ Allocate NumberOfBuses buses and return the next available PCI bus number.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber Current available PCI bus number.
+ @param NumberOfBuses Number of buses enumerated below the StartBusNumber.
+ @param NextBusNumber Next available PCI bus number.
+
+ @retval EFI_SUCCESS Available bus number resource is enough. Next available PCI bus number
+ is returned in NextBusNumber.
+ @retval EFI_OUT_OF_RESOURCES Available bus number resource is not enough for allocation.
+
+**/
+EFI_STATUS
+PciAllocateBusNumber (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ IN UINT8 NumberOfBuses,
+ OUT UINT8 *NextBusNumber
+ )
+{
+ PCI_IO_DEVICE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BusNumberRanges;
+ UINT8 NextNumber;
+ UINT64 MaxNumberInRange;
+
+ //
+ // Get PCI Root Bridge device
+ //
+ RootBridge = Bridge;
+ while (RootBridge->Parent != NULL) {
+ RootBridge = RootBridge->Parent;
+ }
+
+ //
+ // Get next available PCI bus number
+ //
+ BusNumberRanges = RootBridge->BusNumberRanges;
+ while (BusNumberRanges->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ if (StartBusNumber >= BusNumberRanges->AddrRangeMin && StartBusNumber <= MaxNumberInRange) {
+ NextNumber = (UINT8)(StartBusNumber + NumberOfBuses);
+ while (NextNumber > MaxNumberInRange) {
+ ++BusNumberRanges;
+ if (BusNumberRanges->Desc == ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ NextNumber = (UINT8)(NextNumber + (BusNumberRanges->AddrRangeMin - (MaxNumberInRange + 1)));
+ MaxNumberInRange = BusNumberRanges->AddrRangeMin + BusNumberRanges->AddrLen - 1;
+ }
+ *NextBusNumber = NextNumber;
+ return EFI_SUCCESS;
+ }
+ BusNumberRanges++;
+ }
+ return EFI_OUT_OF_RESOURCES;
+}
+
+/**
+ Scan pci bus and assign bus number to the given PCI bus system.
+
+ @param Bridge Bridge device instance.
+ @param StartBusNumber start point.
+ @param SubBusNumber Point to sub bus number.
+ @param PaddedBusRange Customized bus number.
+
+ @retval EFI_SUCCESS Successfully scanned and assigned bus number.
+ @retval other Some error occurred when scanning pci bus.
+
+ @note Feature flag PcdPciBusHotplugDeviceSupport determine whether need support hotplug.
+
+**/
+EFI_STATUS
+PciScanBus (
+ IN PCI_IO_DEVICE *Bridge,
+ IN UINT8 StartBusNumber,
+ OUT UINT8 *SubBusNumber,
+ OUT UINT8 *PaddedBusRange
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 Pci;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 Address;
+ UINT8 SecondBus;
+ UINT8 PaddedSubBus;
+ UINT16 Register;
+ UINTN HpIndex;
+ PCI_IO_DEVICE *PciDevice;
+ EFI_EVENT Event;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_HPC_PADDING_ATTRIBUTES Attributes;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *NextDescriptors;
+ UINT16 BusRange;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ BOOLEAN BusPadding;
+ UINT32 TempReservedBusNum;
+
+ PciRootBridgeIo = Bridge->PciRootBridgeIo;
+ SecondBus = 0;
+ Register = 0;
+ State = 0;
+ Attributes = (EFI_HPC_PADDING_ATTRIBUTES) 0;
+ BusRange = 0;
+ BusPadding = FALSE;
+ PciDevice = NULL;
+ PciAddress = 0;
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ TempReservedBusNum = 0;
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+
+ //
+ // Check to see whether a pci device is present
+ //
+ Status = PciDevicePresent (
+ PciRootBridgeIo,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func
+ );
+
+ if (EFI_ERROR (Status) && Func == 0) {
+ //
+ // go to next device if there is no Function 0
+ //
+ break;
+ }
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Get the PCI device information
+ //
+ Status = PciSearchDevice (
+ Bridge,
+ &Pci,
+ StartBusNumber,
+ Device,
+ Func,
+ &PciDevice
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PciAddress = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, 0);
+
+ if (!IS_PCI_BRIDGE (&Pci)) {
+ //
+ // PCI bridges will be called later
+ // Here just need for PCI device or PCI to cardbus controller
+ // EfiPciBeforeChildBusEnumeration for PCI Device Node
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // For Pci Hotplug controller devcie only
+ //
+ if (gPciHotPlugInit != NULL) {
+ //
+ // Check if it is a Hotplug PCI controller
+ //
+ if (IsRootPciHotPlugController (PciDevice->DevicePath, &HpIndex)) {
+ gPciRootHpcData[HpIndex].Found = TRUE;
+
+ if (!gPciRootHpcData[HpIndex].Initialized) {
+
+ Status = CreateEventForHpc (HpIndex, &Event);
+
+ ASSERT (!EFI_ERROR (Status));
+
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ gPciRootHpcPool[HpIndex].HpcDevicePath,
+ PciAddress,
+ Event,
+ &State
+ );
+
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+ }
+ }
+ }
+ }
+
+ if (IS_PCI_BRIDGE (&Pci) || IS_CARDBUS_BRIDGE (&Pci)) {
+ //
+ // For PPB
+ //
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // If Hot Plug is supported,
+ // Get the bridge information
+ //
+ BusPadding = FALSE;
+ if (gPciHotPlugInit != NULL) {
+
+ if (IsPciHotPlugBus (PciDevice)) {
+
+ //
+ // If it is initialized, get the padded bus range
+ //
+ Status = gPciHotPlugInit->GetResourcePadding (
+ gPciHotPlugInit,
+ PciDevice->DevicePath,
+ PciAddress,
+ &State,
+ (VOID **) &Descriptors,
+ &Attributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BusRange = 0;
+ NextDescriptors = Descriptors;
+ Status = PciGetBusRange (
+ &NextDescriptors,
+ NULL,
+ NULL,
+ &BusRange
+ );
+
+ FreePool (Descriptors);
+
+ if (!EFI_ERROR (Status)) {
+ BusPadding = TRUE;
+ } else if (Status != EFI_NOT_FOUND) {
+ //
+ // EFI_NOT_FOUND is not a real error. It indicates no bus number padding requested.
+ //
+ return Status;
+ }
+ }
+ }
+ }
+
+ Status = PciAllocateBusNumber (Bridge, *SubBusNumber, 1, SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ SecondBus = *SubBusNumber;
+
+ Register = (UINT16) ((SecondBus << 8) | (UINT16) StartBusNumber);
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint16,
+ Address,
+ 1,
+ &Register
+ );
+
+
+ //
+ // If it is PPB, resursively search down this bridge
+ //
+ if (IS_PCI_BRIDGE (&Pci)) {
+
+ //
+ // Temporarily initialize SubBusNumber to maximum bus number to ensure the
+ // PCI configuration transaction to go through any PPB
+ //
+ Register = PciGetMaxBusNumber (Bridge);
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &Register
+ );
+
+ //
+ // Nofify EfiPciBeforeChildBusEnumeration for PCI Brige
+ //
+ PreprocessController (
+ PciDevice,
+ PciDevice->BusNumber,
+ PciDevice->DeviceNumber,
+ PciDevice->FunctionNumber,
+ EfiPciBeforeChildBusEnumeration
+ );
+
+ Status = PciScanBus (
+ PciDevice,
+ SecondBus,
+ SubBusNumber,
+ PaddedBusRange
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport) && BusPadding) {
+ //
+ // Ensure the device is enabled and initialized
+ //
+ if ((Attributes == EfiPaddingPciRootBridge) &&
+ (State & EFI_HPC_STATE_ENABLED) != 0 &&
+ (State & EFI_HPC_STATE_INITIALIZED) != 0) {
+ *PaddedBusRange = (UINT8) ((UINT8) (BusRange) + *PaddedBusRange);
+ } else {
+ //
+ // Reserve the larger one between the actual occupied bus number and padded bus number
+ //
+ Status = PciAllocateBusNumber (PciDevice, SecondBus, (UINT8) (BusRange), &PaddedSubBus);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ *SubBusNumber = MAX (PaddedSubBus, *SubBusNumber);
+ }
+ }
+
+ //
+ // Set the current maximum bus number under the PPB
+ //
+ Address = EFI_PCI_ADDRESS (StartBusNumber, Device, Func, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+
+ Status = PciRootBridgeIo->Pci.Write (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ SubBusNumber
+ );
+ } else {
+ //
+ // It is device. Check PCI IOV for Bus reservation
+ // Go through each function, just reserve the MAX ReservedBusNum for one device
+ //
+ if (PcdGetBool (PcdSrIovSupport) && PciDevice->SrIovCapabilityOffset != 0) {
+ if (TempReservedBusNum < PciDevice->ReservedBusNum) {
+
+ Status = PciAllocateBusNumber (PciDevice, *SubBusNumber, (UINT8) (PciDevice->ReservedBusNum - TempReservedBusNum), SubBusNumber);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ TempReservedBusNum = PciDevice->ReservedBusNum;
+
+ if (Func == 0) {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x\n", *SubBusNumber));
+ } else {
+ DEBUG ((EFI_D_INFO, "PCI-IOV ScanBus - SubBusNumber - 0x%x (Update)\n", *SubBusNumber));
+ }
+ }
+ }
+ }
+
+ if (Func == 0 && !IS_PCI_MULTI_FUNC (&Pci)) {
+
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified root bridge.
+
+ @param Bridge Pci root bridge device instance.
+
+ @retval EFI_SUCCESS Success process.
+ @retval other Some error occurred when processing Option Rom on the root bridge.
+
+**/
+EFI_STATUS
+PciRootBridgeP2CProcess (
+ IN PCI_IO_DEVICE *Bridge
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ PCI_IO_DEVICE *Temp;
+ EFI_HPC_STATE State;
+ UINT64 PciAddress;
+ EFI_STATUS Status;
+
+ CurrentLink = Bridge->ChildList.ForwardLink;
+
+ while (CurrentLink != NULL && CurrentLink != &Bridge->ChildList) {
+
+ Temp = PCI_IO_DEVICE_FROM_LINK (CurrentLink);
+
+ if (IS_CARDBUS_BRIDGE (&Temp->Pci)) {
+
+ if (gPciHotPlugInit != NULL && Temp->Allocated && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+
+ //
+ // Raise the EFI_IOB_PCI_HPC_INIT status code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_IO_BUS_PCI | EFI_IOB_PCI_HPC_INIT,
+ Temp->DevicePath
+ );
+
+ PciAddress = EFI_PCI_ADDRESS (Temp->BusNumber, Temp->DeviceNumber, Temp->FunctionNumber, 0);
+ Status = gPciHotPlugInit->InitializeRootHpc (
+ gPciHotPlugInit,
+ Temp->DevicePath,
+ PciAddress,
+ NULL,
+ &State
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = PciBridgeEnumerator (Temp);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ continue;
+
+ }
+ }
+
+ if (!IsListEmpty (&Temp->ChildList)) {
+ Status = PciRootBridgeP2CProcess (Temp);
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Option Rom on the specified host bridge.
+
+ @param PciResAlloc Pointer to instance of EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL.
+
+ @retval EFI_SUCCESS Success process.
+ @retval EFI_NOT_FOUND Can not find the root bridge instance.
+ @retval other Some error occurred when processing Option Rom on the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeP2CProcess (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ return EFI_SUCCESS;
+ }
+
+ RootBridgeHandle = NULL;
+
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // Get RootBridg Device by handle
+ //
+ RootBridgeDev = GetRootBridgeByHandle (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = PciRootBridgeP2CProcess (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to enumerate the entire host bridge
+ in a given platform.
+
+ @param PciResAlloc A pointer to the PCI Host Resource Allocation protocol.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval EFI_OUT_OF_RESOURCES No enough memory available.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciHostBridgeEnumerator (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *PciResAlloc
+ )
+{
+ EFI_HANDLE RootBridgeHandle;
+ PCI_IO_DEVICE *RootBridgeDev;
+ EFI_STATUS Status;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+ UINT16 MinBus;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptors;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Configuration;
+ UINT8 StartBusNumber;
+ LIST_ENTRY RootBridgeList;
+ LIST_ENTRY *Link;
+
+ if (FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InitializeHotPlugSupport ();
+ }
+
+ InitializeListHead (&RootBridgeList);
+
+ //
+ // Notify the bus allocation phase is about to start
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG((EFI_D_INFO, "PCI Bus First Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ InsertTailList (&RootBridgeList, &(RootBridgeDev->Link));
+ } else {
+ DestroyRootBridge (RootBridgeDev);
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is finished for the first time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+
+ if (gPciHotPlugInit != NULL && FeaturePcdGet (PcdPciBusHotplugDeviceSupport)) {
+ //
+ // Reset all assigned PCI bus number in all PPB
+ //
+ RootBridgeHandle = NULL;
+ Link = GetFirstNode (&RootBridgeList);
+ while ((PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) &&
+ (!IsNull (&RootBridgeList, Link))) {
+ RootBridgeDev = PCI_IO_DEVICE_FROM_LINK (Link);
+ //
+ // Get the Bus information
+ //
+ Status = PciResAlloc->StartBusEnumeration (
+ PciResAlloc,
+ RootBridgeHandle,
+ (VOID **) &Configuration
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the bus number to start with
+ //
+ StartBusNumber = (UINT8) (Configuration->AddrRangeMin);
+
+ ResetAllPpbBusNumber (
+ RootBridgeDev,
+ StartBusNumber
+ );
+
+ FreePool (Configuration);
+ Link = RemoveEntryList (Link);
+ DestroyRootBridge (RootBridgeDev);
+ }
+
+ //
+ // Wait for all HPC initialized
+ //
+ Status = AllRootHPCInitialized (STALL_1_SECOND * 15);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Some root HPC failed to initialize\n"));
+ return Status;
+ }
+
+ //
+ // Notify the bus allocation phase is about to start for the 2nd time
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginBusAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG((EFI_D_INFO, "PCI Bus Second Scanning\n"));
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Enumerate all the buses under this root bridge
+ //
+ Status = PciRootBridgeEnumerator (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ DestroyRootBridge (RootBridgeDev);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Notify the bus allocation phase is to end for the 2nd time
+ //
+ NotifyPhase (PciResAlloc, EfiPciHostBridgeEndBusAllocation);
+ }
+
+ //
+ // Notify the resource allocation phase is to start
+ //
+ Status = NotifyPhase (PciResAlloc, EfiPciHostBridgeBeginResourceAllocation);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ RootBridgeHandle = NULL;
+ while (PciResAlloc->GetNextRootBridge (PciResAlloc, &RootBridgeHandle) == EFI_SUCCESS) {
+
+ //
+ // if a root bridge instance is found, create root bridge device for it
+ //
+ RootBridgeDev = CreateRootBridge (RootBridgeHandle);
+
+ if (RootBridgeDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = StartManagingRootBridge (RootBridgeDev);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciRootBridgeIo = RootBridgeDev->PciRootBridgeIo;
+ Status = PciRootBridgeIo->Configuration (PciRootBridgeIo, (VOID **) &Descriptors);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = PciGetBusRange (&Descriptors, &MinBus, NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Determine root bridge attribute by calling interface of Pcihostbridge
+ // protocol
+ //
+ DetermineRootBridgeAttributes (
+ PciResAlloc,
+ RootBridgeDev
+ );
+
+ //
+ // Collect all the resource information under this root bridge
+ // A database that records all the information about pci device subject to this
+ // root bridge will then be created
+ //
+ Status = PciPciDeviceInfoCollector (
+ RootBridgeDev,
+ (UINT8) MinBus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ InsertRootBridge (RootBridgeDev);
+
+ //
+ // Record the hostbridge handle
+ //
+ AddHostBridgeEnumerator (RootBridgeDev->PciRootBridgeIo->ParentHandle);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to program the Resizable BAR Register.
+
+ @param PciIoDevice A pointer to the PCI_IO_DEVICE.
+ @param ResizableBarOp PciResizableBarMax: Set BAR to max size
+ PciResizableBarMin: set BAR to min size.
+
+ @retval EFI_SUCCESS Successfully enumerated the host bridge.
+ @retval other Some error occurred when enumerating the host bridge.
+
+**/
+EFI_STATUS
+PciProgramResizableBar (
+ IN PCI_IO_DEVICE *PciIoDevice,
+ IN PCI_RESIZABLE_BAR_OPERATION ResizableBarOp
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Capabilities;
+ UINT32 Index;
+ UINT32 Offset;
+ INTN Bit;
+ UINTN ResizableBarNumber;
+ EFI_STATUS Status;
+ PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY Entries[PCI_MAX_BAR];
+
+ ASSERT (PciIoDevice->ResizableBarOffset != 0);
+
+ DEBUG ((DEBUG_INFO, " Programs Resizable BAR register, offset: 0x%08x, number: %d\n",
+ PciIoDevice->ResizableBarOffset, PciIoDevice->ResizableBarNumber));
+
+ ResizableBarNumber = MIN (PciIoDevice->ResizableBarNumber, PCI_MAX_BAR);
+ PciIo = &PciIoDevice->PciIo;
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER),
+ sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY) * ResizableBarNumber,
+ (VOID *)(&Entries)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < ResizableBarNumber; Index++) {
+
+ //
+ // When the bit of Capabilities Set, indicates that the Function supports
+ // operating with the BAR sized to (2^Bit) MB.
+ // Example:
+ // Bit 0 is set: supports operating with the BAR sized to 1 MB
+ // Bit 1 is set: supports operating with the BAR sized to 2 MB
+ // Bit n is set: supports operating with the BAR sized to (2^n) MB
+ //
+ Capabilities = LShiftU64(Entries[Index].ResizableBarControl.Bits.BarSizeCapability, 28)
+ | Entries[Index].ResizableBarCapability.Bits.BarSizeCapability;
+
+ if (ResizableBarOp == PciResizableBarMax) {
+ Bit = HighBitSet64(Capabilities);
+ } else {
+ ASSERT (ResizableBarOp == PciResizableBarMin);
+ Bit = LowBitSet64(Capabilities);
+ }
+
+ ASSERT (Bit >= 0);
+
+ Offset = PciIoDevice->ResizableBarOffset + sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_HEADER)
+ + Index * sizeof (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY)
+ + OFFSET_OF (PCI_EXPRESS_EXTENDED_CAPABILITIES_RESIZABLE_BAR_ENTRY, ResizableBarControl);
+
+ Entries[Index].ResizableBarControl.Bits.BarSize = (UINT32) Bit;
+ DEBUG ((
+ DEBUG_INFO,
+ " Resizable Bar: Offset = 0x%x, Bar Size Capability = 0x%016lx, New Bar Size = 0x%lx\n",
+ OFFSET_OF (PCI_TYPE00, Device.Bar[Entries[Index].ResizableBarControl.Bits.BarIndex]),
+ Capabilities, LShiftU64 (SIZE_1MB, Bit)
+ ));
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ Offset,
+ 1,
+ &Entries[Index].ResizableBarControl.Uint32
+ );
+ }
+
+ return EFI_SUCCESS;
+}