summaryrefslogtreecommitdiffstats
path: root/MdeModulePkg/Bus/Pci/PciHostBridgeDxe
diff options
context:
space:
mode:
Diffstat (limited to 'MdeModulePkg/Bus/Pci/PciHostBridgeDxe')
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c1134
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h252
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf55
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h47
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h568
-rw-r--r--MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c1561
6 files changed, 3617 insertions, 0 deletions
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
new file mode 100644
index 0000000000..08285d84d5
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.c
@@ -0,0 +1,1134 @@
+/** @file
+
+ Provides the basic interfaces to abstract a PCI Host Bridge Resource Allocation.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciHostResource.h"
+
+
+EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+EFI_CPU_IO2_PROTOCOL *mCpuIo;
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
+ L"I/O", L"Mem", L"PMem", L"Mem64", L"PMem64", L"Bus"
+};
+
+/**
+
+ Entry point of this driver.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_DEVICE_ERROR Fail to install PCI_ROOT_BRIDGE_IO protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePciHostBridge (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_ROOT_BRIDGE *RootBridges;
+ UINTN RootBridgeCount;
+ UINTN Index;
+ PCI_ROOT_BRIDGE_APERTURE *MemApertures[4];
+ UINTN MemApertureIndex;
+
+ RootBridges = PciHostBridgeGetRootBridges (&RootBridgeCount);
+ if ((RootBridges == NULL) || (RootBridgeCount == 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->LocateProtocol (&gEfiMetronomeArchProtocolGuid, NULL, (VOID **) &mMetronome);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->LocateProtocol (&gEfiCpuIo2ProtocolGuid, NULL, (VOID **) &mCpuIo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Most systems in the world including complex servers have only one Host Bridge.
+ //
+ HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
+ ASSERT (HostBridge != NULL);
+
+ HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;
+ HostBridge->CanRestarted = TRUE;
+ InitializeListHead (&HostBridge->RootBridges);
+
+ HostBridge->ResAlloc.NotifyPhase = NotifyPhase;
+ HostBridge->ResAlloc.GetNextRootBridge = GetNextRootBridge;
+ HostBridge->ResAlloc.GetAllocAttributes = GetAttributes;
+ HostBridge->ResAlloc.StartBusEnumeration = StartBusEnumeration;
+ HostBridge->ResAlloc.SetBusNumbers = SetBusNumbers;
+ HostBridge->ResAlloc.SubmitResources = SubmitResources;
+ HostBridge->ResAlloc.GetProposedResources = GetProposedResources;
+ HostBridge->ResAlloc.PreprocessController = PreprocessController;
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &HostBridge->Handle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid, &HostBridge->ResAlloc,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (HostBridge);
+ PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
+ return Status;
+ }
+
+ //
+ // Create Root Bridge Device Handle in this Host Bridge
+ //
+ for (Index = 0; Index < RootBridgeCount; Index++) {
+ //
+ // Create Root Bridge Handle Instance
+ //
+ RootBridge = CreateRootBridge (&RootBridges[Index], HostBridge->Handle);
+ ASSERT (RootBridge != NULL);
+ if (RootBridge == NULL) {
+ continue;
+ }
+
+ if (RootBridges[Index].Io.Limit > RootBridges[Index].Io.Base) {
+ Status = gDS->AddIoSpace (
+ EfiGcdIoTypeIo,
+ RootBridges[Index].Io.Base,
+ RootBridges[Index].Io.Limit - RootBridges[Index].Io.Base + 1
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Add all the Mem/PMem aperture to GCD
+ // Mem/PMem shouldn't overlap with each other
+ // Root bridge which needs to combine MEM and PMEM should only report
+ // the MEM aperture in Mem
+ //
+ MemApertures[0] = &RootBridges[Index].Mem;
+ MemApertures[1] = &RootBridges[Index].MemAbove4G;
+ MemApertures[2] = &RootBridges[Index].PMem;
+ MemApertures[3] = &RootBridges[Index].PMemAbove4G;
+
+ for (MemApertureIndex = 0; MemApertureIndex < sizeof (MemApertures) / sizeof (MemApertures[0]); MemApertureIndex++) {
+ if (MemApertures[MemApertureIndex]->Limit > MemApertures[MemApertureIndex]->Base) {
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ MemApertures[MemApertureIndex]->Base,
+ MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+ EFI_MEMORY_UC
+ );
+ ASSERT_EFI_ERROR (Status);
+ Status = gDS->SetMemorySpaceAttributes (
+ MemApertures[MemApertureIndex]->Base,
+ MemApertures[MemApertureIndex]->Limit - MemApertures[MemApertureIndex]->Base + 1,
+ EFI_MEMORY_UC
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ //
+ // Insert Root Bridge Handle Instance
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &RootBridge->Handle,
+ &gEfiDevicePathProtocolGuid, RootBridge->DevicePath,
+ &gEfiPciRootBridgeIoProtocolGuid, &RootBridge->RootBridgeIo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
+ }
+ PciHostBridgeFreeRootBridges (RootBridges, RootBridgeCount);
+ return Status;
+}
+
+/**
+ This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
+
+ @param HostBridge The Host Bridge Instance where the resource adjustment happens.
+**/
+VOID
+ResourceConflict (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridge
+ )
+{
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Resources;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ LIST_ENTRY *Link;
+ UINTN RootBridgeCount;
+ PCI_RESOURCE_TYPE Index;
+ PCI_RES_NODE *ResAllocNode;
+
+ RootBridgeCount = 0;
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridgeCount++;
+ }
+
+ Resources = AllocatePool (
+ RootBridgeCount * (TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)) +
+ sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ ASSERT (Resources != NULL);
+
+ for (Link = GetFirstNode (&HostBridge->RootBridges), Descriptor = Resources
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ ResAllocNode = &RootBridge->ResAllocNode[Index];
+
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Descriptor->AddrRangeMin = ResAllocNode->Base;
+ Descriptor->AddrRangeMax = ResAllocNode->Alignment;
+ Descriptor->AddrLen = ResAllocNode->Length;
+ switch (ResAllocNode->Type) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+
+ case TypeBus:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ break;
+
+ default:
+ break;
+ }
+
+ Descriptor++;
+ }
+ //
+ // Terminate the root bridge resources.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) (End + 1);
+ }
+ //
+ // Terminate the host bridge resources.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ DEBUG ((DEBUG_ERROR, "Call PciHostBridgeResourceConflict().\n"));
+ PciHostBridgeResourceConflict (HostBridge->Handle, Resources);
+ FreePool (Resources);
+}
+
+UINT64
+AllocateResource (
+ BOOLEAN Mmio,
+ UINT64 Length,
+ UINTN BitsOfAlignment,
+ UINT64 BaseAddress,
+ UINT64 Limit
+ )
+{
+ EFI_STATUS Status;
+
+ if (BaseAddress < Limit) {
+ //
+ // Have to make sure Aligment is handled since we are doing direct address allocation
+ //
+ BaseAddress = ALIGN_VALUE (BaseAddress, LShiftU64 (1, BitsOfAlignment));
+
+ while (BaseAddress + Length <= Limit + 1) {
+ if (Mmio) {
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment,
+ Length,
+ &BaseAddress,
+ gImageHandle,
+ NULL
+ );
+ } else {
+ Status = gDS->AllocateIoSpace (
+ EfiGcdAllocateAddress,
+ EfiGcdIoTypeIo,
+ BitsOfAlignment,
+ Length,
+ &BaseAddress,
+ gImageHandle,
+ NULL
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return BaseAddress;
+ }
+ BaseAddress += LShiftU64 (1, BitsOfAlignment);
+ }
+ }
+ return MAX_UINT64;
+}
+/**
+
+ Enter a certain phase of the PCI enumeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Phase The phase during enumeration.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong phase parameter passed in.
+ @retval EFI_NOT_READY Resources have not been submitted yet.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ LIST_ENTRY *Link;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 AddrLen;
+ UINTN BitsOfAlignment;
+ UINT64 Alignment;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ PCI_RESOURCE_TYPE Index;
+ PCI_RESOURCE_TYPE Index1;
+ PCI_RESOURCE_TYPE Index2;
+ BOOLEAN ResNodeHandled[TypeMax];
+ UINT64 MaxAlignment;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+
+ switch (Phase) {
+ case EfiPciHostBridgeBeginEnumeration:
+ if (!HostBridge->CanRestarted) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Reset Root Bridge
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+
+ RootBridge->ResourceSubmitted = FALSE;
+ }
+ }
+
+ HostBridge->CanRestarted = TRUE;
+ break;
+
+ case EfiPciHostBridgeBeginBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ HostBridge->CanRestarted = FALSE;
+ break;
+
+ case EfiPciHostBridgeEndBusAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ break;
+
+ case EfiPciHostBridgeBeginResourceAllocation:
+ //
+ // No specific action is required here, can perform any chipset specific programing
+ //
+ break;
+
+ case EfiPciHostBridgeAllocateResources:
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Make sure the resource for all root bridges has been submitted.
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (!RootBridge->ResourceSubmitted) {
+ return EFI_NOT_READY;
+ }
+ }
+
+ DEBUG ((EFI_D_INFO, "PciHostBridge: NotifyPhase (AllocateResources)\n"));
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ ResNodeHandled[Index] = FALSE;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ DEBUG ((EFI_D_INFO, " RootBridge: %s\n", RootBridge->DevicePathStr));
+
+ for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
+ if (RootBridge->ResAllocNode[Index1].Status == ResNone) {
+ ResNodeHandled[Index1] = TRUE;
+ } else {
+ //
+ // Allocate the resource node with max alignment at first
+ //
+ MaxAlignment = 0;
+ Index = TypeMax;
+ for (Index2 = TypeIo; Index2 < TypeBus; Index2++) {
+ if (ResNodeHandled[Index2]) {
+ continue;
+ }
+ if (MaxAlignment <= RootBridge->ResAllocNode[Index2].Alignment) {
+ MaxAlignment = RootBridge->ResAllocNode[Index2].Alignment;
+ Index = Index2;
+ }
+ }
+
+ ASSERT (Index < TypeMax);
+ ResNodeHandled[Index] = TRUE;
+ AddrLen = RootBridge->ResAllocNode[Index].Length;
+ Alignment = RootBridge->ResAllocNode[Index].Alignment;
+ BitsOfAlignment = LowBitSet64 (Alignment + 1);
+ BaseAddress = MAX_UINT64;
+
+ switch (Index) {
+ case TypeIo:
+ BaseAddress = AllocateResource (
+ FALSE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (15, BitsOfAlignment),
+ ALIGN_VALUE (RootBridge->Io.Base, Alignment + 1),
+ RootBridge->Io.Limit
+ );
+ break;
+
+ case TypeMem64:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (63, BitsOfAlignment),
+ ALIGN_VALUE (RootBridge->MemAbove4G.Base, Alignment + 1),
+ RootBridge->MemAbove4G.Limit
+ );
+ if (BaseAddress != MAX_UINT64) {
+ break;
+ }
+ //
+ // If memory above 4GB is not available, try memory below 4GB
+ //
+
+ case TypeMem32:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (31, BitsOfAlignment),
+ ALIGN_VALUE (RootBridge->Mem.Base, Alignment + 1),
+ RootBridge->Mem.Limit
+ );
+ break;
+
+ case TypePMem64:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (63, BitsOfAlignment),
+ ALIGN_VALUE (RootBridge->PMemAbove4G.Base, Alignment + 1),
+ RootBridge->PMemAbove4G.Limit
+ );
+ if (BaseAddress != MAX_UINT64) {
+ break;
+ }
+ //
+ // If memory above 4GB is not available, try memory below 4GB
+ //
+ case TypePMem32:
+ BaseAddress = AllocateResource (
+ TRUE,
+ RootBridge->ResAllocNode[Index].Length,
+ MIN (31, BitsOfAlignment),
+ ALIGN_VALUE (RootBridge->PMem.Base, Alignment + 1),
+ RootBridge->PMem.Limit
+ );
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ DEBUG ((DEBUG_INFO, " %s: Base/Length/Alignment = %lx/%lx/%lx - ",
+ mPciResourceTypeStr[Index], BaseAddress, RootBridge->ResAllocNode[Index].Length, Alignment));
+ if (BaseAddress != MAX_UINT64) {
+ RootBridge->ResAllocNode[Index].Base = BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ DEBUG ((DEBUG_INFO, "Success\n"));
+ } else {
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ DEBUG ((DEBUG_ERROR, "Out Of Resource!\n"));
+ }
+ }
+ }
+ }
+
+ if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
+ ResourceConflict (HostBridge);
+ }
+
+ //
+ // Set resource to zero for nodes where allocation fails
+ //
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ RootBridge->ResAllocNode[Index].Length = 0;
+ }
+ }
+ }
+ return ReturnStatus;
+
+ case EfiPciHostBridgeSetResources:
+ //
+ // HostBridgeInstance->CanRestarted = FALSE;
+ //
+ break;
+
+ case EfiPciHostBridgeFreeResources:
+ //
+ // HostBridgeInstance->CanRestarted = FALSE;
+ //
+ ReturnStatus = EFI_SUCCESS;
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
+ switch (Index) {
+ case TypeIo:
+ Status = gDS->FreeIoSpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypeMem32:
+ case TypePMem32:
+ case TypeMem64:
+ case TypePMem64:
+ Status = gDS->FreeMemorySpace (RootBridge->ResAllocNode[Index].Base, RootBridge->ResAllocNode[Index].Length);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ }
+ }
+
+ RootBridge->ResourceSubmitted = FALSE;
+ }
+
+ HostBridge->CanRestarted = TRUE;
+ return ReturnStatus;
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ //
+ // The resource allocation phase is completed. No specific action is required
+ // here. This notification can be used to perform any chipset specific programming.
+ //
+ break;
+
+ case EfiPciHostBridgeEndEnumeration:
+ //
+ // The Host Bridge Enumeration is completed. No specific action is required here.
+ // This notification can be used to perform any chipset specific programming.
+ //
+ break;
+
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Return the device handle of the next PCI root bridge that is associated with
+ this Host Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle Returns the device handle of the next PCI Root Bridge.
+ On input, it holds the RootBridgeHandle returned by the most
+ recent call to GetNextRootBridge().The handle for the first
+ PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_NOT_FOUND Next PCI root bridge not found.
+ @retval EFI_INVALID_PARAMETER Wrong parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ )
+{
+ BOOLEAN ReturnNext;
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (RootBridgeHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ ReturnNext = (BOOLEAN) (*RootBridgeHandle == NULL);
+
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (ReturnNext) {
+ *RootBridgeHandle = RootBridge->Handle;
+ return EFI_SUCCESS;
+ }
+
+ ReturnNext = (BOOLEAN) (*RootBridgeHandle == RootBridge->Handle);
+ }
+
+ if (ReturnNext) {
+ ASSERT (IsNull (&HostBridge->RootBridges, Link));
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+}
+
+/**
+
+ Returns the attributes of a PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The device handle of the PCI Root Bridge
+ that the caller is interested in.
+ @param Attributes The pointer to attributes of the PCI Root Bridge.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Attributes parameter passed in is NULL or
+ RootBridgeHandle is not an EFI_HANDLE
+ that was returned on a previous call to
+ GetNextRootBridge().
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Attributes == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ *Attributes = RootBridge->AllocationAttributes;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This is the request from the PCI enumerator to set up
+ the specified PCI Root Bridge for bus enumeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge to be set up.
+ @param Configuration Pointer to the pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ *Configuration = AllocatePool (sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (*Configuration == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) *Configuration;
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ Descriptor->GenFlag = 0;
+ Descriptor->SpecificFlag = 0;
+ Descriptor->AddrSpaceGranularity = 0;
+ Descriptor->AddrRangeMin = RootBridge->Bus.Base;
+ Descriptor->AddrRangeMax = 0;
+ Descriptor->AddrTranslationOffset = 0;
+ Descriptor->AddrLen = RootBridge->Bus.Limit - RootBridge->Bus.Base + 1;
+
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function programs the PCI Root Bridge hardware so that
+ it decodes the specified PCI bus range.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge whose bus range is to be programmed.
+ @param Configuration The pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ UINTN BusStart;
+ UINTN BusEnd;
+ UINTN BusLen;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration;
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) (Descriptor + 1);
+
+ //
+ // Check the Configuration is valid
+ //
+ if ((Descriptor->Desc != ACPI_ADDRESS_SPACE_DESCRIPTOR) ||
+ (Descriptor->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) ||
+ (End->Desc != ACPI_END_TAG_DESCRIPTOR)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ BusStart = (UINTN) Descriptor->AddrRangeMin;
+ BusLen = (UINTN) Descriptor->AddrLen;
+ BusEnd = BusStart + BusLen - 1;
+
+ if (Descriptor->AddrLen == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Descriptor->AddrRangeMin < RootBridge->Bus.Base) ||
+ (Descriptor->AddrRangeMin + Descriptor->AddrLen - 1 > RootBridge->Bus.Limit)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Update the Bus Range
+ //
+ RootBridge->ResAllocNode[TypeBus].Base = Descriptor->AddrRangeMin;
+ RootBridge->ResAllocNode[TypeBus].Length = Descriptor->AddrLen;
+ RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resource requirements.
+ are being submitted.
+ @param Configuration The pointer to the PCI I/O and PCI memory resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER Wrong parameters passed in.
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ PCI_RESOURCE_TYPE Type;
+
+ //
+ // Check the input parameter: Configuration
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ DEBUG ((EFI_D_INFO, "PciHostBridge: SubmitResources for %s\n", RootBridge->DevicePathStr));
+ //
+ // Check the resource descriptors.
+ // If the Configuration includes one or more invalid resource descriptors, all the resource
+ // descriptors are ignored and the function returns EFI_INVALID_PARAMETER.
+ //
+ for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ if (Descriptor->ResType > ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ DEBUG ((EFI_D_INFO, " %s: Granularity/SpecificFlag = %ld / %02x%s\n",
+ mAcpiAddressSpaceTypeStr[Descriptor->ResType], Descriptor->AddrSpaceGranularity, Descriptor->SpecificFlag,
+ (Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0 ? L" (Prefetchable)" : L""
+ ));
+ DEBUG ((EFI_D_INFO, " Length/Alignment = 0x%lx / 0x%lx\n", Descriptor->AddrLen, Descriptor->AddrRangeMax));
+ switch (Descriptor->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+ if (Descriptor->AddrSpaceGranularity != 32 && Descriptor->AddrSpaceGranularity != 64) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (Descriptor->AddrSpaceGranularity == 32 && Descriptor->AddrLen >= SIZE_4GB) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If the PCI root bridge does not support separate windows for nonprefetchable and
+ // prefetchable memory, then the PCI bus driver needs to include requests for
+ // prefetchable memory in the nonprefetchable memory pool.
+ //
+ if (((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) &&
+ ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+ //
+ // Check aligment, it should be of the form 2^n-1
+ //
+ if (GetPowerOfTwo64 (Descriptor->AddrRangeMax + 1) != (Descriptor->AddrRangeMax + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ }
+ if (Descriptor->Desc != ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Configuration; Descriptor->Desc == ACPI_ADDRESS_SPACE_DESCRIPTOR; Descriptor++) {
+ if (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) {
+ if (Descriptor->AddrSpaceGranularity == 32) {
+ if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
+ Type = TypePMem32;
+ } else {
+ Type = TypeMem32;
+ }
+ } else {
+ ASSERT (Descriptor->AddrSpaceGranularity == 64);
+ if ((Descriptor->SpecificFlag & EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE) != 0) {
+ Type = TypePMem64;
+ } else {
+ Type = TypeMem64;
+ }
+ }
+ } else {
+ ASSERT (Descriptor->ResType == ACPI_ADDRESS_SPACE_TYPE_IO);
+ Type = TypeIo;
+ }
+ RootBridge->ResAllocNode[Type].Length = Descriptor->AddrLen;
+ RootBridge->ResAllocNode[Type].Alignment = Descriptor->AddrRangeMax;
+ RootBridge->ResAllocNode[Type].Status = ResSubmitted;
+ }
+ RootBridge->ResourceSubmitted = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function returns the proposed resource settings for the specified
+ PCI Root Bridge.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge handle.
+ @param Configuration The pointer to the pointer to the PCI I/O
+ and memory resource descriptor.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_OUT_OF_RESOURCES Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINTN Index;
+ UINTN Number;
+ VOID *Buffer;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+ UINT64 ResStatus;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ for (Index = 0, Number = 0; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResNone) {
+ Number++;
+ }
+ }
+
+ Buffer = AllocateZeroPool (Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Descriptor = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Buffer;
+ for (Index = 0; Index < TypeBus; Index++) {
+ ResStatus = RootBridge->ResAllocNode[Index].Status;
+ if (ResStatus != ResNone) {
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;;
+ Descriptor->GenFlag = 0;
+ Descriptor->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;
+ Descriptor->AddrRangeMax = 0;
+ Descriptor->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : PCI_RESOURCE_LESS;
+ Descriptor->AddrLen = RootBridge->ResAllocNode[Index].Length;
+
+ switch (Index) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+ }
+
+ Descriptor++;
+ }
+ }
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0;
+
+ *Configuration = Buffer;
+
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+
+ This function is called for all the PCI controllers that the PCI
+ bus driver finds. Can be used to Preprogram the controller.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle The PCI Root Bridge handle.
+ @param PciAddress Address of the controller on the PCI bus.
+ @param Phase The Phase during resource allocation.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_INVALID_PARAMETER RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ )
+{
+ LIST_ENTRY *Link;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if ((UINT32) Phase > EfiPciBeforeResourceCollection) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ for (Link = GetFirstNode (&HostBridge->RootBridges)
+ ; !IsNull (&HostBridge->RootBridges, Link)
+ ; Link = GetNextNode (&HostBridge->RootBridges, Link)
+ ) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (Link);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_INVALID_PARAMETER;
+}
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
new file mode 100644
index 0000000000..288823c778
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridge.h
@@ -0,0 +1,252 @@
+/** @file
+
+ The Header file of the Pci Host Bridge Driver.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PCI_HOST_BRIDGE_H_
+#define _PCI_HOST_BRIDGE_H_
+
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PciHostBridgeLib.h>
+#include <Protocol/PciHostBridgeResourceAllocation.h>
+
+#include "PciRootBridge.h"
+
+#define PCI_HOST_BRIDGE_SIGNATURE SIGNATURE_32 ('p', 'h', 'b', 'g')
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ LIST_ENTRY RootBridges;
+ BOOLEAN CanRestarted;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL ResAlloc;
+} PCI_HOST_BRIDGE_INSTANCE;
+
+#define PCI_HOST_BRIDGE_FROM_THIS(a) CR (a, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE)
+
+//
+// Driver Entry Point
+//
+/**
+
+ Entry point of this driver.
+
+ @param ImageHandle - Image handle of this driver.
+ @param SystemTable - Pointer to standard EFI system table.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_DEVICE_ERROR - Fail to install PCI_ROOT_BRIDGE_IO protocol.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePciHostBridge (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+//
+// HostBridge Resource Allocation interface
+//
+/**
+
+ Enter a certain phase of the PCI enumeration process.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+ @param Phase - The phase during enumeration.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong phase parameter passed in.
+ @retval EFI_NOT_READY - Resources have not been submitted yet.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyPhase (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+
+ Return the device handle of the next PCI root bridge that is associated with
+ this Host Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ RootBridgeHandle - Returns the device handle of the next PCI Root Bridge.
+ On input, it holds the RootBridgeHandle returned by the most
+ recent call to GetNextRootBridge().The handle for the first
+ PCI Root Bridge is returned if RootBridgeHandle is NULL on input.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_NOT_FOUND - Next PCI root bridge not found.
+ @retval EFI_INVALID_PARAMETER - Wrong parameter passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+GetNextRootBridge (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN OUT EFI_HANDLE *RootBridgeHandle
+ );
+
+/**
+
+ Returns the attributes of a PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param RootBridgeHandle - The device handle of the PCI Root Bridge
+ that the caller is interested in
+ @param Attributes - The pointer to attributes of the PCI Root Bridge
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Attributes parameter passed in is NULL or
+ @retval RootBridgeHandle is not an EFI_HANDLE
+ @retval that was returned on a previous call to
+ @retval GetNextRootBridge().
+
+**/
+EFI_STATUS
+EFIAPI
+GetAttributes (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT UINT64 *Attributes
+ );
+
+/**
+
+ This is the request from the PCI enumerator to set up
+ the specified PCI Root Bridge for bus enumeration process.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge to be set up.
+ @param Configuration - Pointer to the pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+StartBusEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+
+ This function programs the PCI Root Bridge hardware so that
+ it decodes the specified PCI bus range.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge whose bus range is to be programmed.
+ @param Configuration - The pointer to the PCI bus resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SetBusNumbers (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+
+ Submits the I/O and memory resource requirements for the specified PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance
+ @param RootBridgeHandle - The PCI Root Bridge whose I/O and memory resource requirements
+ are being submitted
+ @param Configuration - The pointer to the PCI I/O and PCI memory resource descriptor
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - Wrong parameters passed in.
+
+**/
+EFI_STATUS
+EFIAPI
+SubmitResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN VOID *Configuration
+ );
+
+/**
+
+ This function returns the proposed resource settings for the specified
+ PCI Root Bridge.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge handle.
+ @param Configuration - The pointer to the pointer to the PCI I/O
+ and memory resource descriptor.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough pool to be allocated.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+GetProposedResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ OUT VOID **Configuration
+ );
+
+/**
+
+ This function is called for all the PCI controllers that the PCI
+ bus driver finds. Can be used to Preprogram the controller.
+
+ @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PROTOCOL instance.
+ @param RootBridgeHandle - The PCI Root Bridge handle.
+ @param PciAddress - Address of the controller on the PCI bus.
+ @param Phase - The Phase during resource allocation.
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_INVALID_PARAMETER - RootBridgeHandle is not a valid handle.
+
+**/
+EFI_STATUS
+EFIAPI
+PreprocessController (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This,
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase
+ );
+
+/**
+ This routine constructs the resource descriptors for all root bridges and call PciHostBridgeResourceConflict().
+
+ @param HostBridge The Host Bridge Instance where the resource adjustment happens.
+**/
+VOID
+ResourceConflict (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridge
+ );
+
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
new file mode 100644
index 0000000000..ab5d87e1cf
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostBridgeDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# Generic PCI Host Bridge driver.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHostBridgeDxe
+ FILE_GUID = 128FB770-5E79-4176-9E51-9BB268A17DD1
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePciHostBridge
+
+[Sources]
+ PciHostBridge.h
+ PciRootBridge.h
+ PciHostBridge.c
+ PciRootBridgeIo.c
+ PciHostResource.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesTableLib
+ DevicePathLib
+ BaseMemoryLib
+ BaseLib
+ PciSegmentLib
+ PciHostBridgeLib
+
+[Protocols]
+ gEfiMetronomeArchProtocolGuid ## CONSUMES
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiPciRootBridgeIoProtocolGuid ## BY_START
+ gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid AND
+ gEfiMetronomeArchProtocolGuid
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h
new file mode 100644
index 0000000000..f35222b634
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciHostResource.h
@@ -0,0 +1,47 @@
+/** @file
+
+ The Header file of the Pci Host Bridge Driver.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef _PCI_HOST_RESOURCE_H_
+#define _PCI_HOST_RESOURCE_H_
+
+#include <PiDxe.h>
+
+#define PCI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFE
+
+typedef enum {
+ TypeIo = 0,
+ TypeMem32,
+ TypePMem32,
+ TypeMem64,
+ TypePMem64,
+ TypeBus,
+ TypeMax
+} PCI_RESOURCE_TYPE;
+
+typedef enum {
+ ResNone,
+ ResSubmitted,
+ ResAllocated,
+ ResStatusMax
+} RES_STATUS;
+
+typedef struct {
+ PCI_RESOURCE_TYPE Type;
+ UINT64 Base;
+ UINT64 Length;
+ UINT64 Alignment;
+ RES_STATUS Status;
+} PCI_RES_NODE;
+
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
new file mode 100644
index 0000000000..2915981ea5
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridge.h
@@ -0,0 +1,568 @@
+/** @file
+
+ The PCI Root Bridge header file.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PCI_ROOT_BRIDGE_H_
+#define _PCI_ROOT_BRIDGE_H_
+
+#include <PiDxe.h>
+#include <IndustryStandard/Acpi.h>
+#include <IndustryStandard/Pci.h>
+
+//
+// Driver Consumed Protocol Prototypes
+//
+#include <Protocol/Metronome.h>
+#include <Protocol/CpuIo2.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PciSegmentLib.h>
+#include "PciHostResource.h"
+
+
+typedef enum {
+ IoOperation,
+ MemOperation,
+ PciOperation
+} OPERATION_TYPE;
+
+#define MAP_INFO_SIGNATURE SIGNATURE_32 ('_', 'm', 'a', 'p')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} MAP_INFO;
+#define MAP_INFO_FROM_LINK(a) CR (a, MAP_INFO, Link, MAP_INFO_SIGNATURE)
+
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('_', 'p', 'r', 'b')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_HANDLE Handle;
+ UINT64 AllocationAttributes;
+ UINT64 Attributes;
+ UINT64 Supports;
+ PCI_RES_NODE ResAllocNode[TypeMax];
+ PCI_ROOT_BRIDGE_APERTURE Bus;
+ PCI_ROOT_BRIDGE_APERTURE Io;
+ PCI_ROOT_BRIDGE_APERTURE Mem;
+ PCI_ROOT_BRIDGE_APERTURE PMem;
+ PCI_ROOT_BRIDGE_APERTURE MemAbove4G;
+ PCI_ROOT_BRIDGE_APERTURE PMemAbove4G;
+ BOOLEAN DmaAbove4G;
+ VOID *ConfigBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 *DevicePathStr;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL RootBridgeIo;
+
+ BOOLEAN ResourceSubmitted;
+ LIST_ENTRY Maps;
+} PCI_ROOT_BRIDGE_INSTANCE;
+
+#define ROOT_BRIDGE_FROM_THIS(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, RootBridgeIo, PCI_ROOT_BRIDGE_SIGNATURE)
+
+#define ROOT_BRIDGE_FROM_LINK(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE)
+
+/**
+
+ Construct the Pci Root Bridge Io protocol.
+
+ @param Protocol - Protocol to initialize.
+ @param HostBridgeHandle - Handle to the HostBridge.
+
+ @retval EFI_SUCCESS - Success.
+ @retval Others - Fail.
+
+**/
+PCI_ROOT_BRIDGE_INSTANCE *
+CreateRootBridge (
+ IN PCI_ROOT_BRIDGE *Bridge,
+ IN EFI_HANDLE HostBridgeHandle
+ );
+
+//
+// Protocol Member Function Prototypes
+//
+/**
+
+ Poll an address in memory mapped space until an exit condition is met
+ or a timeout occurs.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Width of the memory operation.
+ @param Address - The base address of the memory operation.
+ @param Mask - Mask used for polling criteria.
+ @param Value - Comparison value used for polling exit criteria.
+ @param Delay - Number of 100ns units to poll.
+ @param Result - Pointer to the last value read from memory location.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_TIMEOUT - Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+;
+
+/**
+
+ Poll an address in I/O space until an exit condition is met
+ or a timeout occurs.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Width of I/O operation.
+ @param Address - The base address of the I/O operation.
+ @param Mask - Mask used for polling criteria.
+ @param Value - Comparison value used for polling exit criteria.
+ @param Delay - Number of 100ns units to poll.
+ @param Result - Pointer to the last value read from memory location.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_TIMEOUT - Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+;
+
+/**
+
+ Allow read from memory mapped I/O space.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - The width of memory operation.
+ @param Address - Base address of the memory operation.
+ @param Count - Number of memory opeartion to perform.
+ @param Buffer - The destination buffer to store data.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Allow write to memory mapped I/O space.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - The width of memory operation.
+ @param Address - Base address of the memory operation.
+ @param Count - Number of memory opeartion to perform.
+ @param Buffer - The source buffer to write data from.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Fail due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Enable a PCI driver to read PCI controller registers in the
+ PCI root bridge I/O space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param UserAddress - The base address of the I/O operation.
+ @param Count - The number of I/O operations to perform.
+ @param UserBuffer - The destination buffer to store the results.
+
+ @retval EFI_SUCCESS - The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+;
+
+/**
+
+ Enable a PCI driver to write to PCI controller registers in the
+ PCI root bridge I/O space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param UserAddress - The base address of the I/O operation.
+ @param Count - The number of I/O operations to perform.
+ @param UserBuffer - The source buffer to write data from.
+
+ @retval EFI_SUCCESS - The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+;
+
+/**
+
+ Copy one region of PCI root bridge memory space to be copied to
+ another region of PCI root bridge memory space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Width - Signifies the width of the memory operation.
+ @param DestAddress - Destination address of the memory operation.
+ @param SrcAddress - Source address of the memory operation.
+ @param Count - Number of memory operations to perform.
+
+ @retval EFI_SUCCESS - The data was copied successfully.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ )
+;
+
+/**
+
+ Allows read from PCI configuration space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param Address - The address within the PCI configuration space
+ for the PCI controller.
+ @param Count - The number of PCI configuration operations
+ to perform.
+ @param Buffer - The destination buffer to store the results.
+
+ @retval EFI_SUCCESS - The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Allows write to PCI configuration space.
+
+ @param This - A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width - Signifies the width of the memory operation.
+ @param Address - The address within the PCI configuration space
+ for the PCI controller.
+ @param Count - The number of PCI configuration operations
+ to perform.
+ @param Buffer - The source buffer to get the results.
+
+ @retval EFI_SUCCESS - The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of
+ @retval resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+
+ Provides the PCI controller-specific address needed to access
+ system memory for DMA.
+
+ @param This - A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation - Indicate if the bus master is going to read or write
+ to system memory.
+ @param HostAddress - The system memory address to map on the PCI controller.
+ @param NumberOfBytes - On input the number of bytes to map.
+ On output the number of bytes that were mapped.
+ @param DeviceAddress - The resulting map address for the bus master PCI
+ controller to use to access the system memory's HostAddress.
+ @param Mapping - The value to pass to Unmap() when the bus master DMA
+ operation is complete.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameters found.
+ @retval EFI_UNSUPPORTED - The HostAddress cannot be mapped as a common
+ @retval buffer.
+ @retval EFI_DEVICE_ERROR - The System hardware could not map the requested
+ @retval address.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to
+ @retval lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+;
+
+/**
+
+ Completes the Map() operation and releases any corresponding resources.
+
+ @param This - Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ Mapping - The value returned from Map() operation.
+
+ @retval EFI_SUCCESS - The range was unmapped successfully.
+ @retval EFI_INVALID_PARAMETER - Mapping is not a value that was returned
+ @retval by Map operation.
+ @retval EFI_DEVICE_ERROR - The data was not committed to the target
+ @retval system memory.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+;
+
+/**
+
+ Allocates pages that are suitable for a common buffer mapping.
+
+ @param This - Pointer to EFI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Type - Not used and can be ignored.
+ @param MemoryType - Type of memory to allocate.
+ @param Pages - Number of pages to allocate.
+ @param HostAddress - Pointer to store the base system memory address
+ of the allocated range.
+ @param Attributes - Requested bit mask of attributes of the allocated
+ range.
+
+ @retval EFI_SUCCESS - The requested memory range were allocated.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_UNSUPPORTED - Attributes is unsupported.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+;
+
+/**
+
+ Free memory allocated in AllocateBuffer.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ instance.
+ @param Pages - Number of pages to free.
+ @param HostAddress - The base system memory address of the
+ allocated range.
+
+ @retval EFI_SUCCESS - Requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ )
+;
+
+/**
+
+ Flushes all PCI posted write transactions from a PCI host
+ bridge to system memory.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS - PCI posted write transactions were flushed
+ @retval from PCI host bridge to system memory.
+ @retval EFI_DEVICE_ERROR - Fail due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ )
+;
+
+/**
+
+ Get the attributes that a PCI root bridge supports and
+ the attributes the PCI root bridge is currently using.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ instance.
+ @param Supports - A pointer to the mask of attributes that
+ this PCI root bridge supports.
+ @param Attributes - A pointer to the mask of attributes that
+ this PCI root bridge is currently using.
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ )
+;
+
+/**
+
+ Sets the attributes for a resource range on a PCI root bridge.
+
+ @param This - Pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Attributes - The mask of attributes to set.
+ @param ResourceBase - Pointer to the base address of the resource range
+ to be modified by the attributes specified by Attributes.
+ @param ResourceLength - Pointer to the length of the resource range to be modified.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_INVALID_PARAMETER - Invalid parameter found.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to set the attributes upon.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ )
+;
+
+/**
+
+ Retrieves the current resource settings of this PCI root bridge
+ in the form of a set of ACPI 2.0 resource descriptor.
+
+ @param This - Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Resources - Pointer to the ACPI 2.0 resource descriptor that
+ describe the current configuration of this PCI root
+ bridge.
+
+ @retval EFI_SUCCESS - Success.
+ @retval EFI_UNSUPPORTED - Current configuration of the PCI root bridge
+ @retval could not be retrieved.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ )
+;
+
+
+extern EFI_METRONOME_ARCH_PROTOCOL *mMetronome;
+extern EFI_CPU_IO2_PROTOCOL *mCpuIo;
+#endif
diff --git a/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
new file mode 100644
index 0000000000..79b1da2d7e
--- /dev/null
+++ b/MdeModulePkg/Bus/Pci/PciHostBridgeDxe/PciRootBridgeIo.c
@@ -0,0 +1,1561 @@
+/** @file
+
+ PCI Root Bridge Io Protocol code.
+
+Copyright (c) 1999 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciHostResource.h"
+
+#define NO_MAPPING (VOID *) -1
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mInStride[] = {
+ 1, // EfiPciWidthUint8
+ 2, // EfiPciWidthUint16
+ 4, // EfiPciWidthUint32
+ 8, // EfiPciWidthUint64
+ 0, // EfiPciWidthFifoUint8
+ 0, // EfiPciWidthFifoUint16
+ 0, // EfiPciWidthFifoUint32
+ 0, // EfiPciWidthFifoUint64
+ 1, // EfiPciWidthFillUint8
+ 2, // EfiPciWidthFillUint16
+ 4, // EfiPciWidthFillUint32
+ 8 // EfiPciWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mOutStride[] = {
+ 1, // EfiPciWidthUint8
+ 2, // EfiPciWidthUint16
+ 4, // EfiPciWidthUint32
+ 8, // EfiPciWidthUint64
+ 1, // EfiPciWidthFifoUint8
+ 2, // EfiPciWidthFifoUint16
+ 4, // EfiPciWidthFifoUint32
+ 8, // EfiPciWidthFifoUint64
+ 0, // EfiPciWidthFillUint8
+ 0, // EfiPciWidthFillUint16
+ 0, // EfiPciWidthFillUint32
+ 0 // EfiPciWidthFillUint64
+};
+
+/**
+ Construct the Pci Root Bridge instance.
+
+ @param Bridge The root bridge instance.
+ @param HostBridgeHandle Handle to the HostBridge.
+
+ @return The pointer to PCI_ROOT_BRIDGE_INSTANCE just created
+ or NULL if creation fails.
+**/
+PCI_ROOT_BRIDGE_INSTANCE *
+CreateRootBridge (
+ IN PCI_ROOT_BRIDGE *Bridge,
+ IN EFI_HANDLE HostBridgeHandle
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+ CHAR16 *DevicePathStr;
+
+ DevicePathStr = NULL;
+
+ DEBUG ((EFI_D_INFO, "RootBridge: "));
+ DEBUG ((EFI_D_INFO, "%s\n", DevicePathStr = ConvertDevicePathToText (Bridge->DevicePath, FALSE, FALSE)));
+ DEBUG ((EFI_D_INFO, "Support/Attr: %lx / %lx\n", Bridge->Supports, Bridge->Attributes));
+ DEBUG ((EFI_D_INFO, " DmaAbove4G: %s\n", Bridge->DmaAbove4G ? L"Yes" : L"No"));
+ DEBUG ((EFI_D_INFO, " AllocAttr: %lx (%s%s)\n", Bridge->AllocationAttributes,
+ (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0 ? L"CombineMemPMem " : L"",
+ (Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) != 0 ? L"Mem64Decode" : L""
+ ));
+ DEBUG ((EFI_D_INFO, " Bus: %lx - %lx\n", Bridge->Bus.Base, Bridge->Bus.Limit));
+ DEBUG ((EFI_D_INFO, " Io: %lx - %lx\n", Bridge->Io.Base, Bridge->Io.Limit));
+ DEBUG ((EFI_D_INFO, " Mem: %lx - %lx\n", Bridge->Mem.Base, Bridge->Mem.Limit));
+ DEBUG ((EFI_D_INFO, " MemAbove4G: %lx - %lx\n", Bridge->MemAbove4G.Base, Bridge->MemAbove4G.Limit));
+ DEBUG ((EFI_D_INFO, " PMem: %lx - %lx\n", Bridge->PMem.Base, Bridge->PMem.Limit));
+ DEBUG ((EFI_D_INFO, " PMemAbove4G: %lx - %lx\n", Bridge->PMemAbove4G.Base, Bridge->PMemAbove4G.Limit));
+
+ //
+ // Make sure Mem and MemAbove4G apertures are valid
+ //
+ if (Bridge->Mem.Base < Bridge->Mem.Limit) {
+ ASSERT (Bridge->Mem.Limit < SIZE_4GB);
+ if (Bridge->Mem.Limit >= SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (Bridge->MemAbove4G.Base < Bridge->MemAbove4G.Limit) {
+ ASSERT (Bridge->MemAbove4G.Base >= SIZE_4GB);
+ if (Bridge->MemAbove4G.Base < SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (Bridge->PMem.Base < Bridge->PMem.Limit) {
+ ASSERT (Bridge->PMem.Limit < SIZE_4GB);
+ if (Bridge->PMem.Limit >= SIZE_4GB) {
+ return NULL;
+ }
+ }
+ if (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit) {
+ ASSERT (Bridge->PMemAbove4G.Base >= SIZE_4GB);
+ if (Bridge->PMemAbove4G.Base < SIZE_4GB) {
+ return NULL;
+ }
+ }
+
+ if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM) != 0) {
+ //
+ // If this bit is set, then the PCI Root Bridge does not
+ // support separate windows for Non-prefetchable and Prefetchable
+ // memory.
+ //
+ ASSERT (Bridge->PMem.Base >= Bridge->PMem.Limit);
+ ASSERT (Bridge->PMemAbove4G.Base >= Bridge->PMemAbove4G.Limit);
+ if ((Bridge->PMem.Base < Bridge->PMem.Limit) ||
+ (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit)
+ ) {
+ return NULL;
+ }
+ }
+
+ if ((Bridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_MEM64_DECODE) == 0) {
+ //
+ // If this bit is not set, then the PCI Root Bridge does not support
+ // 64 bit memory windows.
+ //
+ ASSERT (Bridge->MemAbove4G.Base >= Bridge->MemAbove4G.Limit);
+ ASSERT (Bridge->PMemAbove4G.Base >= Bridge->PMemAbove4G.Limit);
+ if ((Bridge->MemAbove4G.Base < Bridge->MemAbove4G.Limit) ||
+ (Bridge->PMemAbove4G.Base < Bridge->PMemAbove4G.Limit)
+ ) {
+ return NULL;
+ }
+ }
+
+ RootBridge = AllocateZeroPool (sizeof (PCI_ROOT_BRIDGE_INSTANCE));
+ ASSERT (RootBridge != NULL);
+
+ RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
+ RootBridge->Supports = Bridge->Supports;
+ RootBridge->Attributes = Bridge->Attributes;
+ RootBridge->DmaAbove4G = Bridge->DmaAbove4G;
+ RootBridge->AllocationAttributes = Bridge->AllocationAttributes;
+ RootBridge->DevicePath = DuplicateDevicePath (Bridge->DevicePath);
+ RootBridge->DevicePathStr = DevicePathStr;
+ RootBridge->ConfigBuffer = AllocatePool (
+ TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ ASSERT (RootBridge->ConfigBuffer != NULL);
+ InitializeListHead (&RootBridge->Maps);
+
+ CopyMem (&RootBridge->Bus, &Bridge->Bus, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->Io, &Bridge->Io, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->Mem, &Bridge->Mem, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+ CopyMem (&RootBridge->MemAbove4G, &Bridge->MemAbove4G, sizeof (PCI_ROOT_BRIDGE_APERTURE));
+
+
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ }
+
+ RootBridge->RootBridgeIo.SegmentNumber = Bridge->Segment;
+ RootBridge->RootBridgeIo.ParentHandle = HostBridgeHandle;
+ RootBridge->RootBridgeIo.PollMem = RootBridgeIoPollMem;
+ RootBridge->RootBridgeIo.PollIo = RootBridgeIoPollIo;
+ RootBridge->RootBridgeIo.Mem.Read = RootBridgeIoMemRead;
+ RootBridge->RootBridgeIo.Mem.Write = RootBridgeIoMemWrite;
+ RootBridge->RootBridgeIo.Io.Read = RootBridgeIoIoRead;
+ RootBridge->RootBridgeIo.Io.Write = RootBridgeIoIoWrite;
+ RootBridge->RootBridgeIo.CopyMem = RootBridgeIoCopyMem;
+ RootBridge->RootBridgeIo.Pci.Read = RootBridgeIoPciRead;
+ RootBridge->RootBridgeIo.Pci.Write = RootBridgeIoPciWrite;
+ RootBridge->RootBridgeIo.Map = RootBridgeIoMap;
+ RootBridge->RootBridgeIo.Unmap = RootBridgeIoUnmap;
+ RootBridge->RootBridgeIo.AllocateBuffer = RootBridgeIoAllocateBuffer;
+ RootBridge->RootBridgeIo.FreeBuffer = RootBridgeIoFreeBuffer;
+ RootBridge->RootBridgeIo.Flush = RootBridgeIoFlush;
+ RootBridge->RootBridgeIo.GetAttributes = RootBridgeIoGetAttributes;
+ RootBridge->RootBridgeIo.SetAttributes = RootBridgeIoSetAttributes;
+ RootBridge->RootBridgeIo.Configuration = RootBridgeIoConfiguration;
+
+ return RootBridge;
+}
+
+/**
+ Check parameters for IO,MMIO,PCI read/write services of PCI Root Bridge IO.
+
+ The I/O operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and I/O width restrictions that a PI
+ System on a platform might require. For example on some platforms, width
+ requests of EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other
+ hand, will be handled by the driver.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @param[in] OperationType I/O operation type: IO/MMIO/PCI.
+
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+
+ @param[in] Address The base address of the I/O operation.
+
+ @param[in] Count The number of I/O operations to perform. The number
+ of bytes moved is Width size * Count, starting at
+ Address.
+
+ @param[in] Buffer For read operations, the destination buffer to
+ store the results. For write operations, the source
+ buffer from which to write data.
+
+ @retval EFI_SUCCESS The parameters for this request pass the
+ checks.
+
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+**/
+EFI_STATUS
+RootBridgeIoCheckParameter (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN OPERATION_TYPE OperationType,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *PciRbAddr;
+ UINT64 Base;
+ UINT64 Limit;
+ UINT32 Size;
+
+ //
+ // Check to see if Buffer is NULL
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Width is in the valid range
+ //
+ if ((UINT32) Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For FIFO type, the target address won't increase during the access,
+ // so treat Count as 1
+ //
+ if (Width >= EfiPciWidthFifoUint8 && Width <= EfiPciWidthFifoUint64) {
+ Count = 1;
+ }
+
+ Width = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ Size = 1 << Width;
+
+ //
+ // Check to see if Address is aligned
+ //
+ if ((Address & (Size - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // Check to see if any address associated with this transfer exceeds the
+ // maximum allowed address. The maximum address implied by the parameters
+ // passed in is Address + Size * Count. If the following condition is met,
+ // then the transfer is not supported.
+ //
+ // Address + Size * Count > Limit + 1
+ //
+ // Since Limit can be the maximum integer value supported by the CPU and
+ // Count can also be the maximum integer value supported by the CPU, this
+ // range check must be adjusted to avoid all oveflow conditions.
+ //
+ if (OperationType == IoOperation) {
+ //
+ // Allow Legacy IO access
+ //
+ if (Address + MultU64x32 (Count, Size) <= 0x1000) {
+ if ((RootBridge->Attributes & (
+ EFI_PCI_ATTRIBUTE_ISA_IO | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO | EFI_PCI_ATTRIBUTE_VGA_IO |
+ EFI_PCI_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_ATTRIBUTE_IDE_SECONDARY_IO |
+ EFI_PCI_ATTRIBUTE_ISA_IO_16 | EFI_PCI_ATTRIBUTE_VGA_PALETTE_IO_16 | EFI_PCI_ATTRIBUTE_VGA_IO_16)) != 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ Base = RootBridge->Io.Base;
+ Limit = RootBridge->Io.Limit;
+ } else if (OperationType == MemOperation) {
+ //
+ // Allow Legacy MMIO access
+ //
+ if ((Address >= 0xA0000) && (Address + MultU64x32 (Count, Size)) <= 0xC0000) {
+ if ((RootBridge->Attributes & EFI_PCI_ATTRIBUTE_VGA_MEMORY) != 0) {
+ return EFI_SUCCESS;
+ }
+ }
+ //
+ // By comparing the Address against Limit we know which range to be used
+ // for checking
+ //
+ if (Address + MultU64x32 (Count, Size) <= RootBridge->Mem.Limit + 1) {
+ Base = RootBridge->Mem.Base;
+ Limit = RootBridge->Mem.Limit;
+ } else {
+ Base = RootBridge->MemAbove4G.Base;
+ Limit = RootBridge->MemAbove4G.Limit;
+ }
+ } else {
+ PciRbAddr = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &Address;
+ if (PciRbAddr->Bus < RootBridge->Bus.Base ||
+ PciRbAddr->Bus > RootBridge->Bus.Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciRbAddr->Device > PCI_MAX_DEVICE ||
+ PciRbAddr->Function > PCI_MAX_FUNC) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (PciRbAddr->ExtendedRegister != 0) {
+ Address = PciRbAddr->ExtendedRegister;
+ } else {
+ Address = PciRbAddr->Register;
+ }
+ Base = 0;
+ Limit = 0xFFF;
+ }
+
+ if (Address < Base) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address + MultU64x32 (Count, Size) > Limit + 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Polls an address in memory mapped I/O space until an exit condition is met,
+ or a timeout occurs.
+
+ This function provides a standard way to poll a PCI memory location. A PCI
+ memory read operation is performed at the PCI memory address specified by
+ Address for the width specified by Width. The result of this PCI memory read
+ operation is stored in Result. This PCI memory read operation is repeated
+ until either a timeout of Delay 100 ns units has expired, or (Result & Mask)
+ is equal to Value.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the memory operations. The caller
+ is responsible for aligning Address if required.
+ @param[in] Mask Mask used for the polling criteria. Bytes above Width
+ in Mask are ignored. The bits in the bytes below Width
+ which are zero in Mask are ignored when polling the
+ memory address.
+ @param[in] Value The comparison value used for the polling exit
+ criteria.
+ @param[in] Delay The number of 100 ns units to poll. Note that timer
+ available may be of poorer granularity.
+ @param[out] Result Pointer to the last value read from the memory
+ location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched
+ the poll exit criteria.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_INVALID_PARAMETER Result is NULL.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINT32 Remainder;
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // No matter what, always do a single poll.
+ //
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+
+ //
+ // Determine the proper # of metronome ticks to wait for polling the
+ // location. The nuber of ticks is Roundup (Delay /
+ // mMetronome->TickPeriod)+1
+ // The "+1" to account for the possibility of the first tick being short
+ // because we started in the middle of a tick.
+ //
+ // BugBug: overriding mMetronome->TickPeriod with UINT32 until Metronome
+ // protocol definition is updated.
+ //
+ NumberOfTicks = DivU64x32Remainder (Delay, (UINT32) mMetronome->TickPeriod,
+ &Remainder);
+ if (Remainder != 0) {
+ NumberOfTicks += 1;
+ }
+ NumberOfTicks += 1;
+
+ while (NumberOfTicks != 0) {
+
+ mMetronome->WaitForTick (mMetronome, 1);
+
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ NumberOfTicks -= 1;
+ }
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Reads from the I/O space of a PCI Root Bridge. Returns when either the
+ polling exit criteria is satisfied or after a defined duration.
+
+ This function provides a standard way to poll a PCI I/O location. A PCI I/O
+ read operation is performed at the PCI I/O address specified by Address for
+ the width specified by Width.
+ The result of this PCI I/O read operation is stored in Result. This PCI I/O
+ read operation is repeated until either a timeout of Delay 100 ns units has
+ expired, or (Result & Mask) is equal to Value.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the I/O operations.
+ @param[in] Address The base address of the I/O operations. The caller is
+ responsible for aligning Address if required.
+ @param[in] Mask Mask used for the polling criteria. Bytes above Width in
+ Mask are ignored. The bits in the bytes below Width
+ which are zero in Mask are ignored when polling the I/O
+ address.
+ @param[in] Value The comparison value used for the polling exit criteria.
+ @param[in] Delay The number of 100 ns units to poll. Note that timer
+ available may be of poorer granularity.
+ @param[out] Result Pointer to the last value read from the memory location.
+
+ @retval EFI_SUCCESS The last data returned from the access matched
+ the poll exit criteria.
+ @retval EFI_INVALID_PARAMETER Width is invalid.
+ @retval EFI_INVALID_PARAMETER Result is NULL.
+ @retval EFI_TIMEOUT Delay expired before a match occurred.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPollIo (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINT64 Mask,
+ IN UINT64 Value,
+ IN UINT64 Delay,
+ OUT UINT64 *Result
+ )
+{
+ EFI_STATUS Status;
+ UINT64 NumberOfTicks;
+ UINT32 Remainder;
+
+ //
+ // No matter what, always do a single poll.
+ //
+
+ if (Result == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ if (Delay == 0) {
+ return EFI_SUCCESS;
+
+ } else {
+
+ //
+ // Determine the proper # of metronome ticks to wait for polling the
+ // location. The number of ticks is Roundup (Delay /
+ // mMetronome->TickPeriod)+1
+ // The "+1" to account for the possibility of the first tick being short
+ // because we started in the middle of a tick.
+ //
+ NumberOfTicks = DivU64x32Remainder (Delay, (UINT32)mMetronome->TickPeriod,
+ &Remainder);
+ if (Remainder != 0) {
+ NumberOfTicks += 1;
+ }
+ NumberOfTicks += 1;
+
+ while (NumberOfTicks != 0) {
+
+ mMetronome->WaitForTick (mMetronome, 1);
+
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+
+ NumberOfTicks -= 1;
+ }
+ }
+ return EFI_TIMEOUT;
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge memory space.
+
+ The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
+ controller registers in the PCI root bridge memory space.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI Root Bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operation.
+ @param[in] Address The base address of the memory operation. The caller
+ is responsible for aligning the Address if required.
+ @param[in] Count The number of memory operations to perform. Bytes
+ moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,
+ Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return mCpuIo->Mem.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge memory space.
+
+ The Mem.Read(), and Mem.Write() functions enable a driver to access PCI
+ controller registers in the PCI root bridge memory space.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI Root Bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operation.
+ @param[in] Address The base address of the memory operation. The caller
+ is responsible for aligning the Address if required.
+ @param[in] Count The number of memory operations to perform. Bytes
+ moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMemWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = RootBridgeIoCheckParameter (This, MemOperation, Width, Address,
+ Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return mCpuIo->Mem.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge I/O space.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the I/O operation. The caller is
+ responsible for aligning the Address if required.
+ @param[in] Count The number of I/O operations to perform. Bytes moved
+ is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ Status = RootBridgeIoCheckParameter (
+ This, IoOperation, Width,
+ Address, Count, Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return mCpuIo->Io.Read (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to access PCI controller registers in the PCI root
+ bridge I/O space.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] Address The base address of the I/O operation. The caller is
+ responsible for aligning the Address if required.
+ @param[in] Count The number of I/O operations to perform. Bytes moved
+ is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store
+ the results. For write operations, the source buffer
+ to write data from.
+
+ @retval EFI_SUCCESS The data was read from or written to the PCI
+ root bridge.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoIoWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ Status = RootBridgeIoCheckParameter (
+ This, IoOperation, Width,
+ Address, Count, Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ return mCpuIo->Io.Write (mCpuIo, (EFI_CPU_IO_PROTOCOL_WIDTH) Width, Address, Count, Buffer);
+}
+
+/**
+ Enables a PCI driver to copy one region of PCI root bridge memory space to
+ another region of PCI root bridge memory space.
+
+ The CopyMem() function enables a PCI driver to copy one region of PCI root
+ bridge memory space to another region of PCI root bridge memory space. This
+ is especially useful for video scroll operation on a memory mapped video
+ buffer.
+ The memory operations are carried out exactly as requested. The caller is
+ responsible for satisfying any alignment and memory width restrictions that a
+ PCI root bridge on a platform might require.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ instance.
+ @param[in] Width Signifies the width of the memory operations.
+ @param[in] DestAddress The destination address of the memory operation. The
+ caller is responsible for aligning the DestAddress if
+ required.
+ @param[in] SrcAddress The source address of the memory operation. The caller
+ is responsible for aligning the SrcAddress if
+ required.
+ @param[in] Count The number of memory operations to perform. Bytes
+ moved is Width size * Count, starting at DestAddress
+ and SrcAddress.
+
+ @retval EFI_SUCCESS The data was copied from one memory region
+ to another memory region.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root bridge.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a
+ lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoCopyMem (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 DestAddress,
+ IN UINT64 SrcAddress,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Forward;
+ UINTN Stride;
+ UINTN Index;
+ UINT64 Result;
+
+ if ((UINT32) Width > EfiPciWidthUint64) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddress == SrcAddress) {
+ return EFI_SUCCESS;
+ }
+
+ Stride = (UINTN) (1 << Width);
+
+ Forward = TRUE;
+ if ((DestAddress > SrcAddress) &&
+ (DestAddress < (SrcAddress + Count * Stride))) {
+ Forward = FALSE;
+ SrcAddress = SrcAddress + (Count - 1) * Stride;
+ DestAddress = DestAddress + (Count - 1) * Stride;
+ }
+
+ for (Index = 0; Index < Count; Index++) {
+ Status = RootBridgeIoMemRead (
+ This,
+ Width,
+ SrcAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = RootBridgeIoMemWrite (
+ This,
+ Width,
+ DestAddress,
+ 1,
+ &Result
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (Forward) {
+ SrcAddress += Stride;
+ DestAddress += Stride;
+ } else {
+ SrcAddress -= Stride;
+ DestAddress -= Stride;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ PCI configuration space access.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Read TRUE indicating it's a read operation.
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The destination buffer to store the results.
+
+ @retval EFI_SUCCESS The data was read/written from/to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciAccess (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN BOOLEAN Read,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress;
+ UINT8 *Uint8Buffer;
+ UINT8 InStride;
+ UINT8 OutStride;
+ UINTN Size;
+
+ Status = RootBridgeIoCheckParameter (This, PciOperation, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Read Pci configuration space
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ CopyMem (&PciAddress, &Address, sizeof (PciAddress));
+
+ if (PciAddress.ExtendedRegister == 0) {
+ PciAddress.ExtendedRegister = PciAddress.Register;
+ }
+
+ Address = PCI_SEGMENT_LIB_ADDRESS (
+ RootBridge->RootBridgeIo.SegmentNumber,
+ PciAddress.Bus,
+ PciAddress.Device,
+ PciAddress.Function,
+ PciAddress.ExtendedRegister
+ );
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ Size = (UINTN) (1 << (Width & 0x03));
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (Read) {
+ PciSegmentReadBuffer (Address, Size, Uint8Buffer);
+ } else {
+ PciSegmentWriteBuffer (Address, Size, Uint8Buffer);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Allows read from PCI configuration space.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The destination buffer to store the results.
+
+ @retval EFI_SUCCESS The data was read from the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciRead (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return RootBridgeIoPciAccess (This, TRUE, Width, Address, Count, Buffer);
+}
+
+/**
+ Allows write to PCI configuration space.
+
+ @param This A pointer to EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
+ @param Width Signifies the width of the memory operation.
+ @param Address The address within the PCI configuration space
+ for the PCI controller.
+ @param Count The number of PCI configuration operations
+ to perform.
+ @param Buffer The source buffer to get the results.
+
+ @retval EFI_SUCCESS The data was written to the PCI root bridge.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoPciWrite (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ )
+{
+ return RootBridgeIoPciAccess (This, FALSE, Width, Address, Count, Buffer);
+}
+
+/**
+
+ Provides the PCI controller-specific address needed to access
+ system memory for DMA.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Operation Indicate if the bus master is going to read or write
+ to system memory.
+ @param HostAddress The system memory address to map on the PCI controller.
+ @param NumberOfBytes On input the number of bytes to map.
+ On output the number of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master PCI
+ controller to use to access the system memory's HostAddress.
+ @param Mapping The value to pass to Unmap() when the bus master DMA
+ operation is complete.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Invalid parameters found.
+ @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The System hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to lack of resources.
+
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoMap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ MAP_INFO *MapInfo;
+
+ if (HostAddress == NULL || NumberOfBytes == NULL || DeviceAddress == NULL ||
+ Mapping == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure that Operation is valid
+ //
+ if ((UINT32) Operation >= EfiPciOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if (!RootBridge->DmaAbove4G && ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB)) {
+ //
+ // If the root bridge can not handle performing DMA above 4GB but
+ // any part of the DMA transfer being mapped is above 4GB, then
+ // map the DMA transfer to a buffer below 4GB.
+ //
+
+ if (Operation == EfiPciOperationBusMasterCommonBuffer ||
+ Operation == EfiPciOperationBusMasterCommonBuffer64) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // if above 4GB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Allocate a MAP_INFO structure to remember the mapping when Unmap() is
+ // called later.
+ //
+ MapInfo = AllocatePool (sizeof (MAP_INFO));
+ if (MapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ MapInfo->Signature = MAP_INFO_SIGNATURE;
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+ MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (MapInfo->NumberOfBytes);
+ MapInfo->HostAddress = PhysicalAddress;
+ MapInfo->MappedHostAddress = SIZE_4GB - 1;
+
+ //
+ // Allocate a buffer below 4GB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ MapInfo->NumberOfPages,
+ &MapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (MapInfo);
+ *NumberOfBytes = 0;
+ return Status;
+ }
+
+ //
+ // If this is a read operation from the Bus Master's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the Bus Master can read the contents of the real buffer.
+ //
+ if (Operation == EfiPciOperationBusMasterRead ||
+ Operation == EfiPciOperationBusMasterRead64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->MappedHostAddress,
+ (VOID *) (UINTN) MapInfo->HostAddress,
+ MapInfo->NumberOfBytes
+ );
+ }
+
+ InsertTailList (&RootBridge->Maps, &MapInfo->Link);
+
+ //
+ // The DeviceAddress is the address of the maped buffer below 4GB
+ //
+ *DeviceAddress = MapInfo->MappedHostAddress;
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = MapInfo;
+ } else {
+ //
+ // If the root bridge CAN handle performing DMA above 4GB or
+ // the transfer is below 4GB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ *Mapping = NO_MAPPING;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Completes the Map() operation and releases any corresponding resources.
+
+ The Unmap() function completes the Map() operation and releases any
+ corresponding resources.
+ If the operation was an EfiPciOperationBusMasterWrite or
+ EfiPciOperationBusMasterWrite64, the data is committed to the target system
+ memory.
+ Any resources used for the mapping are freed.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[in] Mapping The mapping value returned from Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_INVALID_PARAMETER Mapping is not a value that was returned by Map().
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoUnmap (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ MAP_INFO *MapInfo;
+ LIST_ENTRY *Link;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ //
+ // See if the Map() operation associated with this Unmap() required a mapping
+ // buffer. If a mapping buffer was not required, then this function simply
+ // returns EFI_SUCCESS.
+ //
+ if (Mapping == NO_MAPPING) {
+ return EFI_SUCCESS;
+ }
+
+ MapInfo = NO_MAPPING;
+ for (Link = GetFirstNode (&RootBridge->Maps)
+ ; !IsNull (&RootBridge->Maps, Link)
+ ; Link = GetNextNode (&RootBridge->Maps, Link)
+ ) {
+ MapInfo = MAP_INFO_FROM_LINK (Link);
+ if (MapInfo == Mapping) {
+ break;
+ }
+ }
+ //
+ // Mapping is not a valid value returned by Map()
+ //
+ if (MapInfo != Mapping) {
+ return EFI_INVALID_PARAMETER;
+ }
+ RemoveEntryList (&MapInfo->Link);
+
+ //
+ // If this is a write operation from the Bus Master's point of view,
+ // then copy the contents of the mapped buffer into the real buffer
+ // so the processor can read the contents of the real buffer.
+ //
+ if (MapInfo->Operation == EfiPciOperationBusMasterWrite ||
+ MapInfo->Operation == EfiPciOperationBusMasterWrite64) {
+ CopyMem (
+ (VOID *) (UINTN) MapInfo->HostAddress,
+ (VOID *) (UINTN) MapInfo->MappedHostAddress,
+ MapInfo->NumberOfBytes
+ );
+ }
+
+ //
+ // Free the mapped buffer and the MAP_INFO structure.
+ //
+ gBS->FreePages (MapInfo->MappedHostAddress, MapInfo->NumberOfPages);
+ FreePool (Mapping);
+ return EFI_SUCCESS;
+}
+
+/**
+ Allocates pages that are suitable for an EfiPciOperationBusMasterCommonBuffer
+ or EfiPciOperationBusMasterCommonBuffer64 mapping.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Type This parameter is not used and must be ignored.
+ @param MemoryType The type of memory to allocate, EfiBootServicesData or
+ EfiRuntimeServicesData.
+ @param Pages The number of pages to allocate.
+ @param HostAddress A pointer to store the base system memory address of the
+ allocated range.
+ @param Attributes The requested bit mask of attributes for the allocated
+ range. Only the attributes
+ EFI_PCI_ATTRIBUTE_MEMORY_WRITE_COMBINE,
+ EFI_PCI_ATTRIBUTE_MEMORY_CACHED, and
+ EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE may be used with this
+ function.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER MemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER HostAddress is NULL.
+ @retval EFI_UNSUPPORTED Attributes is unsupported. The only legal
+ attribute bits are MEMORY_WRITE_COMBINE,
+ MEMORY_CACHED, and DUAL_ADDRESS_CYCLE.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoAllocateBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_ALLOCATE_TYPE AllocateType;
+
+ //
+ // Validate Attributes
+ //
+ if ((Attributes & EFI_PCI_ATTRIBUTE_INVALID_FOR_ALLOCATE_BUFFER) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check for invalid inputs
+ //
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The only valid memory types are EfiBootServicesData and
+ // EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData &&
+ MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ AllocateType = AllocateAnyPages;
+ if (!RootBridge->DmaAbove4G) {
+ //
+ // Limit allocations to memory below 4GB
+ //
+ AllocateType = AllocateMaxAddress;
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (SIZE_4GB - 1);
+ }
+ Status = gBS->AllocatePages (
+ AllocateType,
+ MemoryType,
+ Pages,
+ &PhysicalAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+ }
+
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with AllocateBuffer().
+
+ The FreeBuffer() function frees memory that was allocated with
+ AllocateBuffer().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Pages The number of pages to free.
+ @param HostAddress The base system memory address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory range specified by HostAddress and
+ Pages was not allocated with AllocateBuffer().
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFreeBuffer (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ OUT VOID *HostAddress
+ )
+{
+ return gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress, Pages);
+}
+
+/**
+ Flushes all PCI posted write transactions from a PCI host bridge to system
+ memory.
+
+ The Flush() function flushes any PCI posted write transactions from a PCI
+ host bridge to system memory. Posted write transactions are generated by PCI
+ bus masters when they perform write transactions to target addresses in
+ system memory.
+ This function does not flush posted write transactions from any PCI bridges.
+ A PCI controller specific action must be taken to guarantee that the posted
+ write transactions have been flushed from the PCI controller and from all the
+ PCI bridges into the PCI host bridge. This is typically done with a PCI read
+ transaction from the PCI controller prior to calling Flush().
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+
+ @retval EFI_SUCCESS The PCI posted write transactions were flushed
+ from the PCI host bridge to system memory.
+ @retval EFI_DEVICE_ERROR The PCI posted write transactions were not flushed
+ from the PCI host bridge due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoFlush (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets the attributes that a PCI root bridge supports setting with
+ SetAttributes(), and the attributes that a PCI root bridge is currently
+ using.
+
+ The GetAttributes() function returns the mask of attributes that this PCI
+ root bridge supports and the mask of attributes that the PCI root bridge is
+ currently using.
+
+ @param This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Supported A pointer to the mask of attributes that this PCI root
+ bridge supports setting with SetAttributes().
+ @param Attributes A pointer to the mask of attributes that this PCI root
+ bridge is currently using.
+
+ @retval EFI_SUCCESS If Supports is not NULL, then the attributes
+ that the PCI root bridge supports is returned
+ in Supports. If Attributes is not NULL, then
+ the attributes that the PCI root bridge is
+ currently using is returned in Attributes.
+ @retval EFI_INVALID_PARAMETER Both Supports and Attributes are NULL.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoGetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT UINT64 *Supported,
+ OUT UINT64 *Attributes
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Attributes == NULL && Supported == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ //
+ // Set the return value for Supported and Attributes
+ //
+ if (Supported != NULL) {
+ *Supported = RootBridge->Supports;
+ }
+
+ if (Attributes != NULL) {
+ *Attributes = RootBridge->Attributes;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets attributes for a resource range on a PCI root bridge.
+
+ The SetAttributes() function sets the attributes specified in Attributes for
+ the PCI root bridge on the resource range specified by ResourceBase and
+ ResourceLength. Since the granularity of setting these attributes may vary
+ from resource type to resource type, and from platform to platform, the
+ actual resource range and the one passed in by the caller may differ. As a
+ result, this function may set the attributes specified by Attributes on a
+ larger resource range than the caller requested. The actual range is returned
+ in ResourceBase and ResourceLength. The caller is responsible for verifying
+ that the actual range for which the attributes were set is acceptable.
+
+ @param This A pointer to the
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param Attributes The mask of attributes to set. If the
+ attribute bit MEMORY_WRITE_COMBINE,
+ MEMORY_CACHED, or MEMORY_DISABLE is set,
+ then the resource range is specified by
+ ResourceBase and ResourceLength. If
+ MEMORY_WRITE_COMBINE, MEMORY_CACHED, and
+ MEMORY_DISABLE are not set, then
+ ResourceBase and ResourceLength are ignored,
+ and may be NULL.
+ @param ResourceBase A pointer to the base address of the
+ resource range to be modified by the
+ attributes specified by Attributes.
+ @param ResourceLength A pointer to the length of the resource
+ range to be modified by the attributes
+ specified by Attributes.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge
+ was returned in Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge
+ could not be retrieved.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoSetAttributes (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN UINT64 Attributes,
+ IN OUT UINT64 *ResourceBase,
+ IN OUT UINT64 *ResourceLength
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if ((Attributes & (~RootBridge->Supports)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ RootBridge->Attributes = Attributes;
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieves the current resource settings of this PCI root bridge in the form
+ of a set of ACPI 2.0 resource descriptors.
+
+ There are only two resource descriptor types from the ACPI Specification that
+ may be used to describe the current resources allocated to a PCI root bridge.
+ These are the QWORD Address Space Descriptor (ACPI 2.0 Section 6.4.3.5.1),
+ and the End Tag (ACPI 2.0 Section 6.4.2.8). The QWORD Address Space
+ Descriptor can describe memory, I/O, and bus number ranges for dynamic or
+ fixed resources. The configuration of a PCI root bridge is described with one
+ or more QWORD Address Space Descriptors followed by an End Tag.
+
+ @param[in] This A pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL.
+ @param[out] Resources A pointer to the ACPI 2.0 resource descriptors that
+ describe the current configuration of this PCI root
+ bridge. The storage for the ACPI 2.0 resource
+ descriptors is allocated by this function. The
+ caller must treat the return buffer as read-only
+ data, and the buffer must not be freed by the
+ caller.
+
+ @retval EFI_SUCCESS The current configuration of this PCI root bridge
+ was returned in Resources.
+ @retval EFI_UNSUPPORTED The current configuration of this PCI root bridge
+ could not be retrieved.
+**/
+EFI_STATUS
+EFIAPI
+RootBridgeIoConfiguration (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ OUT VOID **Resources
+ )
+{
+ PCI_RESOURCE_TYPE Index;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RES_NODE *ResAllocNode;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Descriptor;
+ EFI_ACPI_END_TAG_DESCRIPTOR *End;
+
+ //
+ // Get this instance of the Root Bridge.
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ ZeroMem (
+ RootBridge->ConfigBuffer,
+ TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)
+ );
+ Descriptor = RootBridge->ConfigBuffer;
+ for (Index = TypeIo; Index < TypeMax; Index++) {
+
+ ResAllocNode = &RootBridge->ResAllocNode[Index];
+
+ if (ResAllocNode->Status != ResAllocated) {
+ continue;
+ }
+
+ Descriptor->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Descriptor->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Descriptor->AddrRangeMin = ResAllocNode->Base;
+ Descriptor->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Descriptor->AddrLen = ResAllocNode->Length;
+ switch (ResAllocNode->Type) {
+
+ case TypeIo:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ break;
+
+ case TypePMem32:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem32:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 32;
+ break;
+
+ case TypePMem64:
+ Descriptor->SpecificFlag = EFI_ACPI_MEMORY_RESOURCE_SPECIFIC_FLAG_CACHEABLE_PREFETCHABLE;
+ case TypeMem64:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Descriptor->AddrSpaceGranularity = 64;
+ break;
+
+ case TypeBus:
+ Descriptor->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ break;
+
+ default:
+ break;
+ }
+
+ Descriptor++;
+ }
+ //
+ // Terminate the entries.
+ //
+ End = (EFI_ACPI_END_TAG_DESCRIPTOR *) Descriptor;
+ End->Desc = ACPI_END_TAG_DESCRIPTOR;
+ End->Checksum = 0x0;
+
+ *Resources = RootBridge->ConfigBuffer;
+ return EFI_SUCCESS;
+}