From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: devel@edk2.groups.io
Cc: Isaac Oram <isaac.w.oram@intel.com>,
Mohamed Abbas <mohamed.abbas@intel.com>,
Chasel Chiu <chasel.chiu@intel.com>,
Michael D Kinney <michael.d.kinney@intel.com>,
Liming Gao <gaoliming@byosoft.com.cn>,
Eric Dong <eric.dong@intel.com>,
Michael Kubacki <Michael.Kubacki@microsoft.com>
Subject: [edk2-platforms] [PATCH V1 12/17] WhitleyOpenBoardPkg: Add Feature Modules
Date: Mon, 12 Jul 2021 17:41:26 -0700 [thread overview]
Message-ID: <20210713004131.1782-13-nathaniel.l.desimone@intel.com> (raw)
In-Reply-To: <20210713004131.1782-1-nathaniel.l.desimone@intel.com>
Signed-off-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
Co-authored-by: Isaac Oram <isaac.w.oram@intel.com>
Co-authored-by: Mohamed Abbas <mohamed.abbas@intel.com>
Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Isaac Oram <isaac.w.oram@intel.com>
Cc: Mohamed Abbas <mohamed.abbas@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Michael Kubacki <Michael.Kubacki@microsoft.com>
---
.../Pci/Dxe/PciHostBridge/PciHostBridge.c | 1634 ++++++++++++++++
.../Pci/Dxe/PciHostBridge/PciHostBridge.h | 300 +++
.../Pci/Dxe/PciHostBridge/PciHostBridge.inf | 69 +
.../Dxe/PciHostBridge/PciHostBridgeSupport.c | 127 ++
.../Pci/Dxe/PciHostBridge/PciHostResource.h | 62 +
.../Pci/Dxe/PciHostBridge/PciRebalance.c | 1356 ++++++++++++++
.../Pci/Dxe/PciHostBridge/PciRebalance.h | 158 ++
.../Pci/Dxe/PciHostBridge/PciRebalanceIo.c | 218 +++
.../Dxe/PciHostBridge/PciRebalanceMmio32.c | 163 ++
.../Dxe/PciHostBridge/PciRebalanceMmio64.c | 204 ++
.../Pci/Dxe/PciHostBridge/PciRootBridge.h | 573 ++++++
.../Pci/Dxe/PciHostBridge/PciRootBridgeIo.c | 1664 +++++++++++++++++
.../Dxe/PciPlatform/PciIovPlatformPolicy.c | 99 +
.../Dxe/PciPlatform/PciIovPlatformPolicy.h | 53 +
.../Pci/Dxe/PciPlatform/PciPlatform.c | 541 ++++++
.../Pci/Dxe/PciPlatform/PciPlatform.h | 209 +++
.../Pci/Dxe/PciPlatform/PciPlatform.inf | 87 +
.../Pci/Dxe/PciPlatform/PciPlatformHooks.c | 939 ++++++++++
.../Pci/Dxe/PciPlatform/PciPlatformHooks.h | 31 +
.../Pci/Dxe/PciPlatform/PciSupportLib.c | 108 ++
.../Pci/Dxe/PciPlatform/PciSupportLib.h | 46 +
.../Pei/PlatformVariableInitPei.c | 274 +++
.../Pei/PlatformVariableInitPei.h | 41 +
.../Pei/PlatformVariableInitPei.inf | 58 +
24 files changed, 9014 insertions(+)
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.inf
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridgeSupport.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostResource.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceIo.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio32.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio64.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridge.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridgeIo.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.inf
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.c
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.h
create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.inf
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.c
new file mode 100644
index 0000000000..a15fff4817
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.c
@@ -0,0 +1,1634 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/SocketPciResourceData.h>
+#include <Guid/SocketIioVariable.h>
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciHostResource.h"
+
+#include <CpuAndRevisionDefines.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/IioUds.h>
+#include <Upi/KtiHost.h>
+
+#include <Library/SetupLib.h>
+
+#include "PciRebalance.h"
+
+
+/******************************************************************************
+ * Local definitions.
+ ******************************************************************************/
+typedef struct {
+ PCI_ROOT_BRIDGE_INSTANCE RootBridge;
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH RootDevPath;
+} PCI_ROOT_BRIDGE_WITH_PATH;
+
+
+/******************************************************************************
+ * Variables.
+ ******************************************************************************/
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mAcpiAddressSpaceTypeStr[] = {
+ L"Mem", L"I/O", L"Bus"
+};
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] = {
+ L"I/O", L"Mem32", L"PMem32", L"Mem64", L"PMem64", L"Bus"
+};
+
+//
+// We can hardcode the following for a Simple IIO -
+// Root Bridge Count within the Host bridge
+// Root Bridge's device path
+// Root Bridge's resource appeture
+//
+
+STATIC EFI_PCI_ROOT_BRIDGE_DEVICE_PATH mEfiPciRootBridgeDevicePathTemplate = {
+ {{ACPI_DEVICE_PATH,
+ ACPI_DP,
+ {(UINT8) (sizeof (ACPI_HID_DEVICE_PATH)),
+ (UINT8) ((sizeof (ACPI_HID_DEVICE_PATH)) >> 8)}},
+ EISA_PNP_ID(0x0A03),
+ 0},
+ {END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {END_DEVICE_PATH_LENGTH,
+ 0}}
+ };
+
+STATIC EFI_HANDLE mDriverImageHandle;
+
+EDKII_IOMMU_PROTOCOL *mIoMmu;
+EFI_EVENT mIoMmuEvent;
+VOID *mIoMmuRegistration;
+
+EFI_IIO_UDS_PROTOCOL *mIioUds;
+PCI_HOST_BRIDGE_INSTANCE *mHostBridge;
+
+/**
+ Event notification that is fired when IOMMU protocol is installed.
+
+ @param Event The Event that is being processed.
+ @param Context Event Context.
+
+**/
+VOID
+EFIAPI
+IoMmuProtocolCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEdkiiIoMmuProtocolGuid, NULL, (VOID **)&mIoMmu);
+ if (!EFI_ERROR(Status)) {
+ gBS->CloseEvent (mIoMmuEvent);
+ }
+}
+
+
+/**
+
+ 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;
+ UINTN IioIndex;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINTN IioStack;
+ UINT64 ResourceLength;
+ PCI_ROOT_BRIDGE_RESOURCE_APERTURE RbAperture;
+
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ EFI_PCI_ROOT_BRIDGE_DEVICE_PATH *TempDevicePath;
+ STACK_RES *CurStackRes;
+
+ mDriverImageHandle = ImageHandle;
+ //
+ // Located the IIO Protocol Interface
+ //
+ Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid, NULL, &mIioUds);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Most systems in the world including complex servers have only one Host Bridge.
+ //
+ HostBridge = AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE));
+ if (HostBridge == NULL) {
+ ASSERT(FALSE);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ HostBridge->Signature = PCI_HOST_BRIDGE_SIGNATURE;
+ HostBridge->RootBridgeCount = 0;
+ HostBridge->ResourceSubmited = FALSE;
+ 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->InstallProtocolInterface (
+ &HostBridge->Handle,
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &HostBridge->ResAlloc
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (HostBridge);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Create Root Bridges in this Host Bridge.
+ //
+ for (IioIndex = 0; IioIndex < mIioUds->IioUdsPtr->PlatformData.numofIIO; IioIndex++) {
+
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Valid) {
+ continue;
+ } // No guarantee that the valid IIOs are sequential starting at 0!
+
+ for (IioStack = 0; IioStack < MAX_IIO_STACK; IioStack++) {
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[IioIndex].stackPresentBitmap & (1 << IioStack))) {
+ continue;
+ }
+ // Skip stack which is disabled by resource limitation or DEBUG purpose!
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].Personality >= TYPE_DISABLED) {
+ continue;
+ }
+ //
+ // Create Root Bridge Instance
+ //
+ RootBridge = AllocateZeroPool (sizeof(PCI_ROOT_BRIDGE_WITH_PATH));
+ if (RootBridge == NULL) {
+ ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ TempDevicePath = &((PCI_ROOT_BRIDGE_WITH_PATH*)RootBridge)->RootDevPath;
+
+ RootBridge->Signature = PCI_ROOT_BRIDGE_SIGNATURE;
+ RootBridge->DevicePath = (EFI_DEVICE_PATH_PROTOCOL*)TempDevicePath;
+ CopyMem (TempDevicePath, &mEfiPciRootBridgeDevicePathTemplate, sizeof(*TempDevicePath));
+ TempDevicePath->AcpiDevicePath.UID = (UINT32)(IioIndex * MAX_IIO_STACK + IioStack);
+
+ ZeroMem(&RbAperture, sizeof(RbAperture));
+ {
+ //
+ // Update Root Bridge with UDS resource information
+ //
+ RbAperture.BusBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].BusBase;
+ RbAperture.BusLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].BusLimit;
+ RbAperture.Mem32Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem32Base;
+ RbAperture.Mem32Limit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem32Limit;
+ RbAperture.BusReserve = 0;
+ if ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Limit >
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Base) &&
+ (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllocation)) {
+ RbAperture.Mem64Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Base;
+ RbAperture.Mem64Limit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Limit;
+ }
+ RbAperture.IoBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoBase;
+ RbAperture.IoLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoLimit;
+
+ SimpleIioRootBridgeConstructor (&RootBridge->RootBridgeIo, HostBridge->Handle, &RbAperture,
+ mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[IioIndex].PcieSegment,
+ GetAllocAttributes (HostBridge->RootBridgeCount));
+ DEBUG ((DEBUG_INFO, "[PCI] Create Root Bridge for [%d.%d] in PCI segment %d with below resource:\n", IioIndex, IioStack, RootBridge->RootBridgeIo.SegmentNumber));
+ DEBUG ((DEBUG_INFO, " Bus: Base = 0x%08x, Limit = 0x%08x, BusReserve = 0x%08x\n", RootBridge->Aperture.BusBase, RootBridge->Aperture.BusLimit, RootBridge->Aperture.BusReserve));
+ DEBUG ((DEBUG_INFO, " IO: Base = 0x%08x, Limit = 0x%08x\n", RootBridge->Aperture.IoBase, RootBridge->Aperture.IoLimit));
+ DEBUG ((DEBUG_INFO, " Mem32: Base = 0x%08x, Limit = 0x%08x\n", RootBridge->Aperture.Mem32Base, RootBridge->Aperture.Mem32Limit));
+ DEBUG ((DEBUG_INFO, " Mem64: Base = 0x%lx, Limit = 0x%lx\n", RootBridge->Aperture.Mem64Base, RootBridge->Aperture.Mem64Limit));
+ //
+ // Insert Root Bridge Instance
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &RootBridge->Handle,
+ &gEfiDevicePathProtocolGuid,
+ RootBridge->DevicePath,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ &RootBridge->RootBridgeIo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ InsertTailList (&HostBridge->RootBridges, &RootBridge->Link);
+ mPciRootBridgeTable[IioIndex][IioStack] = RootBridge;
+ HostBridge->RootBridgeCount++;
+ }
+ } // for (IioStack...)
+ } // for (IioIndex...)
+ //
+ // Add PCIE base into Runtime memory so that it can be reported in E820 table
+ //
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ mIioUds->IioUdsPtr->PlatformData.PciExpressBase,
+ mIioUds->IioUdsPtr->PlatformData.PciExpressSize,
+ EFI_MEMORY_RUNTIME | EFI_MEMORY_UC
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ BaseAddress = mIioUds->IioUdsPtr->PlatformData.PciExpressBase;
+
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ mIioUds->IioUdsPtr->PlatformData.PciExpressSize,
+ &BaseAddress,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ Status = gDS->SetMemorySpaceAttributes (
+ mIioUds->IioUdsPtr->PlatformData.PciExpressBase,
+ mIioUds->IioUdsPtr->PlatformData.PciExpressSize,
+ EFI_MEMORY_RUNTIME
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //s4030180
+ for (IioIndex = 0; IioIndex < mIioUds->IioUdsPtr->PlatformData.numofIIO; IioIndex++) {
+
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Valid) {
+ continue;
+ } // No guarantee that the valid IIOs are sequential starting at 0!
+ for (IioStack = 0; IioStack < MAX_IIO_STACK; IioStack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[IioIndex].stackPresentBitmap & (1 << IioStack))) {
+ continue;
+ }
+
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoLimit >
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoBase) {
+ //
+ // At present, we use up the first 4k for fixed ranges like
+ // ICH GPIO, ACPI and ISA devices. The first 4k is not
+ // tracked through GCD. It should be.
+ //
+ Status = gDS->AddIoSpace (
+ EfiGcdIoTypeIo,
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoBase ,
+ (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoLimit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceIoBase + 1)
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CurStackRes = &mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack];
+ if (CurStackRes->PciResourceMem32Limit > CurStackRes->PciResourceMem32Base) {
+ //
+ // Shouldn't the capabilities be UC?
+ //
+ ResourceLength = CurStackRes->PciResourceMem32Limit - CurStackRes->PciResourceMem32Base + 1;
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ CurStackRes->PciResourceMem32Base,
+ ResourceLength,
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Track VT-d bar in GCD.
+ //
+ // We now have a region of memory x-z associated with this stack
+ // and there is also subregion y-z that is the VT-d space (x <= y <= z)
+ BaseAddress = CurStackRes->VtdBarAddress;
+ ResourceLength = CurStackRes->PciResourceMem32Limit - BaseAddress + 1;
+ Status = gDS->AllocateMemorySpace (
+ EfiGcdAllocateAddress,
+ EfiGcdMemoryTypeMemoryMappedIo,
+ 0,
+ ResourceLength,
+ &BaseAddress,
+ ImageHandle,
+ NULL
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ if ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Limit >
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Base) &&
+ (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllocation)) {
+
+ Status = gDS->AddMemorySpace (
+ EfiGcdMemoryTypeMemoryMappedIo,
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Base ,
+ (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes[IioStack].PciResourceMem64Base + 1),
+ 0
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ mIoMmuEvent = EfiCreateProtocolNotifyEvent (
+ &gEdkiiIoMmuProtocolGuid,
+ TPL_CALLBACK,
+ IoMmuProtocolCallback,
+ NULL,
+ &mIoMmuRegistration
+ );
+ }
+ mHostBridge = HostBridge;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enter the EfiPciHostBridgeBeginEnumeration phase of the PCI(e)
+ numeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ instance.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_READY
+*/
+STATIC EFI_STATUS
+BeginBridgeEnumeration (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ LIST_ENTRY *List;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+
+ Index = TypeMax;
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+
+ if (HostBridge->CanRestarted) {
+ //
+ // Reset Root Bridge
+ //
+ List = HostBridge->RootBridges.ForwardLink;
+
+ while (List != &HostBridge->RootBridges) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ 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;
+ } // for
+
+ List = List->ForwardLink;
+ } // while
+
+ HostBridge->ResourceSubmited = FALSE;
+ HostBridge->CanRestarted = TRUE;
+ } else {
+ //
+ // Can not restart
+ //
+ return EFI_NOT_READY;
+ } // if
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enter the EfiPciHostBridgeAllocateResources phase of the
+ PCI(e) numeration process.
+
+ @param[in] This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL instance.
+
+ @retval EFI_SUCCESS
+ @retval EFI_NOT_READY
+ @retval EFI_OUT_OF_RESOURCES
+*/
+STATIC EFI_STATUS
+BridgeAllocateResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+ LIST_ENTRY *List;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 AddrLen;
+ UINTN BitsOfAlignment;
+ UINT64 Alignment;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+ PCI_RESOURCE_TYPE Index1;
+ PCI_RESOURCE_TYPE Index2;
+ BOOLEAN ResNodeHandled[TypeMax];
+ UINT64 MaxAlignment;
+ SOCKET_RESOURCE_ADJUSTMENT_RESULT RatioAdjustResult;
+ UINT8 Socket;
+ UINT8 Stack;
+
+ Index = TypeMax;
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+
+ ReturnStatus = EFI_SUCCESS;
+ if (HostBridge->ResourceSubmited) {
+
+ List = HostBridge->RootBridges.ForwardLink;
+ while (List != &HostBridge->RootBridges) {
+
+ for (Index1 = TypeIo; Index1 < TypeBus; Index1++) {
+ ResNodeHandled[Index1] = FALSE;
+ }
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ Socket = Stack = (UINT8)-1;
+ PciRootBridge2SocketStack (RootBridge, &Socket, &Stack);
+ 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;
+ }
+ } // for
+
+ if (Index < TypeMax) {
+
+ ResNodeHandled[Index] = TRUE;
+ Alignment = RootBridge->ResAllocNode[Index].Alignment;
+ //
+ // Get the number of '1' in Alignment.
+ //
+ for (BitsOfAlignment = 0; Alignment != 0; BitsOfAlignment++) {
+ Alignment = RShiftU64 (Alignment, 1);
+ }
+
+ AddrLen = RootBridge->ResAllocNode[Index].Length;
+ Alignment = RootBridge->ResAllocNode[Index].Alignment;
+
+ DEBUG ((DEBUG_INFO, "\n[%d.%d] Resource Type to assign : %s\n", Socket, Stack, mPciResourceTypeStr[Index]));
+ DEBUG ((DEBUG_INFO, " Length to allocate: %lx\n", RootBridge->ResAllocNode[Index].Length));
+ DEBUG ((DEBUG_INFO, " Alignment: %lx\n", Alignment));
+ DEBUG ((DEBUG_INFO, " Base Address: %lx\n", RootBridge->ResAllocNode[Index].Base));
+
+ switch (Index) {
+ case TypeIo:
+ if (RootBridge->Aperture.IoBase < RootBridge->Aperture.IoLimit) {
+ //
+ // It is impossible for 0xFFFF Alignment for IO16
+ //
+ if (BitsOfAlignment >= 16) {
+ Alignment = 0;
+ }
+ BaseAddress = RootBridge->Aperture.IoBase;
+ //
+ // Have to make sure Alignment is handled seeing we are doing direct address allocation
+ //
+ if ((BaseAddress & ~(Alignment)) != BaseAddress) {
+ BaseAddress = ((BaseAddress + Alignment) & ~(Alignment));
+ }
+
+ while((BaseAddress + AddrLen) <= RootBridge->Aperture.IoLimit + 1) {
+ Status = gDS->AllocateIoSpace (EfiGcdAllocateAddress, EfiGcdIoTypeIo, BitsOfAlignment,
+ AddrLen, &BaseAddress, mDriverImageHandle, NULL );
+
+ if (!EFI_ERROR (Status)) {
+ RootBridge->ResAllocNode[Index].Base = (UINT64) BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ goto TypeIoFound;
+ }
+
+ BaseAddress += (Alignment + 1);
+ } // while
+ } // if
+
+ TypeIoFound:
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ //
+ // No Room at the Inn for this resources request
+ //
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ } // if
+ break;
+
+ case TypeMem32:
+ if (RootBridge->Aperture.Mem32Base < RootBridge->Aperture.Mem32Limit) {
+
+ BaseAddress = RootBridge->Aperture.Mem32Base;
+ //
+ // Have to make sure Alignment is handled seeing we are doing direct address allocation
+ //
+ if ((BaseAddress & ~(Alignment)) != BaseAddress) {
+ BaseAddress = ((BaseAddress + Alignment) & ~(Alignment));
+ }
+
+ while ((BaseAddress + AddrLen) <= RootBridge->Aperture.Mem32Limit + 1) {
+ DEBUG ((DEBUG_INFO, " Attempting %s allocation at 0x%llX.....",
+ mPciResourceTypeStr[Index], BaseAddress));
+ Status = gDS->AllocateMemorySpace (EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL);
+ if (!EFI_ERROR (Status)) {
+ RootBridge->ResAllocNode[Index].Base = (UINT64) BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ DEBUG ((DEBUG_INFO, "Passed\n"));
+ goto TypeMem32Found;
+ } // if
+ DEBUG ((DEBUG_INFO, "Failed\n"));
+ BaseAddress += (Alignment + 1);
+ } // while
+ } // if
+
+ TypeMem32Found:
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ //
+ // No Room at the Inn for this resources request
+ //
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ }
+ break;
+
+ case TypePMem32:
+ StartTypePMem32:
+ if (RootBridge->Aperture.Mem32Base < RootBridge->Aperture.Mem32Limit) {
+ BaseAddress = RootBridge->Aperture.Mem32Limit + 1;
+ BaseAddress -= AddrLen;
+
+ //
+ // Have to make sure Alignment is handled seeing we are doing direct address allocation
+ //
+ if ((BaseAddress & ~(Alignment)) != BaseAddress) {
+ BaseAddress = ((BaseAddress) & ~(Alignment));
+ }
+
+ while (RootBridge->Aperture.Mem32Base <= BaseAddress) {
+
+ DEBUG ((DEBUG_INFO, " Attempting %s allocation at 0x%llX.....",
+ mPciResourceTypeStr[Index], BaseAddress));
+ Status = gDS->AllocateMemorySpace (EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL);
+ if (!EFI_ERROR (Status)) {
+ RootBridge->ResAllocNode[Index].Base = (UINT64) BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ DEBUG ((DEBUG_INFO, "Passed\n"));
+ goto TypePMem32Found;
+ }
+ DEBUG ((DEBUG_INFO, "Failed\n"));
+ BaseAddress -= (Alignment + 1);
+ } // while
+ } // if
+
+ TypePMem32Found:
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ //
+ // No Room at the Inn for this resources request
+ //
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ }
+ break;
+
+ case TypeMem64:
+ case TypePMem64:
+ if ((RootBridge->Aperture.Mem64Limit > RootBridge->Aperture.Mem64Base) &&
+ (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllocation)) {
+
+ if (RootBridge->Aperture.Mem64Limit < AddrLen) {
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ goto TypeMem64Found;
+ }
+ BaseAddress = RootBridge->Aperture.Mem64Limit + 1;
+ BaseAddress -= AddrLen;
+
+ //
+ // Have to make sure Alignment is handled seeing we are doing direct address allocation
+ //
+ if ((BaseAddress & ~(Alignment)) != BaseAddress) {
+ BaseAddress = ((BaseAddress) & ~(Alignment));
+ }
+
+ while (RootBridge->Aperture.Mem64Base <= BaseAddress) {
+
+ DEBUG ((DEBUG_INFO, " Attempting %s allocation at 0x%llX.....",
+ mPciResourceTypeStr[Index], BaseAddress));
+ Status = gDS->AllocateMemorySpace (EfiGcdAllocateAddress, EfiGcdMemoryTypeMemoryMappedIo,
+ BitsOfAlignment, AddrLen, &BaseAddress, mDriverImageHandle, NULL);
+ if (!EFI_ERROR (Status)) {
+ RootBridge->ResAllocNode[Index].Base = (UINT64) BaseAddress;
+ RootBridge->ResAllocNode[Index].Status = ResAllocated;
+ DEBUG ((DEBUG_INFO, "Passed\n"));
+ goto TypeMem64Found;
+ }
+ DEBUG ((DEBUG_INFO, "Failed\n"));
+ BaseAddress -= (Alignment + 1);
+ } // while
+
+ TypeMem64Found:
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ //
+ // No Room at the Inn for this resources request
+ //
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // If 64-bit resourcing is not available, and the requested size is not greater than the Mem32Limit, then try as PMem32
+ //
+ if (AddrLen >= RootBridge->Aperture.Mem32Limit + 1) {
+
+ DEBUG((DEBUG_ERROR, " 64-bit resource length 0x%llX > Mem32Limit (0x%llX). Failed!!\n", AddrLen, RootBridge->Aperture.Mem32Limit + 1));
+ goto TypeMem64Found; // Let it handle out-of-resources case, try MMIO rebalance
+
+ } else {
+
+ DEBUG((DEBUG_ERROR, " 64-bit resourcing not available. Try as PMem32\n"));
+ goto StartTypePMem32;
+ }
+ }
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "[PCI] ERROR: Unhandled resource type (%d)\n", Index));
+ break;
+ } // End switch (Index)
+
+ DEBUG ((DEBUG_INFO, "Resource Type Assigned: %s\n", mPciResourceTypeStr[Index]));
+ if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
+ DEBUG ((DEBUG_INFO, " Base Address Assigned: %lx\n", RootBridge->ResAllocNode[Index].Base));
+ DEBUG ((DEBUG_INFO, " Length Assigned: %lx\n", RootBridge->ResAllocNode[Index].Length));
+ } else {
+ DEBUG ((DEBUG_ERROR, " Resource Allocation failed! There was no room at the inn\n"));
+ }
+ } else {
+ //
+ // Index >= TypeMax
+ //
+ ASSERT (FALSE);
+ }
+ }
+ }
+ List = List->ForwardLink;
+ }
+
+ if (ReturnStatus == EFI_OUT_OF_RESOURCES) {
+
+ DEBUG ((DEBUG_ERROR, "[PCI] Resource allocation failed, rebalance resource allocation and reboot\n"));
+ AdjustResourceAmongRootBridges (HostBridge, &RatioAdjustResult);
+ if (RatioAdjustResult == SocketResourceRatioChanged) {
+ DEBUG ((DEBUG_WARN, "[PCI] WARNING: Resource allocation failed. Adjusted the resource requests and resetting the system.\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+
+ } else {
+
+ DEBUG ((DEBUG_WARN, "[PCI] WARNING: Resource allocation failed, rebalance not possible, continue boot\n"));
+ }
+ }
+
+ //
+ // Set resource to zero for nodes where allocation fails
+ //
+ List = HostBridge->RootBridges.ForwardLink;
+ while (List != &HostBridge->RootBridges) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResAllocated) {
+ RootBridge->ResAllocNode[Index].Length = 0;
+ }
+ }
+ List = List->ForwardLink;
+ }
+ return ReturnStatus;
+ } else {
+ return EFI_NOT_READY;
+ }
+ //
+ // HostBridge->CanRestarted = FALSE;
+ //
+}
+
+
+/**
+ Enter the EfiPciHostBridgeFreeResources phase of the
+ PCI(e) numeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ instance.
+ @retval EFI_SUCCESS Things worked out
+ @retval other Failures as reported by functions leveraged
+*/
+STATIC EFI_STATUS
+BridgeFreeResources (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This
+ )
+{
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+ LIST_ENTRY *List;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ UINT64 AddrLen;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ ReturnStatus = EFI_SUCCESS;
+ List = HostBridge->RootBridges.ForwardLink;
+
+ while (List != &HostBridge->RootBridges) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ for (Index = TypeIo; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status == ResAllocated) {
+ AddrLen = RootBridge->ResAllocNode[Index].Length;
+ BaseAddress = (EFI_PHYSICAL_ADDRESS) RootBridge->ResAllocNode[Index].Base;
+
+ switch (Index) {
+ case TypeIo:
+ Status = gDS->FreeIoSpace (BaseAddress, AddrLen);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypeMem32:
+ Status = gDS->FreeMemorySpace (BaseAddress, AddrLen);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ case TypePMem32:
+ break;
+
+ case TypeMem64:
+ break;
+
+ case TypePMem64:
+ Status = gDS->FreeMemorySpace (BaseAddress, AddrLen);
+ if (EFI_ERROR (Status)) {
+ ReturnStatus = Status;
+ }
+ break;
+
+ default:
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Invalid resource type %d\n", Index));
+ break;
+ }
+
+ RootBridge->ResAllocNode[Index].Type = Index;
+ RootBridge->ResAllocNode[Index].Base = 0;
+ RootBridge->ResAllocNode[Index].Length = 0;
+ RootBridge->ResAllocNode[Index].Status = ResNone;
+ }
+ }
+
+ List = List->ForwardLink;
+ }
+
+ HostBridge->ResourceSubmited = FALSE;
+ HostBridge->CanRestarted = TRUE;
+ return ReturnStatus;
+}
+
+
+/**
+ Enter the EfiPciHostBridgeEndResourceAllocation phase of the
+ PCI(e) numeration process.
+
+ @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
+ instance.
+ @retval EFI_SUCCESS Things worked out
+*/
+STATIC EFI_STATUS
+PciHostBridgeEndResourceAllocation (
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+
+ 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;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+
+ switch (Phase) {
+ case EfiPciHostBridgeBeginEnumeration:
+ return BeginBridgeEnumeration (This);
+
+ case EfiPciHostBridgeEndEnumeration:
+ return EFI_SUCCESS;
+
+ 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:
+ return BridgeAllocateResources (This);
+
+ case EfiPciHostBridgeSetResources:
+ //
+ // HostBridgeInstance->CanRestarted = FALSE;
+ //
+ break;
+
+ case EfiPciHostBridgeFreeResources:
+ return BridgeFreeResources (This);
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ return PciHostBridgeEndResourceAllocation (This);
+
+ 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 NoRootBridge;
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ NoRootBridge = TRUE;
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+
+ while (List != &HostBridge->RootBridges) {
+ NoRootBridge = FALSE;
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (*RootBridgeHandle == NULL) {
+ //
+ // Return the first Root Bridge Handle of the Host Bridge
+ //
+ *RootBridgeHandle = RootBridge->Handle;
+ return EFI_SUCCESS;
+ } else {
+ if (*RootBridgeHandle == RootBridge->Handle) {
+ //
+ // Get next if have
+ //
+ List = List->ForwardLink;
+ if (List != &HostBridge->RootBridges) {
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ *RootBridgeHandle = RootBridge->Handle;
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ List = List->ForwardLink;
+ //
+ // end while
+ //
+ }
+
+ if (NoRootBridge) {
+ 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 *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ VOID *Buffer;
+ UINT8 *Temp;
+ EFI_STATUS Status;
+ UINTN BusStart;
+ UINTN BusEnd;
+ UINT64 BusReserve;
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+
+ while (List != &HostBridge->RootBridges) {
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ //
+ // Set up the Root Bridge for Bus Enumeration
+ //
+ BusStart = RootBridge->Aperture.BusBase;
+ BusEnd = RootBridge->Aperture.BusLimit;
+ BusReserve = RootBridge->Aperture.BusReserve;
+ //
+ // Program the Hardware(if needed) if error return EFI_DEVICE_ERROR
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
+ &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Temp = (UINT8 *) Buffer;
+
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = 0x2B;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->GenFlag = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->SpecificFlag = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrSpaceGranularity = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMin = BusStart;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMax = BusReserve;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrTranslationOffset = 0;
+ ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrLen = BusEnd - BusStart + 1;
+
+ Temp = Temp + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = ACPI_END_TAG_DESCRIPTOR;
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0;
+
+ *Configuration = Buffer;
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ 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 *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT8 *Ptr;
+ UINTN BusStart;
+ UINTN BusEnd;
+ UINTN BusLen;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ptr = Configuration;
+
+ //
+ // Check the Configuration is valid
+ //
+ if (*Ptr != ACPI_ADDRESS_SPACE_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->ResType != ACPI_ADDRESS_SPACE_TYPE_BUS) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Ptr += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ if (*Ptr != ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+ Ptr = Configuration;
+
+ while (List != &HostBridge->RootBridges) {
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ BusStart = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrRangeMin;
+ BusLen = (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->AddrLen;
+ BusEnd = BusStart + BusLen - 1;
+
+ if (BusStart > BusEnd) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BusStart < RootBridge->Aperture.BusBase) || (BusEnd > RootBridge->Aperture.BusLimit)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Update the Bus Range
+ //
+ RootBridge->ResAllocNode[TypeBus].Base = BusStart;
+ RootBridge->ResAllocNode[TypeBus].Length = BusLen + RootBridge->Aperture.BusReserve;
+ RootBridge->ResAllocNode[TypeBus].Status = ResAllocated;
+ RootBridge->BusScanCount++;
+ if (RootBridge->BusScanCount > 0) {
+ //
+ // Only care about the 2nd PCI bus scanning
+ //
+ RootBridge->BusNumberAssigned = TRUE;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ 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 *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
+ UINT64 AddrLen;
+ UINT64 Alignment;
+ UINT64 Value;
+
+ //
+ // Check the input parameter: Configuration
+ //
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+
+ Temp = (UINT8 *) Configuration;
+ while (List != &HostBridge->RootBridges) {
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ //
+ // 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 (; *Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR; Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)) {
+
+ ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ //DEBUG ((DEBUG_ERROR, " ptr->ResType:%x", ptr->ResType));
+ //DEBUG ((DEBUG_ERROR, " ptr->AddrLen:0x%llX AddrRangeMin:0x%llX AddrRangeMax:0x%llX\n",ptr->AddrLen,ptr->AddrRangeMin,ptr->AddrRangeMax));
+ //
+ // A zero-length resource request indicates the PCI root bridge doesn't require
+ // any resources. Skip the check and proceed to the next descriptor.
+ //
+ if (ptr->AddrLen == 0) {
+ continue;
+ }
+
+ switch (ptr->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+ if (ptr->AddrSpaceGranularity != 32 && ptr->AddrSpaceGranularity != 64) {
+
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Inavlid granularity %d for resource type %d\n",
+ ptr->AddrSpaceGranularity, ptr->ResType));
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ptr->AddrSpaceGranularity == 32 && ptr->AddrLen > 0xffffffff) {
+
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Inavlid granularity %d for resource type %d of size 0x%llX\n",
+ ptr->AddrSpaceGranularity, ptr->ResType, ptr->AddrLen));
+ 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 &&
+ ((ptr->SpecificFlag & (BIT2 | BIT1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+ //
+ // Check alignment, it should be of the form 2^n-1
+ //
+ Value = Power2MaxMemory (ptr->AddrRangeMax + 1);
+ if (Value != (ptr->AddrRangeMax + 1)) {
+ CpuDeadLoop();
+ return EFI_INVALID_PARAMETER;
+ }
+ break;
+ case ACPI_ADDRESS_SPACE_TYPE_BUS:
+ default:
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ if (*Temp != ACPI_END_TAG_DESCRIPTOR) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Temp = (UINT8 *) Configuration;
+ for (; *Temp == ACPI_ADDRESS_SPACE_DESCRIPTOR; Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)) {
+ ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+
+ //
+ // If a PCI root bridge does not require any resources, a zero-length resource
+ // request must be explicitly submitted.
+ //
+ if (ptr->AddrLen == 0) {
+ HostBridge->ResourceSubmited = TRUE;
+ continue;
+ }
+
+ switch (ptr->ResType) {
+ case ACPI_ADDRESS_SPACE_TYPE_MEM:
+ AddrLen = (UINT64) ptr->AddrLen;
+ Alignment = (UINT64) ptr->AddrRangeMax;
+ if (ptr->AddrSpaceGranularity == 32) {
+ if (ptr->SpecificFlag == 0x06) {
+ //
+ // Apply from GCD
+ //
+ RootBridge->ResAllocNode[TypePMem32].Status = ResSubmitted;
+ } else {
+ RootBridge->ResAllocNode[TypeMem32].Length = AddrLen;
+ RootBridge->ResAllocNode[TypeMem32].Alignment = Alignment;
+ RootBridge->ResAllocNode[TypeMem32].Status = ResRequested;
+ HostBridge->ResourceSubmited = TRUE;
+ }
+ }
+
+ if (ptr->AddrSpaceGranularity == 64) {
+ if (ptr->SpecificFlag == 0x06) {
+ RootBridge->ResAllocNode[TypePMem64].Status = ResSubmitted;
+ } else {
+ RootBridge->ResAllocNode[TypeMem64].Length = AddrLen;
+ RootBridge->ResAllocNode[TypeMem64].Alignment = Alignment;
+ RootBridge->ResAllocNode[TypeMem64].Status = ResSubmitted;
+ HostBridge->ResourceSubmited = TRUE;
+ }
+ }
+ break;
+
+ case ACPI_ADDRESS_SPACE_TYPE_IO:
+ AddrLen = (UINT64) ptr->AddrLen;
+ Alignment = (UINT64) ptr->AddrRangeMax;
+ RootBridge->ResAllocNode[TypeIo].Length = AddrLen;
+ RootBridge->ResAllocNode[TypeIo].Alignment = Alignment;
+ RootBridge->ResAllocNode[TypeIo].Status = ResRequested;
+ HostBridge->ResourceSubmited = TRUE;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+ List = List->ForwardLink;
+ }
+
+ 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 *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINTN Index;
+ UINTN Number;
+ VOID *Buffer;
+ UINT8 *Temp;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *ptr;
+ EFI_STATUS Status;
+ UINT64 ResStatus;
+
+ Buffer = NULL;
+ Number = 0;
+ //
+ // Get the Host Bridge Instance from the resource allocation protocol
+ //
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+
+ //
+ // Enumerate the root bridges in this Host bridge
+ //
+ while (List != &HostBridge->RootBridges) {
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ for (Index = 0; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResNone) {
+ Number++;
+ }
+ }
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ Number * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
+ &Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (Buffer, sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) * Number + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+
+ Temp = Buffer;
+ for (Index = 0; Index < TypeBus; Index++) {
+ if (RootBridge->ResAllocNode[Index].Status != ResNone) {
+ ptr = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp;
+ ResStatus = RootBridge->ResAllocNode[Index].Status;
+
+ switch (Index) {
+
+ case TypeIo:
+ //
+ // Io
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 1;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
+ ptr->AddrLen = RootBridge->ResAllocNode[Index].Length;
+ break;
+
+ case TypeMem32:
+ //
+ // Memory 32
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrSpaceGranularity = 32;
+ ptr->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
+ ptr->AddrLen = RootBridge->ResAllocNode[Index].Length;
+ break;
+
+ case TypePMem32:
+ //
+ // Prefetch memory 32
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 6;
+ ptr->AddrSpaceGranularity = 32;
+ ptr->AddrRangeMin = 0;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
+ ptr->AddrLen = 0;
+ break;
+
+ case TypeMem64:
+ //
+ // Memory 64
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 0;
+ ptr->AddrSpaceGranularity = 64;
+ ptr->AddrRangeMin = RootBridge->ResAllocNode[Index].Base;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = (ResStatus == ResAllocated) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS;
+ ptr->AddrLen = RootBridge->ResAllocNode[Index].Length;
+ break;
+
+ case TypePMem64:
+ //
+ // Prefetch memory 64
+ //
+ ptr->Desc = 0x8A;
+ ptr->Len = 0x2B;
+ ptr->ResType = 0;
+ ptr->GenFlag = 0;
+ ptr->SpecificFlag = 6;
+ ptr->AddrSpaceGranularity = 64;
+ ptr->AddrRangeMin = 0;
+ ptr->AddrRangeMax = 0;
+ ptr->AddrTranslationOffset = EFI_RESOURCE_NONEXISTENT;
+ ptr->AddrLen = 0;
+ break;
+ default:
+ DEBUG ((EFI_D_INFO, "default case.\n")); //Auto added. Please review.
+ break;
+ }
+
+ Temp += sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR);
+ }
+ }
+
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc = 0x79;
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum = 0x0;
+
+ *Configuration = Buffer;
+
+ return EFI_SUCCESS;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ 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
+ )
+{
+ BOOLEAN RootBridgeFound;
+ LIST_ENTRY *List;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridge;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (RootBridgeHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridgeFound = FALSE;
+ HostBridge = PCI_HOST_BRIDGE_FROM_THIS (This);
+ List = HostBridge->RootBridges.ForwardLink;
+
+ while (List != &HostBridge->RootBridges) {
+
+ RootBridge = ROOT_BRIDGE_FROM_LINK (List);
+ if (RootBridgeHandle == RootBridge->Handle) {
+ RootBridgeFound = TRUE;
+ break;
+ }
+ //
+ // Get next if have
+ //
+ List = List->ForwardLink;
+ }
+
+ if (RootBridgeFound == FALSE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Calculate maximum memory length that can be fit to a mtrr.
+
+ @param MemoryLength - Input memory length.
+
+ @retval Returned Maximum length.
+
+**/
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ )
+{
+ UINT64 Result;
+
+ if (RShiftU64 (MemoryLength, 32)) {
+ Result = LShiftU64 ((UINT64) GetPowerOfTwo64 ((UINT32) RShiftU64 (MemoryLength, 32)), 32);
+ } else {
+ Result = (UINT64) GetPowerOfTwo64 ((UINT32) MemoryLength);
+ }
+
+ return Result;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.h
new file mode 100644
index 0000000000..4c1b757952
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.h
@@ -0,0 +1,300 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#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 <Protocol/IoMmu.h>
+
+#include "PciRootBridge.h"
+
+#define PCI_HOST_BRIDGE_SIGNATURE SIGNATURE_32 ('p', 'h', 'b', 'g')
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ UINTN RootBridgeCount;
+ LIST_ENTRY RootBridges;
+ BOOLEAN ResourceSubmited;
+ 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.
+ @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
+ );
+
+/**
+
+ 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
+ );
+
+//
+// Host Bridge Silicon specific hooks
+//
+/**
+
+ Returns the Allocation attributes for the BNB Root Bridge.
+
+ @param RootBridgeIndex - The root bridge number. 0 based.
+
+ @retval EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | EFI_PCI_HOST_BRIDGE_MEM64_DECODE
+
+**/
+UINT64
+GetAllocAttributes (
+ IN UINTN RootBridgeIndex
+ )
+;
+
+/**
+
+ Returns memory apertures for the BNB Root Bridge.
+
+ @param PciRootBridgeIo - Pointer to Efi Pci root bridge Io protocol interface instance.
+ @param Mem32Base - Pointer to 32 bit memory base. This is the lowest 32 bit memory address
+ that is decoded by the Host Bridge.
+ @param Mem32Limit - Pointer to 32 bit memory limit.This is the highest 32 bit memory address
+ that is decoded by the Host Bridge. The size of the 32 bit window is
+ (Mem32Limit - Mem32base + 1).
+ @param Mem64Base - Pointer to 64 bit memory base. This is the lowest 64 bit memory address
+ that is decoded by the Host Bridge.
+ @param Mem64Limit - Pointer to 64 bit memory limit.This is the highest 64 bit memory address
+ that is decoded by the Host Bridge. The size of the 64 bit window is
+ (Mem64Limit - Mem64base + 1). Set Mem64Limit < Mem64Base if the Host bridge
+ does not support 64 bit memory addresses.
+
+ @retval EFI_SUCCESS - Success.
+
+**/
+EFI_STATUS
+GetHostBridgeMemApertures (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT UINT32 *Mem32Base,
+ OUT UINT32 *Mem32Limit,
+ OUT UINT64 *Mem64Base,
+ OUT UINT64 *Mem64Limit
+ );
+
+/**
+
+ Calculate maximum memory length that can be fit to a mtrr.
+
+ @param MemoryLength - Input memory length.
+
+ @retval Returned Maximum length.
+
+**/
+UINT64
+Power2MaxMemory (
+ IN UINT64 MemoryLength
+ );
+
+extern EDKII_IOMMU_PROTOCOL *mIoMmu;
+
+#endif // _PCI_HOST_BRIDGE_H_
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.inf b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.inf
new file mode 100644
index 0000000000..faea9726f7
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridge.inf
@@ -0,0 +1,69 @@
+## @file
+#
+# @copyright
+# Copyright 2009 - 2021 Intel Corporation. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciHostBridge
+ FILE_GUID = D58EBCE1-AF26-488d-BE66-C164417F8C13
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePciHostBridge
+
+[Sources]
+ PciHostBridge.h
+ PciRootBridge.h
+ PciHostBridge.c
+ PciRootBridgeIo.c
+ PciHostBridgeSupport.c
+ PciHostResource.h
+ PciRebalance.c
+ PciRebalanceIo.c
+ PciRebalanceMmio32.c
+ PciRebalanceMmio64.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ WhitleySiliconPkg/WhitleySiliconPkg.dec
+ WhitleySiliconPkg/SiliconPkg.dec
+ WhitleySiliconPkg/CpRcPkg.dec
+ WhitleySiliconPkg/Cpu/CpuRcPkg.dec
+ WhitleyOpenBoardPkg/PlatformPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ UefiBootServicesTableLib
+ DebugLib
+ DxeServicesTableLib
+ DevicePathLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ TimerLib
+ SetupLib
+
+[Protocols]
+ gEfiCpuIo2ProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiPciRootBridgeIoProtocolGuid ## BY_START
+ gEfiPciHostBridgeResourceAllocationProtocolGuid ## BY_START
+ gEdkiiIoMmuProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIioUdsProtocolGuid
+ gDynamicSiLibraryProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiSocketPciResourceDataGuid
+
+[FixedPcd]
+ gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuSocketCount
+ gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuCoreCount
+
+[Depex]
+ gEfiCpuIo2ProtocolGuid AND
+ gEfiIioUdsProtocolGuid AND
+ gDynamicSiLibraryProtocolGuid
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridgeSupport.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridgeSupport.c
new file mode 100644
index 0000000000..fe3f274f1f
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostBridgeSupport.c
@@ -0,0 +1,127 @@
+/** @file
+ Do platform initialization for PCI bridge.
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PciHostBridge.h"
+
+//
+// The default latency for controllers
+//
+#define DEFAULT_PCI_LATENCY 0x20
+
+
+EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *mPciRootBridgeIo;
+
+/**
+
+ 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 PciBusAddress -- Address of the controller on the PCI bus
+ @param Phase -- The Phase during resource allocation
+
+ @retval EFI_SUCCESS
+
+**/
+EFI_STATUS
+ChipsetPreprocessController (
+ 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
+ )
+{
+
+ EFI_STATUS Status;
+ UINT8 Latency;
+ UINT8 CacheLineSize;
+
+ if (mPciRootBridgeIo == NULL) {
+ //
+ // Get root bridge in the system.
+ //
+ Status = gBS->HandleProtocol (RootBridgeHandle, &gEfiPciRootBridgeIoProtocolGuid, &mPciRootBridgeIo);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (Phase == EfiPciBeforeResourceCollection) {
+ //
+ // Program the latency register, CLS register
+ //
+ PciAddress.Register = PCI_LATENCY_TIMER_OFFSET;
+ mPciRootBridgeIo->Pci.Read (
+ mPciRootBridgeIo,
+ EfiPciWidthUint8,
+ *((UINT64 *) &PciAddress),
+ 1,
+ &Latency
+ );
+
+ //
+ // PCI-x cards come up with a default latency of 0x40. Don't touch them.
+ //
+ if (Latency == 0) {
+ Latency = DEFAULT_PCI_LATENCY;
+ mPciRootBridgeIo->Pci.Write (
+ mPciRootBridgeIo,
+ EfiPciWidthUint8,
+ *((UINT64 *) &PciAddress),
+ 1,
+ &Latency
+ );
+ }
+ //
+ // Program Cache Line Size as 64bytes
+ // 16 of DWORDs = 64bytes (0x10)
+ //
+ PciAddress.Register = PCI_CACHELINE_SIZE_OFFSET;
+ CacheLineSize = 0x10;
+ mPciRootBridgeIo->Pci.Write (
+ mPciRootBridgeIo,
+ EfiPciWidthUint8,
+ *((UINT64 *) &PciAddress),
+ 1,
+ &CacheLineSize
+ );
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Returns the Allocation attributes for the BNB Root Bridge.
+
+ @param RootBridgeIndex - The root bridge number. 0 based.
+
+ @retval EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | EFI_PCI_HOST_BRIDGE_MEM64_DECODE
+
+**/
+UINT64
+GetAllocAttributes (
+ IN UINTN RootBridgeIndex
+ )
+{
+ //
+ // Cannot have more than one Root bridge
+ //
+ //ASSERT (RootBridgeIndex == 0);
+
+ //
+ // PCI Root Bridge does not support separate windows for Non-prefetchable
+ // and Prefetchable memory. A PCI bus driver needs to include requests for
+ // Prefetchable memory in the Non-prefetchable memory pool.
+ // Further TNB does not support 64 bit memory apertures for PCI. BNB
+ // can only have system memory above 4 GB,
+ //
+
+ return EFI_PCI_HOST_BRIDGE_COMBINE_MEM_PMEM | EFI_PCI_HOST_BRIDGE_MEM64_DECODE;
+}
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostResource.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostResource.h
new file mode 100644
index 0000000000..dd95e9773f
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciHostResource.h
@@ -0,0 +1,62 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCI_HOST_RESOURCE_H_
+#define _PCI_HOST_RESOURCE_H_
+
+#include <PiDxe.h>
+#include <UncoreCommonIncludes.h>
+
+#define EFI_RESOURCE_NONEXISTENT 0xFFFFFFFFFFFFFFFF
+#define EFI_RESOURCE_LESS 0xFFFFFFFFFFFFFFFE
+
+typedef struct {
+ UINTN BusBase;
+ UINTN BusLimit;
+ UINTN BusReserve;
+
+ UINT32 Mem32Base;
+ UINT32 Mem32Limit;
+
+ UINT64 Mem64Base;
+ UINT64 Mem64Limit;
+
+ UINTN IoBase;
+ UINTN IoLimit;
+} PCI_ROOT_BRIDGE_RESOURCE_APERTURE;
+
+typedef enum {
+ TypeIo = 0,
+ TypeMem32,
+ TypePMem32,
+ TypeMem64,
+ TypePMem64,
+ TypeBus,
+ TypeMax
+} PCI_RESOURCE_TYPE;
+
+typedef enum {
+ ResNone,
+ ResSubmitted,
+ ResRequested,
+ ResAllocated,
+ ResStatusMax
+} RES_STATUS;
+
+typedef struct {
+ PCI_RESOURCE_TYPE Type;
+ //
+ // Base is a host address
+ //
+ UINT64 Base;
+ UINT64 Length;
+ UINT64 Alignment;
+ RES_STATUS Status;
+} PCI_RES_NODE;
+
+#endif // _PCI_HOST_RESOURCE_H_
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.c
new file mode 100644
index 0000000000..b32f0bf835
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.c
@@ -0,0 +1,1356 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/SocketPciResourceData.h>
+#include <Guid/SocketIioVariable.h>
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include <CpuAndRevisionDefines.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Protocol/IioUds.h>
+
+#include "PciRebalance.h"
+
+
+/******************************************************************************
+ * Local definitions.
+ ******************************************************************************/
+extern CHAR16 *mAcpiAddressSpaceTypeStr[];
+extern CHAR16 *mPciResourceTypeStr[];
+
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+
+/******************************************************************************
+ * Variables.
+ ******************************************************************************/
+/**
+ * The table below is a cache with pointers to protocol instances created at
+ * Host Bridge initialization. It also provides mapping of protocol instance
+ * to the PCI stack.
+ */
+PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTable[MAX_SOCKET][MAX_LOGIC_IIO_STACK] = {0};
+PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTableReserved[MAX_SOCKET][IIO_RESERVED_1] = {0};
+
+
+/******************************************************************************
+ * Functions.
+ ******************************************************************************/
+
+/**
+ Find socket and stack index for given PCI Root Bridge protocol pointer.
+
+ @param[out] PciResConfigPtr - Buffer for the resource configuration variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+PciRootBridge2SocketStack (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridgePtr,
+ OUT UINT8 *SocketPtr,
+ OUT UINT8 *StackPtr
+ )
+{
+ UINT8 Socket;
+ UINT8 Stack;
+
+ if (RootBridgePtr != NULL) {
+
+ for (Socket = 0; Socket < NELEMENTS(mPciRootBridgeTable); Socket++) {
+
+ for (Stack = 0; Stack < NELEMENTS(mPciRootBridgeTable[Socket]); Stack++) {
+
+ if (mPciRootBridgeTable[Socket][Stack] == RootBridgePtr) {
+ if (SocketPtr != NULL) {
+ *SocketPtr = Socket;
+ }
+ if (StackPtr != NULL) {
+ *StackPtr = Stack;
+ }
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ }
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Determine the last stack for a given socket
+
+ @param Socket the socket for which the last socket is desired
+
+ @return the number of the last socket
+*/
+UINT8
+LastStackOfSocket (
+ UINT8 Socket
+ )
+{
+ UINT8 LastStack;
+ BOOLEAN FoundEnabledStack;
+ UINT8 Stack;
+
+ ASSERT (Socket < ARRAY_SIZE(mIioUds->IioUdsPtr->PlatformData.IIO_resource));
+ ASSERT (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid);
+
+ FoundEnabledStack = FALSE;
+ LastStack = 0;
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack)) {
+ LastStack = Stack;
+ FoundEnabledStack = TRUE;
+ }
+ }
+
+ ASSERT (FoundEnabledStack);
+ return LastStack;
+}
+
+
+/**
+ Determine the last stack for a given socket with resources
+
+ @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per stack
+ @param Socket - Index of the Socket
+ @param ResourceType - Type of resource that requires alignment
+ @param LastStack - Pointer that will store the value of the last stack with resources allocated to it
+ @param ResourceSize - Pointer that will store the sum of the requested resource type
+
+ @return The last stack with resources allocated to it and the
+ total amount of resoures requested of the type
+ requested.
+*/
+VOID
+LastStackWithResources (
+ IN CPU_RESOURCE *SocketResources,
+ IN UINT8 Socket,
+ IN PCI_RESOURCE_TYPE ResourceType,
+ OUT UINT8 *LastStack,
+ OUT UINT64 *ResourceSize
+ )
+{
+ UINT8 Stack;
+
+ *LastStack = 0;
+ *ResourceSize = 0;
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+
+ switch (ResourceType) {
+ case TypeIo:
+ if (SocketResources->StackRes[Stack].NumIoPortsDesired != 0) {
+ *ResourceSize += SocketResources->StackRes[Stack].NumIoPortsDesired + 1;
+ *LastStack = Stack;
+ }
+ break;
+ case TypeMem32:
+ if (SocketResources->StackRes[Stack].MmiolLength != 0) {
+ *ResourceSize += SocketResources->StackRes[Stack].MmiolLength + 1;
+ *LastStack = Stack;
+ }
+ break;
+ case TypeMem64:
+ if (SocketResources->StackRes[Stack].MmiohLength != 0) {
+ *ResourceSize += SocketResources->StackRes[Stack].MmiohLength + 1;
+ *LastStack = Stack;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+
+/**
+ Visit all stacks in this socket and recalculate the resource ranges per stack based on resource
+ needs from PCI/PCIe device/functions.
+
+ @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per stack
+ @param Socket - Index of the Socket
+ @param ResourceType - type of resource that requires alignment
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
+**/
+EFI_STATUS
+AdjustResources (
+ CPU_RESOURCE *SocketResources,
+ UINT8 Socket,
+ UINT8 ResourceType
+ )
+{
+ UINT8 Stack;
+ UINT64 NewLength;
+ CONST UINT8 LastStack = LastStackOfSocket (Socket);
+ UINT64 PreviousLimit;
+ BOOLEAN FirstStack = TRUE;
+
+ switch (ResourceType) {
+ case TypeIo:
+ // Return if IoResourceNeeds is not zero which indicates a socket adjustment is needed
+ if(SocketResources->IoResourceNeeds != 0){
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))){
+ continue;
+ }
+ //
+ // For the first enabled stack, use the base I/O address for the socket, otherwise
+ // calculate the new base based off the last enabled stack
+ //
+ if (FirstStack) {
+ // stackPresentBitmap doesn't cover if a valid stack was disable due to resource adjustments.
+ // Start with valid resources for current socket
+ SocketResources->StackRes[Stack].IoBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoBase;
+ FirstStack = FALSE;
+ } else {
+ // Check to see if the previous stack is disabled by checking for equal base and limit
+ if (SocketResources->StackRes[Stack-1].IoBase == SocketResources->StackRes[Stack-1].IoLimit) {
+ if (PreviousLimit % 2 == 1) {
+ PreviousLimit += 1;
+ }
+ SocketResources->StackRes[Stack].IoBase = (UINT16) PreviousLimit;
+ } else {
+ SocketResources->StackRes[Stack].IoBase = (UINT16) PreviousLimit + 1;
+ }
+ }
+
+ NewLength = SocketResources->StackRes[Stack].NumIoPortsDesired;
+
+ //
+ //assign the left space to the last IIO stack. Reserved for across socket resource adjustment.
+ //make adjustments if NewLength is zero
+ //
+ if (Stack == LastStack) {
+ if (NewLength != 0) {
+ if (SocketResources->IoResourcesLeft != 0) {
+ NewLength += SocketResources->IoResourcesLeft + 1;
+ }
+ } else {
+ NewLength = SocketResources->IoResourcesLeft;
+ }
+ }
+
+ SocketResources->StackRes[Stack].NeedIoUpdate = TRUE;
+ SocketResources->StackRes[Stack].IoLimit = (UINT16)(SocketResources->StackRes[Stack].IoBase + NewLength);
+ PreviousLimit = SocketResources->StackRes[Stack].IoLimit;
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoBase =%x newLength = %x\n",Socket,Stack,SocketResources->StackRes[Stack].IoBase,NewLength));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoLimit =%x\n",Socket,Stack,SocketResources->StackRes[Stack].IoLimit));
+ }
+ break;
+
+ case TypeMem32:
+ //
+ // Return if MmiolResourceNeeds is not zero which indicates a socket adjustment is needed
+ //
+ if (SocketResources->MmiolResourceNeeds != 0) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Visit all Stacks in this Socket and recalculate the New Mem32 Ranges per Stack
+ //
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++){
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ //
+ // For the first enabled stack, use the base low mmio address for the socket, otherwize
+ // calculate the new base based off the last enabled stack
+ //
+ if (FirstStack) {
+ // stackPresentBitmap doesn't cover if a valid stack was disable due to resource adjustments.
+ // Start with valid resources for current socket
+ SocketResources->StackRes[Stack].MmiolBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Base;
+ FirstStack = FALSE;
+ } else {
+ // Check to see if the previous stack is disabled by checking for equal base and limit
+ if (SocketResources->StackRes[Stack-1].MmiolBase == SocketResources->StackRes[Stack-1].MmiolLimit) {
+ if (PreviousLimit % 2 == 1) {
+ PreviousLimit += 1;
+ }
+ SocketResources->StackRes[Stack].MmiolBase = (UINT32) PreviousLimit;
+ } else {
+ SocketResources->StackRes[Stack].MmiolBase = (UINT32) PreviousLimit + 1;
+ }
+ }
+ //
+ // Verify if this Stack is the one that requires an update and calculate the new Limit
+ // otherwise assign the new limit based on the Chunk and Extra Chunk calculation and assign the Newlength
+ //
+ NewLength = SocketResources->StackRes[Stack].MmiolLength;
+ //
+ //assign the left space to the last IIO stack. Reserved for across socket resource adjustment.
+ //make adjustments if NewLength is zero
+ //
+ if (Stack == LastStack) {
+ if (NewLength != 0) {
+ if (SocketResources->MmiolResourcesLeft){
+ NewLength += SocketResources->MmiolResourcesLeft + 1;
+ }
+ } else {
+ NewLength = SocketResources->MmiolResourcesLeft;
+ }
+ }
+
+ SocketResources->StackRes[Stack].MmiolUpdate = 1;
+ SocketResources->StackRes[Stack].MmiolLimit = (UINT32)(SocketResources->StackRes[Stack].MmiolBase + NewLength);
+ PreviousLimit = SocketResources->StackRes[Stack].MmiolLimit;
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolBase =%x newLength = %x\n",Socket,Stack,SocketResources->StackRes[Stack].MmiolBase,NewLength));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolLimit =%x\n",Socket,Stack,SocketResources->StackRes[Stack].MmiolLimit));
+ }
+ break;
+
+ case TypeMem64:
+ // Return if MmiohResourceNeeds is not zero which indicates a socket adjustment is needed
+ if (SocketResources->MmiohResourceNeeds != 0){
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Visit all Stacks in this Socket and recalculate the New Mem64 Ranges per Stack
+ //
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+
+ if(!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))){
+ continue;
+ }
+ //
+ // For the first enabled stack, use the base high mmio address for the socket, otherwise
+ // calculate the new base based off the last enabled stack
+ //
+ if (FirstStack) {
+ // stackPresentBitmap doesn't cover if a valid stack was disable due to resource adjustments.
+ // Start with valid resources for current socket
+ SocketResources->StackRes[Stack].MmiohBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Base;
+ FirstStack = FALSE;
+ } else {
+ // Check to see if the previous stack is disabled by checking for equal base and limit
+ if (SocketResources->StackRes[Stack-1].MmiohBase == SocketResources->StackRes[Stack-1].MmiohLimit) {
+ if (PreviousLimit % 2 == 1) {
+ PreviousLimit += 1;
+ }
+ SocketResources->StackRes[Stack].MmiohBase = PreviousLimit;
+ } else {
+ SocketResources->StackRes[Stack].MmiohBase = PreviousLimit + 1;
+ }
+ }
+
+ //
+ // Verify if this Stack is the one that requires an update and calculate the new Limit
+ // otherwise assign the new limit based on the Chunk and Extra Chunk calculation and assign the Newlength
+ //
+
+ NewLength = SocketResources->StackRes[Stack].MmiohLength;
+
+ //
+ //assign the left space to the last IIO stack. Reserved for across socket resource adjustment.
+ //make adjustments if NewLength is zero
+ //
+ if (Stack == LastStack) {
+ if (NewLength != 0) {
+ if (SocketResources->MmiohResourcesLeft) {
+ NewLength += SocketResources->MmiohResourcesLeft + 1;
+ }
+ } else {
+ NewLength = SocketResources->MmiohResourcesLeft;
+ }
+ }
+
+ SocketResources->StackRes[Stack].MmiohUpdate = 1;
+ SocketResources->StackRes[Stack].MmiohLimit = (SocketResources->StackRes[Stack].MmiohBase + NewLength);
+ PreviousLimit = SocketResources->StackRes[Stack].MmiohLimit;
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohBase =%lx newLength = %lx\n",Socket,Stack,SocketResources->StackRes[Stack].MmiohBase,NewLength));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohLimit =%lx\n",Socket,Stack,SocketResources->StackRes[Stack].MmiohLimit));
+
+ } // for Stack
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "[PCI] ERROR: Resource Type Unknown = %x\n", ResourceType));
+ break;
+ }// switch
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Adjust resource ratio assignment among sockets to fit the resource needs from PCI devices.
+
+ @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
+ @param ResourceType - type of resource that requires alignment
+ @param ValidSockets - Number of Valid Sockets, need it to calculate how resources need to be splitted
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
+**/
+EFI_STATUS
+AdjustSocketResources (
+ CPU_RESOURCE *SocketResources,
+ UINT8 ResourceType,
+ UINT8 ValidSockets
+ )
+{
+ EFI_STATUS Status;
+
+ switch(ResourceType){
+ case TypeIo:
+ Status = AdjustSocketIo (SocketResources, ResourceType, ValidSockets);
+ break;
+ case TypeMem32:
+ Status = AdjustSocketMmioL (SocketResources, ResourceType, ValidSockets);
+ break;
+ case TypeMem64:
+ Status = AdjustSocketMmioH (SocketResources, ResourceType, ValidSockets);
+ break;
+ default:
+ DEBUG((DEBUG_ERROR, "ERROR: Resource Type Unknown = %x\n",ResourceType));
+ Status = EFI_INVALID_PARAMETER;
+ break;
+ } // switch
+
+ return Status;
+}
+
+
+/**
+ Calculate current system resource map with retrieved NVRAM variable to see if stored settings were applied
+
+ @param[in] SocketPciResourceData - Pointer to stored CPU resource map
+
+ @retval TRUE - SYSTEM_PCI_BASE_LIMITS has been rejected and was not applied or not initialized
+ @retval FALSE - SYSTEM_PCI_BASE_LIMITS has been applied and still has relevant data
+**/
+BOOLEAN
+IsResourceMapRejected (
+ SYSTEM_PCI_BASE_LIMITS *SocketPciResourceData
+ )
+{
+ UINT8 Socket;
+ UINT8 Stack;
+ BOOLEAN Rejected = FALSE;
+ PCI_BASE_LIMITS *StackLimits;
+ PCI_BASE_LIMITS *UboxStackLimits;
+ PCI_BASE_LIMITS *SocketLimits;
+ STACK_RES *IioUdsUboxStackLimits;
+ STACK_RES *IioUdsStackLimits;
+ IIO_RESOURCE_INSTANCE *IioUdsSocketLimits;
+
+ if (SocketPciResourceData == NULL) {
+ return TRUE;
+ }
+ for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+
+ IioUdsSocketLimits = &mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket];
+ SocketLimits = &SocketPciResourceData->Socket[Socket].SocketLimits;
+ IioUdsUboxStackLimits = &mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UBOX_STACK];
+ UboxStackLimits = &SocketPciResourceData->Socket[Socket].StackLimits[UBOX_STACK];
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+
+ if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack)) {
+
+ IioUdsStackLimits = &mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack];
+ StackLimits = &SocketPciResourceData->Socket[Socket].StackLimits[Stack];
+ //
+ // Per stack
+ //
+ if (Socket == 0 && Stack == 0) {
+ // First base starts at zero, mIioUds struct reserves 4K of Io for legacy purposes
+ if (StackLimits->Io.Base != 0) {
+ Rejected = TRUE;
+ }
+ } else {
+ if (IioUdsStackLimits->PciResourceIoBase != StackLimits->Io.Base && StackLimits->Io.Base != 0) {
+ Rejected = TRUE;
+ }
+ }
+ if (IioUdsStackLimits->PciResourceIoLimit != StackLimits->Io.Limit && StackLimits->Io.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d.%d] Current I/O: 0x%04X..0x%04X\n", Socket, Stack,
+ IioUdsStackLimits->PciResourceIoBase, IioUdsStackLimits->PciResourceIoLimit);
+ PCIDEBUG ("[%d.%d] Saved I/O: 0x%04X..0x%04X %a\n", Socket, Stack,
+ StackLimits->Io.Base, StackLimits->Io.Limit, Rejected ? "rejected" : "");
+
+ if (IioUdsStackLimits->Mmio32Base != StackLimits->LowMmio.Base && StackLimits->LowMmio.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsStackLimits->Mmio32Limit != StackLimits->LowMmio.Limit && StackLimits->LowMmio.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d.%d] Current MMIOL: 0x%08X..0x%08X\n", Socket, Stack,
+ IioUdsStackLimits->Mmio32Base, IioUdsStackLimits->Mmio32Limit);
+ PCIDEBUG ("[%d.%d] Saved MMIOL: 0x%08X..0x%08X %a\n", Socket, Stack,
+ StackLimits->LowMmio.Base, StackLimits->LowMmio.Limit, Rejected ? "rejected" : "");
+
+ if (IioUdsStackLimits->Mmio64Base != StackLimits->HighMmio.Base && StackLimits->HighMmio.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsStackLimits->Mmio64Limit != StackLimits->HighMmio.Limit && StackLimits->HighMmio.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d.%d] Current MMIOH: 0x%012llX..0x%012llX\n", Socket, Stack,
+ IioUdsStackLimits->Mmio64Base, IioUdsStackLimits->Mmio64Limit);
+ PCIDEBUG ("[%d.%d] Saved MMIOH: 0x%012llX..0x%012llX %a\n", Socket, Stack,
+ StackLimits->HighMmio.Base, StackLimits->HighMmio.Limit, Rejected ? "rejected" : "");
+ }
+ }
+ //
+ // Per socket
+ //
+ if (IioUdsSocketLimits->PciResourceIoBase != SocketLimits->Io.Base && SocketLimits->Io.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsSocketLimits->PciResourceIoLimit != SocketLimits->Io.Limit && SocketLimits->Io.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG("[%d] Current I/O: 0x%04X..0x%04X\n", Socket,
+ IioUdsSocketLimits->PciResourceIoBase, IioUdsSocketLimits->PciResourceIoLimit);
+ PCIDEBUG("[%d] Saved I/O: 0x%04X..0x%04X %a\n", Socket,
+ SocketLimits->Io.Base, SocketLimits->Io.Limit, Rejected ? "rejected" : "");
+
+ if (IioUdsSocketLimits->Mmio32Base != SocketLimits->LowMmio.Base && SocketLimits->LowMmio.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsSocketLimits->Mmio32Limit != SocketLimits->LowMmio.Limit && SocketLimits->LowMmio.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d] Current MMIOL: 0x%08X..0x%08X\n", Socket,
+ IioUdsSocketLimits->Mmio32Base, IioUdsSocketLimits->Mmio32Limit);
+ PCIDEBUG ("[%d] Saved MMIOL: 0x%08X..0x%08X %a\n", Socket,
+ SocketLimits->LowMmio.Base, SocketLimits->LowMmio.Limit, Rejected ? "rejected" : "");
+
+ if (IioUdsSocketLimits->Mmio64Base != SocketLimits->HighMmio.Base && SocketLimits->HighMmio.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsSocketLimits->Mmio64Limit != SocketLimits->HighMmio.Limit && SocketLimits->HighMmio.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d] Current MMIOH: 0x%012llX..0x%012llX\n", Socket,
+ IioUdsSocketLimits->Mmio64Base, IioUdsSocketLimits->Mmio64Limit);
+ PCIDEBUG ("[%d] Saved MMIOH: 0x%012llX..0x%012llX %a\n", Socket,
+ SocketLimits->HighMmio.Base, SocketLimits->HighMmio.Limit, Rejected ? "rejected" : "");
+
+ if (IioUdsUboxStackLimits->Mmio64Base != UboxStackLimits->HighMmio.Base && UboxStackLimits->HighMmio.Base != 0) {
+ Rejected = TRUE;
+ }
+ if (IioUdsUboxStackLimits->Mmio64Limit != UboxStackLimits->HighMmio.Limit && UboxStackLimits->HighMmio.Limit != 0) {
+ Rejected = TRUE;
+ }
+ PCIDEBUG ("[%d] Current UBOX: 0x%08X..0x%08X\n", Socket,
+ IioUdsUboxStackLimits->Mmio64Base, IioUdsUboxStackLimits->Mmio64Limit);
+ PCIDEBUG ("[%d] Saved UBOX: 0x%08X..0x%08X %a\n", Socket,
+ UboxStackLimits->HighMmio.Base, UboxStackLimits->HighMmio.Limit, Rejected ? "rejected" : "");
+ }
+ }
+ DEBUG ((DEBUG_INFO, "[PCI] Resource rebalance rejected ? %a\n", Rejected ? "TRUE" : "FALSE"));
+ return Rejected;
+}
+
+
+/**
+ Read SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME variable from flash and verify its content.
+
+ If the variable does not exist, or is not valid for current system configuration
+ the buffer at *PciResConfigPtr is just cleared.
+
+ @param[out] PciResConfigPtr - Buffer for the resource configuration variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+PciHostReadResourceConfig (
+ OUT SYSTEM_PCI_BASE_LIMITS *PciResConfigPtr
+ )
+{
+ UINTN VarSize;
+ EFI_STATUS Status;
+ UINT8 Socket;
+
+ VarSize = sizeof(*PciResConfigPtr);
+ Status = gRT->GetVariable (SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, &gEfiSocketPciResourceDataGuid,
+ NULL, &VarSize, PciResConfigPtr);
+ if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
+ goto ErrExit;
+ }
+ if (Status == EFI_BUFFER_TOO_SMALL || VarSize != sizeof(*PciResConfigPtr)) {
+
+ PCIDEBUG ("Got variable '%s' of unexpected size %d (expect %d) - overwrite\n",
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, VarSize, sizeof(*PciResConfigPtr));
+ Status = EFI_NOT_FOUND;
+ goto ErrExit;
+ }
+ //
+ // If any of the below checks fails clear the buffer and return EFI_NOT_FOUND.
+ //
+ Status = EFI_NOT_FOUND;
+ if (PciResConfigPtr->MmioHBase != mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base ||
+ PciResConfigPtr->MmioHLimit != mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit) {
+
+ PCIDEBUG ("%s: Memory map changed (MMIOH %012llX..%012llX != %012llX..%012llX) - overwrite\n",
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME,
+ PciResConfigPtr->MmioHBase, PciResConfigPtr->MmioHLimit,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit);
+ goto ErrExit;
+ }
+ if (PciResConfigPtr->MmioLBase != mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base ||
+ PciResConfigPtr->MmioLLimit != mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Limit) {
+
+ PCIDEBUG ("%s: Memory map changed (MMIOL %08X..%08X != %08X..%08X) - overwrite\n",
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME,
+ PciResConfigPtr->MmioLBase, PciResConfigPtr->MmioLLimit,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Limit);
+ goto ErrExit;
+ }
+ if (PciResConfigPtr->IoBase != mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoBase ||
+ PciResConfigPtr->IoLimit != mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoLimit) {
+
+ PCIDEBUG ("%s: Memory map changed (I/O %04X..%04X != %04X..%04X) - overwrite\n",
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME,
+ PciResConfigPtr->IoBase, PciResConfigPtr->IoLimit,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoBase,
+ mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoLimit);
+ goto ErrExit;
+ }
+ for (Socket = 0; Socket < NELEMENTS (PciResConfigPtr->Socket); Socket++) {
+
+ if (PciResConfigPtr->StackPresentBitmap[Socket] !=
+ mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap) {
+
+ PCIDEBUG ("%s: Stack bitmap mismach (%04X != %04X) in socket %d - overwrite\n",
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, PciResConfigPtr->StackPresentBitmap[Socket],
+ mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap, Socket);
+ goto ErrExit;
+ }
+ }
+ return EFI_SUCCESS;
+
+ ErrExit:
+ ZeroMem (PciResConfigPtr, sizeof(*PciResConfigPtr));
+ return Status;
+} // PciHostReadResourceConfig()
+
+
+/**
+ Adjust resource ratio assignment among CPU sockets to fit the resource needs from PCI devices.
+ Update Setup variable if there are changes from the existing ratio requests for this boot.
+
+ @param[in] HostBridgeInstance - The Host Bridge Instance where the resource adjustment happens.
+ @param[out] Result - Output parameter. Indicates whether changes have been made.
+**/
+VOID
+AdjustResourceAmongRootBridges (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance,
+ OUT SOCKET_RESOURCE_ADJUSTMENT_RESULT *Result
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgeInstance;
+ LIST_ENTRY *List;
+ CPU_RESOURCE SocketResources[MAX_SOCKET];
+ UINT64 SocketIoLength;
+ UINT64 SocketMem32Length;
+ UINT64 SocketMem64Length;
+ UINT64 SocketIoBase;
+ UINT64 SocketMem32Base;
+ UINT64 SocketMem64Base;
+ UINT64 RsvLenAtBegin;
+ UINT64 RsvLenAtEnd;
+ UINT64 StackLength;
+ UINT64 NewLength;
+ UINT64 Alignment;
+ UINT64 Remainder;
+ UINT8 Socket;
+ UINT8 ValidSockets;
+ BOOLEAN ChangedType[TypeMax];
+ BOOLEAN ChangedTypeOOR[TypeMax]; // Change type for out of resources
+ UINT8 TypeIndex;
+ UINT8 ChangedBitMap;
+ EFI_STATUS Status;
+ SYSTEM_PCI_BASE_LIMITS SocketPciResourceData;
+ UINT8 Stack;
+ UINT8 LastStack;
+ UINT16 IoGranularity;
+ UINT32 MmiolGranularity;
+ UINT64 MmiohGranularity;
+ BOOLEAN OutOfResources;
+ UINT32 UboxMmioSize;
+ BOOLEAN IsVirtualRootBridge;
+ PCI_BASE_LIMITS *CurStackLimits;
+ PCI_BASE_LIMITS *UboxStackLimits;
+ PCI_BASE_LIMITS *CurSocketLimits;
+ UINT32 PlatGlobalMmiolBase;
+ UINT32 VtdBarSize;
+
+ *Result = SocketResourceRatioNotChanged;
+ SetMem (ChangedType, TypeMax, FALSE);
+ SetMem (ChangedTypeOOR, TypeMax, FALSE);
+ ChangedBitMap = 0;
+ OutOfResources = FALSE;
+ IsVirtualRootBridge = FALSE;
+
+ IoGranularity = mIioUds->IioUdsPtr->PlatformData.IoGranularity;
+ MmiolGranularity = mIioUds->IioUdsPtr->PlatformData.MmiolGranularity;
+ MmiohGranularity = (UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.lo;
+ MmiohGranularity |= ((UINT64)mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.hi) << 32;
+ ZeroMem (&SocketResources[0], sizeof(SocketResources));
+ //
+ // Read the system resource cfg from NVRAM. If the variable does not exist, or is
+ // not valid for current system configuration the buffer SocketPciResourceData
+ // is just cleared.
+ //
+ Status = PciHostReadResourceConfig (&SocketPciResourceData);
+ if (EFI_ERROR (Status)) {
+
+ if (Status != EFI_NOT_FOUND) {
+
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+ //
+ // Variable is not initialized yet, go with empty structure.
+ //
+ } else if (IsResourceMapRejected (&SocketPciResourceData)) {
+ //
+ // If variable is already initialized, but rejected by KTI do not reboot to avoid loop.
+ //
+ return;
+ }
+
+ UboxMmioSize = mIioUds->IioUdsPtr->PlatformData.UboxMmioSize;
+ PlatGlobalMmiolBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base;
+ ValidSockets = 0;
+ for (List = HostBridgeInstance->RootBridges.ForwardLink, Socket = 0; Socket < MAX_SOCKET; Socket ++) {
+
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+ continue;
+ }
+ ValidSockets++;
+ //
+ // Calculate the length of resources available per socket
+ //
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoBase >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoLimit) {
+ SocketIoBase = 0;
+ SocketIoLength = 0;
+ } else {
+ SocketIoBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoBase;
+ SocketIoLength = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoLimit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceIoBase;
+ }
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Base >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Limit) {
+ SocketMem32Base = 0;
+ SocketMem32Length = 0;
+ } else {
+ SocketMem32Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Base;
+ SocketMem32Length = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Base;
+ // Reserve 8M for ubox mmio
+ SocketMem32Length = SocketMem32Length - UboxMmioSize;
+ }
+
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Base >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Limit) {
+ SocketMem64Base = 0;
+ SocketMem64Length = 0;
+ } else{
+ SocketMem64Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Base;
+ SocketMem64Length = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Base;
+ }
+
+ // Get all the resources that are in this socket
+ SocketResources[Socket].IoResourcesLeft = (UINT16)SocketIoLength;
+ SocketResources[Socket].MmiolResourcesLeft = (UINT32)SocketMem32Length;
+ SocketResources[Socket].MmiohResourcesLeft = (UINT64)SocketMem64Length;
+
+ LastStack = LastStackOfSocket (Socket);
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ RootBridgeInstance = ROOT_BRIDGE_FROM_LINK (List);
+ //
+ // Check IO Resource
+ //
+ Alignment = RootBridgeInstance->ResAllocNode[TypeIo].Alignment + 1;
+ NewLength = RootBridgeInstance->ResAllocNode[TypeIo].Length;
+
+ if (IsVirtualRootBridge) {
+ NewLength += NewLength;
+ }
+ // IoTrap allocates 256 byte range from GCD for common pool usage
+ // For device to fit move to the next available alignment
+ if ((Socket == 0) && (Stack == 0)) {
+ NewLength += Alignment;
+ }
+
+ if (NewLength != 0) {
+ //
+ // At least 2KB align per KTI requirement. Add the length requested with given alignment.
+ // If the sum is not 2KB aligned add on the remainder that would make it align.
+ // Bump up to 4KB for root bridge requirements
+ // Have to make sure Alignment is handled for direct address allocation
+ //
+ Remainder = SocketIoBase & (Alignment - 1);
+ if (Remainder != 0) {
+ NewLength += Alignment - Remainder;
+ }
+ if (NewLength % (IoGranularity * 2)) {
+ Remainder = (IoGranularity * 2) - (NewLength % (IoGranularity * 2));
+ NewLength += Remainder;
+ }
+ //
+ // Store length as length - 1 for handling
+ //
+ NewLength -= 1;
+
+ // Zero StackLength if its disable or negative
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoBase >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoLimit) {
+ StackLength = 0;
+ } else {
+ StackLength = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoLimit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoBase;
+ }
+ SocketResources[Socket].StackRes[Stack].NumIoPortsDesired = (UINT16)NewLength;
+ // Check if new length can fit in the socket or stack
+ if (SocketResources[Socket].IoResourcesLeft > (UINT16)NewLength) {
+ SocketResources[Socket].IoResourcesLeft -= (UINT16)NewLength + 1;
+ } else if (SocketResources[Socket].IoResourcesLeft == (UINT16)NewLength) {
+ SocketResources[Socket].IoResourcesLeft -= (UINT16)NewLength;
+ } else {
+ // If there are resources left consume them
+ if (SocketResources[Socket].IoResourcesLeft != 0) {
+ NewLength = NewLength - SocketResources[Socket].IoResourcesLeft - 1;
+ SocketResources[Socket].IoResourcesLeft = 0;
+ }
+
+ SocketResources[Socket].IoResourceNeeds += (UINT16)NewLength + 1;
+ OutOfResources = TRUE;
+ ChangedTypeOOR[TypeIo] = TRUE;
+ }
+ SocketResources[Socket].StackRes[Stack].IoAlignment = Alignment;
+ if (NewLength > StackLength) {
+ SocketResources[Socket].StackRes[Stack].NeedIoUpdate = TRUE;
+
+ //IoResourcesLeft is UINT16 type, not 2's-complement value.
+ if (SocketResources[Socket].IoResourcesLeft > SocketIoLength) {
+ DEBUG ((DEBUG_ERROR, "[PCI] Out of Resources for Socket = %x Stack = %x Type = %x\n",
+ Socket, Stack, TypeIo));
+ SocketResources[Socket].IoResourcesLeft = 0;
+ }
+ ChangedType[TypeIo] = TRUE;
+ }
+ SocketIoBase += SocketResources[Socket].StackRes[Stack].NumIoPortsDesired + 1;
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].IoResourceLeft = %x\n",
+ Socket, SocketResources[Socket].IoResourcesLeft));
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoAlignment = %x\n",
+ Socket, Stack, SocketResources[Socket].StackRes[Stack].IoAlignment));
+ } else {
+ SocketResources[Socket].StackRes[Stack].NumIoPortsDesired = 0;
+ }
+ //
+ // Check Mmem32 resource. This Host bridge does not support separated MEM / PMEM requests,
+ // so only count MEM requests here.
+ //
+ Alignment = RootBridgeInstance->ResAllocNode[TypeMem32].Alignment + 1;
+ NewLength = RootBridgeInstance->ResAllocNode[TypeMem32].Length;
+ //
+ // Account for reserved regions at begin and end of the stack MMIO32 region.
+ //
+ RsvLenAtBegin = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Base -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Base;
+
+ RsvLenAtEnd = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Limit;
+ NewLength += RsvLenAtBegin + RsvLenAtEnd;
+ if (Alignment < RsvLenAtBegin) {
+ Alignment = RsvLenAtBegin;
+ }
+ if (Alignment < RsvLenAtEnd) {
+ Alignment = RsvLenAtEnd;
+ }
+ //
+ // Always account for VT-d reserved resource ranges.
+ // TODO: Remove when VTd BAR is included in RsvLenAtEnd.
+ //
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].VtdBarAddress != 0) {
+
+ VtdBarSize = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].VtdBarAddress + 1;
+ NewLength += VtdBarSize;
+ if (Alignment < VtdBarSize) {
+ Alignment = VtdBarSize;
+ }
+ }
+
+ if (IsVirtualRootBridge) {
+ NewLength += NewLength;
+ }
+ // PCH Allocates reserved MMIO for Sx SMI handler use
+ // For device to fit move to the next available alignment
+ if ((Socket == 0) && (Stack == 0)) {
+ NewLength += Alignment;
+ }
+
+ if (NewLength != 0) {
+ //
+ // At least 4MB align per KTI requirement. Add the length requested with given alignment.
+ // If the sum is not 4MB aligned add on the remainder that would make it align.
+ // Have to make sure Alignment is handled for direct address allocation
+ //
+ Remainder = SocketMem32Base & (Alignment - 1);
+ if (Remainder != 0) {
+ NewLength += Alignment - Remainder;
+ }
+ if (NewLength % MmiolGranularity) {
+
+ Remainder = MmiolGranularity - (NewLength % MmiolGranularity);
+ NewLength += Remainder;
+ }
+
+ if (Stack == LastStack) {
+ //
+ // Ubox address must be 8MB aligned for the base address on most processors; skip check
+ // if uboxMmioSize is 0 (avoid divide by zero exception).
+ // At this point the requested resource has already been calculated to be satisfied.
+ // Add granularity padding if necessary to satisfy Ubox requirement.
+ //
+ if (UboxMmioSize != 0 && (SocketMem32Base + NewLength) % UboxMmioSize) {
+ Remainder = UboxMmioSize - (NewLength % UboxMmioSize);
+ NewLength += Remainder;
+ }
+ }
+ //
+ // Store length as length - 1 for handling
+ //
+ NewLength -= 1;
+
+ // Zero StackLength if its disable or negative
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Base >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Limit) {
+ StackLength = 0;
+ } else {
+ StackLength = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio32Base;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiolLength = (UINT32)NewLength;
+
+ // Check if new length can fit in the socket or stack
+ if (SocketResources[Socket].MmiolResourcesLeft > (UINT32)NewLength) {
+ SocketResources[Socket].MmiolResourcesLeft -= (UINT32)NewLength + 1;
+ } else if (SocketResources[Socket].MmiolResourcesLeft == (UINT32)NewLength) {
+ SocketResources[Socket].MmiolResourcesLeft -= (UINT32)NewLength;
+ } else {
+ // If there are resources left consume them
+ if (SocketResources[Socket].MmiolResourcesLeft) {
+ NewLength = NewLength - SocketResources[Socket].MmiolResourcesLeft - 1;
+ SocketResources[Socket].MmiolResourcesLeft = 0;
+ }
+
+ SocketResources[Socket].MmiolResourceNeeds += (UINT32)NewLength + 1;
+ OutOfResources = TRUE;
+ ChangedTypeOOR[TypeMem32] = TRUE;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiolAlignment = Alignment;
+
+ if (NewLength > StackLength) {
+ SocketResources[Socket].StackRes[Stack].MmiolUpdate = 1;
+
+ //MmiolResourcesLeft is UINT32 type, not 2's-complement value.
+ if (SocketResources[Socket].MmiolResourcesLeft > SocketMem32Length) {
+ DEBUG ((DEBUG_ERROR, "Out of Resources for Socket = %x Stack = %x Type = %x\n",
+ Socket, Stack, TypeMem32));
+ SocketResources[Socket].MmiolResourcesLeft = 0;
+ }
+ ChangedType[TypeMem32] = TRUE;
+ }
+ SocketMem32Base += SocketResources[Socket].StackRes[Stack].MmiolLength + 1;
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiolResourceLeft = %x\n",
+ Socket, SocketResources[Socket].MmiolResourcesLeft));
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolAlignment = %x\n",
+ Socket, Stack, SocketResources[Socket].StackRes[Stack].MmiolAlignment));
+ } else {
+ SocketResources[Socket].StackRes[Stack].MmiolLength = 0;
+ }
+ //
+ // Check Mem64 resource. This Host bridge does not support separated MEM / PMEM requests, so only count MEM requests here.
+ //
+ Alignment = RootBridgeInstance->ResAllocNode[TypeMem64].Alignment + 1;
+ NewLength = RootBridgeInstance->ResAllocNode[TypeMem64].Length;
+ //
+ // Account for reserved regions at begin and end of the stack MMIO32 region.
+ //
+ RsvLenAtBegin = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Base -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Base;
+
+ RsvLenAtEnd = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Limit;
+ NewLength += RsvLenAtBegin + RsvLenAtEnd;
+ if (Alignment < RsvLenAtBegin) {
+ Alignment = RsvLenAtBegin;
+ }
+ if (Alignment < RsvLenAtEnd) {
+ Alignment = RsvLenAtEnd;
+ }
+ if (IsVirtualRootBridge) {
+ NewLength += NewLength;
+ }
+
+ if (NewLength != 0) {
+ //
+ // At least 1GB align per KTI requirement. Add the length requested with given alignment.
+ // If the sum is not 1GB aligned add on the remainder that would make it align.
+ // Have to make sure Alignment is handled for direct address allocation
+ //
+ Remainder = SocketMem64Base & (Alignment - 1);
+ if (Remainder != 0) {
+ NewLength += Alignment - Remainder;
+ }
+ if (NewLength % MmiohGranularity) {
+ Remainder = MmiohGranularity - (NewLength % MmiohGranularity);
+ NewLength += Remainder;
+ }
+ //
+ // Store length as length - 1 for handling
+ //
+ NewLength -= 1;
+
+ // Zero StackLength if it's disable or negative
+ if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Base >=
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Limit) {
+ StackLength = 0;
+ } else {
+ StackLength = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Limit -
+ mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].Mmio64Base;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiohLength = NewLength;
+
+ // Check if new length can fit in the socket or stack
+ if (SocketResources[Socket].MmiohResourcesLeft > NewLength) {
+ SocketResources[Socket].MmiohResourcesLeft -= NewLength + 1;
+ } else if (SocketResources[Socket].MmiohResourcesLeft == NewLength) {
+ SocketResources[Socket].MmiohResourcesLeft -= NewLength;
+ } else {
+ // If there are resources left consume them
+ if (SocketResources[Socket].MmiohResourcesLeft != 0) {
+ NewLength = NewLength - SocketResources[Socket].MmiohResourcesLeft - 1;
+ SocketResources[Socket].MmiohResourcesLeft = 0;
+ }
+
+ SocketResources[Socket].MmiohResourceNeeds += NewLength + 1;
+ OutOfResources = TRUE;
+ ChangedTypeOOR[TypeMem64] = TRUE;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiohAlignment = Alignment;
+
+ if (NewLength > StackLength) {
+ SocketResources[Socket].StackRes[Stack].MmiohUpdate = 1;
+
+ //MmiohResourcesLeft is UINT64 type, not 2's-complement value.
+ if (SocketResources[Socket].MmiohResourcesLeft > SocketMem64Length) {
+ DEBUG ((DEBUG_ERROR, "Out of Resources for Socket = %x Stack = %x Type = %x\n",
+ Socket, Stack, TypeMem64));
+ SocketResources[Socket].MmiohResourcesLeft = 0;
+ }
+ ChangedType[TypeMem64] = TRUE;
+ }
+ SocketMem64Base += SocketResources[Socket].StackRes[Stack].MmiohLength + 1;
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiohResourceLeft = %lx\n",
+ Socket, SocketResources[Socket].MmiohResourcesLeft));
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohAlignment = %lx\n",
+ Socket, Stack, SocketResources[Socket].StackRes[Stack].MmiohAlignment));
+ } else {
+ SocketResources[Socket].StackRes[Stack].MmiohLength = 0;
+ }
+
+ List = List->ForwardLink;
+
+ } // for Stack
+
+ // Check and update all resource types in socket that needs adjustment
+ for (TypeIndex = 0; TypeIndex < TypeMax; TypeIndex++) {
+
+ if (ChangedType[TypeIndex]) {
+
+ DEBUG ((DEBUG_INFO, "[%d] Adjust stack %s resources...\n", Socket, mPciResourceTypeStr[TypeIndex]));
+ Status = AdjustResources (&SocketResources[Socket], Socket, TypeIndex);
+ ChangedType[TypeIndex] = FALSE;
+ if (Status == EFI_SUCCESS) {
+ ChangedBitMap |= (1 << TypeIndex);
+ } else {
+ ChangedBitMap &= ~(1 << TypeIndex);
+ }
+ }
+ }
+ //
+ // Account for Ubox resources to accurately calculate new alignments for the next socket
+ //
+ SocketMem32Base += UboxMmioSize;
+ } // for Socket ..
+
+ ASSERT (List == &HostBridgeInstance->RootBridges);
+
+ //
+ // If a socket is out of resources, try to adjusting sockets for more room.
+ //
+ if (OutOfResources && (MAX_SOCKET > 1) && (ValidSockets > 1)) {
+
+ for (TypeIndex = 0; TypeIndex < TypeMax; TypeIndex++) {
+
+ if (ChangedTypeOOR[TypeIndex]) {
+
+ DEBUG ((DEBUG_INFO, "Adjust socket %s resources...\n", mPciResourceTypeStr[TypeIndex]));
+ Status = AdjustSocketResources (SocketResources, TypeIndex, ValidSockets);
+ if (Status == EFI_SUCCESS) {
+ ChangedBitMap |= (1 << TypeIndex);
+ } else {
+ ChangedBitMap &= ~(1 << TypeIndex);
+ }
+ }
+ }
+ } else if (OutOfResources && ChangedTypeOOR[TypeMem64]){
+ //
+ // Allow mmioh to be adjusted to access max available physical address range.
+ //
+ Status = AdjustSocketResources (SocketResources, TypeMem64, ValidSockets);
+ if (Status == EFI_SUCCESS) {
+ ChangedBitMap |= (1 << TypeIndex);
+ } else {
+ ChangedBitMap &= ~(1 << TypeIndex);
+ }
+ }
+
+ // Update changed resource type.
+ // OemGetResourceMapUpdate() will only update changed resource type so it is alright if data is zero.
+ if (ChangedBitMap != 0) {
+
+ for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+
+ SocketPciResourceData.StackPresentBitmap[Socket] = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap;
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ CurStackLimits = &SocketPciResourceData.Socket[Socket].StackLimits[Stack];
+
+ //
+ // Disable stacks that have no resources and are assigned none.
+ // Reaching this far means the stack is valid and should be disabled if base equals limit and
+ // length is zero.
+ // Assigned address will be none zero at this point because CSTACK takes the first 4K in legacy
+ // IO space.
+ //
+ if ((SocketResources[Socket].StackRes[Stack].NeedIoUpdate) &&
+ (SocketResources[Socket].StackRes[Stack].IoLimit -
+ SocketResources[Socket].StackRes[Stack].IoBase == 0)) {
+ SocketResources[Socket].StackRes[Stack].IoBase = (UINT16)(-1);
+ SocketResources[Socket].StackRes[Stack].IoLimit = 0;
+ }
+
+ if ((SocketResources[Socket].StackRes[Stack].MmiolUpdate) &&
+ (SocketResources[Socket].StackRes[Stack].MmiolLimit -
+ SocketResources[Socket].StackRes[Stack].MmiolBase == 0)) {
+ SocketResources[Socket].StackRes[Stack].MmiolBase = (UINT32)(-1);
+ SocketResources[Socket].StackRes[Stack].MmiolLimit = 0;
+ }
+
+ if ((SocketResources[Socket].StackRes[Stack].MmiohUpdate) &&
+ (SocketResources[Socket].StackRes[Stack].MmiohLimit -
+ SocketResources[Socket].StackRes[Stack].MmiohBase == 0)) {
+ SocketResources[Socket].StackRes[Stack].MmiohBase = (UINT64)(-1);
+ SocketResources[Socket].StackRes[Stack].MmiohLimit = 0;
+ }
+
+ // Zero base if 4K because mIioUds struct reserves 4K of Io for legacy purposes
+ // Remove if mIioUds first base starts at zero
+ if (SocketResources[Socket].StackRes[Stack].IoBase == 0x1000){
+ SocketResources[Socket].StackRes[Stack].IoBase = 0;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].NeedIoUpdate) {
+ CurStackLimits->Io.Base = SocketResources[Socket].StackRes[Stack].IoBase;
+ CurStackLimits->Io.Limit = SocketResources[Socket].StackRes[Stack].IoLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiolUpdate) {
+ if ((Socket == 0) && (Stack == 0)) {
+ CurStackLimits->LowMmio.Base = PlatGlobalMmiolBase;
+ } else {
+ CurStackLimits->LowMmio.Base = SocketResources[Socket].StackRes[Stack].MmiolBase;
+ }
+ CurStackLimits->LowMmio.Limit = SocketResources[Socket].StackRes[Stack].MmiolLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiohUpdate) {
+ CurStackLimits->HighMmio.Base = SocketResources[Socket].StackRes[Stack].MmiohBase;
+ CurStackLimits->HighMmio.Limit = SocketResources[Socket].StackRes[Stack].MmiohLimit;
+ }
+
+ DEBUG((DEBUG_INFO, "\nSocketResources[%x].StackRes[%x].IoBase =%x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].IoBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoLimit =%x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].IoLimit));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolBase =%x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiolBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolLimit =%x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiolLimit));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohBase =%lx\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiohBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohLimit =%lx\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiohLimit));
+ } // for Stack
+
+ // Initialize to disabled
+ SocketResources[Socket].IoBase = (UINT16)(-1);
+ SocketResources[Socket].IoLimit = 0;
+ SocketResources[Socket].MmiolBase = (UINT32)(-1);
+ SocketResources[Socket].MmiolLimit = 0;
+ SocketResources[Socket].MmiohBase = (UINT64)(-1);
+ SocketResources[Socket].MmiohLimit = 0;
+
+ // Search backwards to find the beginning valid stack
+ for (Stack = MAX_IIO_STACK - 1; Stack < MAX_IIO_STACK ; Stack--) {
+ CurSocketLimits = &SocketPciResourceData.Socket[Socket].SocketLimits;
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].IoBase != (UINT16)(-1)) {
+ SocketResources[Socket].IoBase = SocketResources[Socket].StackRes[Stack].IoBase;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiolBase != (UINT32)(-1)) {
+ SocketResources[Socket].MmiolBase = SocketResources[Socket].StackRes[Stack].MmiolBase;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiohBase != (UINT64)(-1)) {
+ SocketResources[Socket].MmiohBase = SocketResources[Socket].StackRes[Stack].MmiohBase;
+ }
+ } // for Stack
+
+ // Search to find the last valid limit
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].IoLimit != 0) {
+ SocketResources[Socket].IoLimit = SocketResources[Socket].StackRes[Stack].IoLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiolLimit) {
+ SocketResources[Socket].MmiolLimit = SocketResources[Socket].StackRes[Stack].MmiolLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[Stack].MmiohLimit) {
+ SocketResources[Socket].MmiohLimit = SocketResources[Socket].StackRes[Stack].MmiohLimit;
+ }
+ } // for Stack
+
+ // Update socket level resource range
+ if (SocketResources[Socket].StackRes[0].NeedIoUpdate) {
+ CurSocketLimits->Io.Base = SocketResources[Socket].IoBase;
+ CurSocketLimits->Io.Limit = SocketResources[Socket].IoLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[0].MmiolUpdate) {
+ //
+ // Apply stolen 8M for ubox mmio per socket
+ //
+ if (UboxMmioSize != 0) {
+ UboxStackLimits = &SocketPciResourceData.Socket[Socket].StackLimits[UBOX_STACK];
+
+ UboxStackLimits->LowMmio.Base = SocketResources[Socket].MmiolLimit + 1;
+ SocketResources[Socket].MmiolLimit = (UINT32)UboxStackLimits->LowMmio.Base + UboxMmioSize - 1;
+ UboxStackLimits->LowMmio.Limit = SocketResources[Socket].MmiolLimit;
+ }
+ CurSocketLimits->LowMmio.Base = SocketResources[Socket].MmiolBase;
+ CurSocketLimits->LowMmio.Limit = SocketResources[Socket].MmiolLimit;
+ }
+
+ if (SocketResources[Socket].StackRes[0].MmiohUpdate) {
+ CurSocketLimits->HighMmio.Base = SocketResources[Socket].MmiohBase;
+ CurSocketLimits->HighMmio.Limit = SocketResources[Socket].MmiohLimit;
+ }
+
+ DEBUG((DEBUG_INFO, "\nSocketResources[%x].UboxBase =%x\n",Socket,UboxStackLimits->LowMmio.Base));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].UboxLimit =%x\n",Socket,UboxStackLimits->LowMmio.Limit));
+ DEBUG((DEBUG_INFO, "\nSocketResources[%x].IoBase =%x\n",Socket,SocketResources[Socket].IoBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].IoLimit =%x\n",Socket,SocketResources[Socket].IoLimit));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].MmiolBase =%x\n",Socket,SocketResources[Socket].MmiolBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].MmiolLimit =%x\n",Socket,SocketResources[Socket].MmiolLimit));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].MmiohBase =%lx\n",Socket,SocketResources[Socket].MmiohBase));
+ DEBUG((DEBUG_INFO, "SocketResources[%x].MmiohLimit =%lx\n",Socket,SocketResources[Socket].MmiohLimit));
+ } // for Socket
+ SocketPciResourceData.MmioHBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base;
+ SocketPciResourceData.MmioHLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit;
+ SocketPciResourceData.MmioLBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base;
+ SocketPciResourceData.MmioLLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Limit;
+ SocketPciResourceData.IoBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoBase;
+ SocketPciResourceData.IoLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoLimit;
+
+ PCIDEBUG("Writing resource rebalance request '%s':\n", SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME);
+ PCIDEBUG("System I/O : %04X..%04X\n", SocketPciResourceData.IoBase, SocketPciResourceData.IoLimit);
+ PCIDEBUG("System MMIOL: %08X..%08X\n", SocketPciResourceData.MmioLBase, SocketPciResourceData.MmioLLimit);
+ PCIDEBUG("System MMIOH: %012llX..%012llX\n", SocketPciResourceData.MmioHBase, SocketPciResourceData.MmioHLimit);
+ for (Socket = 0; Socket < NELEMENTS (SocketPciResourceData.Socket); Socket++) {
+
+ PCIDEBUG("[%d] StackPresent: 0x%04X\n", Socket, SocketPciResourceData.StackPresentBitmap[Socket]);
+ PCIDEBUG("[%d] I/O : %04X..%04X\n", Socket,
+ SocketPciResourceData.Socket[Socket].SocketLimits.Io.Base,
+ SocketPciResourceData.Socket[Socket].SocketLimits.Io.Limit);
+ PCIDEBUG("[%d] MMIOL: %08X..%08X\n", Socket,
+ SocketPciResourceData.Socket[Socket].SocketLimits.LowMmio.Base,
+ SocketPciResourceData.Socket[Socket].SocketLimits.LowMmio.Limit);
+ PCIDEBUG("[%d] MMIOH: %012llX..%012llX\n", Socket,
+ SocketPciResourceData.Socket[Socket].SocketLimits.HighMmio.Base,
+ SocketPciResourceData.Socket[Socket].SocketLimits.HighMmio.Limit);
+ for (Stack = 0; Stack < NELEMENTS (SocketPciResourceData.Socket[Socket].StackLimits); Stack++) {
+
+ PCIDEBUG("[%d.%d] I/O : %04X..%04X\n", Socket, Stack,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].Io.Base,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].Io.Limit);
+ PCIDEBUG("[%d.%d] MMIOL: %08X..%08X\n", Socket, Stack,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].LowMmio.Base,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].LowMmio.Limit);
+ PCIDEBUG("[%d.%d] MMIOH: %012llX..%012llX\n", Socket, Stack,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].HighMmio.Base,
+ SocketPciResourceData.Socket[Socket].StackLimits[Stack].HighMmio.Limit);
+ }
+ }
+
+ *Result = SocketResourceRatioChanged;
+ Status = gRT->SetVariable(
+ SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME,
+ &gEfiSocketPciResourceDataGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof(SocketPciResourceData),
+ &SocketPciResourceData
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+
+ return;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.h
new file mode 100644
index 0000000000..85a9192c12
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalance.h
@@ -0,0 +1,158 @@
+/** @file
+
+ @copyright
+ Copyright 2019 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCIREBALANCE_H_
+#define _PCIREBALANCE_H_
+
+/******************************************************************************
+ * Definitions.
+ ******************************************************************************/
+/**
+ Uncomment the PCIDEBUG macro to enable tracing the library activity in a test build.
+ **/
+#define PCIDEBUG(...) // { DEBUG((DEBUG_INFO, "[PCI] " __VA_ARGS__)); }
+
+typedef enum {
+ SocketResourceRatioChanged,
+ SocketResourceRatioNotChanged,
+ SocketResourceAdjustMax
+} SOCKET_RESOURCE_ADJUSTMENT_RESULT;
+
+typedef struct {
+ UINT16 IoBase; // IO base of each stack
+ UINT16 IoLimit; // IO limit for each stack
+ UINT16 NumIoPortsDesired;
+ UINT64 IoAlignment;
+ BOOLEAN NeedIoUpdate; // Resource allocation required.
+ UINT32 MmiolBase; // Mmiol base of each stack
+ UINT32 MmiolLimit; // Mmiol limit of each stack
+ UINT32 MmiolLength;
+ UINT64 MmiolAlignment;
+ UINT8 MmiolUpdate; // Resource allocation required.
+ UINT64 MmiohBase; // Mmioh base of each stack
+ UINT64 MmiohLimit; // Mmioh limit of each stack
+ UINT64 MmiohLength;
+ UINT64 MmiohAlignment;
+ UINT8 MmiohUpdate; // Resource allocation required.
+} STACK_RESOURCE;
+
+typedef struct{
+ UINT16 IoBase; // Io base of each socket
+ UINT16 IoLimit; // Io limit for each socket
+ UINT16 IoResourcesLeft; // Io resources left over in socket
+ UINT16 IoResourceNeeds; // Io resources lacking in socket
+ UINT32 MmiolBase; // Mmiol base of each socket
+ UINT32 MmiolLimit; // Mmiol limit of each socket
+ UINT32 MmiolResourcesLeft; // Mmiol resources left over in socket
+ UINT32 MmiolResourceNeeds; // Mmiol resources lacking in socket
+ UINT64 MmiohBase; // Mmioh base of each socket
+ UINT64 MmiohLimit; // Mmioh limit of each socket
+ UINT64 MmiohResourcesLeft; // Mmioh resources left over in socket
+ UINT64 MmiohResourceNeeds; // Mmioh resources lacking in socket
+ STACK_RESOURCE StackRes[MAX_LOGIC_IIO_STACK];
+} CPU_RESOURCE;
+
+
+/******************************************************************************
+ * Function prototypes.
+ ******************************************************************************/
+extern PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTable[MAX_SOCKET][MAX_LOGIC_IIO_STACK];
+extern PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTableReserved[MAX_SOCKET][IIO_RESERVED_1];
+
+
+/******************************************************************************
+ * Function prototypes.
+ ******************************************************************************/
+
+/**
+ Adjust resource ratio assignment among CPU sockets to fit the resource needs from PCI devices.
+ Update Setup variable if there are changes from the existing ratio requests for this boot.
+
+ @param HostBridgeInstance - The Host Bridge Instance where the resource adjustment happens.
+ @param Result - Output parameter. Indicates whether changes have been made.
+**/
+VOID
+AdjustResourceAmongRootBridges (
+ IN PCI_HOST_BRIDGE_INSTANCE *HostBridgeInstance,
+ OUT SOCKET_RESOURCE_ADJUSTMENT_RESULT *Result
+ );
+
+EFI_STATUS
+AdjustSocketIo (
+ IN OUT CPU_RESOURCE *SocketResources,
+ IN UINT8 ResourceType,
+ IN UINT8 ValidSockets
+ );
+
+EFI_STATUS
+AdjustSocketMmioH (
+ IN OUT CPU_RESOURCE *SocketResources,
+ IN UINT8 ResourceType,
+ IN UINT8 ValidSockets
+ );
+
+EFI_STATUS
+AdjustSocketMmioL (
+ IN OUT CPU_RESOURCE *SocketResources,
+ IN UINT8 ResourceType,
+ IN UINT8 ValidSockets
+ );
+
+/**
+ Determine the last stack for a given socket
+
+ @param Socket the socket for which the last socket is desired
+
+ @return The number of the last stack is returned.
+*/
+UINT8
+LastStackOfSocket (
+ IN UINT8 Socket
+ );
+
+/**
+ Determine the last stack for a given socket with resources
+
+ @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per stack
+ @param Socket - Index of the Socket
+ @param ResourceType - Type of resource that requires alignment
+ @param LastStack - Pointer that will store the value of the last stack with resources allocated to it
+ @param ResourceSize - Pointer that will store the sum of the requested resource type
+
+ @return The last stack with resources allocated to it and the
+ total amount of resoures requested of the type
+ requested.
+*/
+VOID
+LastStackWithResources (
+ IN CPU_RESOURCE *SocketResources,
+ IN UINT8 Socket,
+ IN PCI_RESOURCE_TYPE ResourceType,
+ OUT UINT8 *LastStack,
+ OUT UINT64 *ResourceSize
+ );
+
+/**
+ Find socket and stack index for given PCI Root Bridge protocol pointer.
+
+ @param[out] PciResConfigPtr - Buffer for the resource configuration variable.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The variable was not found.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
+**/
+EFI_STATUS
+PciRootBridge2SocketStack (
+ IN PCI_ROOT_BRIDGE_INSTANCE *RootBridgePtr,
+ OUT UINT8 *SocketPtr,
+ OUT UINT8 *StackPtr
+ );
+
+#endif // _PCIREBALANCE_H_
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceIo.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceIo.c
new file mode 100644
index 0000000000..cc0fd2b562
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceIo.c
@@ -0,0 +1,218 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/SocketPciResourceData.h>
+#include <Guid/SocketIioVariable.h>
+#include <Protocol/IioUds.h>
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciRebalance.h"
+
+
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+
+/**
+ Return TRUE if the specified socket/stack combination exists,
+ otherwise return FALSE
+
+ @param Socket - the socket to be checked
+ @param Stack - the stack of the socket to be checked
+
+ @retval TRUE - the socket/stack combination exists
+ @retval FALSE - the socket/stack combination does not exist
+*/
+STATIC BOOLEAN
+IsStackPresent (
+ UINT8 Socket,
+ UINT8 Stack
+ )
+{
+ BOOLEAN Result;
+ UINT64 Mask;
+
+ ASSERT (Socket < ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)); // simple overrun check
+ if (Socket >= ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)) {
+ Result = FALSE;
+ goto err_exit;
+ }
+
+ //
+ // if the StackPresentBitmap is a single byte, then we can track 8 stacks,
+ // the sizeof will tell us how many bytes we have, we scale by 8 to
+ // determine the maximum number of stacks we can track. Stacks larger
+ // than this are not present essentially by definition, but could also
+ // be a sign that we need a wider type to store the information; hence we
+ // assert
+ //
+ ASSERT (Stack < 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap));
+ if (Stack >= 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0].stackPresentBitmap)) {
+ Result = FALSE;
+ goto err_exit;
+ }
+
+ Mask = 1;
+ Mask <<= Stack;
+ Result = (Mask & mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap) != 0;
+
+err_exit:
+ return Result;
+}
+
+
+/**
+ Adjust resource assignment among sockets to fit the IO
+ resources from the PCI() devices in the system
+
+ @param SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
+ @param ResourceType - type of resource that requires alignment
+ @param ValidSockets - Number of Valid Sockets, need it
+ to calculate how resources need to
+ be split
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
+**/
+EFI_STATUS
+AdjustSocketIo (
+ CPU_RESOURCE *SocketResources,
+ UINT8 ResourceType,
+ UINT8 ValidSockets
+)
+{
+ UINT64 Base; ///< Next base I/O port number to use
+ UINT64 Limit; ///< Most recent limit for I/O port numbers
+ CONST UINT64 MaxLimit = ((UINT64)1 << 16) - 1; ///< Maximum value for limit; used to ensure we don't overflow
+ CPU_RESOURCE *CurSocketResources; ///< Pointer to the CPU_RESOURE structure for the CPU we
+ ///< are examining
+ STACK_RESOURCE *CurStackResources; ///< Pointer to the STACK_RESOURCE structure for the CPU/Stack
+ ///< we are examining
+ UINT16 NumFreePorts; ///< Number of i/o ports allocated to sockets that are not used
+ UINT8 LastStack; ///< Last enabled stack of the last enabled socket
+ CONST UINT8 LastSocketIndex = ValidSockets - 1; ///< Index of the last socket
+ UINT64 TotalResourceSize;
+ UINT64 ResourceSize;
+ UINT8 Socket; ///< Loop variable used to iterate over the sockets
+ UINT8 Stack; ///< Loop variable used to iterate over the stacks of a given socket
+
+ NumFreePorts = 0;
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ CurSocketResources = &SocketResources[Socket];
+ if (CurSocketResources->IoResourceNeeds == 0 && CurSocketResources->IoResourcesLeft != 0) {
+ ASSERT (NumFreePorts < NumFreePorts + CurSocketResources->IoResourcesLeft + 1); // check for overflow
+ NumFreePorts += CurSocketResources->IoResourcesLeft + 1;
+ CurSocketResources->IoResourcesLeft = 0;
+ }
+ }
+
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ CurSocketResources = &SocketResources[Socket];
+ if (CurSocketResources->IoResourceNeeds != 0 && NumFreePorts >= CurSocketResources->IoResourceNeeds) {
+ ASSERT (NumFreePorts > NumFreePorts - CurSocketResources->IoResourceNeeds); // check for underflow
+ NumFreePorts -= CurSocketResources->IoResourceNeeds;
+ CurSocketResources->IoResourceNeeds = 0;
+ }
+ }
+
+ LastStack = LastStackOfSocket (LastSocketIndex);
+
+ if (NumFreePorts > 0) {
+ CurStackResources = &SocketResources[LastSocketIndex].StackRes[LastStack];
+ if (CurStackResources->NumIoPortsDesired != 0) {
+ CurStackResources->NumIoPortsDesired += NumFreePorts;
+ } else {
+ CurStackResources->NumIoPortsDesired += NumFreePorts - 1;
+ }
+ }
+
+ //
+ // Verify all resource requested can fit into the systems address range.
+ //
+ TotalResourceSize = 0;
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ LastStackWithResources (&SocketResources[Socket], Socket, ResourceType, &LastStack, &ResourceSize);
+ TotalResourceSize += ResourceSize;
+ }
+ DEBUG ((DEBUG_INFO, "Total Request IO Range = %xh\n", TotalResourceSize));
+ DEBUG ((DEBUG_INFO, "Total System IO Range = %xh\n", MaxLimit));
+ if (TotalResourceSize > MaxLimit) {
+ //
+ // Not enough system resources to support the request.
+ // Remove all request to update NVRAM variable for this resource type.
+ //
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ SocketResources[Socket].StackRes[Stack].NeedIoUpdate = 0;
+ }
+ }
+ DEBUG ((DEBUG_ERROR, "ERROR: Out of adjustable IO resources. Can't adjust across sockets\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG((DEBUG_ERROR, "Assigning new socket i/o range...\n"));
+
+ Base = mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].PciResourceIoBase;
+ Limit = Base; // assume no resources are allocated
+ for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
+ DEBUG ((DEBUG_INFO, "socket = %d, Base = %x, Limit =%x, MaxLimit = %x\n", Socket, Base, Limit, MaxLimit));
+ ASSERT (Base < MaxLimit);
+ CurSocketResources->IoBase = (UINT16)Base;
+ DEBUG ((DEBUG_INFO, "set socket io base to %x\n", Base));
+
+ for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
+ Stack < MAX_IIO_STACK;
+ Stack++, CurStackResources++) {
+ if (!IsStackPresent (Socket, Stack)) {
+ DEBUG ((DEBUG_INFO, " Stack %d not present, setting base/limit to 0xffff/0\n", Stack));
+ CurStackResources->IoBase = 0xffff;
+ CurStackResources->IoLimit = 0;
+ continue;
+ }
+
+ if (CurStackResources->NumIoPortsDesired == 0) {
+ DEBUG ((DEBUG_INFO, " Stack %d doesn't need i/o resources, setting base/limit to 0xffff/0\n", Stack));
+ CurStackResources->IoBase = 0xffff;
+ CurStackResources->IoLimit = 0;
+ CurStackResources->NeedIoUpdate = TRUE;
+ continue;
+ }
+
+ DEBUG((DEBUG_INFO, " Stack %d setting i/o base to %x, ports desired was %x\n",
+ Stack, Base, CurStackResources->NumIoPortsDesired));
+ ASSERT (Base < MaxLimit);
+ CurStackResources->IoBase = (UINT16)Base;
+ Limit = Base + CurStackResources->NumIoPortsDesired;
+ DEBUG ((DEBUG_INFO, " limit set to %x (var and stack)\n", Limit));
+ ASSERT (Base <= Limit);
+ ASSERT (Limit <= MaxLimit);
+ CurStackResources->IoLimit = (UINT16)Limit;
+ CurStackResources->NeedIoUpdate = TRUE;
+ Base = Limit + 1;
+ DEBUG ((DEBUG_INFO, " Base variable updated to %x\n", Base));
+ }
+ ASSERT (Limit <= MaxLimit);
+ DEBUG ((DEBUG_INFO, " Socket %d limit set to %x\n", Socket, Limit));
+ CurSocketResources->IoLimit = (UINT16)Limit;
+ }
+
+ DEBUG ((DEBUG_INFO, "Dumping new I/O requests\n"));
+ for (Socket = 0, CurSocketResources = SocketResources; Socket < ValidSockets; Socket++, CurSocketResources++) {
+ DEBUG((DEBUG_INFO, "socket %d %x/%x\n", Socket, CurSocketResources->IoBase, CurSocketResources->IoLimit));
+ for (Stack = 0, CurStackResources = CurSocketResources->StackRes;
+ Stack < MAX_IIO_STACK;
+ Stack++, CurStackResources++) {
+ DEBUG ((DEBUG_INFO, "%d/%d: %x/%x\n", Socket, Stack, CurStackResources->IoBase, CurStackResources->IoLimit));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio32.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio32.c
new file mode 100644
index 0000000000..41975dee6f
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio32.c
@@ -0,0 +1,163 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/SocketPciResourceData.h>
+#include <Guid/SocketIioVariable.h>
+#include <Protocol/IioUds.h>
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciRebalance.h"
+
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+
+
+/**
+ Adjust resource assignments among sockets to fit the low
+ MMIO resources (32-bit addresses) from the PCI(e) devices in the system
+
+ @param[in,out] SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
+ @param[in] ResourceType - Type of resource that requires alignment
+ @param[in] ValidSockets - Number of Valid Sockets, need it to calculate how resources need to be splitted
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
+ */
+EFI_STATUS
+AdjustSocketMmioL (
+ IN OUT CPU_RESOURCE *SocketResources,
+ IN UINT8 ResourceType,
+ IN UINT8 ValidSockets
+ )
+{
+ CONST UINT8 LastSocket = ValidSockets - 1;
+ UINT8 Socket;
+ UINT8 Stack;
+ UINT8 LastStack;
+ UINT64 Take;
+ UINT32 UboxMmioSize;
+ UINT64 ResourceSize;
+ UINT64 TotalResourceSize;
+ UINT32 TempMmioBase;
+ UINT32 TempMmioLimit;
+
+ Take = 0;
+ UboxMmioSize = mIioUds->IioUdsPtr->PlatformData.UboxMmioSize;
+ //
+ // Get first and last MMIOL address
+ //
+ TempMmioBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base;
+ TempMmioLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Limit;
+ //
+ // Find all the extra space left
+ //
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ if ((SocketResources[Socket].MmiolResourceNeeds == 0) && (SocketResources[Socket].MmiolResourcesLeft != 0)) {
+
+ Take += SocketResources[Socket].MmiolResourcesLeft + 1;
+ SocketResources[Socket].MmiolResourcesLeft = 0;
+ }
+ }
+ //
+ // Give space to sockets that needs more space favoring first come first served
+ //
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ if ((SocketResources[Socket].MmiolResourceNeeds != 0) && (Take >= SocketResources[Socket].MmiolResourceNeeds)) {
+
+ Take -= SocketResources[Socket].MmiolResourceNeeds;
+ DEBUG((DEBUG_ERROR, "SocketResources[%x].MmiolResourceNeeds = %x\n", Socket, SocketResources[Socket].MmiolResourceNeeds));
+ SocketResources[Socket].MmiolResourceNeeds = 0;
+ }
+ }
+ //
+ // Give away leftover resources
+ //
+ LastStack = LastStackOfSocket (LastSocket);
+ if (Take != 0) {
+ if (SocketResources[LastSocket].StackRes[LastStack].MmiolLength != 0) {
+ SocketResources[LastSocket].StackRes[LastStack].MmiolLength += (UINT32)Take;
+ } else{
+ SocketResources[LastSocket].StackRes[LastStack].MmiolLength += ((UINT32)Take - 1);
+ }
+ }
+ //
+ // Verify all resource requested can fit into the systems address range.
+ //
+ TotalResourceSize = 0;
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ LastStackWithResources (&SocketResources[Socket], Socket, ResourceType, &LastStack, &ResourceSize);
+ TotalResourceSize += ResourceSize + UboxMmioSize;
+ }
+ DEBUG ((DEBUG_INFO, "Total Request MMIOL Range = %08Xh\n", TotalResourceSize));
+ DEBUG ((DEBUG_INFO, "Total System MMIOL Range = %08Xh\n", (TempMmioLimit - TempMmioBase + 1)));
+ if (TotalResourceSize > (TempMmioLimit - TempMmioBase + 1)) {
+ //
+ // Not enough system resources to support the request.
+ // Remove all request to update NVRAM variable for this resource type.
+ //
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiolUpdate = 0;
+ }
+ }
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Out of adjustable MMIOL resources. Can't adjust across sockets\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_ERROR, "Assigning new socket MMIOL range...\n"));
+ for (Socket = 0, TempMmioLimit = TempMmioBase - 1; Socket < ValidSockets; Socket ++) {
+
+ SocketResources[Socket].MmiolBase = TempMmioLimit + 1;
+ //
+ // Update the stacks base and limit values.
+ //
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+
+ SocketResources[Socket].StackRes[Stack].MmiolBase = 0;
+ SocketResources[Socket].StackRes[Stack].MmiolLimit = 0;
+
+ } else {
+
+ SocketResources[Socket].StackRes[Stack].MmiolBase = TempMmioLimit + 1;
+ if (SocketResources[Socket].StackRes[Stack].MmiolLength != 0) {
+ //
+ // MmiolLength is actually length-1, so we should move TempMmioLimit by MmiolLength+1,
+ // but only when it is >0, i.e. only for stack that has resources.
+ //
+ TempMmioLimit += SocketResources[Socket].StackRes[Stack].MmiolLength + 1;
+ SocketResources[Socket].StackRes[Stack].MmiolLimit = TempMmioLimit;
+
+ } else {
+
+ SocketResources[Socket].StackRes[Stack].MmiolLimit = SocketResources[Socket].StackRes[Stack].MmiolBase;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiolUpdate = 1;
+ }
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolBase = %X newLength = %x\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiolBase, SocketResources[Socket].StackRes[Stack].MmiolLength));
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolLimit = %X\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiolLimit));
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolUpdate= %d\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiolUpdate));
+ } // for (Stack...)
+ //
+ // In the socket resources there can be UBOX, unfortunatelly not exposed in stackPresentBitmap
+ // so it has to be handled with such uguly hacks.
+ //
+ TempMmioLimit += UboxMmioSize;
+ SocketResources[Socket].MmiolLimit = TempMmioLimit;
+ } // for (Socket...)
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio64.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio64.c
new file mode 100644
index 0000000000..0101904285
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRebalanceMmio64.c
@@ -0,0 +1,204 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <Guid/SocketPciResourceData.h>
+#include <Guid/SocketIioVariable.h>
+#include <Protocol/IioUds.h>
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+#include "PciRebalance.h"
+
+
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+
+
+/**
+ Adjust resource assignments among sockets to fit the high
+ MMIO resources (64-bit addresses, typically above 4GB) from
+ the PCI(e) devices in the system
+
+ @param[in,out] SocketResources - CPU_RESOURCE structure pointer that stores all resources need per socket
+ @param[in] ResourceType - Type of resource that requires alignment
+ @param[in] ValidSockets - Number of Valid Sockets, need it to calculate how resources need to be splitted
+
+ @retval EFI_SUCCESS - Succeed.
+ @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted within the socket.
+ */
+EFI_STATUS
+AdjustSocketMmioH (
+ IN OUT CPU_RESOURCE *SocketResources,
+ IN UINT8 ResourceType,
+ IN UINT8 ValidSockets
+ )
+{
+ CONST UINT8 LastSocket = ValidSockets - 1;
+ UINT8 Socket;
+ UINT8 Stack;
+ UINT8 LastStack;
+ UINT64 Take;
+ UINT32 UboxMmioSize;
+ UINT64 UnAllocatedMmioh;
+ UINT64 MaxMmioh;
+ UINT64 ResourceSize;
+ UINT64 TotalResourceSize;
+ UINT64 TempMmioBase;
+ UINT64 TempMmioLimit;
+
+ Take = 0;
+ UboxMmioSize = mIioUds->IioUdsPtr->PlatformData.UboxMmioSize;
+ UnAllocatedMmioh = 0;
+ //
+ // Get first and last IO base address
+ //
+ TempMmioBase = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base;
+ TempMmioLimit = mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit;
+
+ // Find all the extra space left
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ if ((SocketResources[Socket].MmiohResourceNeeds == 0) && (SocketResources[Socket].MmiohResourcesLeft != 0)) {
+
+ Take += SocketResources[Socket].MmiohResourcesLeft + 1;
+ SocketResources[Socket].MmiohResourcesLeft = 0;
+ }
+ }
+
+ MaxMmioh = (UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.lo;
+ MaxMmioh |= ((UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.hi) << 32;
+ //
+ // Maximum chunk accessible in the system based on the given granularity
+ //
+ if (UboxMmioSize == 0) {
+ MaxMmioh = MaxMmioh * 32; //for 14nm
+ } else {
+ MaxMmioh = ((UINT64) 1 << mIioUds->IioUdsPtr->PlatformData.MaxAddressBits);
+ }
+
+ //
+ // Find out how much MMIOH has not been allocated
+ //
+ if (MaxMmioh > (TempMmioLimit - TempMmioBase)) {
+ UnAllocatedMmioh = MaxMmioh - (TempMmioLimit - TempMmioBase) - 1;
+ } else {
+ //
+ // Extra MMIOH is not enough to close the gap for a successful adjustment.
+ // Use all extra MMIOH in case if only a small amount is needed for adjustment or
+ // the granularity was reduced due to MMIOH base.
+ // (14nm only) or remove if map is rejected for this case to start over with correct values.
+ // (10nm only) does not have this problem and doesn't need the code below because the limit is removed and we can use max address lines.
+ //
+ Take += MaxMmioh;
+ }
+
+ // Give space to sockets that needs more space favoring first come first served
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ if ((SocketResources[Socket].MmiohResourceNeeds != 0) && (Take >= SocketResources[Socket].MmiohResourceNeeds)) {
+ //
+ // The socket requesting additional resources can be granted by using the already
+ // allocated range given to the whole system originally.
+ //
+ Take -= SocketResources[Socket].MmiohResourceNeeds;
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].MmiohResourceNeeds = %llX\n",Socket, SocketResources[Socket].MmiohResourceNeeds));
+ SocketResources[Socket].MmiohResourceNeeds = 0;
+ } else if ((SocketResources[Socket].MmiohResourceNeeds != 0) &&
+ (Take < SocketResources[Socket].MmiohResourceNeeds) &&
+ ((UnAllocatedMmioh + Take) >= SocketResources[Socket].MmiohResourceNeeds)) {
+ //
+ // Apply unallocated Mmioh to the socket that requires more to satisfy its request
+ // that's outside the allocated range given to the whole system originally.
+ //
+ SocketResources[Socket].MmiohResourceNeeds -= Take;
+ UnAllocatedMmioh -= SocketResources[Socket].MmiohResourceNeeds;
+ DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiohResourceNeeds = %llX\n", Socket, SocketResources[Socket].MmiohResourceNeeds));
+ DEBUG ((DEBUG_INFO, "Unallocated MMIOH left = %llX\n", UnAllocatedMmioh));
+ SocketResources[Socket].MmiohResourceNeeds = 0;
+ }
+ }
+ //
+ // Give away leftover resources
+ //
+ LastStack = LastStackOfSocket (LastSocket);
+ if (Take != 0) {
+ if (SocketResources[LastSocket].StackRes[LastStack].MmiohLength != 0) {
+ SocketResources[LastSocket].StackRes[LastStack].MmiohLength += Take;
+ } else{
+ SocketResources[LastSocket].StackRes[LastStack].MmiohLength += (Take - 1);
+ }
+ }
+ //
+ // Verify all resource requested can fit into the systems address range.
+ //
+ TotalResourceSize = 0;
+ for (Socket = 0; Socket < ValidSockets; Socket++) {
+ LastStackWithResources (&SocketResources[Socket], Socket, ResourceType, &LastStack, &ResourceSize);
+ TotalResourceSize += ResourceSize;
+ }
+ DEBUG ((DEBUG_INFO, "MaxMmioh = %016llXh\n", MaxMmioh));
+ DEBUG ((DEBUG_INFO, "Total Request MMIOH Range= %016llXh\n", TotalResourceSize));
+ DEBUG ((DEBUG_INFO, "Total System MMIOH Range = %016llXh\n", (MaxMmioh - TempMmioBase)));
+ if (TotalResourceSize > MaxMmioh) {
+ //
+ // Not enough system resources to support the request.
+ // Remove all request to update NVRAM variable for this resource type.
+ //
+ for (Socket = 0; Socket < ValidSockets; Socket ++) {
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack ++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiohUpdate = 0;
+ }
+ }
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Out of adjustable MMIOH resources. Can't adjust across sockets\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DEBUG ((DEBUG_ERROR, "Assigning new socket MMIOH range...\n"));
+ for (Socket = 0, TempMmioLimit = TempMmioBase - 1; Socket < ValidSockets; Socket++) {
+
+ SocketResources[Socket].MmiohBase = TempMmioLimit + 1;
+ //
+ // Update the stacks base and limit values.
+ //
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++) {
+
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+
+ SocketResources[Socket].StackRes[Stack].MmiohBase = 0;
+ SocketResources[Socket].StackRes[Stack].MmiohLimit = 0;
+
+ } else {
+
+ SocketResources[Socket].StackRes[Stack].MmiohBase = TempMmioLimit + 1;
+ if (SocketResources[Socket].StackRes[Stack].MmiohLength != 0) {
+ //
+ // MmiohLength is actually length-1, so we should move TempMmioLimit by MmiohLength+1,
+ // but only when it is >0, i.e. only for stack that has resources.
+ //
+ TempMmioLimit += SocketResources[Socket].StackRes[Stack].MmiohLength + 1;
+ SocketResources[Socket].StackRes[Stack].MmiohLimit = TempMmioLimit;
+
+ } else {
+
+ SocketResources[Socket].StackRes[Stack].MmiohLimit = SocketResources[Socket].StackRes[Stack].MmiohBase;
+ }
+ SocketResources[Socket].StackRes[Stack].MmiohUpdate = 1;
+ }
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohBase = %llX newLength = %llX\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiohBase, SocketResources[Socket].StackRes[Stack].MmiohLength));
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohLimit = %llX\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiohLimit));
+ DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohUpdate= %d\n", Socket, Stack,
+ SocketResources[Socket].StackRes[Stack].MmiohUpdate));
+ } // for (Stack...)
+
+ SocketResources[Socket].MmiohLimit = TempMmioLimit;
+ } // for (Socket...)
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridge.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridge.h
new file mode 100644
index 0000000000..54faf82e98
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridge.h
@@ -0,0 +1,573 @@
+/** @file
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#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/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 <Library/UefiLib.h>
+#include <Library/TimerLib.h>
+#include "PciHostResource.h"
+
+
+//
+// Define resource status constant
+//
+typedef struct {
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} MAP_INFO;
+
+typedef struct {
+ ACPI_HID_DEVICE_PATH AcpiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL EndDevicePath;
+} EFI_PCI_ROOT_BRIDGE_DEVICE_PATH;
+
+#define PCI_ROOT_BRIDGE_SIGNATURE SIGNATURE_32 ('e', '2', 'p', '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_RESOURCE_APERTURE Aperture;
+ EFI_LOCK PciLock;
+ UINTN PciAddress;
+ UINTN PciData;
+ UINT32 HecBase;
+ UINT32 HecLen;
+ UINTN BusScanCount;
+ BOOLEAN BusNumberAssigned;
+ BOOLEAN DmaAbove4G;
+ VOID *ConfigBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL RootBridgeIo;
+} 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[out] Protocol - Protocol to initialize.
+ @param[in] HostBridgeHandle - Handle to the HostBridge.
+ @param[in] ResAperture - Resource apperture of the root bridge.
+ @param[in] SegmentNumber - PCI segment of this root bridge
+ @param[in] AllocAttributes - Attribute of resouce allocated.
+
+ @retval EFI_SUCCESS - Success.
+ @retval Others - Fail.
+**/
+EFI_STATUS
+SimpleIioRootBridgeConstructor (
+ OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol,
+ IN EFI_HANDLE HostBridgeHandle,
+ IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE *ResAperture,
+ IN UINT16 SegmentNumber,
+ IN UINT64 AllocAttributes
+ );
+
+//
+// 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 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
+ )
+;
+
+/**
+ 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
+ )
+;
+
+/**
+ 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
+ )
+;
+
+/**
+
+ 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
+ )
+;
+
+/**
+ 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
+ )
+;
+
+/**
+
+ 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 resource descriptor.
+
+ @param This - Pointer to the EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL instance.
+ @param Resources - Pointer to the 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_CPU_IO2_PROTOCOL *mCpuIo;
+#endif
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridgeIo.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridgeIo.c
new file mode 100644
index 0000000000..ed5fb7e4a3
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/PciRootBridgeIo.c
@@ -0,0 +1,1664 @@
+/** @file
+ IIO PCI Root Bridge Io Protocol code. Generic enough to work for all IIOs.
+ Does not support configuration accesses to the extended PCI Express registers yet.
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PciHostBridge.h"
+#include "PciRootBridge.h"
+
+#include <Protocol/IioUds.h>
+#include <Protocol/DynamicSiLibraryProtocol.h>
+
+#include "PciRebalance.h"
+
+extern EFI_IIO_UDS_PROTOCOL *mIioUds;
+
+
+//
+// Pci Root Bridge Io Module Variables
+//
+EFI_CPU_IO2_PROTOCOL *mCpuIo;
+STATIC DYNAMIC_SI_LIBARY_PROTOCOL *mDynamicSiLibraryProtocol;
+
+/**
+ Construct the Pci Root Bridge Io protocol.
+
+ @param[out] Protocol - Protocol to initialize.
+ @param[in] HostBridgeHandle - Handle to the HostBridge.
+ @param[in] ResAperture - Resource apperture of the root bridge.
+ @param[in] SegmentNumber - PCI segment of this root bridge
+ @param[in] AllocAttributes - Attribute of resouce allocated.
+
+ @retval EFI_SUCCESS - Success.
+ @retval Others - Fail.
+**/
+EFI_STATUS
+SimpleIioRootBridgeConstructor (
+ OUT EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Protocol,
+ IN EFI_HANDLE HostBridgeHandle,
+ IN PCI_ROOT_BRIDGE_RESOURCE_APERTURE *ResAperture,
+ IN UINT16 SegmentNumber,
+ IN UINT64 AllocAttributes
+ )
+{
+ EFI_STATUS Status;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RESOURCE_TYPE Index;
+ UINT32 HecBase;
+ UINT32 HecSize;
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (Protocol);
+
+ //
+ // Initialize the apertures with default values
+ //
+ CopyMem (
+ &RootBridge->Aperture,
+ ResAperture,
+ sizeof (PCI_ROOT_BRIDGE_RESOURCE_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;
+ }
+
+ EfiInitializeLock (&RootBridge->PciLock, TPL_HIGH_LEVEL);
+ RootBridge->PciAddress = 0xCF8;
+ RootBridge->PciData = 0xCFC;
+
+ RootBridge->AllocationAttributes = AllocAttributes;
+ RootBridge->Attributes = 0;
+ RootBridge->Supports = 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_MEMORY |
+ EFI_PCI_ATTRIBUTE_VGA_IO_16;
+
+ //
+ // Don't support BASE above 4GB currently
+ // Position to bit 39:28
+ //
+ HecBase = (UINT32) mIioUds->IioUdsPtr->PlatformData.PciExpressBase;
+ HecSize = (UINT32) mIioUds->IioUdsPtr->PlatformData.PciExpressSize;
+ ASSERT (HecBase != 0);
+
+ RootBridge->HecBase = HecBase;
+ RootBridge->HecLen = HecSize;
+
+ RootBridge->BusNumberAssigned = FALSE;
+ RootBridge->BusScanCount = 0;
+
+ Protocol->ParentHandle = HostBridgeHandle;
+
+ Protocol->PollMem = RootBridgeIoPollMem;
+ Protocol->PollIo = RootBridgeIoPollIo;
+
+ Protocol->Mem.Read = RootBridgeIoMemRead;
+ Protocol->Mem.Write = RootBridgeIoMemWrite;
+
+ Protocol->Io.Read = RootBridgeIoIoRead;
+ Protocol->Io.Write = RootBridgeIoIoWrite;
+
+ Protocol->CopyMem = RootBridgeIoCopyMem;
+
+ Protocol->Pci.Read = RootBridgeIoPciRead;
+ Protocol->Pci.Write = RootBridgeIoPciWrite;
+
+ Protocol->Map = RootBridgeIoMap;
+ Protocol->Unmap = RootBridgeIoUnmap;
+
+ Protocol->AllocateBuffer = RootBridgeIoAllocateBuffer;
+ Protocol->FreeBuffer = RootBridgeIoFreeBuffer;
+
+ Protocol->Flush = RootBridgeIoFlush;
+
+ Protocol->GetAttributes = RootBridgeIoGetAttributes;
+ Protocol->SetAttributes = RootBridgeIoSetAttributes;
+
+ Protocol->Configuration = RootBridgeIoConfiguration;
+
+ Protocol->SegmentNumber = SegmentNumber;
+
+ Status = gBS->LocateProtocol (
+ &gEfiCpuIo2ProtocolGuid,
+ NULL,
+ &mCpuIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &mDynamicSiLibraryProtocol);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return the result of (Multiplicand * Multiplier / Divisor).
+
+ @param Multiplicand A 64-bit unsigned value.
+ @param Multiplier A 64-bit unsigned value.
+ @param Divisor A 32-bit unsigned value.
+ @param Remainder A pointer to a 32-bit unsigned value. This parameter is
+ optional and may be NULL.
+
+ @return Multiplicand * Multiplier / Divisor.
+**/
+UINT64
+MultThenDivU64x64x32 (
+ IN UINT64 Multiplicand,
+ IN UINT64 Multiplier,
+ IN UINT32 Divisor,
+ OUT UINT32 *Remainder OPTIONAL
+ )
+{
+ UINT64 Uint64;
+ UINT32 LocalRemainder;
+ UINT32 Uint32;
+ if (Multiplicand > DivU64x64Remainder (MAX_UINT64, Multiplier, NULL)) {
+ //
+ // Make sure Multiplicand is the bigger one.
+ //
+ if (Multiplicand < Multiplier) {
+ Uint64 = Multiplicand;
+ Multiplicand = Multiplier;
+ Multiplier = Uint64;
+ }
+ //
+ // Because Multiplicand * Multiplier overflows,
+ // Multiplicand * Multiplier / Divisor
+ // = (2 * Multiplicand' + 1) * Multiplier / Divisor
+ // = 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divisor
+ //
+ Uint64 = MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multiplier, Divisor, &LocalRemainder);
+ Uint64 = LShiftU64 (Uint64, 1);
+ Uint32 = 0;
+ if ((Multiplicand & 0x1) == 1) {
+ Uint64 += DivU64x32Remainder (Multiplier, Divisor, &Uint32);
+ }
+ return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder, 1), Divisor, Remainder);
+ } else {
+ return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divisor, Remainder);
+ }
+}
+
+/**
+ Return the elapsed tick count from CurrentTick.
+
+ @param CurrentTick On input, the previous tick count.
+ On output, the current tick count.
+ @param StartTick The value the performance counter starts with when it
+ rolls over.
+ @param EndTick The value that the performance counter ends with before
+ it rolls over.
+
+ @return The elapsed tick count from CurrentTick.
+**/
+UINT64
+GetElapsedTick (
+ UINT64 *CurrentTick,
+ UINT64 StartTick,
+ UINT64 EndTick
+ )
+{
+ UINT64 PreviousTick;
+
+ PreviousTick = *CurrentTick;
+ *CurrentTick = GetPerformanceCounter();
+ if (StartTick < EndTick) {
+ return *CurrentTick - PreviousTick;
+ } else {
+ return PreviousTick - *CurrentTick;
+ }
+}
+
+/**
+ 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;
+ UINT64 StartTick;
+ UINT64 EndTick;
+ UINT64 CurrentTick;
+ UINT64 ElapsedTick;
+ UINT64 Frequency;
+
+ 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 {
+ //
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
+ //
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
+ NumberOfTicks++;
+ }
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
+ ; ElapsedTick <= NumberOfTicks
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
+ ) {
+ Status = This->Mem.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ 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;
+ UINT64 StartTick;
+ UINT64 EndTick;
+ UINT64 CurrentTick;
+ UINT64 ElapsedTick;
+ UINT64 Frequency;
+
+ //
+ // 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 {
+ //
+ // NumberOfTicks = Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1)
+ //
+ Frequency = GetPerformanceCounterProperties (&StartTick, &EndTick);
+ NumberOfTicks = MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_TIMER_PERIOD_SECONDS(1), &Remainder);
+ if (Remainder >= (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) {
+ NumberOfTicks++;
+ }
+ for ( ElapsedTick = 0, CurrentTick = GetPerformanceCounter()
+ ; ElapsedTick <= NumberOfTicks
+ ; ElapsedTick += GetElapsedTick (&CurrentTick, StartTick, EndTick)
+ ) {
+ Status = This->Io.Read (This, Width, Address, 1, Result);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((*Result & Mask) == Value) {
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ 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
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 ||Width >= EfiPciWidthMaximum ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+ //
+ // Check memory access limit
+ //
+ if (RootBridge->Aperture.Mem64Limit > RootBridge->Aperture.Mem64Base) {
+ if (Address > RootBridge->Aperture.Mem64Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (Address > RootBridge->Aperture.Mem32Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ 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
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // Check memory access limit
+ //
+ if (RootBridge->Aperture.Mem64Limit > RootBridge->Aperture.Mem64Base) {
+ if (Address > RootBridge->Aperture.Mem64Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if (Address > RootBridge->Aperture.Mem32Limit) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ 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
+ )
+{
+ UINTN AlignMask;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // AlignMask = (1 << Width) - 1;
+ //
+ AlignMask = (1 << (Width & 0x03)) - 1;
+
+ //
+ // check Io access limit
+ //
+ if (Address > RootBridge->Aperture.IoLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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
+ )
+{
+ UINTN AlignMask;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // AlignMask = (1 << Width) - 1;
+ //
+ AlignMask = (1 << (Width & 0x03)) - 1;
+
+ //
+ // Check Io access limit
+ //
+ if (Address > RootBridge->Aperture.IoLimit) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Address & AlignMask) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ 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;
+}
+
+
+/**
+
+Arguments:
+
+**/
+STATIC
+EFI_STATUS
+RootBridgeIoPciRW (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 UserAddress,
+ IN UINTN Count,
+ IN OUT VOID *UserBuffer
+ )
+{
+ PCI_CONFIG_ACCESS_CF8 Pci;
+ PCI_CONFIG_ACCESS_CF8 PciAligned;
+ UINT32 Stride;
+ UINTN PciData;
+ UINTN PciDataStride;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+
+ if (Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ ASSERT (((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*)&UserAddress)->ExtendedRegister == 0x00);
+
+ Stride = 1 << Width;
+
+ Pci.Bits.Reg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Register;
+ Pci.Bits.Func = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Function;
+ Pci.Bits.Dev = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Device;
+ Pci.Bits.Bus = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Bus;
+ Pci.Bits.Reserved = 0;
+ Pci.Bits.Enable = 1;
+
+ //
+ // PCI Configure access are all 32-bit aligned, but by accessing the
+ // CONFIG_DATA_REGISTER (0xcfc) with different widths more cycle types
+ // are possible on PCI.
+ //
+ // To read a byte of PCI configuration space you load 0xcf8 and
+ // read 0xcfc, 0xcfd, 0xcfe, 0xcff
+ //
+ PciDataStride = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAddress)->Register & 0x03;
+
+ while (Count) {
+ PciAligned = Pci;
+ PciAligned.Bits.Reg &= 0xfc;
+ PciData = RootBridge->PciData + PciDataStride;
+ EfiAcquireLock(&RootBridge->PciLock);
+ This->Io.Write (This, EfiPciWidthUint32, \
+ RootBridge->PciAddress, 1, &PciAligned);
+ if (Write) {
+ This->Io.Write (This, Width, PciData, 1, UserBuffer);
+ } else {
+ This->Io.Read (This, Width, PciData, 1, UserBuffer);
+ }
+ EfiReleaseLock(&RootBridge->PciLock);
+ UserBuffer = ((UINT8 *)UserBuffer) + Stride;
+ PciDataStride = (PciDataStride + Stride) % 4;
+ Count -= 1;
+
+ //
+ // Only increment the PCI address if Width is not a FIFO.
+ //
+ if (Width >= EfiPciWidthUint8 && Width <= EfiPciWidthUint64) {
+ Pci.Bits.Reg += Stride;
+ }
+ }
+ 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
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFn;
+ UINT32 PciExtReg;
+ USRA_ADDRESS EndPointPciAddress;
+ UINT8 *pData8 = Buffer;
+ UINT8 Size;
+
+ Size = 1 << (Width & 0x3);
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Read Pci configuration space
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if (RootBridge->HecBase == 0) {
+ return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer);
+ }
+
+ if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister) {
+ PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Register;
+ } else {
+ PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister & 0x0FFF;
+ }
+
+ PciBus = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Bus;
+ PciDev = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Device;
+ PciFn = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Function;
+
+ USRA_BLOCK_PCIE_ADDRESS (EndPointPciAddress, Width, Count, This->SegmentNumber, PciBus, PciDev, PciFn, PciExtReg);
+ mDynamicSiLibraryProtocol->RegisterRead (&EndPointPciAddress, pData8);
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+ )
+{
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ UINT32 PciBus;
+ UINT32 PciDev;
+ UINT32 PciFn;
+ UINT32 PciExtReg;
+ USRA_ADDRESS EndPointPciAddress;
+ UINT8 *pData8 = Buffer;
+ UINT8 Size;
+
+ Size = 1 << (Width & 0x3);
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width < 0 || Width >= EfiPciWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Write Pci configuration space
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if (RootBridge->HecBase == 0) {
+ return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer);
+ }
+
+ if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister) {
+ PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Register;
+ } else {
+ PciExtReg = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->ExtendedRegister & 0x0FFF;
+ }
+
+ PciBus = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Bus;
+ PciDev = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Device;
+ PciFn = ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Function;
+
+ USRA_BLOCK_PCIE_ADDRESS (EndPointPciAddress, Width, Count, This->SegmentNumber, PciBus, PciDev, PciFn, PciExtReg);
+ mDynamicSiLibraryProtocol->RegisterWrite (&EndPointPciAddress, pData8);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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 (NumberOfBytes == NULL || Mapping == NULL || DeviceAddress == NULL || HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Initialize the return values to their defaults
+ //
+ *Mapping = NULL;
+
+ //
+ // Make sure that Operation is valid
+ //
+ if ((UINT32) Operation >= EfiPciOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ if (mIoMmu != NULL) {
+ if (!RootBridge->DmaAbove4G) {
+ //
+ // Clear 64bit support
+ //
+ if (Operation > EfiPciOperationBusMasterCommonBuffer) {
+ Operation = (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operation - EfiPciOperationBusMasterRead64);
+ }
+ }
+ Status = mIoMmu->Map (
+ mIoMmu,
+ (EDKII_IOMMU_OPERATION) Operation,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ return Status;
+ }
+ //
+ // Most PCAT like chipsets can not handle performing DMA above 4GB.
+ // If any part of the DMA transfer being mapped is above 4GB, then
+ // map the DMA transfer to a buffer below 4GB.
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((PhysicalAddress + *NumberOfBytes) > SIZE_4GB) {
+ //
+ // 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.
+ //
+ if (Operation == EfiPciOperationBusMasterCommonBuffer || Operation == EfiPciOperationBusMasterCommonBuffer64) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // 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;
+ }
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = MapInfo;
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ MapInfo->Operation = Operation;
+ MapInfo->NumberOfBytes = *NumberOfBytes;
+ MapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*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
+ );
+ }
+ //
+ // The DeviceAddress is the address of the maped buffer below 4GB
+ //
+ *DeviceAddress = MapInfo->MappedHostAddress;
+ } else {
+ //
+ // The transfer is below 4GB, so the DeviceAddress is simply the HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ }
+
+ 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
+ )
+{
+ EFI_STATUS Status;
+ MAP_INFO *MapInfo;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->Unmap (
+ mIoMmu,
+ Mapping
+ );
+ return Status;
+ }
+ //
+ // 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 != NULL) {
+ //
+ // Get the MAP_INFO structure from Mapping
+ //
+ MapInfo = (MAP_INFO *) Mapping;
+
+ //
+ // 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;
+
+ //
+ // 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);
+
+ if (mIoMmu != NULL) {
+
+ if (!RootBridge->DmaAbove4G) {
+ //
+ // Clear DUAL_ADDRESS_CYCLE
+ //
+ Attributes &= ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE);
+ }
+ Status = mIoMmu->AllocateBuffer (
+ mIoMmu,
+ Type,
+ MemoryType,
+ Pages,
+ HostAddress,
+ Attributes
+ );
+ return Status;
+ }
+
+ //
+ // Limit allocations to memory below 4GB
+ //
+ PhysicalAddress = SIZE_4GB - 1;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ MemoryType,
+ Pages,
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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
+ )
+{
+ EFI_STATUS Status;
+
+ if (mIoMmu != NULL) {
+ Status = mIoMmu->FreeBuffer (
+ mIoMmu,
+ Pages,
+ HostAddress
+ );
+ return Status;
+ }
+
+ 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 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, and the End Tag. 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 resource descriptors that
+ describe the current configuration of this PCI root
+ bridge. The storage for the 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
+ )
+{
+ EFI_STATUS Status;
+ UINTN Idx;
+
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridge;
+ PCI_RES_NODE *ResAllocNode;
+ EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *Config;
+
+ //
+ // Get this instance of the Root Bridge.
+ //
+ RootBridge = ROOT_BRIDGE_FROM_THIS (This);
+
+ //
+ // If the pointer is not NULL, it points to a buffer already allocated.
+ //
+ if (RootBridge->ConfigBuffer == NULL) {
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR),
+ &RootBridge->ConfigBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ Config = RootBridge->ConfigBuffer;
+
+ ZeroMem (Config, TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + sizeof (EFI_ACPI_END_TAG_DESCRIPTOR));
+
+ for (Idx = 0; Idx < TypeMax; Idx++) {
+
+ ResAllocNode = &RootBridge->ResAllocNode[Idx];
+
+ if (ResAllocNode->Status != ResAllocated) {
+ continue;
+ }
+
+ switch (ResAllocNode->Type) {
+
+ case TypeIo:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_IO;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ case TypeMem32:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Config->AddrSpaceGranularity = 32;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ case TypePMem32:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Config->SpecificFlag = 6;
+ Config->AddrSpaceGranularity = 32;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ case TypeMem64:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Config->SpecificFlag = 6;
+ Config->AddrSpaceGranularity = 64;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ case TypePMem64:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_MEM;
+ Config->SpecificFlag = 6;
+ Config->AddrSpaceGranularity = 64;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ case TypeBus:
+ Config->Desc = ACPI_ADDRESS_SPACE_DESCRIPTOR;
+ Config->Len = sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) - 3;
+ Config->ResType = ACPI_ADDRESS_SPACE_TYPE_BUS;
+ Config->AddrRangeMin = ResAllocNode->Base;
+ Config->AddrRangeMax = ResAllocNode->Base + ResAllocNode->Length - 1;
+ Config->AddrLen = ResAllocNode->Length;
+ break;
+
+ default:
+ break;
+ }
+
+ Config++;
+ }
+ //
+ // Terminate the entries.
+ //
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Desc = ACPI_END_TAG_DESCRIPTOR;
+ ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Checksum = 0x0;
+
+ *Resources = RootBridge->ConfigBuffer;
+ return EFI_SUCCESS;
+}
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.c
new file mode 100644
index 0000000000..32775fafe7
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.c
@@ -0,0 +1,99 @@
+/** @file
+
+ @copyright
+ Copyright 2014 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include "PciPlatform.h"
+#include <Guid/SetupVariable.h>
+
+#ifdef EFI_PCI_IOV_SUPPORT
+
+/**
+
+ The GetSystemLowestPageSize() function retrieves the system lowest page size.
+
+ @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL instance.
+ @param SystemLowestPageSize - The system lowest page size. (This system supports a
+ page size of 2^(n+12) if bit n is set.)
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_INVALID_PARAMETER - SystemLowestPageSize is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSystemLowestPageSize (
+ IN EFI_PCI_IOV_PLATFORM_PROTOCOL *This,
+ OUT UINT32 *SystemLowestPageSize
+)
+{
+ UINT8 SystemPageSizeOption;
+
+ CopyMem (&SystemPageSizeOption, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYSTEM_CONFIGURATION, SystemPageSize)), sizeof (UINT8));
+
+ if (SystemLowestPageSize != NULL) {
+ //
+ // Convert page size option to page size
+ // Option is n in 2^n
+ // Page size is number of 4KiB pages
+ //
+
+ *SystemLowestPageSize = (UINT32) (1 << SystemPageSizeOption);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The GetIovPlatformPolicy() function retrieves the platform policy regarding PCI IOV.
+
+ @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL instance.
+ @param PciIovPolicy - The platform policy for PCI IOV configuration.
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_INVALID_PARAMETER - PciPolicy is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetIovPlatformPolicy (
+ IN EFI_PCI_IOV_PLATFORM_PROTOCOL *This,
+ OUT EFI_PCI_IOV_PLATFORM_POLICY *PciIovPolicy
+)
+{
+ UINT8 PolicyEnable;
+ UINT8 ARIEnable;
+ UINT8 SRIOVEnable;
+ UINT8 MRIOVEnable;
+
+ PolicyEnable = 0;
+
+ CopyMem (&ARIEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYSTEM_CONFIGURATION, ARIEnable)), sizeof (UINT8));
+ CopyMem (&SRIOVEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYSTEM_CONFIGURATION, SRIOVEnable)), sizeof (UINT8));
+ CopyMem (&MRIOVEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYSTEM_CONFIGURATION, MRIOVEnable)), sizeof (UINT8));
+
+ if (ARIEnable == TRUE) {
+ PolicyEnable = PolicyEnable | EFI_PCI_IOV_POLICY_ARI;
+ }
+
+ if (SRIOVEnable == TRUE) {
+ PolicyEnable = PolicyEnable | EFI_PCI_IOV_POLICY_SRIOV;
+ }
+
+ if (MRIOVEnable == TRUE) {
+ PolicyEnable = PolicyEnable | EFI_PCI_IOV_POLICY_MRIOV;
+ }
+
+ if (PciIovPolicy != NULL) {
+ //*PciIovPolicy = EFI_PCI_IOV_POLICY_ARI | EFI_PCI_IOV_POLICY_SRIOV;
+ *PciIovPolicy = PolicyEnable;
+ }
+ return EFI_SUCCESS;
+}
+
+#endif
+
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.h
new file mode 100644
index 0000000000..ecd57292e2
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciIovPlatformPolicy.h
@@ -0,0 +1,53 @@
+/** @file
+ Include file for PciIovPlatformPolicy.c
+
+ @copyright
+ Copyright 2014 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCI_IOV_PLATFORM_POLICY_H_
+#define _PCI_IOV_PLATFORM_POLICY_H_
+
+/**
+
+ The GetSystemLowestPageSize() function retrieves the system lowest page size.
+
+ @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL instance.
+ @param SystemLowestPageSize - The system lowest page size. (This system supports a
+ page size of 2^(n+12) if bit n is set.)
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_INVALID_PARAMETER - SystemLowestPageSize is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSystemLowestPageSize (
+ IN EFI_PCI_IOV_PLATFORM_PROTOCOL *This,
+ OUT UINT32 *SystemLowestPageSize
+)
+;
+
+
+/**
+
+ The GetPlatformPolicy() function retrieves the platform policy regarding PCI IOV.
+
+ @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL instance.
+ @param PciIovPolicy - The platform policy for PCI IOV configuration.
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_INVALID_PARAMETER - PciPolicy is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+GetIovPlatformPolicy (
+ IN EFI_PCI_IOV_PLATFORM_PROTOCOL *This,
+ OUT EFI_PCI_IOV_PLATFORM_POLICY *PciIovPolicy
+)
+;
+
+#endif
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.c
new file mode 100644
index 0000000000..8584c0f330
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.c
@@ -0,0 +1,541 @@
+/** @file
+
+ @copyright
+ Copyright 2004 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PiDxe.h>
+#include "PciPlatform.h"
+#include <Library/PcdLib.h>
+#include <Library/PlatformOpromPolicyLib.h>
+#include <Protocol/DynamicSiLibraryProtocol.h>
+#include <Protocol/UbaCfgDb.h>
+#ifdef EFI_PCI_IOV_SUPPORT
+#include "PciIovPlatformPolicy.h"
+#endif
+
+#include <Library/UbaPlatLib.h>
+
+PCI_PLATFORM_PRIVATE_DATA mPciPrivateData;
+
+BOOLEAN FirstCall = TRUE;
+UINT8 sSataRaidLoadEfiDriverOption;
+UINT8 SataRaidLoadEfiDriverOption[PCH_MAX_SATA_CONTROLLERS];
+UINT8 BootNetworkOption;
+
+STATIC
+BOOLEAN
+InternalPlatformCheckPcieRootPort (
+ IN UINTN Bus,
+ IN UINT32 PcieSlotOpromBitMap
+)
+{
+ EFI_STATUS Status;
+
+ UBA_CONFIG_DATABASE_PROTOCOL *UbaConfigProtocol = NULL;
+ UINTN DataLength = 0;
+ PLATFORM_OPTION_ROM_UPDATE_DATA OptionRomUpdateTable;
+
+ Status = gBS->LocateProtocol (
+ &gUbaConfigDatabaseProtocolGuid,
+ NULL,
+ &UbaConfigProtocol
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO," InternalPlatformCheckPcieRootPort fail!\n"));
+ return TRUE;
+ }
+
+ DataLength = sizeof (OptionRomUpdateTable);
+ Status = UbaConfigProtocol->GetData (
+ UbaConfigProtocol,
+ &gPlatformOptionRomUpdateConfigDataGuid,
+ &OptionRomUpdateTable,
+ &DataLength
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_INFO,"InternalPlatformCheckPcieRootPort fail!\n"));
+ return TRUE;
+ }
+
+ ASSERT (OptionRomUpdateTable.Signature == PLATFORM_OPTION_ROM_UPDATE_SIGNATURE);
+ ASSERT (OptionRomUpdateTable.Version == PLATFORM_OPTION_ROM_UPDATE_VERSION);
+
+ return OptionRomUpdateTable.CallCheckRootPort (Bus, PcieSlotOpromBitMap);
+}
+
+STATIC
+EFI_STATUS
+InternalGetSystemBoardInfo (
+ IN OUT DXE_SYSTEM_BOARD_INFO **SystemboardInfoTableBuffer
+ )
+{
+ EFI_STATUS Status;
+ UBA_CONFIG_DATABASE_PROTOCOL *UbaConfigProtocol = NULL;
+ UINTN DataLength = 0;
+ SYSTEM_BOARD_INFO_DATA SystemBoardInfoData;
+
+ Status = gBS->LocateProtocol (
+ &gUbaConfigDatabaseProtocolGuid,
+ NULL,
+ &UbaConfigProtocol
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR," [GetSystemBoardInfo] Locate UbaConfigProtocol fail!\n"));
+ return Status;
+ }
+
+ DataLength = sizeof(SystemBoardInfoData);
+ Status = UbaConfigProtocol->GetData (
+ UbaConfigProtocol,
+ &gSystemBoardInfoConfigDataGuid,
+ &SystemBoardInfoData,
+ &DataLength
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((EFI_D_ERROR," [GetSystemBoardInfo] Get Data fail!\n"));
+ return Status;
+ }
+
+ ASSERT (SystemBoardInfoData.Signature == SYSTEM_SYSTEM_BOARD_INFO_SIGNATURE);
+ ASSERT (SystemBoardInfoData.Version == SYSTEM_SYSTEM_BOARD_INFO_VERSION);
+
+ *SystemboardInfoTableBuffer = SystemBoardInfoData.CallUpdate ();
+
+ return Status;
+}
+
+/**
+
+ Set the PciPolicy as EFI_RESERVE_ISA_IO_NO_ALIAS | EFI_RESERVE_VGA_IO_NO_ALIAS.
+
+ @param This - The pointer to the Protocol itself.
+ PciPolicy - the returned Policy.
+
+ @retval EFI_UNSUPPORTED - Function not supported.
+ @retval EFI_INVALID_PARAMETER - Invalid PciPolicy value.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPolicy (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ OUT EFI_PCI_PLATFORM_POLICY *PciPolicy
+ )
+{
+ if (PciPolicy == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Get an indicated image in raw sections.
+
+ @param NameGuid - NameGuid of the image to get.
+ @param Buffer - Buffer to store the image get.
+ @param Size - size of the image get.
+
+ @retval EFI_NOT_FOUND - Could not find the image.
+ @retval EFI_LOAD_ERROR - Error occurred during image loading.
+ @retval EFI_SUCCESS - Image has been successfully loaded.
+
+**/
+EFI_STATUS
+GetRawImage(
+ IN EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *Size
+ ) {
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINT32 AuthenticationStatus;
+
+ Status = gBS->LocateHandleBuffer(
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR(Status) || HandleCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Find desired image in all Fvs
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &Fv
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_LOAD_ERROR;
+ }
+ //
+ // Try a raw file
+ //
+ *Buffer = NULL;
+ *Size = 0;
+ Status = Fv->ReadSection(
+ Fv,
+ NameGuid,
+ EFI_SECTION_RAW,
+ 0,
+ Buffer,
+ Size,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR(Status)) {
+ DEBUG((EFI_D_INFO, "Read the OROM successfully!\n"));
+ break;
+ }
+ }
+
+ if (Index >= HandleCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Return a PCI ROM image for the onboard device represented by PciHandle.
+
+ @param This - Protocol instance pointer.
+ PciHandle - PCI device to return the ROM image for.
+ RomImage - PCI Rom Image for onboard device.
+ RomSize - Size of RomImage in bytes.
+
+ @retval EFI_SUCCESS - RomImage is valid.
+ @retval EFI_NOT_FOUND - No RomImage.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPciRom (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage,
+ OUT UINTN *RomSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINT16 VendorId;
+ UINT16 DeviceId;
+ UINT16 DeviceClass;
+ UINTN TableIndex;
+ UINTN RomImageNumber;
+ VOID *OpRomBase;
+ UINTN OpRomSize;
+ EFI_PCI_ROM_HEADER RomHeader;
+ PCI_DATA_STRUCTURE *Pcir;
+ OPROM_LOAD_POLICY OpromPolicy;
+ BOOLEAN SlotOptionRomDisabled;
+ DXE_SYSTEM_BOARD_INFO *SystemBoardInfo = NULL;
+ UINT32 Index;
+ DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
+
+ OpRomBase = NULL;
+ OpRomSize = 0;
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ //
+ // Get System Board Info
+ //
+ Status = InternalGetSystemBoardInfo (&SystemBoardInfo);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[GetPciRom] Get system board info fail!\n"));
+ return Status;
+ }
+
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (FirstCall == TRUE) {
+ Status = GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CONFIGURATION, BootNetwork), &BootNetworkOption, sizeof(BootNetworkOption));
+ if (EFI_ERROR (Status)) {
+ BootNetworkOption = 0;
+ }
+ Status = GetOptionData (&gPchSetupVariableGuid,
+ OFFSET_OF(PCH_SETUP, SataRaidLoadEfiDriver),
+ &SataRaidLoadEfiDriverOption,
+ sizeof(SataRaidLoadEfiDriverOption) * PCH_MAX_SATA_CONTROLLERS);
+ if (EFI_ERROR (Status)) {
+ for (Index = 0; Index < DynamicSiLibraryProtocol->MaxSataControllerNum(); Index++) {
+ SataRaidLoadEfiDriverOption[Index] = 0;
+ }
+ }
+
+ FirstCall = FALSE;
+ }
+
+ PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_CLASSCODE_OFFSET + 1, 1, &DeviceClass);
+
+ //
+ // Run PXE ROM only if Boot network is enabled
+ //
+ if ((BootNetworkOption == 0) &&
+ (DeviceClass == ((PCI_CLASS_NETWORK << 8) | PCI_CLASS_NETWORK_ETHERNET))
+ ) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Run each PCI-E slot ROM only if PCI-E Slot Oprom is enabled.
+ //
+ if ( Bus != 0 ) {
+ SlotOptionRomDisabled = InternalPlatformCheckPcieRootPort (Bus, PcdGet32(PcdOemSkuPcieSlotOpromBitMap));
+
+ if (SlotOptionRomDisabled) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET, 1, &VendorId);
+ PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET, 1, &DeviceId);
+
+ //DEBUG ((EFI_D_INFO, "GetPciRom - VenID:DevID: %04x:%04x\n", (UINTN)VendorId, (UINTN)DeviceId));
+
+ //
+ // Fix MS-HD5770 video adapter can not work:
+ // This device is not a OPROM 3.0 and does not have device id list as well.
+ // It only have 1 device id in OPROM.
+ // Device Id in OpROM is not same with the value in PCI configuration space
+ // it will cause VBIOS fails to start
+ //
+ if ((VendorId == 0x1002) && (DeviceId == 0x68BE)) {
+ DEBUG ((DEBUG_INFO, "MS-HD5770 video adapter\n"));
+ RomHeader.Raw = PciIo->RomImage;
+ if (RomHeader.Raw != NULL) {
+ Pcir = (PCI_DATA_STRUCTURE *)(RomHeader.Raw + RomHeader.Generic->PcirOffset);
+ if ((Pcir->VendorId == 0x1002) && (Pcir->DeviceId == 0x68B8)) {
+ //
+ // Assign same device id in PCI configuration space
+ //
+ Pcir->DeviceId = DeviceId;
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "MS-HD5770 video adapter detected but PciIo->RomImage == NULL!\n"));
+ }
+ }
+
+ //Check if user disables the option rom loading for this device.
+ if (!PlatformOpromLoadDevicePolicy(PciIo)) {
+ return EFI_NOT_FOUND;
+ }
+
+ // If setup value requested EFI, we don't load the RAID OROM.
+ if (VendorId == V_SATA_CFG_VENDOR_ID) {
+ for (Index = 0; Index < DynamicSiLibraryProtocol->MaxSataControllerNum(); Index++) {
+ if (Bus == DEFAULT_PCI_BUS_NUMBER_PCH &&
+ Device == DynamicSiLibraryProtocol->SataDevNumber (Index) &&
+ Function == DynamicSiLibraryProtocol->SataFuncNumber (Index) &&
+ SataRaidLoadEfiDriverOption[Index] == 1) {
+ return EFI_NOT_FOUND;
+ }
+ }
+ }
+
+ //
+ // Loop through table of video option rom descriptions
+ //
+ RomImageNumber = 0;
+ for (TableIndex = 0; SystemBoardInfo->PciOptionRomTable[TableIndex].VendorId != 0xffff; TableIndex++) {
+ //
+ // See if the PCI device specified by PciHandle matches at device in mPciOptionRomTable
+ //
+ if (VendorId != SystemBoardInfo->PciOptionRomTable[TableIndex].VendorId ||
+ DeviceId != SystemBoardInfo->PciOptionRomTable[TableIndex].DeviceId ||
+ Device != SystemBoardInfo->PciOptionRomTable[TableIndex].Device ||
+ Function != SystemBoardInfo->PciOptionRomTable[TableIndex].Function
+ ) {
+ continue;
+ }
+
+ //Check if user wants to exclusively run this option rom for the device.
+ OpromPolicy = PlatformOpromLoadTypePolicy(PciHandle, TableIndex);
+ if(OpromPolicy == DONT_LOAD) {
+ continue;
+ }
+
+ Status = GetRawImage (
+ &SystemBoardInfo->PciOptionRomTable[TableIndex].FileName,
+ &OpRomBase,
+ &OpRomSize
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ } else {
+ RomImageNumber++;
+ if (RomImageNumber == PcdGet8(PcdMaxOptionRomNumber) || OpromPolicy == EXCLUSIVE_LOAD) {
+ break;
+ }
+ }
+ }
+
+ if (RomImageNumber == 0) {
+
+ return EFI_NOT_FOUND;
+
+ } else {
+
+ *RomImage = OpRomBase;
+ *RomSize = OpRomSize;
+
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+
+ GC_TODO: Add function description
+
+ @param This - GC_TODO: add argument description
+ @param Function - GC_TODO: add argument description
+ @param Phase - GC_TODO: add argument description
+
+ @retval EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
+ @retval EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
+ @retval EFI_UNSUPPORTED - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterPciCallback (
+ IN EFI_PCI_CALLBACK_PROTOCOL *This,
+ IN EFI_PCI_CALLBACK_FUNC Function,
+ IN EFI_PCI_ENUMERATION_PHASE Phase
+ )
+{
+ LIST_ENTRY *NodeEntry;
+ PCI_CALLBACK_DATA *PciCallbackData;
+
+ if (Function == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ( (Phase & (EfiPciEnumerationDeviceScanning | EfiPciEnumerationBusNumberAssigned \
+ | EfiPciEnumerationResourceAssigned)) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Check if the node has been added
+ //
+ NodeEntry = GetFirstNode (&mPciPrivateData.PciCallbackList);
+ while (!IsNull (&mPciPrivateData.PciCallbackList, NodeEntry)) {
+ PciCallbackData = PCI_CALLBACK_DATA_FROM_LINK (NodeEntry);
+ if (PciCallbackData->Function == Function) {
+ return EFI_UNSUPPORTED;
+ }
+
+ NodeEntry = GetNextNode (&mPciPrivateData.PciCallbackList, NodeEntry);
+ }
+
+ PciCallbackData = NULL;
+ PciCallbackData = AllocateZeroPool (sizeof (PCI_CALLBACK_DATA));
+ ASSERT (PciCallbackData != NULL);
+
+ if(PciCallbackData != NULL){
+ PciCallbackData->Signature = PCI_CALLBACK_DATA_SIGNATURE;
+ PciCallbackData->Function = Function;
+ PciCallbackData->Phase = Phase;
+ InsertTailList (&mPciPrivateData.PciCallbackList, &PciCallbackData->Link);
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+
+
+/**
+
+ Main Entry point of the Pci Platform Driver.
+
+ @param ImageHandle - Handle to the image.
+ @param SystemTable - Handle to System Table.
+
+ @retval EFI_STATUS - Status of the function calling.
+
+**/
+EFI_STATUS
+EFIAPI
+PciPlatformDriverEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+
+
+ GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid);
+ ASSERT (GuidHob != NULL);
+ if (GuidHob == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ mPciPrivateData.PlatformInfo = GET_GUID_HOB_DATA(GuidHob);
+
+ //EDK2_TODO Check if clearing mPciPrivateData.PlatformInfo (got above) is intended.
+ ZeroMem (&mPciPrivateData, sizeof (mPciPrivateData));
+ InitializeListHead (&mPciPrivateData.PciCallbackList);
+
+ mPciPrivateData.PciPlatform.PlatformNotify = PhaseNotify;
+ mPciPrivateData.PciPlatform.PlatformPrepController = PlatformPrepController;
+ mPciPrivateData.PciPlatform.GetPlatformPolicy = GetPlatformPolicy;
+ mPciPrivateData.PciPlatform.GetPciRom = GetPciRom;
+ mPciPrivateData.PciCallback.RegisterPciCallback = RegisterPciCallback;
+#ifdef EFI_PCI_IOV_SUPPORT
+ mPciPrivateData.PciIovPlatform.GetSystemLowestPageSize = GetSystemLowestPageSize;
+ mPciPrivateData.PciIovPlatform.GetPlatformPolicy = GetIovPlatformPolicy;
+#endif
+
+ //
+ // Install on a new handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mPciPrivateData.PciPlatformHandle,
+ &gEfiPciPlatformProtocolGuid,
+ &mPciPrivateData.PciPlatform,
+ &gEfiPciCallbackProtocolGuid,
+ &mPciPrivateData.PciCallback,
+#ifdef EFI_PCI_IOV_SUPPORT
+ &gEfiPciIovPlatformProtocolGuid,
+ &mPciPrivateData.PciIovPlatform,
+#endif
+ NULL
+ );
+
+ return Status;
+}
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.h
new file mode 100644
index 0000000000..45d9c38b16
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.h
@@ -0,0 +1,209 @@
+/** @file
+ This is PCI platform initialization code.
+
+ @copyright
+ Copyright 2004 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCI_PLATFORM_MODULE_H_
+#define _PCI_PLATFORM_MODULE_H_
+
+#include <PiDxe.h>
+#include <Register/PchRegsEva.h>
+#include <PchAccess.h>
+#include <Platform.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/S3PciLib.h>
+#include <Library/PciLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/SetupLib.h>
+#include <Protocol/Runtime.h>
+#include <Protocol/CpuIo2.h>
+#include <Protocol/PciCallback.h>
+#include <Protocol/PciPlatform.h>
+#include <Protocol/PciIovPlatform.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <SystemBoard.h>
+#include <Guid/SetupVariable.h>
+#include <Guid/SocketVariable.h>
+#include <Guid/PlatformInfo.h>
+#include <IndustryStandard/Pci.h>
+
+
+#ifndef NELEMENTS
+#define NELEMENTS(Array) (sizeof(Array)/sizeof((Array)[0]))
+#endif
+//
+// Global variables for Option ROMs
+//
+
+#define INVALID 0xBD
+
+#define PCI_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('P', 'c', 'i', 'c')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_PCI_CALLBACK_FUNC Function;
+ EFI_PCI_ENUMERATION_PHASE Phase;
+} PCI_CALLBACK_DATA;
+
+typedef struct {
+ EFI_HANDLE PciPlatformHandle;
+ EFI_HANDLE RootBridgeHandle;
+ EFI_PCI_PLATFORM_PROTOCOL PciPlatform;
+ EFI_PCI_CALLBACK_PROTOCOL PciCallback;
+#ifdef EFI_PCI_IOV_SUPPORT
+ EFI_PCI_IOV_PLATFORM_PROTOCOL PciIovPlatform;
+#endif
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo[MAX_SOCKET][MAX_IIO_STACK];
+ EFI_CPU_IO2_PROTOCOL *CpuIo;
+ EFI_LIST_ENTRY PciCallbackList;
+ EFI_PCI_CALLBACK_CONTEXT Context;
+ EFI_PCI_ENUMERATION_PHASE PciEnumerationPhase;
+ EFI_PLATFORM_INFO *PlatformInfo;
+ UINT8 BusAssignedTime;
+} PCI_PLATFORM_PRIVATE_DATA;
+
+#define PCI_CALLBACK_DATA_FROM_LINK(_node) \
+ CR ( \
+ _node, \
+ PCI_CALLBACK_DATA, \
+ Link, \
+ PCI_CALLBACK_DATA_SIGNATURE \
+ )
+
+extern PCI_PLATFORM_PRIVATE_DATA mPciPrivateData;
+extern EFI_GUID gPchSataEfiLoadProtocolGuid;
+
+/**
+
+ Perform initialization by the phase indicated.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI Host bridge handle.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - Must return with success.
+
+**/
+EFI_STATUS
+EFIAPI
+PhaseNotify (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+;
+
+/**
+
+ The PlatformPrepController() function can be used to notify the platform driver so that
+ it can perform platform-specific actions. No specific actions are required.
+ Several notification points are defined at this time. More synchronization points may be
+ added as required in the future. The PCI bus driver calls the platform driver twice for
+ every PCI controller-once before the PCI Host Bridge Resource Allocation Protocol driver
+ is notified, and once after the PCI Host Bridge Resource Allocation Protocol driver has
+ been notified.
+ This member function may not perform any error checking on the input parameters. It also
+ does not return any error codes. If this member function detects any error condition, it
+ needs to handle those errors on its own because there is no way to surface any errors to
+ the caller.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI Host bridge handle.
+ @param RootBridge - The associated PCI root bridge handle.
+ @param PciAddress - The address of the PCI device on the PCI bus.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPrepController (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_HANDLE RootBridge,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+;
+
+/**
+
+ Set the PciPolicy as EFI_RESERVE_ISA_IO_NO_ALIAS | EFI_RESERVE_VGA_IO_NO_ALIAS.
+
+ @param This - The pointer to the Protocol itself.
+ PciPolicy - the returned Policy.
+
+ @retval EFI_UNSUPPORTED - Function not supported.
+ @retval EFI_INVALID_PARAMETER - Invalid PciPolicy value.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPolicy (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ OUT EFI_PCI_PLATFORM_POLICY *PciPolicy
+ )
+;
+
+/**
+
+ Return a PCI ROM image for the onboard device represented by PciHandle.
+
+ @param This - Protocol instance pointer.
+ PciHandle - PCI device to return the ROM image for.
+ RomImage - PCI Rom Image for onboard device.
+ RomSize - Size of RomImage in bytes.
+
+ @retval EFI_SUCCESS - RomImage is valid.
+ @retval EFI_NOT_FOUND - No RomImage.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPciRom (
+ IN CONST EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage,
+ OUT UINTN *RomSize
+ )
+;
+
+/**
+
+ Register a callback during PCI bus enumeration
+
+ @param This - Protocol instance pointer.
+ @param Function - Callback function pointer.
+ @param Phase - PCI enumeration phase.
+
+ @retval EFI_SUCCESS - Function has registed successfully
+ @retval EFI_UNSUPPORTED - The function has been regisered
+ @retval EFI_InVALID_PARAMETER - The parameter is incorrect
+
+**/
+EFI_STATUS
+EFIAPI
+RegisterPciCallback (
+ IN EFI_PCI_CALLBACK_PROTOCOL *This,
+ IN EFI_PCI_CALLBACK_FUNC Function,
+ IN EFI_PCI_ENUMERATION_PHASE Phase
+ )
+;
+
+#endif
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.inf b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.inf
new file mode 100644
index 0000000000..4121ea8982
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatform.inf
@@ -0,0 +1,87 @@
+## @file
+#
+# @copyright
+# Copyright 2006 - 2021 Intel Corporation. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PciPlatform
+ FILE_GUID = E2441B64-7EF4-41fe-B3A3-8CAA7F8D3017
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciPlatformDriverEntry
+
+[Sources]
+ PciPlatform.c
+ PciPlatform.h
+ PciPlatformHooks.c
+ PciPlatformHooks.h
+ PciIovPlatformPolicy.c
+ PciIovPlatformPolicy.h
+ PciSupportLib.c
+ PciSupportLib.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ WhitleySiliconPkg/WhitleySiliconPkg.dec
+ WhitleySiliconPkg/SiliconPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ WhitleySiliconPkg/CpRcPkg.dec
+ WhitleySiliconPkg/Cpu/CpuRcPkg.dec
+ WhitleyOpenBoardPkg/PlatformPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ IoLib
+ BaseMemoryLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ HobLib
+ S3PciLib
+ SetupLib
+ PcdLib
+ PlatformOpromPolicyLib
+
+[Protocols]
+ gEfiPciCallbackProtocolGuid
+ gEfiCpuIo2ProtocolGuid
+ gEfiFirmwareVolume2ProtocolGuid
+ gEfiPciIoProtocolGuid
+ gEfiPciPlatformProtocolGuid
+ gEfiIioUdsProtocolGuid
+ gEfiPciRootBridgeIoProtocolGuid
+ gEfiPciIovPlatformProtocolGuid
+ gEfiIioSystemProtocolGuid
+ gEfiPciHostBridgeResourceAllocationProtocolGuid
+ gUbaConfigDatabaseProtocolGuid
+ gDynamicSiLibraryProtocolGuid ## CONSUMES
+
+[Guids]
+ gEfiPlatformInfoGuid
+ gEfiSetupVariableGuid
+ gPchSetupVariableGuid
+ gSystemBoardInfoConfigDataGuid
+
+[Pcd]
+ gPlatformTokenSpaceGuid.PcdOemSkuPcieSlotOpromBitMap
+ gPlatformTokenSpaceGuid.PcdMaxOptionRomNumber
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSystemPageSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSrIovSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAriSupport
+ gEfiMdeModulePkgTokenSpaceGuid.PcdMrIovSupport
+ gStructPcdTokenSpaceGuid.PcdSetup
+
+[FixedPcd]
+ gEfiCpRcPkgTokenSpaceGuid.PcdMaxNestedLevel
+ gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuSocketCount
+ gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuCoreCount
+
+[Depex]
+ gSystemBoardInfoConfigDataGuid AND
+ gEfiPciHostBridgeResourceAllocationProtocolGuid AND
+ gUbaConfigDatabaseProtocolGuid AND
+ gDynamicSiLibraryProtocolGuid
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.c
new file mode 100644
index 0000000000..89154cb6e1
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.c
@@ -0,0 +1,939 @@
+/** @file
+
+ @copyright
+ Copyright 2004 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include <PchLimits.h>
+#include <PiDxe.h>
+#include <Protocol/IioUds.h>
+#include <PciPlatform.h>
+#include <PciPlatformHooks.h>
+#include <PciSupportLib.h>
+#include <IoApic.h>
+#include <Library/S3BootScriptLib.h>
+#include <Library/IoLib.h>
+#include <Protocol/DynamicSiLibraryProtocol.h>
+#include "../PciHostBridge/PciRootBridge.h"
+#include "../PciHostBridge/PciHostBridge.h"
+
+
+/******************************************************************************
+ * Local definitions.
+ ******************************************************************************/
+/**
+ Uncomment the PCIDEBUG macro to enable tracing the library activity in a test build.
+ **/
+#define PCIDEBUG(...) // { DEBUG((DEBUG_INFO, "[PCI] " __VA_ARGS__)); }
+
+
+/******************************************************************************
+ * Variables.
+ ******************************************************************************/
+SYSTEM_CONFIGURATION mSystemConfiguration;
+EFI_IIO_UDS_PROTOCOL *mIioUds = NULL;
+
+
+/******************************************************************************
+ * Functions.
+ ******************************************************************************/
+VOID
+ChipsetCallback (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_ENUMERATION_PHASE Phase,
+ IN EFI_PCI_CALLBACK_CONTEXT *ContextPtr
+ )
+{
+ EFI_LIST_ENTRY *NodePtr;
+ PCI_CALLBACK_DATA *CallbackDataPtr;
+
+ //
+ // Check if the node has been added
+ //
+ for (NodePtr = GetFirstNode (&mPciPrivateData.PciCallbackList);
+ !IsNull (&mPciPrivateData.PciCallbackList, NodePtr);
+ NodePtr = GetNextNode (&mPciPrivateData.PciCallbackList, NodePtr)) {
+ CallbackDataPtr = PCI_CALLBACK_DATA_FROM_LINK (NodePtr);
+ if (CallbackDataPtr->Phase & Phase) {
+ (CallbackDataPtr->Function) (RootBridgeHandle, PciAddress, Phase, ContextPtr);
+ }
+ }
+}
+
+/**
+
+ GC_TODO: add routine description
+
+ @param StartBus - GC_TODO: add arg description
+
+ @retval EFI_SUCCESS - GC_TODO: add retval description
+
+**/
+EFI_STATUS
+PciTreeTraverse (
+ IN UINT8 Socket,
+ IN UINT8 Stack,
+ IN UINT8 StartBus
+ )
+{
+ UINT64 PciAddress;
+ UINT8 Device;
+ UINT8 Func;
+ UINT8 SecondaryBus;
+ BOOLEAN MultiFunc;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo;
+
+ if (Socket >= NELEMENTS (mPciPrivateData.PciRootBridgeIo) ||
+ Stack >= NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]) ||
+ mPciPrivateData.PciRootBridgeIo[Socket][Stack] == NULL) {
+ ASSERT (FALSE);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PciRootBridgeIo = mPciPrivateData.PciRootBridgeIo[Socket][Stack];
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ MultiFunc = FALSE;
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ if (IsPciDevicePresent (
+ PciRootBridgeIo,
+ &mPciPrivateData.Context.PciHeader,
+ StartBus,
+ Device,
+ Func
+ )) {
+ if ((Func == 0) && IS_PCI_MULTI_FUNC(&mPciPrivateData.Context.PciHeader)) {
+ MultiFunc = TRUE;
+ }
+ PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, 0);
+ mPciPrivateData.Context.PciRootBridgeIo = PciRootBridgeIo;
+ ChipsetCallback (
+ mPciPrivateData.RootBridgeHandle,
+ *(EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &PciAddress,
+ mPciPrivateData.PciEnumerationPhase,
+ &(mPciPrivateData.Context)
+ );
+ if (IS_PCI_BRIDGE (&(mPciPrivateData.Context.PciHeader))) {
+ PciAddress = EFI_PCI_ADDRESS (StartBus, Device, Func, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint8,
+ *(UINT64 *) &PciAddress,
+ 1,
+ &SecondaryBus
+ );
+ if ((SecondaryBus > 0) && (SecondaryBus < 0xFF)) {
+ //
+ // Recursive call for next bus in this stack
+ //
+ PciTreeTraverse (Socket, Stack, SecondaryBus);
+ }
+ }
+ }
+
+ if (!MultiFunc) {
+ //
+ // Skip sub functions, this is not a multi function device
+ //
+ Func = PCI_MAX_FUNC;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Program Io Apic Id
+
+ @param IoApicAddress and IoApicId
+
+ @retval None
+
+**/
+VOID
+ProgramIoApicId (
+ IN UINT32 IoApicAddress,
+ IN UINT8 IoApicId
+ )
+{
+
+ UINT32 Data;
+
+ mPciPrivateData.CpuIo->Mem.Read (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ //
+ // IOAPIC is not there
+ //
+ if (Data == (UINT32) -1) {
+ return ;
+ }
+ //
+ // Set up IO APIC ID and enable FSB delivery
+ // Use CPU IO protocol since the IO APIC ranges
+ // are not included in PCI apertures
+ //
+ Data = EFI_IO_APIC_ID_REGISTER;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = IoApicId << EFI_IO_APIC_ID_BITSHIFT;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = EFI_IO_APIC_BOOT_CONFIG_REGISTER;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_INDEX_OFFSET,
+ 1,
+ &Data
+ );
+
+ Data = EFI_IO_APIC_FSB_INT_DELIVERY;
+ mPciPrivateData.CpuIo->Mem.Write (
+ mPciPrivateData.CpuIo,
+ EfiCpuIoWidthUint32,
+ IoApicAddress + EFI_IO_APIC_DATA_OFFSET,
+ 1,
+ &Data
+ );
+}
+
+#ifdef EFI_PCI_IOV_SUPPORT
+/**
+
+ Initialize the Pci Iov Platform Data.
+
+ @param ImageHandle - Handle to the image.
+ @param SystemTable - Handle to System Table.
+
+ @retval EFI_STATUS - Status of the function calling.
+
+**/
+EFI_STATUS
+EFIAPI
+PciPlatformInitPciIovData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IOV_PLATFORM_POLICY PciIovPolicy;
+ UINT32 SystemPageSize;
+ EFI_PCI_IOV_PLATFORM_PROTOCOL *gPciIovPlatformProtocol;
+
+ Status = gBS->LocateProtocol (
+ &gEfiPciIovPlatformProtocolGuid,
+ NULL,
+ &gPciIovPlatformProtocol
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gPciIovPlatformProtocol->GetSystemLowestPageSize (
+ gPciIovPlatformProtocol,
+ &SystemPageSize
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PcdSet32S (PcdSrIovSystemPageSize, SystemPageSize);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ return Status;
+ }
+ Status = gPciIovPlatformProtocol->GetPlatformPolicy (
+ gPciIovPlatformProtocol,
+ &PciIovPolicy
+ );
+ if (!EFI_ERROR (Status)) {
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_ARI) {
+ Status = PcdSetBoolS (PcdAriSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ Status = PcdSetBoolS (PcdAriSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_SRIOV) {
+ Status = PcdSetBoolS (PcdSrIovSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ Status = PcdSetBoolS (PcdSrIovSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+ if (PciIovPolicy & EFI_PCI_IOV_POLICY_MRIOV) {
+ Status = PcdSetBoolS (PcdMrIovSupport, TRUE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ } else {
+ Status = PcdSetBoolS (PcdMrIovSupport, FALSE);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+ }
+ } else {
+ return Status;
+ }
+ DEBUG ((
+ EFI_D_INFO,
+ " Initialized SR-IOV Platform Data: PCIIovPolicy = 0x%x; SystemPageSize = 0x%x;\n",
+ PciIovPolicy, SystemPageSize
+ ));
+ } else {
+ DEBUG ((
+ EFI_D_INFO,
+ " Using default values for SystemPageSize;\n"
+ ));
+ }
+ return Status;
+}
+#endif
+
+/**
+
+ Platform Pci Express init.
+
+ @param HostBridgeInstance - Pointer to Host Bridge private data
+ does not support 64 bit memory addresses.
+
+ @retval EFI_SUCCESS - Success.
+
+**/
+EFI_STATUS
+PciPlatformEarlyInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+#ifdef EFI_PCI_IOV_SUPPORT
+ Status = PciPlatformInitPciIovData(); // Update IOV PCD values
+#endif
+ return Status;
+}
+
+/**
+
+ Attempts to set the XHCI controller's PCI CMD.MSE and CMD.BME bits to enable OS kernel debugging over XHCI.
+
+**/
+VOID
+AttemptToSetXhciMse (
+ )
+
+{
+ UINT32 XhciBar;
+ UINT16 Command;
+ DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ //
+ // Step 1. Make sure the XHCI BAR is initialized.
+ // Check if lower 32 bits of 64-bit BAR are configured.
+ //
+ XhciBar = MmioRead32 (DynamicSiLibraryProtocol->MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI) + R_XHCI_CFG_BAR0) & ~(0xF);
+ if (XhciBar == 0xFFFFFFF0) {
+ return;
+ }
+ if ((XhciBar & 0xFFFF0000) == 0) {
+ //
+ // If lower 32 bits are not configured, check upper 32 bits.
+ //
+ XhciBar = MmioRead32 (DynamicSiLibraryProtocol->MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI) + R_XHCI_CFG_BAR0 + 4);
+ if (XhciBar == 0) {
+ return;
+ }
+ }
+
+ //
+ // Step 2. If XHCI's MSE (Memory Space Enable) or BME (Bus Master Enable) bits are cleared, set them.
+ //
+ Command = MmioRead16 (DynamicSiLibraryProtocol->MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI) + PCI_COMMAND_OFFSET);
+ if ((Command & (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER)) != (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER)) {
+ MmioOr16 (DynamicSiLibraryProtocol->MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI) + PCI_COMMAND_OFFSET, (EFI_PCI_COMMAND_MEMORY_SPACE | EFI_PCI_COMMAND_BUS_MASTER));
+ }
+}
+
+
+/**
+
+ Init pci device registers after the device resources have been allocated, so
+ that devices behind a bus could be accessed.
+
+ @param HostBridgeInstance - PCI_HOST_BRIDGE_INSTANCE.
+
+ @retval EFI_SUCCESS - Function has completed successfully.
+
+**/
+EFI_STATUS
+PciPlatformPostInit (
+ VOID
+ )
+{
+ DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
+ EFI_STATUS Status;
+
+ //
+ // Program all the IOAPIC in system
+ //
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ UINT8 Socket, Stack, IoApicId, ApicIndex = 0;
+ CPU_CSR_ACCESS_VAR *CpuCsrAccessVarPtr = NULL;
+ Stack = 0;
+ IoApicId = 0;
+ CpuCsrAccessVarPtr = DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar ();
+ DEBUG ((DEBUG_INFO, "PciPlatformPostInit: setting up IOAPIC for PCH\n"));
+ ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackRes[0].IoApicBase, PCH_IOAPIC_ID);
+ for (Socket = 0; Socket < MAX_SOCKET; Socket++) {
+ if (!(CpuCsrAccessVarPtr->socketPresentBitMap & (1 << Socket))) {
+ continue;
+ }
+
+ for (Stack = 0; Stack < MAX_IIO_STACK; Stack++, ApicIndex++) {
+ if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap & (1 << Stack))) {
+ continue;
+ }
+ switch (ApicIndex) {
+ case 0:
+ IoApicId = PC00_IOAPIC_ID;
+ break;
+ case 1:
+ IoApicId = PC01_IOAPIC_ID;
+ break;
+ case 2:
+ IoApicId = PC02_IOAPIC_ID;
+ break;
+ case 3:
+ IoApicId = PC03_IOAPIC_ID;
+ break;
+ case 4:
+ IoApicId = PC04_IOAPIC_ID;
+ break;
+ case 5:
+ IoApicId = PC05_IOAPIC_ID;
+ break;
+ case 6:
+ IoApicId = PC06_IOAPIC_ID;
+ break;
+ case 7:
+ IoApicId = PC07_IOAPIC_ID;
+ break;
+ case 8:
+ IoApicId = PC08_IOAPIC_ID;
+ break;
+ case 9:
+ IoApicId = PC09_IOAPIC_ID;
+ break;
+ case 10:
+ IoApicId = PC10_IOAPIC_ID;
+ break;
+ case 11:
+ IoApicId = PC11_IOAPIC_ID;
+ break;
+ case 12:
+ IoApicId = PC12_IOAPIC_ID;
+ break;
+ case 13:
+ IoApicId = PC13_IOAPIC_ID;
+ break;
+ case 14:
+ IoApicId = PC14_IOAPIC_ID;
+ break;
+ case 15:
+ IoApicId = PC15_IOAPIC_ID;
+ break;
+ case 16:
+ IoApicId = PC16_IOAPIC_ID;
+ break;
+ case 17:
+ IoApicId = PC17_IOAPIC_ID;
+ break;
+ case 18:
+ IoApicId = PC18_IOAPIC_ID;
+ break;
+ case 19:
+ IoApicId = PC19_IOAPIC_ID;
+ break;
+ case 20:
+ IoApicId = PC20_IOAPIC_ID;
+ break;
+ case 21:
+ IoApicId = PC21_IOAPIC_ID;
+ break;
+ case 22:
+ IoApicId = PC22_IOAPIC_ID;
+ break;
+ case 23:
+ IoApicId = PC23_IOAPIC_ID;
+ break;
+ case 24:
+ IoApicId = PC24_IOAPIC_ID;
+ break;
+ case 25:
+ IoApicId = PC25_IOAPIC_ID;
+ break;
+ case 26:
+ IoApicId = PC26_IOAPIC_ID;
+ break;
+ case 27:
+ IoApicId = PC27_IOAPIC_ID;
+ break;
+ case 28:
+ IoApicId = PC28_IOAPIC_ID;
+ break;
+ case 29:
+ IoApicId = PC29_IOAPIC_ID;
+ break;
+ case 30:
+ IoApicId = PC30_IOAPIC_ID;
+ break;
+ case 31:
+ IoApicId = PC31_IOAPIC_ID;
+ break;
+ case 32:
+ IoApicId = PC32_IOAPIC_ID;
+ break;
+ case 33:
+ IoApicId = PC33_IOAPIC_ID;
+ break;
+ case 34:
+ IoApicId = PC34_IOAPIC_ID;
+ break;
+ case 35:
+ IoApicId = PC35_IOAPIC_ID;
+ break;
+ case 36:
+ IoApicId = PC36_IOAPIC_ID;
+ break;
+ case 37:
+ IoApicId = PC37_IOAPIC_ID;
+ break;
+ case 38:
+ IoApicId = PC38_IOAPIC_ID;
+ break;
+ case 39:
+ IoApicId = PC39_IOAPIC_ID;
+ break;
+ case 40:
+ IoApicId = PC40_IOAPIC_ID;
+ break;
+ case 41:
+ IoApicId = PC41_IOAPIC_ID;
+ break;
+ case 42:
+ IoApicId = PC42_IOAPIC_ID;
+ break;
+ case 43:
+ IoApicId = PC43_IOAPIC_ID;
+ break;
+ case 44:
+ IoApicId = PC44_IOAPIC_ID;
+ break;
+ case 45:
+ IoApicId = PC45_IOAPIC_ID;
+ break;
+ case 46:
+ IoApicId = PC46_IOAPIC_ID;
+ break;
+ case 47:
+ IoApicId = PC47_IOAPIC_ID;
+ break;
+ default:
+ break;
+ }
+ if ((Socket == 0) && (Stack == 0)) {
+ ProgramIoApicId ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase + 0x1000), IoApicId);
+ } else {
+ ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].IoApicBase, IoApicId);
+ }
+ }
+ }
+
+ AttemptToSetXhciMse ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ The PlatformPrepController() function can be used to notify the platform driver so that
+ it can perform platform-specific actions. No specific actions are required.
+ Several notification points are defined at this time. More synchronization points may be
+ added as required in the future. The PCI bus driver calls the platform driver twice for
+ every PCI controller-once before the PCI Host Bridge Resource Allocation Protocol driver
+ is notified, and once after the PCI Host Bridge Resource Allocation Protocol driver has
+ been notified.
+ This member function may not perform any error checking on the input parameters. It also
+ does not return any error codes. If this member function detects any error condition, it
+ needs to handle those errors on its own because there is no way to surface any errors to
+ the caller.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI Host bridge handle.
+ @param RootBridge - The associated PCI root bridge handle.
+ @param PciAddress - The address of the PCI device on the PCI bus.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - The function completed successfully.
+ @retval EFI_UNSUPPORTED - Not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformPrepController (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_HANDLE RootBridge,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_CONTROLLER_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo;
+ PCI_TYPE00 Pci0;
+ UINT64 Address;
+ UINT8 SecBus;
+ UINT8 Device;
+ UINT8 Func;
+ UINT64 DummyData = 0xFFFFFFFF;
+ UINT32 DidVid;
+ DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
+
+ if (mPciPrivateData.RootBridgeHandle == NULL) {
+ mPciPrivateData.RootBridgeHandle = RootBridge;
+ }
+
+ Status = gBS->HandleProtocol (
+ mPciPrivateData.RootBridgeHandle,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ (VOID **) &RootBridgeIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+// Workaround for PCI devices under Pilot IV, this video controller can only be exposed if write 0xFFFFFFFF to it and read back
+ if (Phase == EfiPciBeforeChildBusEnumeration && ChipsetPhase == ChipsetExit ) {
+
+// Read the entire config header
+ Address = EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, 0);
+ Status = RootBridgeIo->Pci.Read (
+ RootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ sizeof (PCI_TYPE00) / sizeof (UINT32),
+ &Pci0
+ );
+
+ if (!EFI_ERROR (Status) && IS_PCI_BRIDGE(&Pci0)) {
+
+ // Read the secondary bus number
+ Address = EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAddress.Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ Status = RootBridgeIo->Pci.Read (
+ RootBridgeIo,
+ EfiPciWidthUint8,
+ Address,
+ 1,
+ &SecBus
+ );
+
+ if (!EFI_ERROR (Status)) {
+
+ //
+ // For this bridge with existing secondary bus apply PCI Intel WAs
+ //
+ DidVid = ((Pci0.Hdr).DeviceId << 16) | (Pci0.Hdr).VendorId;
+ DynamicSiLibraryProtocol->IioPciHookBeforeEnumeration ((UINT8)RootBridgeIo->SegmentNumber, PciAddress.Bus, PciAddress.Device, PciAddress.Function, DidVid);
+
+ for (Device = 0; Device <= PCI_MAX_DEVICE; Device++) {
+ for (Func = 0; Func <= PCI_MAX_FUNC; Func++) {
+ Address = EFI_PCI_ADDRESS (SecBus, Device, Func, 0);
+ Status = RootBridgeIo->Pci.Read (
+ RootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Pci0
+ );
+
+ if ( !EFI_ERROR (Status) && (Pci0.Hdr).VendorId == 0xffff) {
+
+ Status = RootBridgeIo->Pci.Write(
+ RootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &DummyData
+ );
+ PCIDEBUG ("%a: For B(0x%x)-D(0x%x)-F(0x%x),Pci.Write() returns with %r\n",
+ __FUNCTION__, SecBus, Device, Func, Status);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If error, go to next function
+ //
+ continue;
+ } else {
+ Func = PCI_MAX_FUNC; // skip the remaining function
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Perform initialization by the phase indicated.
+
+ @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instance.
+ @param HostBridge - The associated PCI Host bridge handle.
+ @param Phase - The phase of the PCI controller enumeration.
+ @param ChipsetPhase - Defines the execution phase of the PCI chipset driver.
+
+ @retval EFI_SUCCESS - Must return with success.
+
+**/
+EFI_STATUS
+EFIAPI
+PhaseNotify (
+ IN EFI_PCI_PLATFORM_PROTOCOL *This,
+ IN EFI_HANDLE HostBridge,
+ IN EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PHASE Phase,
+ IN EFI_PCI_CHIPSET_EXECUTION_PHASE ChipsetPhase
+ )
+{
+ EFI_STATUS Status = EFI_SUCCESS;
+ UINT16 StackBit;
+ UINT8 Socket;
+ UINT8 Stack;
+ EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL *HostResAllocPtr;
+ PCI_HOST_BRIDGE_INSTANCE *HostBridgePtr;
+ PCI_ROOT_BRIDGE_INSTANCE *RootBridgePtr;
+ LIST_ENTRY *NodePtr;
+ CPU_CSR_ACCESS_VAR *CpuCsrAccessVarPtr;
+ DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL;
+
+ static CHAR8 *NotifyPhase2Name[] = {"EfiPciHostBridgeBeginEnumeration",
+ "EfiPciHostBridgeBeginBusAllocation",
+ "EfiPciHostBridgeEndBusAllocation",
+ "EfiPciHostBridgeBeginResourceAllocation",
+ "EfiPciHostBridgeAllocateResources",
+ "EfiPciHostBridgeSetResources",
+ "EfiPciHostBridgeFreeResources",
+ "EfiPciHostBridgeEndResourceAllocation",
+ "EfiPciHostBridgeEndEnumeration"};
+
+ if (Phase < NELEMENTS (NotifyPhase2Name)) {
+ DEBUG ((DEBUG_INFO, "[PCI] %a phase notified (execution %d)\n", NotifyPhase2Name[Phase], ChipsetPhase));
+ } else {
+ DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Unknown phase %d notified (execution %d)\n", Phase, ChipsetPhase));
+ }
+
+ Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol);
+ if (EFI_ERROR (Status)) {
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+ }
+
+ CpuCsrAccessVarPtr = DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar ();
+
+ if (ChipsetPhase == ChipsetEntry) {
+ return EFI_SUCCESS;
+ }
+ //
+ // If for multiple Host bridges, need special consideration
+ //
+ switch (Phase) {
+
+ case EfiPciHostBridgeBeginEnumeration:
+ //
+ // Pre-initialization before PCI bus enumeration
+ // No bus number and no PCI resource
+ // Locate the IIO Protocol Interface
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiIioUdsProtocolGuid,
+ NULL,
+ &mIioUds
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (
+ &gEfiCpuIo2ProtocolGuid,
+ NULL,
+ &mPciPrivateData.CpuIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mPciPrivateData.Context.CpuIo = mPciPrivateData.CpuIo;
+ DEBUG ((DEBUG_INFO, "[PCI] Platform Pre-Initialization (Before bus scanning)\n"));
+ //
+ // Locate gEfiPciRootBridgeIoProtocolGuid instance created for each IIO stack.
+ // They were created by host bridge driver and linked to the
+ // gEfiPciHostBridgeResourceAllocationProtocolGuid protocol.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiPciHostBridgeResourceAllocationProtocolGuid,
+ NULL,
+ &HostResAllocPtr
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HostBridgePtr = CR (HostResAllocPtr, PCI_HOST_BRIDGE_INSTANCE, ResAlloc, PCI_HOST_BRIDGE_SIGNATURE);
+ for (NodePtr = GetFirstNode (&HostBridgePtr->RootBridges);
+ !IsNull (&HostBridgePtr->RootBridges, NodePtr);
+ NodePtr = GetNextNode (&HostBridgePtr->RootBridges, NodePtr)) {
+ RootBridgePtr = CR (NodePtr, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_ROOT_BRIDGE_SIGNATURE);
+ for (Socket = 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo); Socket++) {
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+ continue;
+ }
+ for (StackBit = 1, Stack = 0;
+ Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]);
+ StackBit <<= 1, Stack++) {
+ if ((CpuCsrAccessVarPtr->stackPresentBitmap[Socket] & StackBit) &&
+ CpuCsrAccessVarPtr->StackBus[Socket][Stack] == RootBridgePtr->Aperture.BusBase) {
+ //
+ // This is the stack handled by this instance of root bridge IO protocol. Store it for future use.
+ //
+ mPciPrivateData.PciRootBridgeIo[Socket][Stack] = &RootBridgePtr->RootBridgeIo;
+ Socket = NELEMENTS (mPciPrivateData.PciRootBridgeIo);
+ break;
+ }
+ }
+ }
+ }
+ PciPlatformEarlyInit ();
+ break;
+
+ case EfiPciHostBridgeEndBusAllocation:
+ //
+ // There are two rounds PCI bus scanning
+ // First round will initilize the PCI hotplug device
+ // Second round will be the final one
+ //
+ if (mPciPrivateData.BusAssignedTime == 0) {
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationDeviceScanning;
+ for (Socket = 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo); Socket++) {
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+ continue;
+ }
+ for (Stack = 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]); Stack ++) {
+ if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] == NULL) {
+ continue;
+ }
+ PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Socket][Stack]);
+ }
+ }
+ mPciPrivateData.BusAssignedTime++;
+ DEBUG ((DEBUG_INFO, "[PCI] Platform bus assigned\n"));
+ }
+ break;
+
+ case EfiPciHostBridgeBeginResourceAllocation:
+ //
+ // PCI bus number has been assigned, but resource is still empty
+ //
+ DEBUG ((DEBUG_INFO, "[PCI] Platform Mid-Initialization (After bus number assignment)\n"));
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationBusNumberAssigned;
+ for (Socket = 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo); Socket++) {
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+ continue;
+ }
+ for (Stack = 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]); Stack ++) {
+ if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] == NULL) {
+ continue;
+ }
+ PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Socket][Stack]);
+ }
+ }
+ //PciPlatformMidInit ();
+ break;
+
+ case EfiPciHostBridgeEndResourceAllocation:
+ //
+ // Resource enumeration is done.
+ // Both bus number and resource have been assigned
+ // Do any post initialization.
+ //
+ DEBUG ((DEBUG_INFO, "[PCI] Platform Post-Initialization (After resource alloction)\n"));
+ mPciPrivateData.PciEnumerationPhase = EfiPciEnumerationResourceAssigned;
+ for (Socket = 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo); Socket++) {
+ if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) {
+ continue;
+ }
+ for (Stack = 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]); Stack ++) {
+ if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] == NULL) {
+ continue;
+ }
+ PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Socket][Stack]);
+ }
+ }
+ PciPlatformPostInit ();
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.h
new file mode 100644
index 0000000000..b52b5de16e
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPlatformHooks.h
@@ -0,0 +1,31 @@
+/** @file
+ This code supports a the private implementation
+ of the Legacy BIOS Platform protocol
+
+ @copyright
+ Copyright 2004 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PCI_PLATFORM_HOOKS_H_
+#define _PCI_PLATFORM_HOOKS_H_
+
+#include <Library/IoLib.h>
+
+VOID
+ChipsetCallback (
+ IN EFI_HANDLE RootBridgeHandle,
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS PciAddress,
+ IN EFI_PCI_ENUMERATION_PHASE Phase,
+ EFI_PCI_CALLBACK_CONTEXT *Context
+ );
+
+EFI_STATUS
+PciTreeTraverse (
+ IN UINT8 Socket,
+ IN UINT8 Stack,
+ IN UINT8 StartBus
+ );
+
+#endif
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.c
new file mode 100644
index 0000000000..7b5d45711d
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.c
@@ -0,0 +1,108 @@
+/** @file
+ Support PCI chipset initialization.
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PiDxe.h"
+#include <Base.h>
+#include <Guid/SocketIioVariable.h>
+#include <Library/IoLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include "IndustryStandard/Pci.h"
+#include "PciSupportLib.h"
+
+PCIE_STACK mPcieStack;
+
+
+/**
+
+ This routine is used to check whether the pci device is present
+
+ @retval None
+
+**/
+BOOLEAN
+IsPciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ UINT8 Bus,
+ UINT8 Device,
+ UINT8 Func
+ )
+// TODO: PciRootBridgeIo - add argument and description to function comment
+// TODO: Pci - add argument and description to function comment
+// TODO: Bus - add argument and description to function comment
+// TODO: Device - add argument and description to function comment
+// TODO: Func - add argument and description to function comment
+// TODO: EFI_SUCCESS - add return value to function comment
+// TODO: EFI_NOT_FOUND - add return value to function comment
+{
+ UINT64 Address;
+ UINT32 Dummy;
+ EFI_STATUS Status;
+
+ Dummy = 0xFFFFFFFF;
+ //
+ // Create PCI address map in terms of Bus, Device and Func
+ //
+ Address = EFI_PCI_ADDRESS (Bus, Device, Func, 0);
+
+ //
+ // Read the Vendor Id register
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ Pci
+ );
+ if ((Pci->Hdr).VendorId == 0xFFFF) {
+ //
+ // The PCIe card could have been assigned a temporary bus number earlier in
+ // the boot flow. Performing a write cycle can be used to cause the PCIe
+ // card to latch the new bus number. Try to writing the Vendor Id register,
+ // then recheck if the card is present.
+ //
+ Status = PciRootBridgeIo->Pci.Write(
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ &Dummy
+ );
+
+ //
+ // Retry the previous read after the PCI write cycle.
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ 1,
+ Pci
+ );
+ }
+
+ if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId != 0xFFFF) {
+ //
+ // Read the entire config header for the device
+ //
+ Status = PciRootBridgeIo->Pci.Read (
+ PciRootBridgeIo,
+ EfiPciWidthUint32,
+ Address,
+ sizeof (PCI_TYPE00) / sizeof (UINT32),
+ Pci
+ );
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.h
new file mode 100644
index 0000000000..e173125c97
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSupportLib.h
@@ -0,0 +1,46 @@
+/** @file
+ Support PCI chipset initialization.
+
+ @copyright
+ Copyright 1999 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _EFI_PCI_SUPPORT_H_
+#define _EFI_PCI_SUPPORT_H_
+
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Guid/SetupVariable.h>
+
+typedef struct {
+ UINT8 PcieCapPtr;
+ UINT8 Function;
+ UINT8 Device;
+ UINT8 Bus;
+ UINT16 PcieLnkCap;
+ UINT16 PcieDevCap;
+ //Added to Support AtomicOp Request-->Start
+ UINT16 PcieDevCap2;
+ //Added to Support AtomicOp Request-->End
+} PCIE_CAP_INFO;
+
+typedef struct {
+ INTN Top;
+ PCIE_CAP_INFO PcieCapInfo[FixedPcdGet32(PcdMaxNestedLevel)];
+} PCIE_STACK;
+
+extern PCIE_STACK mPcieStack;
+
+BOOLEAN
+IsPciDevicePresent (
+ IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *PciRootBridgeIo,
+ OUT PCI_TYPE00 *Pci,
+ UINT8 Bus,
+ UINT8 Device,
+ UINT8 Func
+ );
+
+
+#endif
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.c
new file mode 100644
index 0000000000..003787a163
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.c
@@ -0,0 +1,274 @@
+/** @file
+ Platform variable initialization PEIM.
+
+ This PEIM determines whether to load variable defaults. Ordinarily, the
+ decision is based on the boot mode, but an OEM hook is provided to override
+ that. The appropriate HOBs and PCDs are created to signal DXE code to update
+ the variable default values.
+
+ @copyright
+ Copyright 2012 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#include "PlatformVariableInitPei.h"
+#include <Guid/PlatformVariableCommon.h>
+#include <Uefi/UefiInternalFormRepresentation.h>
+
+UINT16 BoardId = BOARD_ID_DEFAULT;
+
+EFI_PEI_PPI_DESCRIPTOR mPpiListPlatformVariableInit = {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gPlatformVariableInitPpiGuid,
+ NULL
+};
+
+/**
+Apply platform variable defaults.
+
+Create HOBs and set PCDs to prompt the (re-)loading of variable defaults.
+Each step is attempted regardless of whether the previous steps succeeded.
+If multiple errors occur, only the last error code is returned.
+
+@param[in] Events Bitmap of events that occurred.
+@param[in] DefaultId Default store ID, STANDARD or MANUFACTURING.
+
+@retval EFI_SUCCESS All steps completed successfully.
+@retval EFI_OUT_OF_RESOURCES One of the HOBs could not be created.
+@retval EFI_NOT_FOUND The default data could not be found in FFS.
+**/
+
+EFI_STATUS
+ApplyPlatformVariableDefaults(
+ IN UINT8 Events,
+ IN UINT16 DefaultId
+ )
+{
+ VOID *Hob;
+ EFI_STATUS Status;
+ EFI_STATUS ReturnStatus;
+
+ DEBUG((DEBUG_INFO, "Applying platform variable defaults:\n"));
+ DEBUG((DEBUG_INFO, " Events = 0x%02x\n", Events));
+ DEBUG((DEBUG_INFO, " DefaultId = 0x%04x\n", DefaultId));
+
+ //
+ // Assume success up front. This will be overwritten if errors occur.
+ //
+ ReturnStatus = EFI_SUCCESS;
+
+ //
+ // Send the bitmap of events to the platform variable DXE driver.
+ //
+ Hob = BuildGuidDataHob(&gPlatformVariableHobGuid, &Events, sizeof(Events));
+ if (Hob == NULL) {
+ DEBUG((DEBUG_ERROR, "Create platform var event HOB: %r!\n", EFI_OUT_OF_RESOURCES));
+ ReturnStatus = EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Locate variable default data in FFS and send it to the core variable DXE
+ // driver to write.
+ //
+ Status = CreateDefaultVariableHob(DefaultId, BoardId);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "create default var HOB: %r!\n", Status));
+ ReturnStatus = Status;
+ }
+
+ //
+ // Set the PCD SKU ID.
+ //
+ LibPcdSetSku(BoardId);
+
+ //
+ // Set the PCD default store ID.
+ //
+ Status = PcdSet16S(PcdSetNvStoreDefaultId, DefaultId);
+ if (EFI_ERROR(Status)) {
+ DEBUG((DEBUG_ERROR, "setNVstore default ID PCD: %r!\n", Status));
+ ReturnStatus = Status;
+ }
+
+ return ReturnStatus;
+}
+
+/**
+Perform the default variable initializations after variable service is ready.
+
+@param[in] PeiServices General purpose services available to every PEIM.
+@param[in] NotifyDescriptor Pointer to Notify PPI descriptor.
+@param[in] Interface Pointer to PPI.
+
+@retval EFI_SUCCESS Default setting is initialized into variable.
+@retval Other values Can't find the matched default setting.
+**/
+EFI_STATUS
+EFIAPI
+PlatformVariablePeiInit(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Interface
+)
+{
+ EFI_STATUS Status;
+ UINT8 *SystemConfiguration;
+ EFI_GUID *SystemConfigurationGuid;
+ UINTN DataSize;
+ EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariableServices;
+ UINT8 Events;
+ UINT16 DefaultId;
+ BOOLEAN ApplyDefaults;
+
+ SystemConfigurationGuid = PcdGetPtr(PcdSetupVariableGuid);
+ Events = 0;
+ DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+
+ if (PlatformVariableHookForHobGeneration(Interface, &Events, &DefaultId)) {
+ //
+ // Use events bitmap and default ID returned by PlatformVariableHook.
+ //
+ ApplyDefaults = TRUE;
+ }
+ else {
+ //
+ // If the setup variable does not exist (yet), defaults should be applied.
+ //
+ VariableServices = (EFI_PEI_READ_ONLY_VARIABLE2_PPI *)Interface;
+ SystemConfiguration = NULL;
+ DataSize = 0;
+ Status = VariableServices->GetVariable(
+ VariableServices,
+ PLATFORM_SETUP_VARIABLE_NAME,
+ SystemConfigurationGuid,
+ NULL,
+ &DataSize,
+ SystemConfiguration
+ );
+ //
+ // Setup variable is not found. So, set the default setting.
+ //
+ if (Status == EFI_NOT_FOUND) {
+ Events = NULL_VARIABLE_EVENT;
+ DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ ApplyDefaults = TRUE;
+ }
+ else {
+ ApplyDefaults = FALSE;
+ }
+ }
+
+
+ if (ApplyDefaults) {
+ Status = ApplyPlatformVariableDefaults(Events, DefaultId);
+ }
+ else {
+ //
+ // Normal case boot flow
+ //
+ Events = 0; // no events occurred
+ BuildGuidDataHob (&gPlatformVariableHobGuid, &Events, sizeof (UINT8));
+
+ //
+ // Patch RP variable value with PC variable in the begining of PEI
+ //
+ Status = CreateRPVariableHob (EFI_HII_DEFAULT_CLASS_STANDARD, BoardId);
+ }
+
+ PeiServicesInstallPpi (&mPpiListPlatformVariableInit);
+ return Status;
+}
+
+
+/**
+Variable Init BootMode CallBack
+Prepare Knob values based on boot mode
+Execute after discovering BootMode
+
+@param[in] PeiServices General purpose services available to every PEIM.
+@param[in] NotifyDescriptor Pointer to Notify PPI descriptor.
+@param[in] Interface Pointer to PPI.
+
+@retval EFI_SUCCESS Knob Values.
+@retval Other values
+**/
+EFI_STATUS
+EFIAPI
+VariableInitBootModeCallBack(
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDescriptor,
+ IN VOID *Interface
+) {
+ EFI_BOOT_MODE BootMode;
+ BOOLEAN ApplyDefaults;
+ UINT8 Events;
+ UINT16 DefaultId;
+ EFI_STATUS Status;
+
+ Events = 0;
+ DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ ApplyDefaults = FALSE;
+
+ //
+ // Certain boot modes require defaults to be (re-)applied.
+ //
+ Status = PeiServicesGetBootMode(&BootMode);
+ ASSERT_EFI_ERROR(Status);
+ if (EFI_ERROR(Status)) {
+ BootMode = BOOT_WITH_DEFAULT_SETTINGS;
+ }
+ if (BootMode == BOOT_WITH_MFG_MODE_SETTINGS) {
+ Events = MFG_MODE_EVENT;
+ DefaultId = EFI_HII_DEFAULT_CLASS_MANUFACTURING;
+ ApplyDefaults = TRUE;
+ }
+ else if (BootMode == BOOT_IN_RECOVERY_MODE) {
+ Events = RECOVERY_MODE_EVENT;
+ DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ ApplyDefaults = TRUE;
+ }
+ else if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Events = CMOS_CLEAR_EVENT;
+ DefaultId = EFI_HII_DEFAULT_CLASS_STANDARD;
+ ApplyDefaults = TRUE;
+ }
+ if (ApplyDefaults) {
+ Status = ApplyPlatformVariableDefaults(Events, DefaultId);
+ }
+ return Status;
+}
+
+EFI_PEI_NOTIFY_DESCRIPTOR mVariableNotifyList[] = {
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK),
+ &gEfiPeiReadOnlyVariable2PpiGuid,
+ PlatformVariablePeiInit
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gUpdateBootModePpiGuid,
+ VariableInitBootModeCallBack
+ }
+};
+
+EFI_STATUS
+EFIAPI
+PlatformVariableInitPeiEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+/*++
+
+--*/
+{
+ EFI_STATUS Status;
+
+ PlatformVariableHookForEntry();
+
+ // Register notify to set default variable once variable service is ready.
+ //
+ Status = PeiServicesNotifyPpi(&mVariableNotifyList[0]);
+
+ return Status;
+}
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.h
new file mode 100644
index 0000000000..f4701426ff
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.h
@@ -0,0 +1,41 @@
+/** @file
+ Platform variable initialization PEIM.
+
+ This PEIM determines whether to load variable defaults. Ordinarily, the
+ decision is based on the boot mode, but an OEM hook is provided to override
+ that. The appropriate HOBs and PCDs are created to signal DXE code to update
+ the variable default values.
+
+ @copyright
+ Copyright 2012 - 2021 Intel Corporation. <BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+
+#ifndef _PLATFORM_VARIABLE_INIT_PEI_H_
+#define _PLATFORM_VARIABLE_INIT_PEI_H_
+
+#include <PiPei.h>
+
+#include <Library/MultiPlatSupportLib.h>
+
+#include <Ppi/ReadOnlyVariable2.h>
+#include <Ppi/FirmwareVolumeInfo.h>
+#include <Ppi/CpuIo.h>
+
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/IoLib.h>
+#include <Library/PlatformVariableHookLib.h>
+#include <Library/PlatformSetupVariableSyncLib.h>
+
+//
+// We only have one ID for all the platforms.
+//
+#define BOARD_ID_DEFAULT 0
+
+#endif // #ifndef _PLATFORM_VARIABLE_INIT_PEI_H_
diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.inf b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.inf
new file mode 100644
index 0000000000..02d216206e
--- /dev/null
+++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformVariable/Pei/PlatformVariableInitPei.inf
@@ -0,0 +1,58 @@
+## @file
+# Platform variable initialization PEIM.
+#
+# This PEIM determines whether to load variable defaults. Ordinarily, the
+# decision is based on the boot mode, but an OEM hook is provided to override
+# that. The appropriate HOBs and PCDs are created to signal DXE code to update
+# the variable default values.
+#
+# @copyright
+# Copyright 2012 - 2021 Intel Corporation. <BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformVariableInitPei
+ FILE_GUID = B88303F6-2E0E-41cc-8510-F5892BF1D9D9
+ MODULE_TYPE = PEIM
+ ENTRY_POINT = PlatformVariableInitPeiEntry
+
+[Sources]
+ PlatformVariableInitPei.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ SecurityPkg/SecurityPkg.dec
+ WhitleySiliconPkg/WhitleySiliconPkg.dec
+ WhitleySiliconPkg/SiliconPkg.dec
+ WhitleyOpenBoardPkg/PlatformPkg.dec
+
+[LibraryClasses]
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ HobLib
+ IoLib
+ PciLib
+ PcdLib
+ MultiPlatSupportLib
+ PlatformVariableHookLib
+ PlatformSetupVariableSyncLib
+
+[Pcd]
+ gPlatformTokenSpaceGuid.PcdSetupVariableGuid ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetNvStoreDefaultId ## PRODUCES
+
+[Guids]
+ gPlatformVariableHobGuid ## PRODUCES ## HOB
+
+[Ppis]
+ gPlatformVariableInitPpiGuid ## PRODUCES
+ gEfiPeiReadOnlyVariable2PpiGuid ## SOMETIMES_CONSUMES ## NOTIFY
+ gUpdateBootModePpiGuid ## CONSUMES
+
+[Depex]
+ TRUE
--
2.27.0.windows.1
next prev parent reply other threads:[~2021-07-13 0:42 UTC|newest]
Thread overview: 20+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-07-13 0:41 [edk2-platforms] [PATCH V1 00/17] Add IceLake-SP and CooperLake Support to MinPlatform Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 01/17] WhitleySiliconPkg: Add DEC and DSC files Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 02/17] WhitleySiliconPkg: Add Includes and Libraries Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 03/17] WhitleySiliconPkg: Add Cpu Includes Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 04/17] WhitleySiliconPkg: Add Me Includes Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 05/17] WhitleySiliconPkg: Add PCH Register Includes Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 06/17] WhitleySiliconPkg: Add PCH Includes Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 07/17] WhitleySiliconPkg: Add PCH Libraries Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 08/17] WhitleySiliconPkg: Add Security Includes Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 09/17] WhitleySiliconPkg: Add SiliconPolicyInit Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 10/17] WhitleyOpenBoardPkg: Add Includes and Libraries Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 11/17] WhitleyOpenBoardPkg: Add Platform Modules Nate DeSimone
2021-07-13 0:41 ` Nate DeSimone [this message]
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 13/17] WhitleyOpenBoardPkg: Add UBA Modules Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 14/17] WhitleyOpenBoardPkg: Add build scripts and package metadata Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 15/17] Platform/Intel: Add WhitleyOpenBoardPkg to build_bios.py Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 16/17] Readme.md: Add WhitleyOpenBoardPkg Nate DeSimone
2021-07-13 0:41 ` [edk2-platforms] [PATCH V1 17/17] Maintainers.txt: Add WhitleyOpenBoardPkg and WhitleySiliconPkg Nate DeSimone
2021-07-13 1:35 ` [edk2-platforms] [PATCH V1 00/17] Add IceLake-SP and CooperLake Support to MinPlatform Oram, Isaac W
2021-07-14 2:03 ` Michael D Kinney
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20210713004131.1782-13-nathaniel.l.desimone@intel.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox