From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga17.intel.com (mga17.intel.com [192.55.52.151]) by mx.groups.io with SMTP id smtpd.web10.2606.1626136926448691985 for ; Mon, 12 Jul 2021 17:42:06 -0700 Authentication-Results: mx.groups.io; dkim=missing; spf=pass (domain: intel.com, ip: 192.55.52.151, mailfrom: nathaniel.l.desimone@intel.com) X-IronPort-AV: E=McAfee;i="6200,9189,10043"; a="190456242" X-IronPort-AV: E=Sophos;i="5.84,235,1620716400"; d="scan'208";a="190456242" Received: from fmsmga005.fm.intel.com ([10.253.24.32]) by fmsmga107.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jul 2021 17:42:00 -0700 X-IronPort-AV: E=Sophos;i="5.84,235,1620716400"; d="scan'208";a="653422989" Received: from nldesimo-desk1.amr.corp.intel.com ([10.212.211.135]) by fmsmga005-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 12 Jul 2021 17:41:58 -0700 From: "Nate DeSimone" To: devel@edk2.groups.io Cc: Isaac Oram , Mohamed Abbas , Chasel Chiu , Michael D Kinney , Liming Gao , Eric Dong , Michael Kubacki Subject: [edk2-platforms] [PATCH V1 12/17] WhitleyOpenBoardPkg: Add Feature Modules Date: Mon, 12 Jul 2021 17:41:26 -0700 Message-Id: <20210713004131.1782-13-nathaniel.l.desimone@intel.com> X-Mailer: git-send-email 2.27.0.windows.1 In-Reply-To: <20210713004131.1782-1-nathaniel.l.desimone@intel.com> References: <20210713004131.1782-1-nathaniel.l.desimone@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Signed-off-by: Nate DeSimone Co-authored-by: Isaac Oram Co-authored-by: Mohamed Abbas Cc: Chasel Chiu Cc: Michael D Kinney Cc: Isaac Oram Cc: Mohamed Abbas Cc: Liming Gao Cc: Eric Dong Cc: Michael Kubacki --- .../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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include "PciHostBridge.h" +#include "PciRootBridge.h" +#include "PciHostResource.h" + +#include +#include +#include +#include + +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCI_HOST_BRIDGE_H_ +#define _PCI_HOST_BRIDGE_H_ + + +#include +#include +#include +#include +#include +#include +#include + +#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.
+# +# 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.
+ + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCI_HOST_RESOURCE_H_ +#define _PCI_HOST_RESOURCE_H_ + +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include "PciHostBridge.h" +#include "PciRootBridge.h" +#include +#include +#include + +#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.
+ + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCI_ROOT_BRIDGE_H_ +#define _PCI_ROOT_BRIDGE_H_ + +#include +#include +#include + +// +// Driver Consumed Protocol Prototypes +// +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PciHostBridge.h" +#include "PciRootBridge.h" + +#include +#include + +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include "PciPlatform.h" +#include + +#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.
+ + 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include "PciPlatform.h" +#include +#include +#include +#include +#ifdef EFI_PCI_IOV_SUPPORT +#include "PciIovPlatformPolicy.h" +#endif + +#include + +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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCI_PLATFORM_MODULE_H_ +#define _PCI_PLATFORM_MODULE_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#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.
+# +# 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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PCI_PLATFORM_HOOKS_H_ +#define _PCI_PLATFORM_HOOKS_H_ + +#include + +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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PiDxe.h" +#include +#include +#include +#include +#include +#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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _EFI_PCI_SUPPORT_H_ +#define _EFI_PCI_SUPPORT_H_ + +#include + +#include + +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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PlatformVariableInitPei.h" +#include +#include + +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.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _PLATFORM_VARIABLE_INIT_PEI_H_ +#define _PLATFORM_VARIABLE_INIT_PEI_H_ + +#include + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// +// 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.
+# +# 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