From nobody Fri Dec 19 22:03:16 2025 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+77716+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+77716+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1626136933; cv=none; d=zohomail.com; s=zohoarc; b=lSVBeVQJxnGCUg8wkrdFNHq9FJbM/dHjjqhH8RCnmYs0+4+WV5+jtqHJSPf8zq+vdlwyVHGJOnUDuHpmRuuBZfqJAy2GhhQFZLX9nlDzIkKpehVx5WfT+8e9ujJcU7hQR8g+UCsxuKdu78hFjIlOhZN2TcQT9FvBQ0kVBUEVE2Y= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1626136933; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=pciKb1d2p2rZHuck6eINTfnvMGl6cQJNedUBFzVYRXw=; b=XC9ts1IKai5xoden/KWnAAYjvzWI+Ob0JLTb6mql8P1VR/Nbkb3XqyPCVic+/igc42eonTpxHqF4zwVBEjNOJRRiJJUlQY2vNF4At3TPX8tyZym/6uQAjgmFnLcYQw4J6CCjZL9dlKNwmjnV7kjzEgZWlUcc0tAVy2bOkkz524Y= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+77716+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1626136933025125.61525098160132; Mon, 12 Jul 2021 17:42:13 -0700 (PDT) Return-Path: X-Received: by 127.0.0.2 with SMTP id B8qaYY1788612xBMmmibuveD; Mon, 12 Jul 2021 17:42:12 -0700 X-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 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" X-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" X-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-devel] [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> In-Reply-To: <20210713004131.1782-1-nathaniel.l.desimone@intel.com> References: <20210713004131.1782-1-nathaniel.l.desimone@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,nathaniel.l.desimone@intel.com X-Gm-Message-State: nz7V3qoddVOT72KmYojBTugrx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1626136932; bh=ERNXZuV+/nWEasAJZW7GjjPV1KCwl3346hzVD9RO7kg=; h=Cc:Date:From:Reply-To:Subject:To; b=Xr8HttyIb9XzmLddfT+GxQVxqIN+NSnJm6N9YPIEIQBcWJAY7Y/xPsiyosl3tl3yzNJ 2Ibx+8VpDF2BA7l9XLz6p2O9roiMthWwvqBxjFwx3dmctFF+Tw0QCiyIosEjAxy/3PjXj TqOXB+0jbjW3Y1JOCK1JnRK+sH0pGOfC8A4= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1626136934150100009 Content-Type: text/plain; charset="utf-8" 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/Pci= HostBridge/PciHostBridge.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciHostBridge.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciHostBridge.inf create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciHostBridgeSupport.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciHostResource.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRebalance.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRebalance.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRebalanceIo.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRebalanceMmio32.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRebalanceMmio64.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRootBridge.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= HostBridge/PciRootBridgeIo.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciIovPlatformPolicy.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciIovPlatformPolicy.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatform.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatform.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatform.inf create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatformHooks.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatformHooks.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciSupportLib.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciSupportLib.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/Pl= atformVariable/Pei/PlatformVariableInitPei.c create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/Pl= atformVariable/Pei/PlatformVariableInitPei.h create mode 100644 Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/Pl= atformVariable/Pei/PlatformVariableInitPei.inf diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/PciHostBridge.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/P= ciHostBridge/PciHostBridge.c new file mode 100644 index 0000000000..a15fff4817 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= HostBridge.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[] =3D { + L"Mem", L"I/O", L"Bus" +}; +GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 *mPciResourceTypeStr[] =3D { + 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 mEfiPciRootBridgeDevicePathTempl= ate =3D { + {{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 =3D 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 =3D ImageHandle; + // + // Located the IIO Protocol Interface + // + Status =3D gBS->LocateProtocol (&gEfiIioUdsProtocolGuid, NULL, &mIioUds); + ASSERT_EFI_ERROR (Status); + + // + // Most systems in the world including complex servers have only one Hos= t Bridge. + // + HostBridge =3D AllocateZeroPool (sizeof (PCI_HOST_BRIDGE_INSTANCE)); + if (HostBridge =3D=3D NULL) { + ASSERT(FALSE); + return EFI_OUT_OF_RESOURCES; + } + HostBridge->Signature =3D PCI_HOST_BRIDGE_SIGNATURE; + HostBridge->RootBridgeCount =3D 0; + HostBridge->ResourceSubmited =3D FALSE; + HostBridge->CanRestarted =3D TRUE; + InitializeListHead (&HostBridge->RootBridges); + + HostBridge->ResAlloc.NotifyPhase =3D NotifyPhase; + HostBridge->ResAlloc.GetNextRootBridge =3D GetNextRootBridge; + HostBridge->ResAlloc.GetAllocAttributes =3D GetAttributes; + HostBridge->ResAlloc.StartBusEnumeration =3D StartBusEnumeration; + HostBridge->ResAlloc.SetBusNumbers =3D SetBusNumbers; + HostBridge->ResAlloc.SubmitResources =3D SubmitResources; + HostBridge->ResAlloc.GetProposedResources =3D GetProposedResources; + HostBridge->ResAlloc.PreprocessController =3D PreprocessController; + + Status =3D 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 =3D 0; IioIndex < mIioUds->IioUdsPtr->PlatformData.numofII= O; IioIndex++) { + + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Valid) { + continue; + } // No guarantee that the valid IIOs are sequential starting at 0! + + for (IioStack =3D 0; IioStack < MAX_IIO_STACK; IioStack++) { + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[IioIndex].stackPre= sentBitmap & (1 << IioStack))) { + continue; + } + // Skip stack which is disabled by resource limitation or DEBUG purp= ose! + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes= [IioStack].Personality >=3D TYPE_DISABLED) { + continue; + } + // + // Create Root Bridge Instance + // + RootBridge =3D AllocateZeroPool (sizeof(PCI_ROOT_BRIDGE_WITH_PATH)); + if (RootBridge =3D=3D NULL) { + ASSERT_EFI_ERROR (EFI_OUT_OF_RESOURCES); + return EFI_OUT_OF_RESOURCES; + } + TempDevicePath =3D &((PCI_ROOT_BRIDGE_WITH_PATH*)RootBridge)->RootDe= vPath; + + RootBridge->Signature =3D PCI_ROOT_BRIDGE_SIGNATURE; + RootBridge->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL*)TempDevicePath; + CopyMem (TempDevicePath, &mEfiPciRootBridgeDevicePathTemplate, sizeo= f(*TempDevicePath)); + TempDevicePath->AcpiDevicePath.UID =3D (UINT32)(IioIndex * MAX_IIO_S= TACK + IioStack); + + ZeroMem(&RbAperture, sizeof(RbAperture)); + { + // + // Update Root Bridge with UDS resource information + // + RbAperture.BusBase =3D mIioUds->IioUdsPtr->PlatformData.IIO_resour= ce[IioIndex].StackRes[IioStack].BusBase; + RbAperture.BusLimit =3D mIioUds->IioUdsPtr->PlatformData.IIO_resou= rce[IioIndex].StackRes[IioStack].BusLimit; + RbAperture.Mem32Base =3D mIioUds->IioUdsPtr->PlatformData.IIO_reso= urce[IioIndex].StackRes[IioStack].PciResourceMem32Base; + RbAperture.Mem32Limit =3D mIioUds->IioUdsPtr->PlatformData.IIO_res= ource[IioIndex].StackRes[IioStack].PciResourceMem32Limit; + RbAperture.BusReserve =3D 0; + if ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Stack= Res[IioStack].PciResourceMem64Limit > + mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Stack= Res[IioStack].PciResourceMem64Base) && + (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllocation))= { + RbAperture.Mem64Base =3D mIioUds->IioUdsPtr->PlatformData.IIO_re= source[IioIndex].StackRes[IioStack].PciResourceMem64Base; + RbAperture.Mem64Limit =3D mIioUds->IioUdsPtr->PlatformData.IIO_r= esource[IioIndex].StackRes[IioStack].PciResourceMem64Limit; + } + RbAperture.IoBase =3D mIioUds->IioUdsPtr->PlatformData.IIO_resourc= e[IioIndex].StackRes[IioStack].PciResourceIoBase; + RbAperture.IoLimit =3D mIioUds->IioUdsPtr->PlatformData.IIO_resour= ce[IioIndex].StackRes[IioStack].PciResourceIoLimit; + + SimpleIioRootBridgeConstructor (&RootBridge->RootBridgeIo, HostBri= dge->Handle, &RbAperture, + mIioUds->IioUdsPtr->PlatformData.C= puQpiInfo[IioIndex].PcieSegment, + GetAllocAttributes (HostBridge->Ro= otBridgeCount)); + DEBUG ((DEBUG_INFO, "[PCI] Create Root Bridge for [%d.%d] in PCI s= egment %d with below resource:\n", IioIndex, IioStack, RootBridge->RootBrid= geIo.SegmentNumber)); + DEBUG ((DEBUG_INFO, " Bus: Base =3D 0x%08x, Limit =3D 0x%08= x, BusReserve =3D 0x%08x\n", RootBridge->Aperture.BusBase, RootBridge->Aper= ture.BusLimit, RootBridge->Aperture.BusReserve)); + DEBUG ((DEBUG_INFO, " IO: Base =3D 0x%08x, Limit =3D 0x%08= x\n", RootBridge->Aperture.IoBase, RootBridge->Aperture.IoLimit)); + DEBUG ((DEBUG_INFO, " Mem32: Base =3D 0x%08x, Limit =3D 0x%08= x\n", RootBridge->Aperture.Mem32Base, RootBridge->Aperture.Mem32Limit)); + DEBUG ((DEBUG_INFO, " Mem64: Base =3D 0x%lx, Limit =3D 0x%lx\= n", RootBridge->Aperture.Mem64Base, RootBridge->Aperture.Mem64Limit)); + // + // Insert Root Bridge Instance + // + Status =3D gBS->InstallMultipleProtocolInterfaces ( + &RootBridge->Handle, + &gEfiDevicePathProtocolGuid, + RootBridge->DevicePath, + &gEfiPciRootBridgeIoProtocolGuid, + &RootBridge->RootBridgeIo, + NULL + ); + ASSERT_EFI_ERROR (Status); + InsertTailList (&HostBridge->RootBridges, &RootBridge->Link); + mPciRootBridgeTable[IioIndex][IioStack] =3D RootBridge; + HostBridge->RootBridgeCount++; + } + } // for (IioStack...) + } // for (IioIndex...) + // + // Add PCIE base into Runtime memory so that it can be reported in E820 = table + // + Status =3D gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + mIioUds->IioUdsPtr->PlatformData.PciExpressBase, + mIioUds->IioUdsPtr->PlatformData.PciExpressSize, + EFI_MEMORY_RUNTIME | EFI_MEMORY_UC + ); + ASSERT_EFI_ERROR(Status); + + BaseAddress =3D mIioUds->IioUdsPtr->PlatformData.PciExpressBase; + + Status =3D gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeMemoryMappedIo, + 0, + mIioUds->IioUdsPtr->PlatformData.PciExpressSize, + &BaseAddress, + ImageHandle, + NULL + ); + ASSERT_EFI_ERROR(Status); + + Status =3D gDS->SetMemorySpaceAttributes ( + mIioUds->IioUdsPtr->PlatformData.PciExpressBase, + mIioUds->IioUdsPtr->PlatformData.PciExpressSize, + EFI_MEMORY_RUNTIME + ); + ASSERT_EFI_ERROR (Status); + + //s4030180 + for (IioIndex =3D 0; IioIndex < mIioUds->IioUdsPtr->PlatformData.numofII= O; IioIndex++) { + + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Valid) { + continue; + } // No guarantee that the valid IIOs are sequential starting at 0! + for (IioStack =3D 0; IioStack < MAX_IIO_STACK; IioStack++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[IioIndex].stackPre= sentBitmap & (1 << IioStack))) { + continue; + } + + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRes= [IioStack].PciResourceIoLimit > + mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRe= s[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 =3D gDS->AddIoSpace ( + EfiGcdIoTypeIo, + mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioI= ndex].StackRes[IioStack].PciResourceIoBase , + (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Iio= Index].StackRes[IioStack].PciResourceIoLimit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Iio= Index].StackRes[IioStack].PciResourceIoBase + 1) + ); + ASSERT_EFI_ERROR (Status); + } + + CurStackRes =3D &mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIn= dex].StackRes[IioStack]; + if (CurStackRes->PciResourceMem32Limit > CurStackRes->PciResourceMem= 32Base) { + // + // Shouldn't the capabilities be UC? + // + ResourceLength =3D CurStackRes->PciResourceMem32Limit - CurStackRe= s->PciResourceMem32Base + 1; + Status =3D 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 <=3D = y <=3D z) + BaseAddress =3D CurStackRes->VtdBarAddress; + ResourceLength =3D CurStackRes->PciResourceMem32Limit - BaseAddres= s + 1; + Status =3D gDS->AllocateMemorySpace ( + EfiGcdAllocateAddress, + EfiGcdMemoryTypeMemoryMappedIo, + 0, + ResourceLength, + &BaseAddress, + ImageHandle, + NULL + ); + ASSERT_EFI_ERROR(Status); + } + + if ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].StackRe= s[IioStack].PciResourceMem64Limit > + mIioUds->IioUdsPtr->PlatformData.IIO_resource[IioIndex].Stack= Res[IioStack].PciResourceMem64Base) && + (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllocation)= ) { + + Status =3D gDS->AddMemorySpace ( + EfiGcdMemoryTypeMemoryMappedIo, + mIioUds->IioUdsPtr->PlatformData.IIO_resource[I= ioIndex].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 =3D EfiCreateProtocolNotifyEvent ( + &gEdkiiIoMmuProtocolGuid, + TPL_CALLBACK, + IoMmuProtocolCallback, + NULL, + &mIoMmuRegistration + ); + } + mHostBridge =3D 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 =3D TypeMax; + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + + if (HostBridge->CanRestarted) { + // + // Reset Root Bridge + // + List =3D HostBridge->RootBridges.ForwardLink; + + while (List !=3D &HostBridge->RootBridges) { + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + for (Index =3D TypeIo; Index < TypeMax; Index++) { + RootBridge->ResAllocNode[Index].Type =3D Index; + RootBridge->ResAllocNode[Index].Base =3D 0; + RootBridge->ResAllocNode[Index].Length =3D 0; + RootBridge->ResAllocNode[Index].Status =3D ResNone; + } // for + + List =3D List->ForwardLink; + } // while + + HostBridge->ResourceSubmited =3D FALSE; + HostBridge->CanRestarted =3D 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 ins= tance. + + @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 =3D TypeMax; + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + + ReturnStatus =3D EFI_SUCCESS; + if (HostBridge->ResourceSubmited) { + + List =3D HostBridge->RootBridges.ForwardLink; + while (List !=3D &HostBridge->RootBridges) { + + for (Index1 =3D TypeIo; Index1 < TypeBus; Index1++) { + ResNodeHandled[Index1] =3D FALSE; + } + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + Socket =3D Stack =3D (UINT8)-1; + PciRootBridge2SocketStack (RootBridge, &Socket, &Stack); + for (Index1 =3D TypeIo; Index1 < TypeBus; Index1++) { + + if (RootBridge->ResAllocNode[Index1].Status =3D=3D ResNone) { + + ResNodeHandled[Index1] =3D TRUE; + + } else { + // + // Allocate the resource node with max alignment at first + // + MaxAlignment =3D 0; + Index =3D TypeMax; + for (Index2 =3D TypeIo; Index2 < TypeBus; Index2++) { + + if (ResNodeHandled[Index2]) { + continue; + } + if (MaxAlignment <=3D RootBridge->ResAllocNode[Index2].Alignme= nt) { + MaxAlignment =3D RootBridge->ResAllocNode[Index2].Alignment; + Index =3D Index2; + } + } // for + + if (Index < TypeMax) { + + ResNodeHandled[Index] =3D TRUE; + Alignment =3D RootBridge->ResAllocNode[Index].Alignment; + // + // Get the number of '1' in Alignment. + // + for (BitsOfAlignment =3D 0; Alignment !=3D 0; BitsOfAlignment+= +) { + Alignment =3D RShiftU64 (Alignment, 1); + } + + AddrLen =3D RootBridge->ResAllocNode[Index].Length; + Alignment =3D 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.IoLim= it) { + // + // It is impossible for 0xFFFF Alignment for IO16 + // + if (BitsOfAlignment >=3D 16) { + Alignment =3D 0; + } + BaseAddress =3D RootBridge->Aperture.IoBase; + // + // Have to make sure Alignment is handled seeing we are do= ing direct address allocation + // + if ((BaseAddress & ~(Alignment)) !=3D BaseAddress) { + BaseAddress =3D ((BaseAddress + Alignment) & ~(Alignment= )); + } + + while((BaseAddress + AddrLen) <=3D RootBridge->Aperture.Io= Limit + 1) { + Status =3D gDS->AllocateIoSpace (EfiGcdAllocateAddress, = EfiGcdIoTypeIo, BitsOfAlignment, + AddrLen, &BaseAddress, mDriverImageHandle, NULL ); + + if (!EFI_ERROR (Status)) { + RootBridge->ResAllocNode[Index].Base =3D (UINT64) B= aseAddress; + RootBridge->ResAllocNode[Index].Status =3D ResAllocat= ed; + goto TypeIoFound; + } + + BaseAddress +=3D (Alignment + 1); + } // while + } // if + + TypeIoFound: + if (RootBridge->ResAllocNode[Index].Status !=3D ResAllocate= d) { + // + // No Room at the Inn for this resources request + // + ReturnStatus =3D EFI_OUT_OF_RESOURCES; + } // if + break; + + case TypeMem32: + if (RootBridge->Aperture.Mem32Base < RootBridge->Aperture.= Mem32Limit) { + + BaseAddress =3D RootBridge->Aperture.Mem32Base; + // + // Have to make sure Alignment is handled seeing we are = doing direct address allocation + // + if ((BaseAddress & ~(Alignment)) !=3D BaseAddress) { + BaseAddress =3D ((BaseAddress + Alignment) & ~(Alignme= nt)); + } + + while ((BaseAddress + AddrLen) <=3D RootBridge->Aperture= .Mem32Limit + 1) { + DEBUG ((DEBUG_INFO, " Attempting %s allocation at= 0x%llX.....", + mPciResourceTypeStr[Index], BaseAddress)); + Status =3D gDS->AllocateMemorySpace (EfiGcdAllocateAdd= ress, EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, Ad= drLen, &BaseAddress, mDriverImageHandle, NULL); + if (!EFI_ERROR (Status)) { + RootBridge->ResAllocNode[Index].Base =3D (UINT64)= BaseAddress; + RootBridge->ResAllocNode[Index].Status =3D ResAlloc= ated; + DEBUG ((DEBUG_INFO, "Passed\n")); + goto TypeMem32Found; + } // if + DEBUG ((DEBUG_INFO, "Failed\n")); + BaseAddress +=3D (Alignment + 1); + } // while + } // if + + TypeMem32Found: + if (RootBridge->ResAllocNode[Index].Status !=3D ResAlloca= ted) { + // + // No Room at the Inn for this resources request + // + ReturnStatus =3D EFI_OUT_OF_RESOURCES; + } + break; + + case TypePMem32: + StartTypePMem32: + if (RootBridge->Aperture.Mem32Base < RootBridge->Aperture.= Mem32Limit) { + BaseAddress =3D RootBridge->Aperture.Mem32Limit + 1; + BaseAddress -=3D AddrLen; + + // + // Have to make sure Alignment is handled seeing we are = doing direct address allocation + // + if ((BaseAddress & ~(Alignment)) !=3D BaseAddress) { + BaseAddress =3D ((BaseAddress) & ~(Alignment)); + } + + while (RootBridge->Aperture.Mem32Base <=3D BaseAddress) { + + DEBUG ((DEBUG_INFO, " Attempting %s allocation at= 0x%llX.....", + mPciResourceTypeStr[Index], BaseAddress)); + Status =3D gDS->AllocateMemorySpace (EfiGcdAllocateAdd= ress, EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, Ad= drLen, &BaseAddress, mDriverImageHandle, NULL); + if (!EFI_ERROR (Status)) { + RootBridge->ResAllocNode[Index].Base =3D (UINT64)= BaseAddress; + RootBridge->ResAllocNode[Index].Status =3D ResAlloc= ated; + DEBUG ((DEBUG_INFO, "Passed\n")); + goto TypePMem32Found; + } + DEBUG ((DEBUG_INFO, "Failed\n")); + BaseAddress -=3D (Alignment + 1); + } // while + } // if + + TypePMem32Found: + if (RootBridge->ResAllocNode[Index].Status !=3D ResAlloca= ted) { + // + // No Room at the Inn for this resources request + // + ReturnStatus =3D EFI_OUT_OF_RESOURCES; + } + break; + + case TypeMem64: + case TypePMem64: + if ((RootBridge->Aperture.Mem64Limit > RootBridge->Apertur= e.Mem64Base) && + (mIioUds->IioUdsPtr->PlatformData.Pci64BitResourceAllo= cation)) { + + if (RootBridge->Aperture.Mem64Limit < AddrLen) { + RootBridge->ResAllocNode[Index].Status =3D ResNone; + goto TypeMem64Found; + } + BaseAddress =3D RootBridge->Aperture.Mem64Limit + 1; + BaseAddress -=3D AddrLen; + + // + // Have to make sure Alignment is handled seeing we are = doing direct address allocation + // + if ((BaseAddress & ~(Alignment)) !=3D BaseAddress) { + BaseAddress =3D ((BaseAddress) & ~(Alignment)); + } + + while (RootBridge->Aperture.Mem64Base <=3D BaseAddress) { + + DEBUG ((DEBUG_INFO, " Attempting %s allocation at= 0x%llX.....", + mPciResourceTypeStr[Index], BaseAddress)); + Status =3D gDS->AllocateMemorySpace (EfiGcdAllocateAdd= ress, EfiGcdMemoryTypeMemoryMappedIo, + BitsOfAlignment, Ad= drLen, &BaseAddress, mDriverImageHandle, NULL); + if (!EFI_ERROR (Status)) { + RootBridge->ResAllocNode[Index].Base =3D (UINT64)= BaseAddress; + RootBridge->ResAllocNode[Index].Status =3D ResAlloc= ated; + DEBUG ((DEBUG_INFO, "Passed\n")); + goto TypeMem64Found; + } + DEBUG ((DEBUG_INFO, "Failed\n")); + BaseAddress -=3D (Alignment + 1); + } // while + + TypeMem64Found: + if (RootBridge->ResAllocNode[Index].Status !=3D ResAlloc= ated) { + // + // No Room at the Inn for this resources request + // + ReturnStatus =3D EFI_OUT_OF_RESOURCES; + } + } else { + // + // If 64-bit resourcing is not available, and the reques= ted size is not greater than the Mem32Limit, then try as PMem32 + // + if (AddrLen >=3D RootBridge->Aperture.Mem32Limit + 1) { + + DEBUG((DEBUG_ERROR, " 64-bit resource length 0x%l= lX > Mem32Limit (0x%llX). Failed!!\n", AddrLen, RootBridge->Aperture.Mem32L= imit + 1)); + goto TypeMem64Found; // Let it handle out-of-resources= case, try MMIO rebalance + + } else { + + DEBUG((DEBUG_ERROR, " 64-bit resourcing not avail= able. 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", mPciReso= urceTypeStr[Index])); + if (RootBridge->ResAllocNode[Index].Status =3D=3D ResAllocated= ) { + DEBUG ((DEBUG_INFO, " Base Address Assigned: %lx\n", RootBr= idge->ResAllocNode[Index].Base)); + DEBUG ((DEBUG_INFO, " Length Assigned: %lx\n", RootBr= idge->ResAllocNode[Index].Length)); + } else { + DEBUG ((DEBUG_ERROR, " Resource Allocation failed! There w= as no room at the inn\n")); + } + } else { + // + // Index >=3D TypeMax + // + ASSERT (FALSE); + } + } + } + List =3D List->ForwardLink; + } + + if (ReturnStatus =3D=3D EFI_OUT_OF_RESOURCES) { + + DEBUG ((DEBUG_ERROR, "[PCI] Resource allocation failed, rebalance re= source allocation and reboot\n")); + AdjustResourceAmongRootBridges (HostBridge, &RatioAdjustResult); + if (RatioAdjustResult =3D=3D SocketResourceRatioChanged) { + DEBUG ((DEBUG_WARN, "[PCI] WARNING: Resource allocation failed. Ad= justed the resource requests and resetting the system.\n")); + gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL); + + } else { + + DEBUG ((DEBUG_WARN, "[PCI] WARNING: Resource allocation failed, re= balance not possible, continue boot\n")); + } + } + + // + // Set resource to zero for nodes where allocation fails + // + List =3D HostBridge->RootBridges.ForwardLink; + while (List !=3D &HostBridge->RootBridges) { + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + for (Index =3D TypeIo; Index < TypeBus; Index++) { + if (RootBridge->ResAllocNode[Index].Status !=3D ResAllocated) { + RootBridge->ResAllocNode[Index].Length =3D 0; + } + } + List =3D List->ForwardLink; + } + return ReturnStatus; + } else { + return EFI_NOT_READY; + } + // + // HostBridge->CanRestarted =3D 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 =3D PCI_HOST_BRIDGE_FROM_THIS (This); + ReturnStatus =3D EFI_SUCCESS; + List =3D HostBridge->RootBridges.ForwardLink; + + while (List !=3D &HostBridge->RootBridges) { + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + for (Index =3D TypeIo; Index < TypeBus; Index++) { + if (RootBridge->ResAllocNode[Index].Status =3D=3D ResAllocated) { + AddrLen =3D RootBridge->ResAllocNode[Index].Length; + BaseAddress =3D (EFI_PHYSICAL_ADDRESS) RootBridge->ResAllocNode[In= dex].Base; + + switch (Index) { + case TypeIo: + Status =3D gDS->FreeIoSpace (BaseAddress, AddrLen); + if (EFI_ERROR (Status)) { + ReturnStatus =3D Status; + } + break; + + case TypeMem32: + Status =3D gDS->FreeMemorySpace (BaseAddress, AddrLen); + if (EFI_ERROR (Status)) { + ReturnStatus =3D Status; + } + break; + + case TypePMem32: + break; + + case TypeMem64: + break; + + case TypePMem64: + Status =3D gDS->FreeMemorySpace (BaseAddress, AddrLen); + if (EFI_ERROR (Status)) { + ReturnStatus =3D Status; + } + break; + + default: + DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Invalid resource type %d\n", = Index)); + break; + } + + RootBridge->ResAllocNode[Index].Type =3D Index; + RootBridge->ResAllocNode[Index].Base =3D 0; + RootBridge->ResAllocNode[Index].Length =3D 0; + RootBridge->ResAllocNode[Index].Status =3D ResNone; + } + } + + List =3D List->ForwardLink; + } + + HostBridge->ResourceSubmited =3D FALSE; + HostBridge->CanRestarted =3D 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 insta= nce. + @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 =3D 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 specif= ic programing + // + HostBridge->CanRestarted =3D FALSE; + break; + + case EfiPciHostBridgeEndBusAllocation: + // + // No specific action is required here, can perform any chipset specif= ic programing + // + break; + + case EfiPciHostBridgeBeginResourceAllocation: + // + // No specific action is required here, can perform any chipset specif= ic programing + // + break; + + case EfiPciHostBridgeAllocateResources: + return BridgeAllocateResources (This); + + case EfiPciHostBridgeSetResources: + // + // HostBridgeInstance->CanRestarted =3D 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_ PR= OTOCOL instance. + @param RootBridgeHandle Returns the device handle of the next PCI Root = Bridge. + On input, it holds the RootBridgeHandle returne= d by the most + recent call to GetNextRootBridge().The handle f= or 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 =3D TRUE; + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + + while (List !=3D &HostBridge->RootBridges) { + NoRootBridge =3D FALSE; + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (*RootBridgeHandle =3D=3D NULL) { + // + // Return the first Root Bridge Handle of the Host Bridge + // + *RootBridgeHandle =3D RootBridge->Handle; + return EFI_SUCCESS; + } else { + if (*RootBridgeHandle =3D=3D RootBridge->Handle) { + // + // Get next if have + // + List =3D List->ForwardLink; + if (List !=3D &HostBridge->RootBridges) { + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + *RootBridgeHandle =3D RootBridge->Handle; + return EFI_SUCCESS; + } else { + return EFI_NOT_FOUND; + } + } + } + + List =3D 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_ PR= OTOCOL 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 Bridg= e. + + @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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + for (Link =3D GetFirstNode (&HostBridge->RootBridges) + ; !IsNull (&HostBridge->RootBridges, Link) + ; Link =3D GetNextNode (&HostBridge->RootBridges, Link) + ) { + RootBridge =3D ROOT_BRIDGE_FROM_LINK (Link); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + *Attributes =3D 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_ PR= OTOCOL 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 =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + + while (List !=3D &HostBridge->RootBridges) { + + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + // + // Set up the Root Bridge for Bus Enumeration + // + BusStart =3D RootBridge->Aperture.BusBase; + BusEnd =3D RootBridge->Aperture.BusLimit; + BusReserve =3D RootBridge->Aperture.BusReserve; + // + // Program the Hardware(if needed) if error return EFI_DEVICE_ERROR + // + Status =3D 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 =3D (UINT8 *) Buffer; + + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Desc = =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->Len = =3D 0x2B; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->ResType = =3D ACPI_ADDRESS_SPACE_TYPE_BUS; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->GenFlag = =3D 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->SpecificFlag = =3D 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrSpaceGranularity = =3D 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMin = =3D BusStart; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrRangeMax = =3D BusReserve; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrTranslationOffset = =3D 0; + ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp)->AddrLen = =3D BusEnd - BusStart + 1; + + Temp =3D Temp + sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc =3D ACPI_END_TAG_DESCRI= PTOR; + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum =3D 0x0; + + *Configuration =3D Buffer; + return EFI_SUCCESS; + } + + List =3D 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_ PR= OTOCOL instance. + @param RootBridgeHandle The PCI Root Bridge whose bus range is to be pr= ogrammed. + @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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + Ptr =3D Configuration; + + // + // Check the Configuration is valid + // + if (*Ptr !=3D ACPI_ADDRESS_SPACE_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + if (((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->ResType !=3D ACPI_ADDRE= SS_SPACE_TYPE_BUS) { + return EFI_INVALID_PARAMETER; + } + + Ptr +=3D sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + if (*Ptr !=3D ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + Ptr =3D Configuration; + + while (List !=3D &HostBridge->RootBridges) { + + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + BusStart =3D (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->A= ddrRangeMin; + BusLen =3D (UINTN) ((EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Ptr)->A= ddrLen; + BusEnd =3D BusStart + BusLen - 1; + + if (BusStart > BusEnd) { + return EFI_INVALID_PARAMETER; + } + + if ((BusStart < RootBridge->Aperture.BusBase) || (BusEnd > RootBridg= e->Aperture.BusLimit)) { + return EFI_INVALID_PARAMETER; + } + // + // Update the Bus Range + // + RootBridge->ResAllocNode[TypeBus].Base =3D BusStart; + RootBridge->ResAllocNode[TypeBus].Length =3D BusLen + RootBridge->A= perture.BusReserve; + RootBridge->ResAllocNode[TypeBus].Status =3D ResAllocated; + RootBridge->BusScanCount++; + if (RootBridge->BusScanCount > 0) { + // + // Only care about the 2nd PCI bus scanning + // + RootBridge->BusNumberAssigned =3D TRUE; + } + + return EFI_SUCCESS; + } + + List =3D List->ForwardLink; + } + + return EFI_INVALID_PARAMETER; +} + + +/** + + Submits the I/O and memory resource requirements for the specified PCI R= oot Bridge. + + @param This The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_ PR= OTOCOL instance. + @param RootBridgeHandle The PCI Root Bridge whose I/O and memory resour= ce requirements. + are being submitted. + @param Configuration The pointer to the PCI I/O and PCI memory resou= rce 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + + Temp =3D (UINT8 *) Configuration; + while (List !=3D &HostBridge->RootBridges) { + + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + // + // Check the resource descriptors. + // If the Configuration includes one or more invalid resource descri= ptors, all the resource + // descriptors are ignored and the function returns EFI_INVALID_PARA= METER. + // + for (; *Temp =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR; Temp +=3D sizeof = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)) { + + ptr =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + //DEBUG ((DEBUG_ERROR, " ptr->ResType:%x", ptr->ResType)); + //DEBUG ((DEBUG_ERROR, " ptr->AddrLen:0x%llX AddrRangeMin:0x%llX A= ddrRangeMax:0x%llX\n",ptr->AddrLen,ptr->AddrRangeMin,ptr->AddrRangeMax)); + // + // A zero-length resource request indicates the PCI root bridge do= esn't require + // any resources. Skip the check and proceed to the next descripto= r. + // + if (ptr->AddrLen =3D=3D 0) { + continue; + } + + switch (ptr->ResType) { + case ACPI_ADDRESS_SPACE_TYPE_MEM: + if (ptr->AddrSpaceGranularity !=3D 32 && ptr->AddrSpaceGranula= rity !=3D 64) { + + DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Inavlid granularity %d fo= r resource type %d\n", + ptr->AddrSpaceGranularity, ptr->ResType)); + return EFI_INVALID_PARAMETER; + } + if (ptr->AddrSpaceGranularity =3D=3D 32 && ptr->AddrLen > 0xff= ffffff) { + + DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Inavlid granularity %d fo= r resource type %d of size 0x%llX\n", + ptr->AddrSpaceGranularity, ptr->ResType, ptr->AddrLe= n)); + return EFI_INVALID_PARAMETER; + } + // + // If the PCI root bridge does not support separate windows fo= r nonprefetchable and + // prefetchable memory, then the PCI bus driver needs to inclu= de requests for + // prefetchable memory in the nonprefetchable memory pool. + // + if ((RootBridge->AllocationAttributes & EFI_PCI_HOST_BRIDGE_CO= MBINE_MEM_PMEM) !=3D 0 && + ((ptr->SpecificFlag & (BIT2 | BIT1)) !=3D 0)) { + return EFI_INVALID_PARAMETER; + } + case ACPI_ADDRESS_SPACE_TYPE_IO: + // + // Check alignment, it should be of the form 2^n-1 + // + Value =3D Power2MaxMemory (ptr->AddrRangeMax + 1); + if (Value !=3D (ptr->AddrRangeMax + 1)) { + CpuDeadLoop(); + return EFI_INVALID_PARAMETER; + } + break; + case ACPI_ADDRESS_SPACE_TYPE_BUS: + default: + return EFI_INVALID_PARAMETER; + } + } + if (*Temp !=3D ACPI_END_TAG_DESCRIPTOR) { + return EFI_INVALID_PARAMETER; + } + + Temp =3D (UINT8 *) Configuration; + for (; *Temp =3D=3D ACPI_ADDRESS_SPACE_DESCRIPTOR; Temp +=3D sizeof = (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)) { + ptr =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + + // + // If a PCI root bridge does not require any resources, a zero-len= gth resource + // request must be explicitly submitted. + // + if (ptr->AddrLen =3D=3D 0) { + HostBridge->ResourceSubmited =3D TRUE; + continue; + } + + switch (ptr->ResType) { + case ACPI_ADDRESS_SPACE_TYPE_MEM: + AddrLen =3D (UINT64) ptr->AddrLen; + Alignment =3D (UINT64) ptr->AddrRangeMax; + if (ptr->AddrSpaceGranularity =3D=3D 32) { + if (ptr->SpecificFlag =3D=3D 0x06) { + // + // Apply from GCD + // + RootBridge->ResAllocNode[TypePMem32].Status =3D ResSubmitted; + } else { + RootBridge->ResAllocNode[TypeMem32].Length =3D AddrLen; + RootBridge->ResAllocNode[TypeMem32].Alignment =3D Alignment; + RootBridge->ResAllocNode[TypeMem32].Status =3D ResRequest= ed; + HostBridge->ResourceSubmited =3D TRUE; + } + } + + if (ptr->AddrSpaceGranularity =3D=3D 64) { + if (ptr->SpecificFlag =3D=3D 0x06) { + RootBridge->ResAllocNode[TypePMem64].Status =3D ResSubmitted; + } else { + RootBridge->ResAllocNode[TypeMem64].Length =3D AddrLen; + RootBridge->ResAllocNode[TypeMem64].Alignment =3D Alignment; + RootBridge->ResAllocNode[TypeMem64].Status =3D ResSubmitt= ed; + HostBridge->ResourceSubmited =3D TRUE; + } + } + break; + + case ACPI_ADDRESS_SPACE_TYPE_IO: + AddrLen =3D (UINT64) ptr->AddrLen; + Alignment =3D (UINT64) ptr->AddrRangeMax; + RootBridge->ResAllocNode[TypeIo].Length =3D AddrLen; + RootBridge->ResAllocNode[TypeIo].Alignment =3D Alignment; + RootBridge->ResAllocNode[TypeIo].Status =3D ResRequested; + HostBridge->ResourceSubmited =3D TRUE; + break; + + default: + break; + } + } + + return EFI_SUCCESS; + } + List =3D 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_ PR= OTOCOL 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 =3D NULL; + Number =3D 0; + // + // Get the Host Bridge Instance from the resource allocation protocol + // + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + + // + // Enumerate the root bridges in this Host bridge + // + while (List !=3D &HostBridge->RootBridges) { + + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + for (Index =3D 0; Index < TypeBus; Index++) { + if (RootBridge->ResAllocNode[Index].Status !=3D ResNone) { + Number++; + } + } + + Status =3D 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 =3D Buffer; + for (Index =3D 0; Index < TypeBus; Index++) { + if (RootBridge->ResAllocNode[Index].Status !=3D ResNone) { + ptr =3D (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *) Temp; + ResStatus =3D RootBridge->ResAllocNode[Index].Status; + + switch (Index) { + + case TypeIo: + // + // Io + // + ptr->Desc =3D 0x8A; + ptr->Len =3D 0x2B; + ptr->ResType =3D 1; + ptr->GenFlag =3D 0; + ptr->SpecificFlag =3D 0; + ptr->AddrRangeMin =3D RootBridge->ResAllocNode[Index= ].Base; + ptr->AddrRangeMax =3D 0; + ptr->AddrTranslationOffset =3D (ResStatus =3D=3D ResAllocated= ) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen =3D RootBridge->ResAllocNode[Index= ].Length; + break; + + case TypeMem32: + // + // Memory 32 + // + ptr->Desc =3D 0x8A; + ptr->Len =3D 0x2B; + ptr->ResType =3D 0; + ptr->GenFlag =3D 0; + ptr->SpecificFlag =3D 0; + ptr->AddrSpaceGranularity =3D 32; + ptr->AddrRangeMin =3D RootBridge->ResAllocNode[Index= ].Base; + ptr->AddrRangeMax =3D 0; + ptr->AddrTranslationOffset =3D (ResStatus =3D=3D ResAllocated= ) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen =3D RootBridge->ResAllocNode[Index= ].Length; + break; + + case TypePMem32: + // + // Prefetch memory 32 + // + ptr->Desc =3D 0x8A; + ptr->Len =3D 0x2B; + ptr->ResType =3D 0; + ptr->GenFlag =3D 0; + ptr->SpecificFlag =3D 6; + ptr->AddrSpaceGranularity =3D 32; + ptr->AddrRangeMin =3D 0; + ptr->AddrRangeMax =3D 0; + ptr->AddrTranslationOffset =3D EFI_RESOURCE_NONEXISTENT; + ptr->AddrLen =3D 0; + break; + + case TypeMem64: + // + // Memory 64 + // + ptr->Desc =3D 0x8A; + ptr->Len =3D 0x2B; + ptr->ResType =3D 0; + ptr->GenFlag =3D 0; + ptr->SpecificFlag =3D 0; + ptr->AddrSpaceGranularity =3D 64; + ptr->AddrRangeMin =3D RootBridge->ResAllocNode[Index= ].Base; + ptr->AddrRangeMax =3D 0; + ptr->AddrTranslationOffset =3D (ResStatus =3D=3D ResAllocated= ) ? EFI_RESOURCE_SATISFIED : EFI_RESOURCE_LESS; + ptr->AddrLen =3D RootBridge->ResAllocNode[Index= ].Length; + break; + + case TypePMem64: + // + // Prefetch memory 64 + // + ptr->Desc =3D 0x8A; + ptr->Len =3D 0x2B; + ptr->ResType =3D 0; + ptr->GenFlag =3D 0; + ptr->SpecificFlag =3D 6; + ptr->AddrSpaceGranularity =3D 64; + ptr->AddrRangeMin =3D 0; + ptr->AddrRangeMax =3D 0; + ptr->AddrTranslationOffset =3D EFI_RESOURCE_NONEXISTENT; + ptr->AddrLen =3D 0; + break; + default: + DEBUG ((EFI_D_INFO, "default case.\n")); //Auto added. Plea= se review. + break; + } + + Temp +=3D sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR); + } + } + + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Desc =3D 0x79; + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Temp)->Checksum =3D 0x0; + + *Configuration =3D Buffer; + + return EFI_SUCCESS; + } + + List =3D 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_ PR= OTOCOL 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 RootBridge= Handle, + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + RootBridgeFound =3D FALSE; + HostBridge =3D PCI_HOST_BRIDGE_FROM_THIS (This); + List =3D HostBridge->RootBridges.ForwardLink; + + while (List !=3D &HostBridge->RootBridges) { + + RootBridge =3D ROOT_BRIDGE_FROM_LINK (List); + if (RootBridgeHandle =3D=3D RootBridge->Handle) { + RootBridgeFound =3D TRUE; + break; + } + // + // Get next if have + // + List =3D List->ForwardLink; + } + + if (RootBridgeFound =3D=3D 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 =3D LShiftU64 ((UINT64) GetPowerOfTwo64 ((UINT32) RShiftU64 (Me= moryLength, 32)), 32); + } else { + Result =3D (UINT64) GetPowerOfTwo64 ((UINT32) MemoryLength); + } + + return Result; +} + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/PciHostBridge.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/P= ciHostBridge/PciHostBridge.h new file mode 100644 index 0000000000..4c1b757952 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= HostBridge.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, ResA= lloc, 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 insta= nce. + @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_ PR= OTOCOL instance. + @param RootBridgeHandle Returns the device handle of the next PCI Root = Bridge. + On input, it holds the RootBridgeHandle returne= d by the most + recent call to GetNextRootBridge().The handle f= or 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 Br= idge + + @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 resour= ce 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 descript= or. + + @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 R= oot Bridge. + + @param This - The EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_= PROTOCOL instance + @param RootBridgeHandle - The PCI Root Bridge whose I/O and memory res= ource requirements + are being submitted + @param Configuration - The pointer to the PCI I/O and PCI memory re= source 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 RootBridgeH= andle, + 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 in= terface instance. + @param Mem32Base - Pointer to 32 bit memory base. This is the lo= west 32 bit memory address + that is decoded by the Host Bridge. + @param Mem32Limit - Pointer to 32 bit memory limit.This is the hi= ghest 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 lo= west 64 bit memory address + that is decoded by the Host Bridge. + @param Mem64Limit - Pointer to 64 bit memory limit.This is the hi= ghest 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/PciHostBri= dge/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/Pci= HostBridge.inf @@ -0,0 +1,69 @@ +## @file +# +# @copyright +# Copyright 2009 - 2021 Intel Corporation.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PciHostBridge + FILE_GUID =3D D58EBCE1-AF26-488d-BE66-C164417F8C13 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/PciHostBri= dge/PciHostBridgeSupport.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pc= i/Dxe/PciHostBridge/PciHostBridgeSupport.c new file mode 100644 index 0000000000..fe3f274f1f --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= HostBridgeSupport.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 RootBridge= Handle, + 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 =3D=3D NULL) { + // + // Get root bridge in the system. + // + Status =3D gBS->HandleProtocol (RootBridgeHandle, &gEfiPciRootBridgeIo= ProtocolGuid, &mPciRootBridgeIo); + ASSERT_EFI_ERROR (Status); + } + + if (Phase =3D=3D EfiPciBeforeResourceCollection) { + // + // Program the latency register, CLS register + // + PciAddress.Register =3D 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 the= m. + // + if (Latency =3D=3D 0) { + Latency =3D DEFAULT_PCI_LATENCY; + mPciRootBridgeIo->Pci.Write ( + mPciRootBridgeIo, + EfiPciWidthUint8, + *((UINT64 *) &PciAddress), + 1, + &Latency + ); + } + // + // Program Cache Line Size as 64bytes + // 16 of DWORDs =3D 64bytes (0x10) + // + PciAddress.Register =3D PCI_CACHELINE_SIZE_OFFSET; + CacheLineSize =3D 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 =3D=3D 0); + + // + // PCI Root Bridge does not support separate windows for Non-prefetchable + // and Prefetchable memory. A PCI bus driver needs to include requests f= or + // 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_MEM6= 4_DECODE; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/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/Pci= HostResource.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 =3D 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/PciHostBri= dge/PciRebalance.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pc= iHostBridge/PciRebalance.c new file mode 100644 index 0000000000..b32f0bf835 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= Rebalance.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 instan= ce + * to the PCI stack. + */ +PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTable[MAX_SOCKET][MAX_LOGIC_IIO_ST= ACK] =3D {0}; +PCI_ROOT_BRIDGE_INSTANCE *mPciRootBridgeTableReserved[MAX_SOCKET][IIO_RESE= RVED_1] =3D {0}; + + +/*************************************************************************= ***** + * Functions. + *************************************************************************= *****/ + +/** + Find socket and stack index for given PCI Root Bridge protocol pointer. + + @param[out] PciResConfigPtr - Buffer for the resource configuration varia= ble. + + @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 !=3D NULL) { + + for (Socket =3D 0; Socket < NELEMENTS(mPciRootBridgeTable); Socket++) { + + for (Stack =3D 0; Stack < NELEMENTS(mPciRootBridgeTable[Socket]); St= ack++) { + + if (mPciRootBridgeTable[Socket][Stack] =3D=3D RootBridgePtr) { + if (SocketPtr !=3D NULL) { + *SocketPtr =3D Socket; + } + if (StackPtr !=3D NULL) { + *StackPtr =3D 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_resourc= e)); + ASSERT (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid); + + FoundEnabledStack =3D FALSE; + LastStack =3D 0; + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBi= tmap & (1 << Stack)) { + LastStack =3D Stack; + FoundEnabledStack =3D TRUE; + } + } + + ASSERT (FoundEnabledStack); + return LastStack; +} + + +/** + Determine the last stack for a given socket with resources + + @param SocketResources - CPU_RESOURCE structure pointer that stores al= l 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 reques= ted 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 =3D 0; + *ResourceSize =3D 0; + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresent= Bitmap & (1 << Stack))) { + continue; + } + + switch (ResourceType) { + case TypeIo: + if (SocketResources->StackRes[Stack].NumIoPortsDesired !=3D 0) { + *ResourceSize +=3D SocketResources->StackRes[Stack].NumIoPortsDe= sired + 1; + *LastStack =3D Stack; + } + break; + case TypeMem32: + if (SocketResources->StackRes[Stack].MmiolLength !=3D 0) { + *ResourceSize +=3D SocketResources->StackRes[Stack].MmiolLength = + 1; + *LastStack =3D Stack; + } + break; + case TypeMem64: + if (SocketResources->StackRes[Stack].MmiohLength !=3D 0) { + *ResourceSize +=3D SocketResources->StackRes[Stack].MmiohLength = + 1; + *LastStack =3D 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 a= ll 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 wi= thin the socket. +**/ +EFI_STATUS +AdjustResources ( + CPU_RESOURCE *SocketResources, + UINT8 Socket, + UINT8 ResourceType + ) +{ + UINT8 Stack; + UINT64 NewLength; + CONST UINT8 LastStack =3D LastStackOfSocket (Socket); + UINT64 PreviousLimit; + BOOLEAN FirstStack =3D TRUE; + + switch (ResourceType) { + case TypeIo: + // Return if IoResourceNeeds is not zero which indicates a socket ad= justment is needed + if(SocketResources->IoResourceNeeds !=3D 0){ + return EFI_OUT_OF_RESOURCES; + } + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))){ + continue; + } + // + // For the first enabled stack, use the base I/O address for the s= ocket, 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 =3D mIioUds->IioUdsPtr->= PlatformData.IIO_resource[Socket].PciResourceIoBase; + FirstStack =3D FALSE; + } else { + // Check to see if the previous stack is disabled by checking fo= r equal base and limit + if (SocketResources->StackRes[Stack-1].IoBase =3D=3D SocketResou= rces->StackRes[Stack-1].IoLimit) { + if (PreviousLimit % 2 =3D=3D 1) { + PreviousLimit +=3D 1; + } + SocketResources->StackRes[Stack].IoBase =3D (UINT16) PreviousL= imit; + } else { + SocketResources->StackRes[Stack].IoBase =3D (UINT16) PreviousL= imit + 1; + } + } + + NewLength =3D 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 =3D=3D LastStack) { + if (NewLength !=3D 0) { + if (SocketResources->IoResourcesLeft !=3D 0) { + NewLength +=3D SocketResources->IoResourcesLeft + 1; + } + } else { + NewLength =3D SocketResources->IoResourcesLeft; + } + } + + SocketResources->StackRes[Stack].NeedIoUpdate =3D TRUE; + SocketResources->StackRes[Stack].IoLimit =3D (UINT16)(SocketResour= ces->StackRes[Stack].IoBase + NewLength); + PreviousLimit =3D SocketResources->StackRes[Stack].IoLimit; + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoBase =3D%x = newLength =3D %x\n",Socket,Stack,SocketResources->StackRes[Stack].IoBase,= NewLength)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoLimit =3D%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 !=3D 0) { + return EFI_OUT_OF_RESOURCES; + } + // + // Visit all Stacks in this Socket and recalculate the New Mem32 R= anges per Stack + // + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++){ + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackP= resentBitmap & (1 << Stack))) { + continue; + } + // + // For the first enabled stack, use the base low mmio address fo= r the socket, otherwize + // calculate the new base based off the last enabled stack + // + if (FirstStack) { + // stackPresentBitmap doesn't cover if a valid stack was disab= le due to resource adjustments. + // Start with valid resources for current socket + SocketResources->StackRes[Stack].MmiolBase =3D mIioUds->IioUds= Ptr->PlatformData.IIO_resource[Socket].Mmio32Base; + FirstStack =3D FALSE; + } else { + // Check to see if the previous stack is disabled by checking = for equal base and limit + if (SocketResources->StackRes[Stack-1].MmiolBase =3D=3D Socket= Resources->StackRes[Stack-1].MmiolLimit) { + if (PreviousLimit % 2 =3D=3D 1) { + PreviousLimit +=3D 1; + } + SocketResources->StackRes[Stack].MmiolBase =3D (UINT32) Prev= iousLimit; + } else { + SocketResources->StackRes[Stack].MmiolBase =3D (UINT32) Prev= iousLimit + 1; + } + } + // + // Verify if this Stack is the one that requires an update and c= alculate the new Limit + // otherwise assign the new limit based on the Chunk and Extra C= hunk calculation and assign the Newlength + // + NewLength =3D SocketResources->StackRes[Stack].MmiolLength; + // + //assign the left space to the last IIO stack. Reserved for acro= ss socket resource adjustment. + //make adjustments if NewLength is zero + // + if (Stack =3D=3D LastStack) { + if (NewLength !=3D 0) { + if (SocketResources->MmiolResourcesLeft){ + NewLength +=3D SocketResources->MmiolResourcesLeft + 1; + } + } else { + NewLength =3D SocketResources->MmiolResourcesLeft; + } + } + + SocketResources->StackRes[Stack].MmiolUpdate =3D 1; + SocketResources->StackRes[Stack].MmiolLimit =3D (UINT32)(Socket= Resources->StackRes[Stack].MmiolBase + NewLength); + PreviousLimit =3D SocketResources->StackRes[Stack].MmiolLimit; + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolBase = =3D%x newLength =3D %x\n",Socket,Stack,SocketResources->StackRes[Stack].M= miolBase,NewLength)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolLimit = =3D%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 !=3D 0){ + return EFI_OUT_OF_RESOURCES; + } + // + // Visit all Stacks in this Socket and recalculate the New Mem64 Ran= ges per Stack + // + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + + if(!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPres= entBitmap & (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 =3D mIioUds->IioUdsPt= r->PlatformData.IIO_resource[Socket].Mmio64Base; + FirstStack =3D FALSE; + } else { + // Check to see if the previous stack is disabled by checking f= or equal base and limit + if (SocketResources->StackRes[Stack-1].MmiohBase =3D=3D SocketRe= sources->StackRes[Stack-1].MmiohLimit) { + if (PreviousLimit % 2 =3D=3D 1) { + PreviousLimit +=3D 1; + } + SocketResources->StackRes[Stack].MmiohBase =3D PreviousLimit; + } else { + SocketResources->StackRes[Stack].MmiohBase =3D PreviousLimit += 1; + } + } + + // + // Verify if this Stack is the one that requires an update and cal= culate the new Limit + // otherwise assign the new limit based on the Chunk and Extra Chu= nk calculation and assign the Newlength + // + + NewLength =3D 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 =3D=3D LastStack) { + if (NewLength !=3D 0) { + if (SocketResources->MmiohResourcesLeft) { + NewLength +=3D SocketResources->MmiohResourcesLeft + 1; + } + } else { + NewLength =3D SocketResources->MmiohResourcesLeft; + } + } + + SocketResources->StackRes[Stack].MmiohUpdate =3D 1; + SocketResources->StackRes[Stack].MmiohLimit =3D (SocketResources-= >StackRes[Stack].MmiohBase + NewLength); + PreviousLimit =3D SocketResources->StackRes[Stack].MmiohLimit; + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohBase =3D= %lx newLength =3D %lx\n",Socket,Stack,SocketResources->StackRes[Stack].Mm= iohBase,NewLength)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohLimit = =3D%lx\n",Socket,Stack,SocketResources->StackRes[Stack].MmiohLimit)); + + } // for Stack + break; + default: + DEBUG((DEBUG_ERROR, "[PCI] ERROR: Resource Type Unknown =3D %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 a= ll resources need per socket + @param ResourceType - type of resource that requires alignment + @param ValidSockets - Number of Valid Sockets, need it to calcula= te how resources need to be splitted + + @retval EFI_SUCCESS - Succeed. + @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted wi= thin the socket. +**/ +EFI_STATUS +AdjustSocketResources ( + CPU_RESOURCE *SocketResources, + UINT8 ResourceType, + UINT8 ValidSockets + ) +{ + EFI_STATUS Status; + + switch(ResourceType){ + case TypeIo: + Status =3D AdjustSocketIo (SocketResources, ResourceType, ValidSocke= ts); + break; + case TypeMem32: + Status =3D AdjustSocketMmioL (SocketResources, ResourceType, ValidSo= ckets); + break; + case TypeMem64: + Status =3D AdjustSocketMmioH (SocketResources, ResourceType, ValidSo= ckets); + break; + default: + DEBUG((DEBUG_ERROR, "ERROR: Resource Type Unknown =3D %x\n",Resource= Type)); + Status =3D EFI_INVALID_PARAMETER; + break; + } // switch + + return Status; +} + + +/** + Calculate current system resource map with retrieved NVRAM variable to s= ee 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 ap= plied or not initialized + @retval FALSE - SYSTEM_PCI_BASE_LIMITS has been applied and still has r= elevant data +**/ +BOOLEAN +IsResourceMapRejected ( + SYSTEM_PCI_BASE_LIMITS *SocketPciResourceData + ) +{ + UINT8 Socket; + UINT8 Stack; + BOOLEAN Rejected =3D 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 =3D=3D NULL) { + return TRUE; + } + for (Socket =3D 0; Socket < MAX_SOCKET; Socket++) { + + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) { + + IioUdsSocketLimits =3D &mIioUds->IioUdsPtr->PlatformData.IIO_resourc= e[Socket]; + SocketLimits =3D &SocketPciResourceData->Socket[Socket].SocketLimits; + IioUdsUboxStackLimits =3D &mIioUds->IioUdsPtr->PlatformData.IIO_reso= urce[Socket].StackRes[UBOX_STACK]; + UboxStackLimits =3D &SocketPciResourceData->Socket[Socket].StackLimi= ts[UBOX_STACK]; + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + + if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPrese= ntBitmap & (1 << Stack)) { + + IioUdsStackLimits =3D &mIioUds->IioUdsPtr->PlatformData.IIO_reso= urce[Socket].StackRes[Stack]; + StackLimits =3D &SocketPciResourceData->Socket[Socket].StackLimi= ts[Stack]; + // + // Per stack + // + if (Socket =3D=3D 0 && Stack =3D=3D 0) { + // First base starts at zero, mIioUds struct reserves 4K of Io= for legacy purposes + if (StackLimits->Io.Base !=3D 0) { + Rejected =3D TRUE; + } + } else { + if (IioUdsStackLimits->PciResourceIoBase !=3D StackLimits->Io.= Base && StackLimits->Io.Base !=3D 0) { + Rejected =3D TRUE; + } + } + if (IioUdsStackLimits->PciResourceIoLimit !=3D StackLimits->Io.L= imit && StackLimits->Io.Limit !=3D 0) { + Rejected =3D TRUE; + } + PCIDEBUG ("[%d.%d] Current I/O: 0x%04X..0x%04X\n", Socket, Stack, + IioUdsStackLimits->PciResourceIoBase, IioUdsStackLimit= s->PciResourceIoLimit); + PCIDEBUG ("[%d.%d] Saved I/O: 0x%04X..0x%04X %a\n", Socket, St= ack, + StackLimits->Io.Base, StackLimits->Io.Limit, Rejected ?= "rejected" : ""); + + if (IioUdsStackLimits->Mmio32Base !=3D StackLimits->LowMmio.Base= && StackLimits->LowMmio.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsStackLimits->Mmio32Limit !=3D StackLimits->LowMmio.Lim= it && StackLimits->LowMmio.Limit !=3D 0) { + Rejected =3D TRUE; + } + PCIDEBUG ("[%d.%d] Current MMIOL: 0x%08X..0x%08X\n", Socket, Sta= ck, + IioUdsStackLimits->Mmio32Base, IioUdsStackLimits->Mmio= 32Limit); + PCIDEBUG ("[%d.%d] Saved MMIOL: 0x%08X..0x%08X %a\n", Socket, = Stack, + StackLimits->LowMmio.Base, StackLimits->LowMmio.Limit,= Rejected ? "rejected" : ""); + + if (IioUdsStackLimits->Mmio64Base !=3D StackLimits->HighMmio.Bas= e && StackLimits->HighMmio.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsStackLimits->Mmio64Limit !=3D StackLimits->HighMmio.Li= mit && StackLimits->HighMmio.Limit !=3D 0) { + Rejected =3D TRUE; + } + PCIDEBUG ("[%d.%d] Current MMIOH: 0x%012llX..0x%012llX\n", Socke= t, Stack, + IioUdsStackLimits->Mmio64Base, IioUdsStackLimits->Mmio= 64Limit); + PCIDEBUG ("[%d.%d] Saved MMIOH: 0x%012llX..0x%012llX %a\n", So= cket, Stack, + StackLimits->HighMmio.Base, StackLimits->HighMmio.Limi= t, Rejected ? "rejected" : ""); + } + } + // + // Per socket + // + if (IioUdsSocketLimits->PciResourceIoBase !=3D SocketLimits->Io.Base= && SocketLimits->Io.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsSocketLimits->PciResourceIoLimit !=3D SocketLimits->Io.Lim= it && SocketLimits->Io.Limit !=3D 0) { + Rejected =3D 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 !=3D SocketLimits->LowMmio.Base &= & SocketLimits->LowMmio.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsSocketLimits->Mmio32Limit !=3D SocketLimits->LowMmio.Limit= && SocketLimits->LowMmio.Limit !=3D 0) { + Rejected =3D TRUE; + } + PCIDEBUG ("[%d] Current MMIOL: 0x%08X..0x%08X\n", Socket, + IioUdsSocketLimits->Mmio32Base, IioUdsSocketLimits->Mmio32L= imit); + PCIDEBUG ("[%d] Saved MMIOL: 0x%08X..0x%08X %a\n", Socket, + SocketLimits->LowMmio.Base, SocketLimits->LowMmio.Limit, R= ejected ? "rejected" : ""); + + if (IioUdsSocketLimits->Mmio64Base !=3D SocketLimits->HighMmio.Base = && SocketLimits->HighMmio.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsSocketLimits->Mmio64Limit !=3D SocketLimits->HighMmio.Limi= t && SocketLimits->HighMmio.Limit !=3D 0) { + Rejected =3D TRUE; + } + PCIDEBUG ("[%d] Current MMIOH: 0x%012llX..0x%012llX\n", Socket, + IioUdsSocketLimits->Mmio64Base, IioUdsSocketLimits->Mmio64L= imit); + PCIDEBUG ("[%d] Saved MMIOH: 0x%012llX..0x%012llX %a\n", Socket, + SocketLimits->HighMmio.Base, SocketLimits->HighMmio.Limit,= Rejected ? "rejected" : ""); + + if (IioUdsUboxStackLimits->Mmio64Base !=3D UboxStackLimits->HighMmio= .Base && UboxStackLimits->HighMmio.Base !=3D 0) { + Rejected =3D TRUE; + } + if (IioUdsUboxStackLimits->Mmio64Limit !=3D UboxStackLimits->HighMmi= o.Limit && UboxStackLimits->HighMmio.Limit !=3D 0) { + Rejected =3D 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 config= uration + the buffer at *PciResConfigPtr is just cleared. + + @param[out] PciResConfigPtr - Buffer for the resource configuration varia= ble. + + @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 =3D sizeof(*PciResConfigPtr); + Status =3D gRT->GetVariable (SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME= , &gEfiSocketPciResourceDataGuid, + NULL, &VarSize, PciResConfigPtr); + if (EFI_ERROR (Status) && Status !=3D EFI_BUFFER_TOO_SMALL) { + goto ErrExit; + } + if (Status =3D=3D EFI_BUFFER_TOO_SMALL || VarSize !=3D sizeof(*PciResCon= figPtr)) { + + PCIDEBUG ("Got variable '%s' of unexpected size %d (expect %d) - overw= rite\n", + SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, VarSize, sizeof= (*PciResConfigPtr)); + Status =3D EFI_NOT_FOUND; + goto ErrExit; + } + // + // If any of the below checks fails clear the buffer and return EFI_NOT_= FOUND. + // + Status =3D EFI_NOT_FOUND; + if (PciResConfigPtr->MmioHBase !=3D mIioUds->IioUdsPtr->PlatformData.Pla= tGlobalMmio64Base || + PciResConfigPtr->MmioHLimit !=3D mIioUds->IioUdsPtr->PlatformData.Pl= atGlobalMmio64Limit) { + + PCIDEBUG ("%s: Memory map changed (MMIOH %012llX..%012llX !=3D %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 !=3D mIioUds->IioUdsPtr->PlatformData.Pla= tGlobalMmio32Base || + PciResConfigPtr->MmioLLimit !=3D mIioUds->IioUdsPtr->PlatformData.Pl= atGlobalMmio32Limit) { + + PCIDEBUG ("%s: Memory map changed (MMIOL %08X..%08X !=3D %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 !=3D mIioUds->IioUdsPtr->PlatformData.PlatGl= obalIoBase || + PciResConfigPtr->IoLimit !=3D mIioUds->IioUdsPtr->PlatformData.PlatG= lobalIoLimit) { + + PCIDEBUG ("%s: Memory map changed (I/O %04X..%04X !=3D %04X..%04X) - o= verwrite\n", + SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, + PciResConfigPtr->IoBase, PciResConfigPtr->IoLimit, + mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoBase, + mIioUds->IioUdsPtr->PlatformData.PlatGlobalIoLimit); + goto ErrExit; + } + for (Socket =3D 0; Socket < NELEMENTS (PciResConfigPtr->Socket); Socket+= +) { + + if (PciResConfigPtr->StackPresentBitmap[Socket] !=3D + mIioUds->IioUdsPtr->Platform= Data.CpuQpiInfo[Socket].stackPresentBitmap) { + + PCIDEBUG ("%s: Stack bitmap mismach (%04X !=3D %04X) in socket %d - = overwrite\n", + SYSTEM_PCI_RESOURCE_CONFIGURATION_DATA_NAME, PciResConfigP= tr->StackPresentBitmap[Socket], + mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackP= resentBitmap, 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 n= eeds from PCI devices. + Update Setup variable if there are changes from the existing ratio reque= sts 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]; // Chang= e 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 =3D SocketResourceRatioNotChanged; + SetMem (ChangedType, TypeMax, FALSE); + SetMem (ChangedTypeOOR, TypeMax, FALSE); + ChangedBitMap =3D 0; + OutOfResources =3D FALSE; + IsVirtualRootBridge =3D FALSE; + + IoGranularity =3D mIioUds->IioUdsPtr->PlatformData.IoGranularity; + MmiolGranularity =3D mIioUds->IioUdsPtr->PlatformData.MmiolGranularity; + MmiohGranularity =3D (UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGran= ularity.lo; + MmiohGranularity |=3D ((UINT64)mIioUds->IioUdsPtr->PlatformData.MmiohGra= nularity.hi) << 32; + ZeroMem (&SocketResources[0], sizeof(SocketResources)); + // + // Read the system resource cfg from NVRAM. If the variable does not exi= st, or is + // not valid for current system configuration the buffer SocketPciResour= ceData + // is just cleared. + // + Status =3D PciHostReadResourceConfig (&SocketPciResourceData); + if (EFI_ERROR (Status)) { + + if (Status !=3D 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 rebo= ot to avoid loop. + // + return; + } + + UboxMmioSize =3D mIioUds->IioUdsPtr->PlatformData.UboxMmioSize; + PlatGlobalMmiolBase =3D mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio3= 2Base; + ValidSockets =3D 0; + for (List =3D HostBridgeInstance->RootBridges.ForwardLink, Socket =3D 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].PciResourceI= oBase >=3D + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].PciResourceI= oLimit) { + SocketIoBase =3D 0; + SocketIoLength =3D 0; + } else { + SocketIoBase =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socke= t].PciResourceIoBase; + SocketIoLength =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Soc= ket].PciResourceIoLimit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socke= t].PciResourceIoBase; + } + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio32Base >= =3D + mIioUds->IioUdsPtr->Pla= tformData.IIO_resource[Socket].Mmio32Limit) { + SocketMem32Base =3D 0; + SocketMem32Length =3D 0; + } else { + SocketMem32Base =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].Mmio32Base; + SocketMem32Length =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[= Socket].Mmio32Limit - + mIioUds->IioUdsPtr->= PlatformData.IIO_resource[Socket].Mmio32Base; + // Reserve 8M for ubox mmio + SocketMem32Length =3D SocketMem32Length - UboxMmioSize; + } + + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Mmio64Base >= =3D + mIioUds->IioUdsPtr->Pla= tformData.IIO_resource[Socket].Mmio64Limit) { + SocketMem64Base =3D 0; + SocketMem64Length =3D 0; + } else{ + SocketMem64Base =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].Mmio64Base; + SocketMem64Length =3D 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 =3D (UINT16)SocketIoLength; + SocketResources[Socket].MmiolResourcesLeft =3D (UINT32)SocketMem32Leng= th; + SocketResources[Socket].MmiohResourcesLeft =3D (UINT64)SocketMem64Leng= th; + + LastStack =3D LastStackOfSocket (Socket); + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPrese= ntBitmap & (1 << Stack))) { + continue; + } + RootBridgeInstance =3D ROOT_BRIDGE_FROM_LINK (List); + // + // Check IO Resource + // + Alignment =3D RootBridgeInstance->ResAllocNode[TypeIo].Alignment + 1; + NewLength =3D RootBridgeInstance->ResAllocNode[TypeIo].Length; + + if (IsVirtualRootBridge) { + NewLength +=3D NewLength; + } + // IoTrap allocates 256 byte range from GCD for common pool usage + // For device to fit move to the next available alignment + if ((Socket =3D=3D 0) && (Stack =3D=3D 0)) { + NewLength +=3D Alignment; + } + + if (NewLength !=3D 0) { + // + // At least 2KB align per KTI requirement. Add the length requeste= d with given alignment. + // If the sum is not 2KB aligned add on the remainder that would m= ake it align. + // Bump up to 4KB for root bridge requirements + // Have to make sure Alignment is handled for direct address alloc= ation + // + Remainder =3D SocketIoBase & (Alignment - 1); + if (Remainder !=3D 0) { + NewLength +=3D Alignment - Remainder; + } + if (NewLength % (IoGranularity * 2)) { + Remainder =3D (IoGranularity * 2) - (NewLength % (IoGranularity = * 2)); + NewLength +=3D Remainder; + } + // + // Store length as length - 1 for handling + // + NewLength -=3D 1; + + // Zero StackLength if its disable or negative + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes= [Stack].PciResourceIoBase >=3D + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes= [Stack].PciResourceIoLimit) { + StackLength =3D 0; + } else { + StackLength =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].StackRes[Stack].PciResourceIoLimit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Sock= et].StackRes[Stack].PciResourceIoBase; + } + SocketResources[Socket].StackRes[Stack].NumIoPortsDesired =3D (UIN= T16)NewLength; + // Check if new length can fit in the socket or stack + if (SocketResources[Socket].IoResourcesLeft > (UINT16)NewLength) { + SocketResources[Socket].IoResourcesLeft -=3D (UINT16)NewLengt= h + 1; + } else if (SocketResources[Socket].IoResourcesLeft =3D=3D (UINT16)= NewLength) { + SocketResources[Socket].IoResourcesLeft -=3D (UINT16)NewLengt= h; + } else { + // If there are resources left consume them + if (SocketResources[Socket].IoResourcesLeft !=3D 0) { + NewLength =3D NewLength - SocketResources[Socket].IoResourcesL= eft - 1; + SocketResources[Socket].IoResourcesLeft =3D 0; + } + + SocketResources[Socket].IoResourceNeeds +=3D (UINT16)NewLength += 1; + OutOfResources =3D TRUE; + ChangedTypeOOR[TypeIo] =3D TRUE; + } + SocketResources[Socket].StackRes[Stack].IoAlignment =3D Alignment; + if (NewLength > StackLength) { + SocketResources[Socket].StackRes[Stack].NeedIoUpdate =3D TRUE; + + //IoResourcesLeft is UINT16 type, not 2's-complement value. + if (SocketResources[Socket].IoResourcesLeft > SocketIoLength) { + DEBUG ((DEBUG_ERROR, "[PCI] Out of Resources for Socket =3D %x= Stack =3D %x Type =3D %x\n", + Socket, Stack, TypeIo)); + SocketResources[Socket].IoResourcesLeft =3D 0; + } + ChangedType[TypeIo] =3D TRUE; + } + SocketIoBase +=3D SocketResources[Socket].StackRes[Stack].NumIoPor= tsDesired + 1; + DEBUG ((DEBUG_INFO, "SocketResources[%x].IoResourceLeft =3D %x\n", + Socket, SocketResources[Socket].IoResourcesLeft)); + DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoAlignment = =3D %x\n", + Socket, Stack, SocketResources[Socket].StackRes[Stack].IoAl= ignment)); + } else { + SocketResources[Socket].StackRes[Stack].NumIoPortsDesired =3D 0; + } + // + // Check Mmem32 resource. This Host bridge does not support separate= d MEM / PMEM requests, + // so only count MEM requests here. + // + Alignment =3D RootBridgeInstance->ResAllocNode[TypeMem32].Alignment = + 1; + NewLength =3D RootBridgeInstance->ResAllocNode[TypeMem32].Length; + // + // Account for reserved regions at begin and end of the stack MMIO32= region. + // + RsvLenAtBegin =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Sock= et].StackRes[Stack].PciResourceMem32Base - + mIioUds->IioUdsPtr->PlatformData.IIO= _resource[Socket].StackRes[Stack].Mmio32Base; + + RsvLenAtEnd =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket= ].StackRes[Stack].Mmio32Limit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[S= ocket].StackRes[Stack].PciResourceMem32Limit; + NewLength +=3D RsvLenAtBegin + RsvLenAtEnd; + if (Alignment < RsvLenAtBegin) { + Alignment =3D RsvLenAtBegin; + } + if (Alignment < RsvLenAtEnd) { + Alignment =3D 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[S= tack].VtdBarAddress !=3D 0) { + + VtdBarSize =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socke= t].StackRes[Stack].PciResourceMem32Limit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket]= .StackRes[Stack].VtdBarAddress + 1; + NewLength +=3D VtdBarSize; + if (Alignment < VtdBarSize) { + Alignment =3D VtdBarSize; + } + } + + if (IsVirtualRootBridge) { + NewLength +=3D NewLength; + } + // PCH Allocates reserved MMIO for Sx SMI handler use + // For device to fit move to the next available alignment + if ((Socket =3D=3D 0) && (Stack =3D=3D 0)) { + NewLength +=3D Alignment; + } + + if (NewLength !=3D 0) { + // + // At least 4MB align per KTI requirement. Add the length requeste= d with given alignment. + // If the sum is not 4MB aligned add on the remainder that would m= ake it align. + // Have to make sure Alignment is handled for direct address alloc= ation + // + Remainder =3D SocketMem32Base & (Alignment - 1); + if (Remainder !=3D 0) { + NewLength +=3D Alignment - Remainder; + } + if (NewLength % MmiolGranularity) { + + Remainder =3D MmiolGranularity - (NewLength % MmiolGranularity); + NewLength +=3D Remainder; + } + + if (Stack =3D=3D 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 calcula= ted to be satisfied. + // Add granularity padding if necessary to satisfy Ubox requirem= ent. + // + if (UboxMmioSize !=3D 0 && (SocketMem32Base + NewLength) % UboxM= mioSize) { + Remainder =3D UboxMmioSize - (NewLength % UboxMmioSize); + NewLength +=3D Remainder; + } + } + // + // Store length as length - 1 for handling + // + NewLength -=3D 1; + + // Zero StackLength if its disable or negative + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes= [Stack].Mmio32Base >=3D + mIioUds->IioUdsPtr->PlatformData.IIO_re= source[Socket].StackRes[Stack].Mmio32Limit) { + StackLength =3D 0; + } else { + StackLength =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].StackRes[Stack].Mmio32Limit - + mIioUds->IioUdsPtr->PlatformData.IIO= _resource[Socket].StackRes[Stack].Mmio32Base; + } + SocketResources[Socket].StackRes[Stack].MmiolLength =3D (UINT32)Ne= wLength; + + // Check if new length can fit in the socket or stack + if (SocketResources[Socket].MmiolResourcesLeft > (UINT32)NewLength= ) { + SocketResources[Socket].MmiolResourcesLeft -=3D (UINT32)NewLe= ngth + 1; + } else if (SocketResources[Socket].MmiolResourcesLeft =3D=3D (UINT= 32)NewLength) { + SocketResources[Socket].MmiolResourcesLeft -=3D (UINT32)NewLe= ngth; + } else { + // If there are resources left consume them + if (SocketResources[Socket].MmiolResourcesLeft) { + NewLength =3D NewLength - SocketResources[Socket].MmiolRes= ourcesLeft - 1; + SocketResources[Socket].MmiolResourcesLeft =3D 0; + } + + SocketResources[Socket].MmiolResourceNeeds +=3D (UINT32)NewLen= gth + 1; + OutOfResources =3D TRUE; + ChangedTypeOOR[TypeMem32] =3D TRUE; + } + SocketResources[Socket].StackRes[Stack].MmiolAlignment =3D Alignme= nt; + + if (NewLength > StackLength) { + SocketResources[Socket].StackRes[Stack].MmiolUpdate =3D 1; + + //MmiolResourcesLeft is UINT32 type, not 2's-complement value. + if (SocketResources[Socket].MmiolResourcesLeft > SocketMem32Leng= th) { + DEBUG ((DEBUG_ERROR, "Out of Resources for Socket =3D %x Stac= k =3D %x Type =3D %x\n", + Socket, Stack, TypeMem32)); + SocketResources[Socket].MmiolResourcesLeft =3D 0; + } + ChangedType[TypeMem32] =3D TRUE; + } + SocketMem32Base +=3D SocketResources[Socket].StackRes[Stack].Mmiol= Length + 1; + DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiolResourceLeft =3D %x\= n", + Socket, SocketResources[Socket].MmiolResourcesLeft)); + DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolAlignme= nt =3D %x\n", + Socket, Stack, SocketResources[Socket].StackRes[Stack].Mmio= lAlignment)); + } else { + SocketResources[Socket].StackRes[Stack].MmiolLength =3D 0; + } + // + // Check Mem64 resource. This Host bridge does not support separated= MEM / PMEM requests, so only count MEM requests here. + // + Alignment =3D RootBridgeInstance->ResAllocNode[TypeMem64].Alignment = + 1; + NewLength =3D RootBridgeInstance->ResAllocNode[TypeMem64].Length; + // + // Account for reserved regions at begin and end of the stack MMIO32= region. + // + RsvLenAtBegin =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Sock= et].StackRes[Stack].PciResourceMem64Base - + mIioUds->IioUdsPtr->PlatformData.IIO= _resource[Socket].StackRes[Stack].Mmio64Base; + + RsvLenAtEnd =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket= ].StackRes[Stack].Mmio64Limit - + mIioUds->IioUdsPtr->PlatformData.IIO_resource[S= ocket].StackRes[Stack].PciResourceMem64Limit; + NewLength +=3D RsvLenAtBegin + RsvLenAtEnd; + if (Alignment < RsvLenAtBegin) { + Alignment =3D RsvLenAtBegin; + } + if (Alignment < RsvLenAtEnd) { + Alignment =3D RsvLenAtEnd; + } + if (IsVirtualRootBridge) { + NewLength +=3D NewLength; + } + + if (NewLength !=3D 0) { + // + // At least 1GB align per KTI requirement. Add the length requeste= d with given alignment. + // If the sum is not 1GB aligned add on the remainder that would m= ake it align. + // Have to make sure Alignment is handled for direct address alloc= ation + // + Remainder =3D SocketMem64Base & (Alignment - 1); + if (Remainder !=3D 0) { + NewLength +=3D Alignment - Remainder; + } + if (NewLength % MmiohGranularity) { + Remainder =3D MmiohGranularity - (NewLength % MmiohGranularity); + NewLength +=3D Remainder; + } + // + // Store length as length - 1 for handling + // + NewLength -=3D 1; + + // Zero StackLength if it's disable or negative + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes= [Stack].Mmio64Base >=3D + mIioUds->IioUdsPtr->PlatformData.IIO_re= source[Socket].StackRes[Stack].Mmio64Limit) { + StackLength =3D 0; + } else { + StackLength =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].StackRes[Stack].Mmio64Limit - + mIioUds->IioUdsPtr->PlatformData.IIO= _resource[Socket].StackRes[Stack].Mmio64Base; + } + SocketResources[Socket].StackRes[Stack].MmiohLength =3D NewLength; + + // Check if new length can fit in the socket or stack + if (SocketResources[Socket].MmiohResourcesLeft > NewLength) { + SocketResources[Socket].MmiohResourcesLeft -=3D NewLength + 1; + } else if (SocketResources[Socket].MmiohResourcesLeft =3D=3D NewLe= ngth) { + SocketResources[Socket].MmiohResourcesLeft -=3D NewLength; + } else { + // If there are resources left consume them + if (SocketResources[Socket].MmiohResourcesLeft !=3D 0) { + NewLength =3D NewLength - SocketResources[Socket].MmiohResourc= esLeft - 1; + SocketResources[Socket].MmiohResourcesLeft =3D 0; + } + + SocketResources[Socket].MmiohResourceNeeds +=3D NewLength + 1; + OutOfResources =3D TRUE; + ChangedTypeOOR[TypeMem64] =3D TRUE; + } + SocketResources[Socket].StackRes[Stack].MmiohAlignment =3D Alignme= nt; + + if (NewLength > StackLength) { + SocketResources[Socket].StackRes[Stack].MmiohUpdate =3D 1; + + //MmiohResourcesLeft is UINT64 type, not 2's-complement value. + if (SocketResources[Socket].MmiohResourcesLeft > SocketMem64Leng= th) { + DEBUG ((DEBUG_ERROR, "Out of Resources for Socket =3D %x Stac= k =3D %x Type =3D %x\n", + Socket, Stack, TypeMem64)); + SocketResources[Socket].MmiohResourcesLeft =3D 0; + } + ChangedType[TypeMem64] =3D TRUE; + } + SocketMem64Base +=3D SocketResources[Socket].StackRes[Stack].Mmioh= Length + 1; + DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiohResourceLeft =3D %lx= \n", + Socket, SocketResources[Socket].MmiohResourcesLeft)); + DEBUG ((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohAlignme= nt =3D %lx\n", + Socket, Stack, SocketResources[Socket].StackRes[Stack].Mmio= hAlignment)); + } else { + SocketResources[Socket].StackRes[Stack].MmiohLength =3D 0; + } + + List =3D List->ForwardLink; + + } // for Stack + + // Check and update all resource types in socket that needs adjustment + for (TypeIndex =3D 0; TypeIndex < TypeMax; TypeIndex++) { + + if (ChangedType[TypeIndex]) { + + DEBUG ((DEBUG_INFO, "[%d] Adjust stack %s resources...\n", Socket,= mPciResourceTypeStr[TypeIndex])); + Status =3D AdjustResources (&SocketResources[Socket], Socket, Type= Index); + ChangedType[TypeIndex] =3D FALSE; + if (Status =3D=3D EFI_SUCCESS) { + ChangedBitMap |=3D (1 << TypeIndex); + } else { + ChangedBitMap &=3D ~(1 << TypeIndex); + } + } + } + // + // Account for Ubox resources to accurately calculate new alignments f= or the next socket + // + SocketMem32Base +=3D UboxMmioSize; + } // for Socket .. + + ASSERT (List =3D=3D &HostBridgeInstance->RootBridges); + + // + // If a socket is out of resources, try to adjusting sockets for more ro= om. + // + if (OutOfResources && (MAX_SOCKET > 1) && (ValidSockets > 1)) { + + for (TypeIndex =3D 0; TypeIndex < TypeMax; TypeIndex++) { + + if (ChangedTypeOOR[TypeIndex]) { + + DEBUG ((DEBUG_INFO, "Adjust socket %s resources...\n", mPciResourc= eTypeStr[TypeIndex])); + Status =3D AdjustSocketResources (SocketResources, TypeIndex, Vali= dSockets); + if (Status =3D=3D EFI_SUCCESS) { + ChangedBitMap |=3D (1 << TypeIndex); + } else { + ChangedBitMap &=3D ~(1 << TypeIndex); + } + } + } + } else if (OutOfResources && ChangedTypeOOR[TypeMem64]){ + // + // Allow mmioh to be adjusted to access max available physical address= range. + // + Status =3D AdjustSocketResources (SocketResources, TypeMem64, ValidSoc= kets); + if (Status =3D=3D EFI_SUCCESS) { + ChangedBitMap |=3D (1 << TypeIndex); + } else { + ChangedBitMap &=3D ~(1 << TypeIndex); + } + } + + // Update changed resource type. + // OemGetResourceMapUpdate() will only update changed resource type so i= t is alright if data is zero. + if (ChangedBitMap !=3D 0) { + + for (Socket =3D 0; Socket < MAX_SOCKET; Socket++) { + + SocketPciResourceData.StackPresentBitmap[Socket] =3D mIioUds->IioUds= Ptr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap; + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + CurStackLimits =3D &SocketPciResourceData.Socket[Socket].StackLimi= ts[Stack]; + + // + // Disable stacks that have no resources and are assigned none. + // Reaching this far means the stack is valid and should be disabl= ed 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 =3D=3D 0)) { + SocketResources[Socket].StackRes[Stack].IoBase =3D (UINT16)(-1); + SocketResources[Socket].StackRes[Stack].IoLimit =3D 0; + } + + if ((SocketResources[Socket].StackRes[Stack].MmiolUpdate) && + (SocketResources[Socket].StackRes[Stack].MmiolLimit - + SocketResources[Socket].StackRes[Stack].MmiolBase =3D=3D 0)) { + SocketResources[Socket].StackRes[Stack].MmiolBase =3D (UINT32)(-= 1); + SocketResources[Socket].StackRes[Stack].MmiolLimit =3D 0; + } + + if ((SocketResources[Socket].StackRes[Stack].MmiohUpdate) && + (SocketResources[Socket].StackRes[Stack].MmiohLimit - + SocketResources[Socket].StackRes[Stack].MmiohBase =3D=3D 0)) { + SocketResources[Socket].StackRes[Stack].MmiohBase =3D (UINT64)(-= 1); + SocketResources[Socket].StackRes[Stack].MmiohLimit =3D 0; + } + + // Zero base if 4K because mIioUds struct reserves 4K of Io for le= gacy purposes + // Remove if mIioUds first base starts at zero + if (SocketResources[Socket].StackRes[Stack].IoBase =3D=3D 0x1000){ + SocketResources[Socket].StackRes[Stack].IoBase =3D 0; + } + + if (SocketResources[Socket].StackRes[Stack].NeedIoUpdate) { + CurStackLimits->Io.Base =3D SocketResources[Socket].StackRes[Sta= ck].IoBase; + CurStackLimits->Io.Limit =3D SocketResources[Socket].StackRes[St= ack].IoLimit; + } + + if (SocketResources[Socket].StackRes[Stack].MmiolUpdate) { + if ((Socket =3D=3D 0) && (Stack =3D=3D 0)) { + CurStackLimits->LowMmio.Base =3D PlatGlobalMmiolBase; + } else { + CurStackLimits->LowMmio.Base =3D SocketResources[Socket].Stack= Res[Stack].MmiolBase; + } + CurStackLimits->LowMmio.Limit =3D SocketResources[Socket].StackR= es[Stack].MmiolLimit; + } + + if (SocketResources[Socket].StackRes[Stack].MmiohUpdate) { + CurStackLimits->HighMmio.Base =3D SocketResources[Socket].StackR= es[Stack].MmiohBase; + CurStackLimits->HighMmio.Limit =3D SocketResources[Socket].Stack= Res[Stack].MmiohLimit; + } + + DEBUG((DEBUG_INFO, "\nSocketResources[%x].StackRes[%x].IoBase =3D%= x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].IoBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].IoLimit =3D%x= \n",Socket,Stack,SocketResources[Socket].StackRes[Stack].IoLimit)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolBase =3D= %x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiolBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiolLimit = =3D%x\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiolLimit)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohBase =3D= %lx\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiohBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].StackRes[%x].MmiohLimit = =3D%lx\n",Socket,Stack,SocketResources[Socket].StackRes[Stack].MmiohLimit)); + } // for Stack + + // Initialize to disabled + SocketResources[Socket].IoBase =3D (UINT16)(-1); + SocketResources[Socket].IoLimit =3D 0; + SocketResources[Socket].MmiolBase =3D (UINT32)(-1); + SocketResources[Socket].MmiolLimit =3D 0; + SocketResources[Socket].MmiohBase =3D (UINT64)(-1); + SocketResources[Socket].MmiohLimit =3D 0; + + // Search backwards to find the beginning valid stack + for (Stack =3D MAX_IIO_STACK - 1; Stack < MAX_IIO_STACK ; Stack--) { + CurSocketLimits =3D &SocketPciResourceData.Socket[Socket].SocketLi= mits; + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + + if (SocketResources[Socket].StackRes[Stack].IoBase !=3D (UINT16)(-= 1)) { + SocketResources[Socket].IoBase =3D SocketResources[Socket].Stack= Res[Stack].IoBase; + } + + if (SocketResources[Socket].StackRes[Stack].MmiolBase !=3D (UINT32= )(-1)) { + SocketResources[Socket].MmiolBase =3D SocketResources[Socket].St= ackRes[Stack].MmiolBase; + } + + if (SocketResources[Socket].StackRes[Stack].MmiohBase !=3D (UINT64= )(-1)) { + SocketResources[Socket].MmiohBase =3D SocketResources[Socket].St= ackRes[Stack].MmiohBase; + } + } // for Stack + + // Search to find the last valid limit + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + + if (SocketResources[Socket].StackRes[Stack].IoLimit !=3D 0) { + SocketResources[Socket].IoLimit =3D SocketResources[Socket].Stac= kRes[Stack].IoLimit; + } + + if (SocketResources[Socket].StackRes[Stack].MmiolLimit) { + SocketResources[Socket].MmiolLimit =3D SocketResources[Socket].S= tackRes[Stack].MmiolLimit; + } + + if (SocketResources[Socket].StackRes[Stack].MmiohLimit) { + SocketResources[Socket].MmiohLimit =3D SocketResources[Socket].S= tackRes[Stack].MmiohLimit; + } + } // for Stack + + // Update socket level resource range + if (SocketResources[Socket].StackRes[0].NeedIoUpdate) { + CurSocketLimits->Io.Base =3D SocketResources[Socket].IoBase; + CurSocketLimits->Io.Limit =3D SocketResources[Socket].IoLimit; + } + + if (SocketResources[Socket].StackRes[0].MmiolUpdate) { + // + // Apply stolen 8M for ubox mmio per socket + // + if (UboxMmioSize !=3D 0) { + UboxStackLimits =3D &SocketPciResourceData.Socket[Socket].StackL= imits[UBOX_STACK]; + + UboxStackLimits->LowMmio.Base =3D SocketResources[Socket].MmiolL= imit + 1; + SocketResources[Socket].MmiolLimit =3D (UINT32)UboxStackLimits->= LowMmio.Base + UboxMmioSize - 1; + UboxStackLimits->LowMmio.Limit =3D SocketResources[Socket].Mmiol= Limit; + } + CurSocketLimits->LowMmio.Base =3D SocketResources[Socket].MmiolBas= e; + CurSocketLimits->LowMmio.Limit =3D SocketResources[Socket].MmiolLi= mit; + } + + if (SocketResources[Socket].StackRes[0].MmiohUpdate) { + CurSocketLimits->HighMmio.Base =3D SocketResources[Socket].MmiohB= ase; + CurSocketLimits->HighMmio.Limit =3D SocketResources[Socket].MmiohL= imit; + } + + DEBUG((DEBUG_INFO, "\nSocketResources[%x].UboxBase =3D%x\n",Socket,U= boxStackLimits->LowMmio.Base)); + DEBUG((DEBUG_INFO, "SocketResources[%x].UboxLimit =3D%x\n",Socket,Ub= oxStackLimits->LowMmio.Limit)); + DEBUG((DEBUG_INFO, "\nSocketResources[%x].IoBase =3D%x\n",Socket,Soc= ketResources[Socket].IoBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].IoLimit =3D%x\n",Socket,Sock= etResources[Socket].IoLimit)); + DEBUG((DEBUG_INFO, "SocketResources[%x].MmiolBase =3D%x\n",Socket,So= cketResources[Socket].MmiolBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].MmiolLimit =3D%x\n",Socket,S= ocketResources[Socket].MmiolLimit)); + DEBUG((DEBUG_INFO, "SocketResources[%x].MmiohBase =3D%lx\n",Socket,S= ocketResources[Socket].MmiohBase)); + DEBUG((DEBUG_INFO, "SocketResources[%x].MmiohLimit =3D%lx\n",Socket,= SocketResources[Socket].MmiohLimit)); + } // for Socket + SocketPciResourceData.MmioHBase =3D mIioUds->IioUdsPtr->PlatformData.P= latGlobalMmio64Base; + SocketPciResourceData.MmioHLimit =3D mIioUds->IioUdsPtr->PlatformData.= PlatGlobalMmio64Limit; + SocketPciResourceData.MmioLBase =3D mIioUds->IioUdsPtr->PlatformData.P= latGlobalMmio32Base; + SocketPciResourceData.MmioLLimit =3D mIioUds->IioUdsPtr->PlatformData.= PlatGlobalMmio32Limit; + SocketPciResourceData.IoBase =3D mIioUds->IioUdsPtr->PlatformData.Plat= GlobalIoBase; + SocketPciResourceData.IoLimit =3D mIioUds->IioUdsPtr->PlatformData.Pla= tGlobalIoLimit; + + PCIDEBUG("Writing resource rebalance request '%s':\n", SYSTEM_PCI_RESO= URCE_CONFIGURATION_DATA_NAME); + PCIDEBUG("System I/O : %04X..%04X\n", SocketPciResourceData.IoBase, S= ocketPciResourceData.IoLimit); + PCIDEBUG("System MMIOL: %08X..%08X\n", SocketPciResourceData.MmioLBase= , SocketPciResourceData.MmioLLimit); + PCIDEBUG("System MMIOH: %012llX..%012llX\n", SocketPciResourceData.Mmi= oHBase, SocketPciResourceData.MmioHLimit); + for (Socket =3D 0; Socket < NELEMENTS (SocketPciResourceData.Socket); = Socket++) { + + PCIDEBUG("[%d] StackPresent: 0x%04X\n", Socket, SocketPciResourceDat= a.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.B= ase, + SocketPciResourceData.Socket[Socket].SocketLimits.LowMmio.L= imit); + PCIDEBUG("[%d] MMIOH: %012llX..%012llX\n", Socket, + SocketPciResourceData.Socket[Socket].SocketLimits.HighMmio.= Base, + SocketPciResourceData.Socket[Socket].SocketLimits.HighMmio.= Limit); + for (Stack =3D 0; Stack < NELEMENTS (SocketPciResourceData.Socket[S= ocket].StackLimits); Stack++) { + + PCIDEBUG("[%d.%d] I/O : %04X..%04X\n", Socket, Stack, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].I= o.Base, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].I= o.Limit); + PCIDEBUG("[%d.%d] MMIOL: %08X..%08X\n", Socket, Stack, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].L= owMmio.Base, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].L= owMmio.Limit); + PCIDEBUG("[%d.%d] MMIOH: %012llX..%012llX\n", Socket, Stack, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].H= ighMmio.Base, + SocketPciResourceData.Socket[Socket].StackLimits[Stack].H= ighMmio.Limit); + } + } + + *Result =3D SocketResourceRatioChanged; + Status =3D 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/PciHostBri= dge/PciRebalance.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pc= iHostBridge/PciRebalance.h new file mode 100644 index 0000000000..85a9192c12 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= Rebalance.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][I= IO_RESERVED_1]; + + +/*************************************************************************= ***** + * Function prototypes. + *************************************************************************= *****/ + +/** + Adjust resource ratio assignment among CPU sockets to fit the resource n= eeds from PCI devices. + Update Setup variable if there are changes from the existing ratio reque= sts for this boot. + + @param HostBridgeInstance - The Host Bridge Instance where the resou= rce adjustment happens. + @param Result - Output parameter. Indicates whether chan= ges 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 al= l 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 reques= ted 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 varia= ble. + + @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/PciHostBri= dge/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/Pci= RebalanceIo.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 >=3D ARRAY_SIZE (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo)= ) { + Result =3D FALSE; + goto err_exit; + } + + // + // if the StackPresentBitmap is a single byte, then we can track 8 stack= s, + // 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 >=3D 8 * sizeof(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[0]= .stackPresentBitmap)) { + Result =3D FALSE; + goto err_exit; + } + + Mask =3D 1; + Mask <<=3D Stack; + Result =3D (Mask & mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].s= tackPresentBitmap) !=3D 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 a= ll 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 wi= thin 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 f= or I/O port numbers + CONST UINT64 MaxLimit =3D ((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 STAC= K_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 =3D 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 =3D 0; + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + CurSocketResources =3D &SocketResources[Socket]; + if (CurSocketResources->IoResourceNeeds =3D=3D 0 && CurSocketResources= ->IoResourcesLeft !=3D 0) { + ASSERT (NumFreePorts < NumFreePorts + CurSocketResources->IoResource= sLeft + 1); // check for overflow + NumFreePorts +=3D CurSocketResources->IoResourcesLeft + 1; + CurSocketResources->IoResourcesLeft =3D 0; + } + } + + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + CurSocketResources =3D &SocketResources[Socket]; + if (CurSocketResources->IoResourceNeeds !=3D 0 && NumFreePorts >=3D Cu= rSocketResources->IoResourceNeeds) { + ASSERT (NumFreePorts > NumFreePorts - CurSocketResources->IoResource= Needs); // check for underflow + NumFreePorts -=3D CurSocketResources->IoResourceNeeds; + CurSocketResources->IoResourceNeeds =3D 0; + } + } + + LastStack =3D LastStackOfSocket (LastSocketIndex); + + if (NumFreePorts > 0) { + CurStackResources =3D &SocketResources[LastSocketIndex].StackRes[LastS= tack]; + if (CurStackResources->NumIoPortsDesired !=3D 0) { + CurStackResources->NumIoPortsDesired +=3D NumFreePorts; + } else { + CurStackResources->NumIoPortsDesired +=3D NumFreePorts - 1; + } + } + + // + // Verify all resource requested can fit into the systems address range. + // + TotalResourceSize =3D 0; + for (Socket =3D 0; Socket < ValidSockets; Socket ++) { + LastStackWithResources (&SocketResources[Socket], Socket, ResourceType= , &LastStack, &ResourceSize); + TotalResourceSize +=3D ResourceSize; + } + DEBUG ((DEBUG_INFO, "Total Request IO Range =3D %xh\n", TotalResourceSiz= e)); + DEBUG ((DEBUG_INFO, "Total System IO Range =3D %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 =3D 0; Socket < ValidSockets; Socket ++) { + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack ++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + SocketResources[Socket].StackRes[Stack].NeedIoUpdate =3D 0; + } + } + DEBUG ((DEBUG_ERROR, "ERROR: Out of adjustable IO resources. Can't adj= ust across sockets\n")); + return EFI_OUT_OF_RESOURCES; + } + + DEBUG((DEBUG_ERROR, "Assigning new socket i/o range...\n")); + + Base =3D mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].PciResourceIoB= ase; + Limit =3D Base; // assume no resources are allocated + for (Socket =3D 0, CurSocketResources =3D SocketResources; Socket < Vali= dSockets; Socket++, CurSocketResources++) { + DEBUG ((DEBUG_INFO, "socket =3D %d, Base =3D %x, Limit =3D%x, MaxLimit= =3D %x\n", Socket, Base, Limit, MaxLimit)); + ASSERT (Base < MaxLimit); + CurSocketResources->IoBase =3D (UINT16)Base; + DEBUG ((DEBUG_INFO, "set socket io base to %x\n", Base)); + + for (Stack =3D 0, CurStackResources =3D 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 =3D 0xffff; + CurStackResources->IoLimit =3D 0; + continue; + } + + if (CurStackResources->NumIoPortsDesired =3D=3D 0) { + DEBUG ((DEBUG_INFO, " Stack %d doesn't need i/o resources, settin= g base/limit to 0xffff/0\n", Stack)); + CurStackResources->IoBase =3D 0xffff; + CurStackResources->IoLimit =3D 0; + CurStackResources->NeedIoUpdate =3D 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 =3D (UINT16)Base; + Limit =3D Base + CurStackResources->NumIoPortsDesired; + DEBUG ((DEBUG_INFO, " limit set to %x (var and stack)\n", Limit)); + ASSERT (Base <=3D Limit); + ASSERT (Limit <=3D MaxLimit); + CurStackResources->IoLimit =3D (UINT16)Limit; + CurStackResources->NeedIoUpdate =3D TRUE; + Base =3D Limit + 1; + DEBUG ((DEBUG_INFO, " Base variable updated to %x\n", Base)); + } + ASSERT (Limit <=3D MaxLimit); + DEBUG ((DEBUG_INFO, " Socket %d limit set to %x\n", Socket, Limit)); + CurSocketResources->IoLimit =3D (UINT16)Limit; + } + + DEBUG ((DEBUG_INFO, "Dumping new I/O requests\n")); + for (Socket =3D 0, CurSocketResources =3D SocketResources; Socket < Vali= dSockets; Socket++, CurSocketResources++) { + DEBUG((DEBUG_INFO, "socket %d %x/%x\n", Socket, CurSocketResources->Io= Base, CurSocketResources->IoLimit)); + for (Stack =3D 0, CurStackResources =3D CurSocketResources->StackRes; + Stack < MAX_IIO_STACK; + Stack++, CurStackResources++) { + DEBUG ((DEBUG_INFO, "%d/%d: %x/%x\n", Socket, Stack, CurStackResourc= es->IoBase, CurStackResources->IoLimit)); + } + } + + return EFI_SUCCESS; +} + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/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/Pci= RebalanceMmio32.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 sto= res all resources need per socket + @param[in] ResourceType - Type of resource that requires alignment + @param[in] ValidSockets - Number of Valid Sockets, need it to cal= culate how resources need to be splitted + + @retval EFI_SUCCESS - Succeed. + @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted wi= thin the socket. + */ +EFI_STATUS +AdjustSocketMmioL ( + IN OUT CPU_RESOURCE *SocketResources, + IN UINT8 ResourceType, + IN UINT8 ValidSockets + ) +{ + CONST UINT8 LastSocket =3D ValidSockets - 1; + UINT8 Socket; + UINT8 Stack; + UINT8 LastStack; + UINT64 Take; + UINT32 UboxMmioSize; + UINT64 ResourceSize; + UINT64 TotalResourceSize; + UINT32 TempMmioBase; + UINT32 TempMmioLimit; + + Take =3D 0; + UboxMmioSize =3D mIioUds->IioUdsPtr->PlatformData.UboxMmioSize; + // + // Get first and last MMIOL address + // + TempMmioBase =3D mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Base; + TempMmioLimit =3D mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio32Limit; + // + // Find all the extra space left + // + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + if ((SocketResources[Socket].MmiolResourceNeeds =3D=3D 0) && (SocketRe= sources[Socket].MmiolResourcesLeft !=3D 0)) { + + Take +=3D SocketResources[Socket].MmiolResourcesLeft + 1; + SocketResources[Socket].MmiolResourcesLeft =3D 0; + } + } + // + // Give space to sockets that needs more space favoring first come first= served + // + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + if ((SocketResources[Socket].MmiolResourceNeeds !=3D 0) && (Take >=3D = SocketResources[Socket].MmiolResourceNeeds)) { + + Take -=3D SocketResources[Socket].MmiolResourceNeeds; + DEBUG((DEBUG_ERROR, "SocketResources[%x].MmiolResourceNeeds =3D %x\n= ", Socket, SocketResources[Socket].MmiolResourceNeeds)); + SocketResources[Socket].MmiolResourceNeeds =3D 0; + } + } + // + // Give away leftover resources + // + LastStack =3D LastStackOfSocket (LastSocket); + if (Take !=3D 0) { + if (SocketResources[LastSocket].StackRes[LastStack].MmiolLength !=3D 0= ) { + SocketResources[LastSocket].StackRes[LastStack].MmiolLength +=3D (UI= NT32)Take; + } else{ + SocketResources[LastSocket].StackRes[LastStack].MmiolLength +=3D ((U= INT32)Take - 1); + } + } + // + // Verify all resource requested can fit into the systems address range. + // + TotalResourceSize =3D 0; + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + LastStackWithResources (&SocketResources[Socket], Socket, ResourceType= , &LastStack, &ResourceSize); + TotalResourceSize +=3D ResourceSize + UboxMmioSize; + } + DEBUG ((DEBUG_INFO, "Total Request MMIOL Range =3D %08Xh\n", TotalResour= ceSize)); + DEBUG ((DEBUG_INFO, "Total System MMIOL Range =3D %08Xh\n", (TempMmioLi= mit - 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 =3D 0; Socket < ValidSockets; Socket ++) { + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack ++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + SocketResources[Socket].StackRes[Stack].MmiolUpdate =3D 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 =3D 0, TempMmioLimit =3D TempMmioBase - 1; Socket < ValidSoc= kets; Socket ++) { + + SocketResources[Socket].MmiolBase =3D TempMmioLimit + 1; + // + // Update the stacks base and limit values. + // + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPrese= ntBitmap & (1 << Stack))) { + + SocketResources[Socket].StackRes[Stack].MmiolBase =3D 0; + SocketResources[Socket].StackRes[Stack].MmiolLimit =3D 0; + + } else { + + SocketResources[Socket].StackRes[Stack].MmiolBase =3D TempMmioLimi= t + 1; + if (SocketResources[Socket].StackRes[Stack].MmiolLength !=3D 0) { + // + // MmiolLength is actually length-1, so we should move TempMmioL= imit by MmiolLength+1, + // but only when it is >0, i.e. only for stack that has resource= s. + // + TempMmioLimit +=3D SocketResources[Socket].StackRes[Stack].Mmiol= Length + 1; + SocketResources[Socket].StackRes[Stack].MmiolLimit =3D TempMmioL= imit; + + } else { + + SocketResources[Socket].StackRes[Stack].MmiolLimit =3D SocketRes= ources[Socket].StackRes[Stack].MmiolBase; + } + SocketResources[Socket].StackRes[Stack].MmiolUpdate =3D 1; + } + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolBase = =3D %X newLength =3D %x\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiolBase, SocketRes= ources[Socket].StackRes[Stack].MmiolLength)); + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolLimit = =3D %X\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiolLimit)); + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiolUpdate= =3D %d\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiolUpdate)); + } // for (Stack...) + // + // In the socket resources there can be UBOX, unfortunatelly not expos= ed in stackPresentBitmap + // so it has to be handled with such uguly hacks. + // + TempMmioLimit +=3D UboxMmioSize; + SocketResources[Socket].MmiolLimit =3D TempMmioLimit; + } // for (Socket...) + + return EFI_SUCCESS; +} + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/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/Pci= RebalanceMmio64.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 sto= res all resources need per socket + @param[in] ResourceType - Type of resource that requires alignment + @param[in] ValidSockets - Number of Valid Sockets, need it to cal= culate how resources need to be splitted + + @retval EFI_SUCCESS - Succeed. + @retval EFI_OUT_OF_RESOURCES - Not enough resources to be adjusted wi= thin the socket. + */ +EFI_STATUS +AdjustSocketMmioH ( + IN OUT CPU_RESOURCE *SocketResources, + IN UINT8 ResourceType, + IN UINT8 ValidSockets + ) +{ + CONST UINT8 LastSocket =3D 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 =3D 0; + UboxMmioSize =3D mIioUds->IioUdsPtr->PlatformData.UboxMmioSize; + UnAllocatedMmioh =3D 0; + // + // Get first and last IO base address + // + TempMmioBase =3D mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Base; + TempMmioLimit =3D mIioUds->IioUdsPtr->PlatformData.PlatGlobalMmio64Limit; + + // Find all the extra space left + for (Socket =3D 0; Socket < ValidSockets; Socket ++) { + if ((SocketResources[Socket].MmiohResourceNeeds =3D=3D 0) && (SocketRe= sources[Socket].MmiohResourcesLeft !=3D 0)) { + + Take +=3D SocketResources[Socket].MmiohResourcesLeft + 1; + SocketResources[Socket].MmiohResourcesLeft =3D 0; + } + } + + MaxMmioh =3D (UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularity.= lo; + MaxMmioh |=3D ((UINT64) mIioUds->IioUdsPtr->PlatformData.MmiohGranularit= y.hi) << 32; + // + // Maximum chunk accessible in the system based on the given granularity + // + if (UboxMmioSize =3D=3D 0) { + MaxMmioh =3D MaxMmioh * 32; //for 14nm + } else { + MaxMmioh =3D ((UINT64) 1 << mIioUds->IioUdsPtr->PlatformData.MaxAddres= sBits); + } + + // + // Find out how much MMIOH has not been allocated + // + if (MaxMmioh > (TempMmioLimit - TempMmioBase)) { + UnAllocatedMmioh =3D MaxMmioh - (TempMmioLimit - TempMmioBase) - 1; + } else { + // + // Extra MMIOH is not enough to close the gap for a successful adjustm= ent. + // Use all extra MMIOH in case if only a small amount is needed for ad= justment or + // the granularity was reduced due to MMIOH base. + // (14nm only) or remove if map is rejected for this case to start ove= r with correct values. + // (10nm only) does not have this problem and doesn't need the code be= low because the limit is removed and we can use max address lines. + // + Take +=3D MaxMmioh; + } + + // Give space to sockets that needs more space favoring first come first= served + for (Socket =3D 0; Socket < ValidSockets; Socket ++) { + if ((SocketResources[Socket].MmiohResourceNeeds !=3D 0) && (Take >=3D = SocketResources[Socket].MmiohResourceNeeds)) { + // + // The socket requesting additional resources can be granted by usin= g the already + // allocated range given to the whole system originally. + // + Take -=3D SocketResources[Socket].MmiohResourceNeeds; + DEBUG ((DEBUG_ERROR, "SocketResources[%x].MmiohResourceNeeds =3D %ll= X\n",Socket, SocketResources[Socket].MmiohResourceNeeds)); + SocketResources[Socket].MmiohResourceNeeds =3D 0; + } else if ((SocketResources[Socket].MmiohResourceNeeds !=3D 0) && + (Take < SocketResources[Socket].MmiohResourceNeeds) && + ((UnAllocatedMmioh + Take) >=3D SocketResources[Socket].Mmi= ohResourceNeeds)) { + // + // Apply unallocated Mmioh to the socket that requires more to satis= fy its request + // that's outside the allocated range given to the whole system orig= inally. + // + SocketResources[Socket].MmiohResourceNeeds -=3D Take; + UnAllocatedMmioh -=3D SocketResources[Socket].MmiohResourceNeeds; + DEBUG ((DEBUG_INFO, "SocketResources[%x].MmiohResourceNeeds =3D %llX= \n", Socket, SocketResources[Socket].MmiohResourceNeeds)); + DEBUG ((DEBUG_INFO, "Unallocated MMIOH left =3D %llX\n", UnAllocated= Mmioh)); + SocketResources[Socket].MmiohResourceNeeds =3D 0; + } + } + // + // Give away leftover resources + // + LastStack =3D LastStackOfSocket (LastSocket); + if (Take !=3D 0) { + if (SocketResources[LastSocket].StackRes[LastStack].MmiohLength !=3D 0= ) { + SocketResources[LastSocket].StackRes[LastStack].MmiohLength +=3D Tak= e; + } else{ + SocketResources[LastSocket].StackRes[LastStack].MmiohLength +=3D (Ta= ke - 1); + } + } + // + // Verify all resource requested can fit into the systems address range. + // + TotalResourceSize =3D 0; + for (Socket =3D 0; Socket < ValidSockets; Socket++) { + LastStackWithResources (&SocketResources[Socket], Socket, ResourceType= , &LastStack, &ResourceSize); + TotalResourceSize +=3D ResourceSize; + } + DEBUG ((DEBUG_INFO, "MaxMmioh =3D %016llXh\n", MaxMmioh)= ); + DEBUG ((DEBUG_INFO, "Total Request MMIOH Range=3D %016llXh\n", TotalReso= urceSize)); + DEBUG ((DEBUG_INFO, "Total System MMIOH Range =3D %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 =3D 0; Socket < ValidSockets; Socket ++) { + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack ++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPre= sentBitmap & (1 << Stack))) { + continue; + } + SocketResources[Socket].StackRes[Stack].MmiohUpdate =3D 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 =3D 0, TempMmioLimit =3D TempMmioBase - 1; Socket < ValidSoc= kets; Socket++) { + + SocketResources[Socket].MmiohBase =3D TempMmioLimit + 1; + // + // Update the stacks base and limit values. + // + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++) { + + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPrese= ntBitmap & (1 << Stack))) { + + SocketResources[Socket].StackRes[Stack].MmiohBase =3D 0; + SocketResources[Socket].StackRes[Stack].MmiohLimit =3D 0; + + } else { + + SocketResources[Socket].StackRes[Stack].MmiohBase =3D TempMmioLimi= t + 1; + if (SocketResources[Socket].StackRes[Stack].MmiohLength !=3D 0) { + // + // MmiohLength is actually length-1, so we should move TempMmioL= imit by MmiohLength+1, + // but only when it is >0, i.e. only for stack that has resource= s. + // + TempMmioLimit +=3D SocketResources[Socket].StackRes[Stack].Mmioh= Length + 1; + SocketResources[Socket].StackRes[Stack].MmiohLimit =3D TempMmioL= imit; + + } else { + + SocketResources[Socket].StackRes[Stack].MmiohLimit =3D SocketRes= ources[Socket].StackRes[Stack].MmiohBase; + } + SocketResources[Socket].StackRes[Stack].MmiohUpdate =3D 1; + } + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohBase = =3D %llX newLength =3D %llX\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiohBase, SocketRes= ources[Socket].StackRes[Stack].MmiohLength)); + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohLimit = =3D %llX\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiohLimit)); + DEBUG ((DEBUG_ERROR, "SocketResources[%x].StackRes[%x].MmiohUpdate= =3D %d\n", Socket, Stack, + SocketResources[Socket].StackRes[Stack].MmiohUpdate)); + } // for (Stack...) + + SocketResources[Socket].MmiohLimit =3D TempMmioLimit; + } // for (Socket...) + return EFI_SUCCESS; +} + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBri= dge/PciRootBridge.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/P= ciHostBridge/PciRootBridge.h new file mode 100644 index 0000000000..54faf82e98 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciHostBridge/Pci= RootBridge.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, RootBrid= geIo, PCI_ROOT_BRIDGE_SIGNATURE) + +#define ROOT_BRIDGE_FROM_LINK(a) CR (a, PCI_ROOT_BRIDGE_INSTANCE, Link, PC= I_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 br= idge. + @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 b= ridge. + @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 inst= ance. + @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 br= idge. + @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 b= ridge. + @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 wri= te + to system memory. + @param HostAddress The system memory address to map on the PCI contro= ller. + @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 Ho= stAddress. + @param Mapping The value to pass to Unmap() when the bus master D= MA + operation is complete. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameters found. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a com= mon buffer. + @retval EFI_DEVICE_ERROR The System hardware could not map the req= uested 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 sys= tem + 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 EfiPciOperationBusMasterCommonB= uffer + 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 attribu= tes + that the PCI root bridge supports is retu= rned + in Supports. If Attributes is not NULL, t= hen + 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 ins= tance. + @param Attributes - The mask of attributes to set. + @param ResourceBase - Pointer to the base address of the resource ra= nge + 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 attrib= utes 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 inst= ance. + @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/PciHostBri= dge/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/Pci= RootBridgeIo.c @@ -0,0 +1,1664 @@ +/** @file + IIO PCI Root Bridge Io Protocol code. Generic enough to work for all IIO= s. + Does not support configuration accesses to the extended PCI Express regi= sters 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 =3D ROOT_BRIDGE_FROM_THIS (Protocol); + + // + // Initialize the apertures with default values + // + CopyMem ( + &RootBridge->Aperture, + ResAperture, + sizeof (PCI_ROOT_BRIDGE_RESOURCE_APERTURE) + ); + + for (Index =3D TypeIo; Index < TypeMax; Index++) { + RootBridge->ResAllocNode[Index].Type =3D Index; + RootBridge->ResAllocNode[Index].Base =3D 0; + RootBridge->ResAllocNode[Index].Length =3D 0; + RootBridge->ResAllocNode[Index].Status =3D ResNone; + } + + EfiInitializeLock (&RootBridge->PciLock, TPL_HIGH_LEVEL); + RootBridge->PciAddress =3D 0xCF8; + RootBridge->PciData =3D 0xCFC; + + RootBridge->AllocationAttributes =3D AllocAttributes; + RootBridge->Attributes =3D 0; + RootBridge->Supports =3D 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 =3D (UINT32) mIioUds->IioUdsPtr->PlatformData.PciExpressBase; + HecSize =3D (UINT32) mIioUds->IioUdsPtr->PlatformData.PciExpressSize; + ASSERT (HecBase !=3D 0); + + RootBridge->HecBase =3D HecBase; + RootBridge->HecLen =3D HecSize; + + RootBridge->BusNumberAssigned =3D FALSE; + RootBridge->BusScanCount =3D 0; + + Protocol->ParentHandle =3D HostBridgeHandle; + + Protocol->PollMem =3D RootBridgeIoPollMem; + Protocol->PollIo =3D RootBridgeIoPollIo; + + Protocol->Mem.Read =3D RootBridgeIoMemRead; + Protocol->Mem.Write =3D RootBridgeIoMemWrite; + + Protocol->Io.Read =3D RootBridgeIoIoRead; + Protocol->Io.Write =3D RootBridgeIoIoWrite; + + Protocol->CopyMem =3D RootBridgeIoCopyMem; + + Protocol->Pci.Read =3D RootBridgeIoPciRead; + Protocol->Pci.Write =3D RootBridgeIoPciWrite; + + Protocol->Map =3D RootBridgeIoMap; + Protocol->Unmap =3D RootBridgeIoUnmap; + + Protocol->AllocateBuffer =3D RootBridgeIoAllocateBuffer; + Protocol->FreeBuffer =3D RootBridgeIoFreeBuffer; + + Protocol->Flush =3D RootBridgeIoFlush; + + Protocol->GetAttributes =3D RootBridgeIoGetAttributes; + Protocol->SetAttributes =3D RootBridgeIoSetAttributes; + + Protocol->Configuration =3D RootBridgeIoConfiguration; + + Protocol->SegmentNumber =3D SegmentNumber; + + Status =3D gBS->LocateProtocol ( + &gEfiCpuIo2ProtocolGuid, + NULL, + &mCpuIo + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &m= DynamicSiLibraryProtocol); + 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 =3D Multiplicand; + Multiplicand =3D Multiplier; + Multiplier =3D Uint64; + } + // + // Because Multiplicand * Multiplier overflows, + // Multiplicand * Multiplier / Divisor + // =3D (2 * Multiplicand' + 1) * Multiplier / Divisor + // =3D 2 * (Multiplicand' * Multiplier / Divisor) + Multiplier / Divis= or + // + Uint64 =3D MultThenDivU64x64x32 (RShiftU64 (Multiplicand, 1), Multipli= er, Divisor, &LocalRemainder); + Uint64 =3D LShiftU64 (Uint64, 1); + Uint32 =3D 0; + if ((Multiplicand & 0x1) =3D=3D 1) { + Uint64 +=3D DivU64x32Remainder (Multiplier, Divisor, &Uint32); + } + return Uint64 + DivU64x32Remainder (Uint32 + LShiftU64 (LocalRemainder= , 1), Divisor, Remainder); + } else { + return DivU64x32Remainder (MultU64x64 (Multiplicand, Multiplier), Divi= sor, 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 be= fore + it rolls over. + + @return The elapsed tick count from CurrentTick. +**/ +UINT64 +GetElapsedTick ( + UINT64 *CurrentTick, + UINT64 StartTick, + UINT64 EndTick + ) +{ + UINT64 PreviousTick; + + PreviousTick =3D *CurrentTick; + *CurrentTick =3D 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 m= et, + or a timeout occurs. + + This function provides a standard way to poll a PCI memory location. A P= CI + 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 & M= ask) + 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 ca= ller + is responsible for aligning Address if required. + @param[in] Mask Mask used for the polling criteria. Bytes above W= idth + in Mask are ignored. The bits in the bytes below = Width + which are zero in Mask are ignored when polling t= he + 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 tim= er + 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 ma= tched + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32)Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + // + // No matter what, always do a single poll. + // + Status =3D This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) =3D=3D Value) { + return EFI_SUCCESS; + } + + if (Delay =3D=3D 0) { + return EFI_SUCCESS; + + } else { + // + // NumberOfTicks =3D Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1) + // + Frequency =3D GetPerformanceCounterProperties (&StartTick, &EndTic= k); + NumberOfTicks =3D MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_= TIMER_PERIOD_SECONDS(1), &Remainder); + if (Remainder >=3D (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) { + NumberOfTicks++; + } + for ( ElapsedTick =3D 0, CurrentTick =3D GetPerformanceCounter() + ; ElapsedTick <=3D NumberOfTicks + ; ElapsedTick +=3D GetElapsedTick (&CurrentTick, StartTick, EndTic= k) + ) { + Status =3D This->Mem.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) =3D=3D 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 Wid= th 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 crit= eria. + @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 loca= tion. + + @retval EFI_SUCCESS The last data returned from the access ma= tched + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ((UINT32)Width > EfiPciWidthUint64) { + return EFI_INVALID_PARAMETER; + } + + Status =3D This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + if ((*Result & Mask) =3D=3D Value) { + return EFI_SUCCESS; + } + + if (Delay =3D=3D 0) { + return EFI_SUCCESS; + + } else { + // + // NumberOfTicks =3D Frenquency * Delay / EFI_TIMER_PERIOD_SECONDS(1) + // + Frequency =3D GetPerformanceCounterProperties (&StartTick, &EndTic= k); + NumberOfTicks =3D MultThenDivU64x64x32 (Frequency, Delay, (UINT32)EFI_= TIMER_PERIOD_SECONDS(1), &Remainder); + if (Remainder >=3D (UINTN)EFI_TIMER_PERIOD_SECONDS(1) / 2) { + NumberOfTicks++; + } + for ( ElapsedTick =3D 0, CurrentTick =3D GetPerformanceCounter() + ; ElapsedTick <=3D NumberOfTicks + ; ElapsedTick +=3D GetElapsedTick (&CurrentTick, StartTick, EndTic= k) + ) { + Status =3D This->Io.Read (This, Width, Address, 1, Result); + if (EFI_ERROR (Status)) { + return Status; + } + + if ((*Result & Mask) =3D=3D 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 t= hat 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 cal= ler + is responsible for aligning the Address if requir= ed. + @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 st= ore + the results. For write operations, the source buf= fer + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 ||Width >=3D EfiPciWidthMaximum ) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D 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 t= hat 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 cal= ler + is responsible for aligning the Address if requir= ed. + @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 st= ore + the results. For write operations, the source buf= fer + 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >=3D EfiPciWidthMaximum ) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D 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_PROTOCO= L. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the I/O operation. The call= er is + responsible for aligning the Address if require= d. + @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 b= uffer + to write data from. + + @retval EFI_SUCCESS The data was read from or written to th= e PCI + root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root brid= ge. + @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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >=3D EfiPciWidthMaximum ) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + // + // AlignMask =3D (1 << Width) - 1; + // + AlignMask =3D (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_PROTOCO= L. + @param[in] Width Signifies the width of the memory operations. + @param[in] Address The base address of the I/O operation. The call= er is + responsible for aligning the Address if require= d. + @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 b= uffer + to write data from. + + @retval EFI_SUCCESS The data was read from or written to th= e PCI + root bridge. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root brid= ge. + @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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >=3D EfiPciWidthMaximum ) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + // + // AlignMask =3D (1 << Width) - 1; + // + AlignMask =3D (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 ro= ot + bridge memory space to another region of PCI root bridge memory space. T= his + 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 t= hat 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 DestAddres= s if + required. + @param[in] SrcAddress The source address of the memory operation. The c= aller + 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 DestAddr= ess + and SrcAddress. + + @retval EFI_SUCCESS The data was copied from one memory reg= ion + to another memory region. + @retval EFI_INVALID_PARAMETER Width is invalid for this PCI root brid= ge. + @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 =3D=3D SrcAddress) { + return EFI_SUCCESS; + } + + Stride =3D (UINTN)1 << Width; + + Forward =3D TRUE; + if ((DestAddress > SrcAddress) && + (DestAddress < (SrcAddress + Count * Stride))) { + Forward =3D FALSE; + SrcAddress =3D SrcAddress + (Count - 1) * Stride; + DestAddress =3D DestAddress + (Count - 1) * Stride; + } + + for (Index =3D 0; Index < Count; Index++) { + Status =3D RootBridgeIoMemRead ( + This, + Width, + SrcAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + Status =3D RootBridgeIoMemWrite ( + This, + Width, + DestAddress, + 1, + &Result + ); + if (EFI_ERROR (Status)) { + return Status; + } + if (Forward) { + SrcAddress +=3D Stride; + DestAddress +=3D Stride; + } else { + SrcAddress -=3D Stride; + DestAddress -=3D 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 >=3D EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + ASSERT (((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*)&UserAddress)->Ex= tendedRegister =3D=3D 0x00); + + Stride =3D 1 << Width; + + Pci.Bits.Reg =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAd= dress)->Register; + Pci.Bits.Func =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserA= ddress)->Function; + Pci.Bits.Dev =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAd= dress)->Device; + Pci.Bits.Bus =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserAd= dress)->Bus; + Pci.Bits.Reserved =3D 0; + Pci.Bits.Enable =3D 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 =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS*) &UserA= ddress)->Register & 0x03; + + while (Count) { + PciAligned =3D Pci; + PciAligned.Bits.Reg &=3D 0xfc; + PciData =3D 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 =3D ((UINT8 *)UserBuffer) + Stride; + PciDataStride =3D (PciDataStride + Stride) % 4; + Count -=3D 1; + + // + // Only increment the PCI address if Width is not a FIFO. + // + if (Width >=3D EfiPciWidthUint8 && Width <=3D EfiPciWidthUint64) { + Pci.Bits.Reg +=3D 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 =3D Buffer; + UINT8 Size; + + Size =3D 1 << (Width & 0x3); + + if (Buffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >=3D EfiPciWidthMaximum ) { + return EFI_INVALID_PARAMETER; + } + + // + // Read Pci configuration space + // + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + if (RootBridge->HecBase =3D=3D 0) { + return RootBridgeIoPciRW (This, FALSE, Width, Address, Count, Buffer); + } + + if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Extende= dRegister) { + PciExtReg =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addres= s)->Register; + } else { + PciExtReg =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addres= s)->ExtendedRegister & 0x0FFF; + } + + PciBus =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Bus; + PciDev =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Device; + PciFn =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Function; + + USRA_BLOCK_PCIE_ADDRESS (EndPointPciAddress, Width, Count, This->Segment= Number, 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 brid= ge. + @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 =3D Buffer; + UINT8 Size; + + Size =3D 1 << (Width & 0x3); + + if (Buffer =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if (Width < 0 || Width >=3D EfiPciWidthMaximum) { + return EFI_INVALID_PARAMETER; + } + + // + // Write Pci configuration space + // + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + if (RootBridge->HecBase =3D=3D 0) { + return RootBridgeIoPciRW (This, TRUE, Width, Address, Count, Buffer); + } + + if (!((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Address)->Extende= dRegister) { + PciExtReg =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addres= s)->Register; + } else { + PciExtReg =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addres= s)->ExtendedRegister & 0x0FFF; + } + + PciBus =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Bus; + PciDev =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Device; + PciFn =3D ((EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_PCI_ADDRESS *) &Addr= ess)->Function; + + USRA_BLOCK_PCIE_ADDRESS (EndPointPciAddress, Width, Count, This->Segment= Number, 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 wri= te + to system memory. + @param HostAddress The system memory address to map on the PCI contro= ller. + @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 Ho= stAddress. + @param Mapping The value to pass to Unmap() when the bus master D= MA + operation is complete. + + @retval EFI_SUCCESS Success. + @retval EFI_INVALID_PARAMETER Invalid parameters found. + @retval EFI_UNSUPPORTED The HostAddress cannot be mapped as a com= mon buffer. + @retval EFI_DEVICE_ERROR The System hardware could not map the req= uested 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 =3D=3D NULL || Mapping =3D=3D NULL || DeviceAddress = =3D=3D NULL || HostAddress =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Initialize the return values to their defaults + // + *Mapping =3D NULL; + + // + // Make sure that Operation is valid + // + if ((UINT32) Operation >=3D EfiPciOperationMaximum) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + if (mIoMmu !=3D NULL) { + if (!RootBridge->DmaAbove4G) { + // + // Clear 64bit support + // + if (Operation > EfiPciOperationBusMasterCommonBuffer) { + Operation =3D (EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL_OPERATION) (Operati= on - EfiPciOperationBusMasterRead64); + } + } + Status =3D 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 =3D (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 ret= urn + // an error. + // + if (Operation =3D=3D EfiPciOperationBusMasterCommonBuffer || Operation= =3D=3D EfiPciOperationBusMasterCommonBuffer64) { + return EFI_INVALID_PARAMETER; + } + // + // Allocate a MAP_INFO structure to remember the mapping when Unmap() = is + // called later. + // + MapInfo =3D AllocatePool (sizeof (MAP_INFO)); + if (MapInfo =3D=3D NULL) { + *NumberOfBytes =3D 0; + return EFI_OUT_OF_RESOURCES; + } + // + // Return a pointer to the MAP_INFO structure in Mapping + // + *Mapping =3D MapInfo; + + // + // Initialize the MAP_INFO structure + // + MapInfo->Operation =3D Operation; + MapInfo->NumberOfBytes =3D *NumberOfBytes; + MapInfo->NumberOfPages =3D EFI_SIZE_TO_PAGES (*NumberOfBytes); + MapInfo->HostAddress =3D PhysicalAddress; + MapInfo->MappedHostAddress =3D SIZE_4GB - 1; + + // + // Allocate a buffer below 4GB to map the transfer to. + // + Status =3D gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + MapInfo->NumberOfPages, + &MapInfo->MappedHostAddress + ); + if (EFI_ERROR (Status)) { + FreePool (MapInfo); + *NumberOfBytes =3D 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 =3D=3D EfiPciOperationBusMasterRead || Operation =3D=3D = EfiPciOperationBusMasterRead64) { + CopyMem ( + (VOID *) (UINTN) MapInfo->MappedHostAddress, + (VOID *) (UINTN) MapInfo->HostAddress, + MapInfo->NumberOfBytes + ); + } + // + // The DeviceAddress is the address of the maped buffer below 4GB + // + *DeviceAddress =3D MapInfo->MappedHostAddress; + } else { + // + // The transfer is below 4GB, so the DeviceAddress is simply the HostA= ddress + // + *DeviceAddress =3D 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 sys= tem + 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 !=3D NULL) { + Status =3D mIoMmu->Unmap ( + mIoMmu, + Mapping + ); + return Status; + } + // + // See if the Map() operation associated with this Unmap() required a ma= pping buffer. + // If a mapping buffer was not required, then this function simply retur= ns EFI_SUCCESS. + // + if (Mapping !=3D NULL) { + // + // Get the MAP_INFO structure from Mapping + // + MapInfo =3D (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 =3D=3D EfiPciOperationBusMasterWrite) || + (MapInfo->Operation =3D=3D 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 EfiPciOperationBusMasterCommonB= uffer + 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) !=3D 0)= { + return EFI_UNSUPPORTED; + } + + // + // Check for invalid inputs + // + if (HostAddress =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // The only valid memory types are EfiBootServicesData and + // EfiRuntimeServicesData + // + if (MemoryType !=3D EfiBootServicesData && + MemoryType !=3D EfiRuntimeServicesData) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + + if (mIoMmu !=3D NULL) { + + if (!RootBridge->DmaAbove4G) { + // + // Clear DUAL_ADDRESS_CYCLE + // + Attributes &=3D ~((UINT64) EFI_PCI_ATTRIBUTE_DUAL_ADDRESS_CYCLE); + } + Status =3D mIoMmu->AllocateBuffer ( + mIoMmu, + Type, + MemoryType, + Pages, + HostAddress, + Attributes + ); + return Status; + } + + // + // Limit allocations to memory below 4GB + // + PhysicalAddress =3D SIZE_4GB - 1; + + Status =3D gBS->AllocatePages ( + AllocateMaxAddress, + MemoryType, + Pages, + &PhysicalAddress + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *HostAddress =3D (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 AllocateBuff= er(). +**/ +EFI_STATUS +EFIAPI +RootBridgeIoFreeBuffer ( + IN EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *This, + IN UINTN Pages, + OUT VOID *HostAddress + ) +{ + EFI_STATUS Status; + + if (mIoMmu !=3D NULL) { + Status =3D 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 syst= em + 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 brid= ges. + A PCI controller specific action must be taken to guarantee that the pos= ted + write transactions have been flushed from the PCI controller and from al= l 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 fl= ushed + from the PCI host bridge due to a hardware er= ror. +**/ +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 attribu= tes + that the PCI root bridge supports is retu= rned + in Supports. If Attributes is not NULL, t= hen + 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 =3D=3D NULL && Supported =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + RootBridge =3D ROOT_BRIDGE_FROM_THIS (This); + // + // Set the return value for Supported and Attributes + // + if (Supported !=3D NULL) { + *Supported =3D RootBridge->Supports; + } + + if (Attributes !=3D NULL) { + *Attributes =3D 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 va= ry + 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 ret= urned + in ResourceBase and ResourceLength. The caller is responsible for verify= ing + 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 roo= t bridge + was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI roo= t 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 =3D ROOT_BRIDGE_FROM_THIS (This); + + if ((Attributes & (~RootBridge->Supports)) !=3D 0) { + return EFI_UNSUPPORTED; + } + + RootBridge->Attributes =3D Attributes; + return EFI_SUCCESS; +} + +/** + Retrieves the current resource settings of this PCI root bridge in the f= orm + 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 br= idge. + 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 de= scribed + 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_PROTOCO= L. + @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 brid= ge + was returned in Resources. + @retval EFI_UNSUPPORTED The current configuration of this PCI root brid= ge + 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 =3D ROOT_BRIDGE_FROM_THIS (This); + + // + // If the pointer is not NULL, it points to a buffer already allocated. + // + if (RootBridge->ConfigBuffer =3D=3D NULL) { + Status =3D 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 =3D RootBridge->ConfigBuffer; + + ZeroMem (Config, TypeMax * sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR) + = sizeof (EFI_ACPI_END_TAG_DESCRIPTOR)); + + for (Idx =3D 0; Idx < TypeMax; Idx++) { + + ResAllocNode =3D &RootBridge->ResAllocNode[Idx]; + + if (ResAllocNode->Status !=3D ResAllocated) { + continue; + } + + switch (ResAllocNode->Type) { + + case TypeIo: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)= - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_IO; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode->Length = - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + case TypeMem32: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DES= CRIPTOR) - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_MEM; + Config->AddrSpaceGranularity =3D 32; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode-= >Length - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + case TypePMem32: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DES= CRIPTOR) - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_MEM; + Config->SpecificFlag =3D 6; + Config->AddrSpaceGranularity =3D 32; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode-= >Length - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + case TypeMem64: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DES= CRIPTOR) - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_MEM; + Config->SpecificFlag =3D 6; + Config->AddrSpaceGranularity =3D 64; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode-= >Length - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + case TypePMem64: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DES= CRIPTOR) - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_MEM; + Config->SpecificFlag =3D 6; + Config->AddrSpaceGranularity =3D 64; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode-= >Length - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + case TypeBus: + Config->Desc =3D ACPI_ADDRESS_SPACE_DESCRIPTOR; + Config->Len =3D sizeof (EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR)= - 3; + Config->ResType =3D ACPI_ADDRESS_SPACE_TYPE_BUS; + Config->AddrRangeMin =3D ResAllocNode->Base; + Config->AddrRangeMax =3D ResAllocNode->Base + ResAllocNode->Length = - 1; + Config->AddrLen =3D ResAllocNode->Length; + break; + + default: + break; + } + + Config++; + } + // + // Terminate the entries. + // + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Desc =3D ACPI_END_TAG_DES= CRIPTOR; + ((EFI_ACPI_END_TAG_DESCRIPTOR *) Config)->Checksum =3D 0x0; + + *Resources =3D RootBridge->ConfigBuffer; + return EFI_SUCCESS; +} + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatfor= m/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/PciIo= vPlatformPolicy.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 pag= e size. + + @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROT= OCOL instance. + @param SystemLowestPageSize - The system lowest page size. (This syste= m 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)) + OFFSE= T_OF (SYSTEM_CONFIGURATION, SystemPageSize)), sizeof (UINT8)); + + if (SystemLowestPageSize !=3D NULL) { + // + // Convert page size option to page size + // Option is n in 2^n + // Page size is number of 4KiB pages + // + + *SystemLowestPageSize =3D (UINT32) (1 << SystemPageSizeOption); + } + return EFI_SUCCESS; +} + +/** + + The GetIovPlatformPolicy() function retrieves the platform policy rega= rding PCI IOV. + + @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL ins= tance. + @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 =3D 0; + + CopyMem (&ARIEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYS= TEM_CONFIGURATION, ARIEnable)), sizeof (UINT8)); + CopyMem (&SRIOVEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYS= TEM_CONFIGURATION, SRIOVEnable)), sizeof (UINT8)); + CopyMem (&MRIOVEnable, (((UINT8*) PcdGetPtr (PcdSetup)) + OFFSET_OF (SYS= TEM_CONFIGURATION, MRIOVEnable)), sizeof (UINT8)); + + if (ARIEnable =3D=3D TRUE) { + PolicyEnable =3D PolicyEnable | EFI_PCI_IOV_POLICY_ARI; + } + + if (SRIOVEnable =3D=3D TRUE) { + PolicyEnable =3D PolicyEnable | EFI_PCI_IOV_POLICY_SRIOV; + } + + if (MRIOVEnable =3D=3D TRUE) { + PolicyEnable =3D PolicyEnable | EFI_PCI_IOV_POLICY_MRIOV; + } + + if (PciIovPolicy !=3D NULL) { + //*PciIovPolicy =3D EFI_PCI_IOV_POLICY_ARI | EFI_PCI_IOV_POLICY_SRIOV; + *PciIovPolicy =3D PolicyEnable; + } + return EFI_SUCCESS; +} + +#endif + diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatfor= m/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/PciIo= vPlatformPolicy.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 pag= e size. + + @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROT= OCOL instance. + @param SystemLowestPageSize - The system lowest page size. (This syste= m 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 regardi= ng PCI IOV. + + @param This - Pointer to the EFI_PCI_IOV_PLATFORM_PROTOCOL ins= tance. + @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/PciPlatfor= m/PciPlatform.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPl= atform/PciPlatform.c new file mode 100644 index 0000000000..8584c0f330 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPl= atform.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 =3D TRUE; +UINT8 sSataRaidLoadEfiDriverOption; +UINT8 SataRaidLoadEfiDriverOption[PCH_MAX_SATA_CONTROL= LERS]; +UINT8 BootNetworkOption; + +STATIC +BOOLEAN +InternalPlatformCheckPcieRootPort ( + IN UINTN Bus, + IN UINT32 PcieSlotOpromBitMap +) +{ + EFI_STATUS Status; + + UBA_CONFIG_DATABASE_PROTOCOL *UbaConfigProtocol =3D NULL; + UINTN DataLength =3D 0; + PLATFORM_OPTION_ROM_UPDATE_DATA OptionRomUpdateTable; + + Status =3D gBS->LocateProtocol ( + &gUbaConfigDatabaseProtocolGuid, + NULL, + &UbaConfigProtocol + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO," InternalPlatformCheckPcieRootPort fail!\n")); + return TRUE; + } + + DataLength =3D sizeof (OptionRomUpdateTable); + Status =3D UbaConfigProtocol->GetData ( + UbaConfigProtocol, + &gPlatformOptionRomUpdateConfigDataGuid, + &OptionRomUpdateTable, + &DataLength + ); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_INFO,"InternalPlatformCheckPcieRootPort fail!\n")); + return TRUE; + } + + ASSERT (OptionRomUpdateTable.Signature =3D=3D PLATFORM_OPTION_ROM_UPDATE= _SIGNATURE); + ASSERT (OptionRomUpdateTable.Version =3D=3D PLATFORM_OPTION_ROM_UPDATE_V= ERSION); + + return OptionRomUpdateTable.CallCheckRootPort (Bus, PcieSlotOpromBitMap); +} + +STATIC +EFI_STATUS +InternalGetSystemBoardInfo ( + IN OUT DXE_SYSTEM_BOARD_INFO **SystemboardInfoTableBuffer + ) +{ + EFI_STATUS Status; + UBA_CONFIG_DATABASE_PROTOCOL *UbaConfigProtocol =3D NULL; + UINTN DataLength =3D 0; + SYSTEM_BOARD_INFO_DATA SystemBoardInfoData; + + Status =3D gBS->LocateProtocol ( + &gUbaConfigDatabaseProtocolGuid, + NULL, + &UbaConfigProtocol + ); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR," [GetSystemBoardInfo] Locate UbaConfigProtocol f= ail!\n")); + return Status; + } + + DataLength =3D sizeof(SystemBoardInfoData); + Status =3D UbaConfigProtocol->GetData ( + UbaConfigProtocol, + &gSystemBoardInfoConfigDataGuid, + &SystemBoardInfoData, + &DataLength + ); + + if (EFI_ERROR(Status)) { + DEBUG ((EFI_D_ERROR," [GetSystemBoardInfo] Get Data fail!\n")); + return Status; + } + + ASSERT (SystemBoardInfoData.Signature =3D=3D SYSTEM_SYSTEM_BOARD_INFO_SI= GNATURE); + ASSERT (SystemBoardInfoData.Version =3D=3D SYSTEM_SYSTEM_BOARD_INFO_VE= RSION); + + *SystemboardInfoTableBuffer =3D 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 =3D=3D 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 =3D gBS->LocateHandleBuffer( + ByProtocol, + &gEfiFirmwareVolume2ProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR(Status) || HandleCount =3D=3D 0) { + return EFI_NOT_FOUND; + } + // + // Find desired image in all Fvs + // + for (Index =3D 0; Index < HandleCount; Index++) { + Status =3D gBS->HandleProtocol( + HandleBuffer[Index], + &gEfiFirmwareVolume2ProtocolGuid, + &Fv + ); + if (EFI_ERROR(Status)) { + return EFI_LOAD_ERROR; + } + // + // Try a raw file + // + *Buffer =3D NULL; + *Size =3D 0; + Status =3D 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 >=3D 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 =3D NULL; + UINT32 Index; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol =3D NULL; + + OpRomBase =3D NULL; + OpRomSize =3D 0; + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &D= ynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // Get System Board Info + // + Status =3D InternalGetSystemBoardInfo (&SystemBoardInfo); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "[GetPciRom] Get system board info fail!\n")); + return Status; + } + + Status =3D gBS->HandleProtocol ( + PciHandle, + &gEfiPciIoProtocolGuid, + (VOID **) &PciIo + ); + if (EFI_ERROR (Status)) { + return EFI_NOT_FOUND; + } + + if (FirstCall =3D=3D TRUE) { + Status =3D GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CON= FIGURATION, BootNetwork), &BootNetworkOption, sizeof(BootNetworkOption)); + if (EFI_ERROR (Status)) { + BootNetworkOption =3D 0; + } + Status =3D GetOptionData (&gPchSetupVariableGuid, + OFFSET_OF(PCH_SETUP, SataRaidLoadEfiDriver), + &SataRaidLoadEfiDriverOption, + sizeof(SataRaidLoadEfiDriverOption) * PCH_MAX_SA= TA_CONTROLLERS); + if (EFI_ERROR (Status)) { + for (Index =3D 0; Index < DynamicSiLibraryProtocol->MaxSataControlle= rNum(); Index++) { + SataRaidLoadEfiDriverOption[Index] =3D 0; + } + } + + FirstCall =3D 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 =3D=3D 0) && + (DeviceClass =3D=3D ((PCI_CLASS_NETWORK << 8) | PCI_CLASS_NETWORK_ET= HERNET)) + ) { + return EFI_NOT_FOUND; + } + + // + // Run each PCI-E slot ROM only if PCI-E Slot Oprom is enabled. + // + if ( Bus !=3D 0 ) { + SlotOptionRomDisabled =3D InternalPlatformCheckPcieRootPort (Bus, PcdG= et32(PcdOemSkuPcieSlotOpromBitMap)); + + if (SlotOptionRomDisabled) { + return EFI_NOT_FOUND; + } + } + + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_VENDOR_ID_OFFSET, 1, &V= endorId); + PciIo->Pci.Read (PciIo, EfiPciIoWidthUint16, PCI_DEVICE_ID_OFFSET, 1, &D= eviceId); + + //DEBUG ((EFI_D_INFO, "GetPciRom - VenID:DevID: %04x:%04x\n", (UINTN)Ven= dorId, (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 we= ll. + // It only have 1 device id in OPROM. + // Device Id in OpROM is not same with the value in PCI configuration sp= ace + // it will cause VBIOS fails to start + // + if ((VendorId =3D=3D 0x1002) && (DeviceId =3D=3D 0x68BE)) { + DEBUG ((DEBUG_INFO, "MS-HD5770 video adapter\n")); + RomHeader.Raw =3D PciIo->RomImage; + if (RomHeader.Raw !=3D NULL) { + Pcir =3D (PCI_DATA_STRUCTURE *)(RomHeader.Raw + RomHeader.Generic->P= cirOffset); + if ((Pcir->VendorId =3D=3D 0x1002) && (Pcir->DeviceId =3D=3D 0x68B8)= ) { + // + // Assign same device id in PCI configuration space + // + Pcir->DeviceId =3D DeviceId; + } + } else { + DEBUG ((EFI_D_ERROR, "MS-HD5770 video adapter detected but PciIo->Ro= mImage =3D=3D 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 =3D=3D V_SATA_CFG_VENDOR_ID) { + for (Index =3D 0; Index < DynamicSiLibraryProtocol->MaxSataControllerN= um(); Index++) { + if (Bus =3D=3D DEFAULT_PCI_BUS_NUMBER_PCH && + Device =3D=3D DynamicSiLibraryProtocol->SataDevNumber (Index) && + Function =3D=3D DynamicSiLibraryProtocol->SataFuncNumber (Index)= && + SataRaidLoadEfiDriverOption[Index] =3D=3D 1) { + return EFI_NOT_FOUND; + } + } + } + + // + // Loop through table of video option rom descriptions + // + RomImageNumber =3D 0; + for (TableIndex =3D 0; SystemBoardInfo->PciOptionRomTable[TableIndex].Ve= ndorId !=3D 0xffff; TableIndex++) { + // + // See if the PCI device specified by PciHandle matches at device in m= PciOptionRomTable + // + if (VendorId !=3D SystemBoardInfo->PciOptionRomTable[TableIndex].Vendo= rId || + DeviceId !=3D SystemBoardInfo->PciOptionRomTable[TableIndex].Devic= eId || + Device !=3D SystemBoardInfo->PciOptionRomTable[TableIndex].Device = || + Function !=3D SystemBoardInfo->PciOptionRomTable[TableIndex].Funct= ion + ) { + continue; + } + + //Check if user wants to exclusively run this option rom for the devic= e. + OpromPolicy =3D PlatformOpromLoadTypePolicy(PciHandle, TableIndex); + if(OpromPolicy =3D=3D DONT_LOAD) { + continue; + } + + Status =3D GetRawImage ( + &SystemBoardInfo->PciOptionRomTable[TableIndex].FileName, + &OpRomBase, + &OpRomSize + ); + + if (EFI_ERROR (Status)) { + continue; + } else { + RomImageNumber++; + if (RomImageNumber =3D=3D PcdGet8(PcdMaxOptionRomNumber) || OpromPol= icy =3D=3D EXCLUSIVE_LOAD) { + break; + } + } + } + + if (RomImageNumber =3D=3D 0) { + + return EFI_NOT_FOUND; + + } else { + + *RomImage =3D OpRomBase; + *RomSize =3D 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 =3D=3D NULL) { + return EFI_INVALID_PARAMETER; + } + + if ( (Phase & (EfiPciEnumerationDeviceScanning | EfiPciEnumerationBusNu= mberAssigned \ + | EfiPciEnumerationResourceAssigned)) =3D=3D 0) { + return EFI_INVALID_PARAMETER; + } + // + // Check if the node has been added + // + NodeEntry =3D GetFirstNode (&mPciPrivateData.PciCallbackList); + while (!IsNull (&mPciPrivateData.PciCallbackList, NodeEntry)) { + PciCallbackData =3D PCI_CALLBACK_DATA_FROM_LINK (NodeEntry); + if (PciCallbackData->Function =3D=3D Function) { + return EFI_UNSUPPORTED; + } + + NodeEntry =3D GetNextNode (&mPciPrivateData.PciCallbackList, NodeEntry= ); + } + + PciCallbackData =3D NULL; + PciCallbackData =3D AllocateZeroPool (sizeof (PCI_CALLBACK_DATA)); + ASSERT (PciCallbackData !=3D NULL); + + if(PciCallbackData !=3D NULL){ + PciCallbackData->Signature =3D PCI_CALLBACK_DATA_SIGNATURE; + PciCallbackData->Function =3D Function; + PciCallbackData->Phase =3D Phase; + InsertTailList (&mPciPrivateData.PciCallbackList, &PciCallbackData->Li= nk); + 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 =3D GetFirstGuidHob (&gEfiPlatformInfoGuid); + ASSERT (GuidHob !=3D NULL); + if (GuidHob =3D=3D NULL) { + return EFI_NOT_FOUND; + } + mPciPrivateData.PlatformInfo =3D GET_GUID_HOB_DATA(GuidHob); + + //EDK2_TODO Check if clearing mPciPrivateData.PlatformInfo (got above) i= s intended. + ZeroMem (&mPciPrivateData, sizeof (mPciPrivateData)); + InitializeListHead (&mPciPrivateData.PciCallbackList); + + mPciPrivateData.PciPlatform.PlatformNotify =3D PhaseNotify; + mPciPrivateData.PciPlatform.PlatformPrepController =3D PlatformPrepCont= roller; + mPciPrivateData.PciPlatform.GetPlatformPolicy =3D GetPlatformPolic= y; + mPciPrivateData.PciPlatform.GetPciRom =3D GetPciRom; + mPciPrivateData.PciCallback.RegisterPciCallback =3D RegisterPciCallb= ack; +#ifdef EFI_PCI_IOV_SUPPORT + mPciPrivateData.PciIovPlatform.GetSystemLowestPageSize =3D GetSystemLowe= stPageSize; + mPciPrivateData.PciIovPlatform.GetPlatformPolicy =3D GetIovPlatfor= mPolicy; +#endif + + // + // Install on a new handle + // + Status =3D 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/PciPlatfor= m/PciPlatform.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPl= atform/PciPlatform.h new file mode 100644 index 0000000000..45d9c38b16 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPl= atform.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_STA= CK]; + 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 instanc= e. + @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 d= river. + + @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 requir= ed. + Several notification points are defined at this time. More synchronizati= on points may be + added as required in the future. The PCI bus driver calls the platform d= river 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 Prot= ocol driver has + been notified. + This member function may not perform any error checking on the input par= ameters. It also + does not return any error codes. If this member function detects any err= or condition, it + needs to handle those errors on its own because there is no way to surfa= ce any errors to + the caller. + + @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instanc= e. + @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 d= river. + + @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/PciPlatfor= m/PciPlatform.inf b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciPlatform.inf new file mode 100644 index 0000000000..4121ea8982 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciPl= atform.inf @@ -0,0 +1,87 @@ +## @file +# +# @copyright +# Copyright 2006 - 2021 Intel Corporation.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PciPlatform + FILE_GUID =3D E2441B64-7EF4-41fe-B3A3-8CAA7F8D3017 + MODULE_TYPE =3D DXE_DRIVER + VERSION_STRING =3D 1.0 + ENTRY_POINT =3D 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/PciPlatfor= m/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/PciPl= atformHooks.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 =3D 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 =3D GetFirstNode (&mPciPrivateData.PciCallbackList); + !IsNull (&mPciPrivateData.PciCallbackList, NodePtr); + NodePtr =3D GetNextNode (&mPciPrivateData.PciCallbackList, NodePtr)= ) { + CallbackDataPtr =3D PCI_CALLBACK_DATA_FROM_LINK (NodePtr); + if (CallbackDataPtr->Phase & Phase) { + (CallbackDataPtr->Function) (RootBridgeHandle, PciAddress, Phase, Co= ntextPtr); + } + } +} + +/** + + 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 >=3D NELEMENTS (mPciPrivateData.PciRootBridgeIo) || + Stack >=3D NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]) || + mPciPrivateData.PciRootBridgeIo[Socket][Stack] =3D=3D NULL) { + ASSERT (FALSE); + return EFI_INVALID_PARAMETER; + } + + PciRootBridgeIo =3D mPciPrivateData.PciRootBridgeIo[Socket][Stack]; + + for (Device =3D 0; Device <=3D PCI_MAX_DEVICE; Device++) { + MultiFunc =3D FALSE; + for (Func =3D 0; Func <=3D PCI_MAX_FUNC; Func++) { + if (IsPciDevicePresent ( + PciRootBridgeIo, + &mPciPrivateData.Context.PciHeader, + StartBus, + Device, + Func + )) { + if ((Func =3D=3D 0) && IS_PCI_MULTI_FUNC(&mPciPrivateData.Context.= PciHeader)) { + MultiFunc =3D TRUE; + } + PciAddress =3D EFI_PCI_ADDRESS (StartBus, Device, Func, 0); + mPciPrivateData.Context.PciRootBridgeIo =3D 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 =3D EFI_PCI_ADDRESS (StartBus, Device, Func, PCI_BRID= GE_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 =3D 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 =3D=3D (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 =3D EFI_IO_APIC_ID_REGISTER; + mPciPrivateData.CpuIo->Mem.Write ( + mPciPrivateData.CpuIo, + EfiCpuIoWidthUint32, + IoApicAddress + EFI_IO_APIC_INDEX_OFFSET, + 1, + &Data + ); + + Data =3D IoApicId << EFI_IO_APIC_ID_BITSHIFT; + mPciPrivateData.CpuIo->Mem.Write ( + mPciPrivateData.CpuIo, + EfiCpuIoWidthUint32, + IoApicAddress + EFI_IO_APIC_DATA_OFFSET, + 1, + &Data + ); + + Data =3D EFI_IO_APIC_BOOT_CONFIG_REGISTER; + mPciPrivateData.CpuIo->Mem.Write ( + mPciPrivateData.CpuIo, + EfiCpuIoWidthUint32, + IoApicAddress + EFI_IO_APIC_INDEX_OFFSET, + 1, + &Data + ); + + Data =3D 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 =3D gBS->LocateProtocol ( + &gEfiPciIovPlatformProtocolGuid, + NULL, + &gPciIovPlatformProtocol + ); + if (!EFI_ERROR (Status)) { + Status =3D gPciIovPlatformProtocol->GetSystemLowestPageSize ( + gPciIovPlatformProtocol, + &SystemPageSize + ); + if (!EFI_ERROR (Status)) { + Status =3D PcdSet32S (PcdSrIovSystemPageSize, SystemPageSize); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } else { + return Status; + } + Status =3D gPciIovPlatformProtocol->GetPlatformPolicy ( + gPciIovPlatformProtocol, + &PciIovPolicy + ); + if (!EFI_ERROR (Status)) { + if (PciIovPolicy & EFI_PCI_IOV_POLICY_ARI) { + Status =3D PcdSetBoolS (PcdAriSupport, TRUE); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } else { + Status =3D PcdSetBoolS (PcdAriSupport, FALSE); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } + if (PciIovPolicy & EFI_PCI_IOV_POLICY_SRIOV) { + Status =3D PcdSetBoolS (PcdSrIovSupport, TRUE); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } else { + Status =3D PcdSetBoolS (PcdSrIovSupport, FALSE); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } + if (PciIovPolicy & EFI_PCI_IOV_POLICY_MRIOV) { + Status =3D PcdSetBoolS (PcdMrIovSupport, TRUE); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR(Status)) { + return Status; + } + } else { + Status =3D 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 =3D 0x%x; Syste= mPageSize =3D 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 =3D EFI_SUCCESS; + +#ifdef EFI_PCI_IOV_SUPPORT + Status =3D PciPlatformInitPciIovData(); // Update IOV PCD values +#endif + return Status; +} + +/** + + Attempts to set the XHCI controller's PCI CMD.MSE and CMD.BME bits to en= able OS kernel debugging over XHCI. + +**/ +VOID +AttemptToSetXhciMse ( + ) + +{ + UINT32 XhciBar; + UINT16 Command; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol =3D NULL; + EFI_STATUS Status; + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &D= ynamicSiLibraryProtocol); + 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 =3D 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 =3D=3D 0xFFFFFFF0) { + return; + } + if ((XhciBar & 0xFFFF0000) =3D=3D 0) { + // + // If lower 32 bits are not configured, check upper 32 bits. + // + XhciBar =3D MmioRead32 (DynamicSiLibraryProtocol->MmPciBase (DEFAULT_P= CI_BUS_NUMBER_PCH, PCI_DEVICE_NUMBER_PCH_XHCI, PCI_FUNCTION_NUMBER_PCH_XHCI= ) + R_XHCI_CFG_BAR0 + 4); + if (XhciBar =3D=3D 0) { + return; + } + } + + // + // Step 2. If XHCI's MSE (Memory Space Enable) or BME (Bus Master Enable= ) bits are cleared, set them. + // + Command =3D 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_MASTE= R)) !=3D (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_COMMAN= D_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 =3D NULL; + EFI_STATUS Status; + + // + // Program all the IOAPIC in system + // + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &D= ynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + UINT8 Socket, Stack, IoApicId, ApicIndex =3D 0; + CPU_CSR_ACCESS_VAR *CpuCsrAccessVarPtr =3D NULL; + Stack =3D 0; + IoApicId =3D 0; + CpuCsrAccessVarPtr =3D DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar (= ); + DEBUG ((DEBUG_INFO, "PciPlatformPostInit: setting up IOAPIC for PCH\n")); + ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackR= es[0].IoApicBase, PCH_IOAPIC_ID); + for (Socket =3D 0; Socket < MAX_SOCKET; Socket++) { + if (!(CpuCsrAccessVarPtr->socketPresentBitMap & (1 << Socket))) { + continue; + } + + for (Stack =3D 0; Stack < MAX_IIO_STACK; Stack++, ApicIndex++) { + if (!(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPrese= ntBitmap & (1 << Stack))) { + continue; + } + switch (ApicIndex) { + case 0: + IoApicId =3D PC00_IOAPIC_ID; + break; + case 1: + IoApicId =3D PC01_IOAPIC_ID; + break; + case 2: + IoApicId =3D PC02_IOAPIC_ID; + break; + case 3: + IoApicId =3D PC03_IOAPIC_ID; + break; + case 4: + IoApicId =3D PC04_IOAPIC_ID; + break; + case 5: + IoApicId =3D PC05_IOAPIC_ID; + break; + case 6: + IoApicId =3D PC06_IOAPIC_ID; + break; + case 7: + IoApicId =3D PC07_IOAPIC_ID; + break; + case 8: + IoApicId =3D PC08_IOAPIC_ID; + break; + case 9: + IoApicId =3D PC09_IOAPIC_ID; + break; + case 10: + IoApicId =3D PC10_IOAPIC_ID; + break; + case 11: + IoApicId =3D PC11_IOAPIC_ID; + break; + case 12: + IoApicId =3D PC12_IOAPIC_ID; + break; + case 13: + IoApicId =3D PC13_IOAPIC_ID; + break; + case 14: + IoApicId =3D PC14_IOAPIC_ID; + break; + case 15: + IoApicId =3D PC15_IOAPIC_ID; + break; + case 16: + IoApicId =3D PC16_IOAPIC_ID; + break; + case 17: + IoApicId =3D PC17_IOAPIC_ID; + break; + case 18: + IoApicId =3D PC18_IOAPIC_ID; + break; + case 19: + IoApicId =3D PC19_IOAPIC_ID; + break; + case 20: + IoApicId =3D PC20_IOAPIC_ID; + break; + case 21: + IoApicId =3D PC21_IOAPIC_ID; + break; + case 22: + IoApicId =3D PC22_IOAPIC_ID; + break; + case 23: + IoApicId =3D PC23_IOAPIC_ID; + break; + case 24: + IoApicId =3D PC24_IOAPIC_ID; + break; + case 25: + IoApicId =3D PC25_IOAPIC_ID; + break; + case 26: + IoApicId =3D PC26_IOAPIC_ID; + break; + case 27: + IoApicId =3D PC27_IOAPIC_ID; + break; + case 28: + IoApicId =3D PC28_IOAPIC_ID; + break; + case 29: + IoApicId =3D PC29_IOAPIC_ID; + break; + case 30: + IoApicId =3D PC30_IOAPIC_ID; + break; + case 31: + IoApicId =3D PC31_IOAPIC_ID; + break; + case 32: + IoApicId =3D PC32_IOAPIC_ID; + break; + case 33: + IoApicId =3D PC33_IOAPIC_ID; + break; + case 34: + IoApicId =3D PC34_IOAPIC_ID; + break; + case 35: + IoApicId =3D PC35_IOAPIC_ID; + break; + case 36: + IoApicId =3D PC36_IOAPIC_ID; + break; + case 37: + IoApicId =3D PC37_IOAPIC_ID; + break; + case 38: + IoApicId =3D PC38_IOAPIC_ID; + break; + case 39: + IoApicId =3D PC39_IOAPIC_ID; + break; + case 40: + IoApicId =3D PC40_IOAPIC_ID; + break; + case 41: + IoApicId =3D PC41_IOAPIC_ID; + break; + case 42: + IoApicId =3D PC42_IOAPIC_ID; + break; + case 43: + IoApicId =3D PC43_IOAPIC_ID; + break; + case 44: + IoApicId =3D PC44_IOAPIC_ID; + break; + case 45: + IoApicId =3D PC45_IOAPIC_ID; + break; + case 46: + IoApicId =3D PC46_IOAPIC_ID; + break; + case 47: + IoApicId =3D PC47_IOAPIC_ID; + break; + default: + break; + } + if ((Socket =3D=3D 0) && (Stack =3D=3D 0)) { + ProgramIoApicId ((mIioUds->IioUdsPtr->PlatformData.IIO_resource[So= cket].StackRes[Stack].IoApicBase + 0x1000), IoApicId); + } else { + ProgramIoApicId (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Soc= ket].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 requir= ed. + Several notification points are defined at this time. More synchronizati= on points may be + added as required in the future. The PCI bus driver calls the platform d= river 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 Prot= ocol driver has + been notified. + This member function may not perform any error checking on the input par= ameters. It also + does not return any error codes. If this member function detects any err= or condition, it + needs to handle those errors on its own because there is no way to surfa= ce any errors to + the caller. + + @param This - Pointer to the EFI_PCI_PLATFORM_PROTOCOL instanc= e. + @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 d= river. + + @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 =3D EFI_SUCCESS; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *RootBridgeIo; + PCI_TYPE00 Pci0; + UINT64 Address; + UINT8 SecBus; + UINT8 Device; + UINT8 Func; + UINT64 DummyData =3D 0xFFFFFFFF; + UINT32 DidVid; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol =3D NULL; + + if (mPciPrivateData.RootBridgeHandle =3D=3D NULL) { + mPciPrivateData.RootBridgeHandle =3D RootBridge; + } + + Status =3D gBS->HandleProtocol ( + mPciPrivateData.RootBridgeHandle, + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **) &RootBridgeIo + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &D= ynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + +// Workaround for PCI devices under Pilot IV, this video controller can on= ly be exposed if write 0xFFFFFFFF to it and read back + if (Phase =3D=3D EfiPciBeforeChildBusEnumeration && ChipsetPhase =3D=3D = ChipsetExit ) { + +// Read the entire config header + Address =3D EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciAdd= ress.Function, 0); + Status =3D 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 =3D EFI_PCI_ADDRESS (PciAddress.Bus, PciAddress.Device, PciA= ddress.Function, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET); + Status =3D RootBridgeIo->Pci.Read ( + RootBridgeIo, + EfiPciWidthUint8, + Address, + 1, + &SecBus + ); + + if (!EFI_ERROR (Status)) { + + // + // For this bridge with existing secondary bus apply PCI Intel WAs + // + DidVid =3D ((Pci0.Hdr).DeviceId << 16) | (Pci0.Hdr).VendorId; + DynamicSiLibraryProtocol->IioPciHookBeforeEnumeration ((UINT8)Root= BridgeIo->SegmentNumber, PciAddress.Bus, PciAddress.Device, PciAddress.Func= tion, DidVid); + + for (Device =3D 0; Device <=3D PCI_MAX_DEVICE; Device++) { + for (Func =3D 0; Func <=3D PCI_MAX_FUNC; Func++) { + Address =3D EFI_PCI_ADDRESS (SecBus, Device, Func, 0); + Status =3D RootBridgeIo->Pci.Read ( + RootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &Pci0 + ); + + if ( !EFI_ERROR (Status) && (Pci0.Hdr).VendorId =3D=3D 0xffff)= { + + Status =3D RootBridgeIo->Pci.Write( + RootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &DummyData + ); + PCIDEBUG ("%a: For B(0x%x)-D(0x%x)-F(0x%x),Pci.Write() retur= ns with %r\n", + __FUNCTION__, SecBus, Device, Func, Status); + + if (EFI_ERROR (Status)) { + // + // If error, go to next function + // + continue; + } else { + Func =3D 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 instanc= e. + @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 d= river. + + @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 =3D 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 *DynamicSiLibraryProto= col =3D NULL; + + static CHAR8 *NotifyPhase2Name[] =3D {"EfiPciHostBridgeBeginEnumeration", + "EfiPciHostBridgeBeginBusAllocation", + "EfiPciHostBridgeEndBusAllocation", + "EfiPciHostBridgeBeginResourceAlloca= tion", + "EfiPciHostBridgeAllocateResources", + "EfiPciHostBridgeSetResources", + "EfiPciHostBridgeFreeResources", + "EfiPciHostBridgeEndResourceAllocati= on", + "EfiPciHostBridgeEndEnumeration"}; + + if (Phase < NELEMENTS (NotifyPhase2Name)) { + DEBUG ((DEBUG_INFO, "[PCI] %a phase notified (execution %d)\n", Notify= Phase2Name[Phase], ChipsetPhase)); + } else { + DEBUG ((DEBUG_ERROR, "[PCI] ERROR: Unknown phase %d notified (executio= n %d)\n", Phase, ChipsetPhase)); + } + + Status =3D gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &D= ynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + CpuCsrAccessVarPtr =3D DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar (= ); + + if (ChipsetPhase =3D=3D 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 =3D gBS->LocateProtocol ( + &gEfiIioUdsProtocolGuid, + NULL, + &mIioUds + ); + ASSERT_EFI_ERROR (Status); + + Status =3D gBS->LocateProtocol ( + &gEfiCpuIo2ProtocolGuid, + NULL, + &mPciPrivateData.CpuIo + ); + ASSERT_EFI_ERROR (Status); + + mPciPrivateData.Context.CpuIo =3D mPciPrivateData.CpuIo; + DEBUG ((DEBUG_INFO, "[PCI] Platform Pre-Initialization (Before bus sca= nning)\n")); + // + // Locate gEfiPciRootBridgeIoProtocolGuid instance created for each II= O stack. + // They were created by host bridge driver and linked to the + // gEfiPciHostBridgeResourceAllocationProtocolGuid protocol. + // + Status =3D gBS->LocateProtocol ( + &gEfiPciHostBridgeResourceAllocationProtocolGuid, + NULL, + &HostResAllocPtr + ); + ASSERT_EFI_ERROR (Status); + + HostBridgePtr =3D CR (HostResAllocPtr, PCI_HOST_BRIDGE_INSTANCE, ResAl= loc, PCI_HOST_BRIDGE_SIGNATURE); + for (NodePtr =3D GetFirstNode (&HostBridgePtr->RootBridges); + !IsNull (&HostBridgePtr->RootBridges, NodePtr); + NodePtr =3D GetNextNode (&HostBridgePtr->RootBridges, NodePtr)) { + RootBridgePtr =3D CR (NodePtr, PCI_ROOT_BRIDGE_INSTANCE, Link, PCI_R= OOT_BRIDGE_SIGNATURE); + for (Socket =3D 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridge= Io); Socket++) { + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) { + continue; + } + for (StackBit =3D 1, Stack =3D 0; + Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo[Socket]); + StackBit <<=3D 1, Stack++) { + if ((CpuCsrAccessVarPtr->stackPresentBitmap[Socket] & StackBit) = && + CpuCsrAccessVarPtr->StackBus[Socket][Stack] =3D=3D RootBridg= ePtr->Aperture.BusBase) { + // + // This is the stack handled by this instance of root bridge I= O protocol. Store it for future use. + // + mPciPrivateData.PciRootBridgeIo[Socket][Stack] =3D &RootBridge= Ptr->RootBridgeIo; + Socket =3D 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 =3D=3D 0) { + mPciPrivateData.PciEnumerationPhase =3D EfiPciEnumerationDeviceScann= ing; + for (Socket =3D 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridge= Io); Socket++) { + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) { + continue; + } + for (Stack =3D 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridge= Io[Socket]); Stack ++) { + if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] =3D=3D NULL) { + continue; + } + PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Soc= ket][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 numb= er assignment)\n")); + mPciPrivateData.PciEnumerationPhase =3D EfiPciEnumerationBusNumberAssi= gned; + for (Socket =3D 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo= ); Socket++) { + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) { + continue; + } + for (Stack =3D 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo= [Socket]); Stack ++) { + if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] =3D=3D NULL) { + continue; + } + PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Socke= t][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 resourc= e alloction)\n")); + mPciPrivateData.PciEnumerationPhase =3D EfiPciEnumerationResourceAssig= ned; + for (Socket =3D 0; Socket < NELEMENTS (mPciPrivateData.PciRootBridgeIo= ); Socket++) { + if (!mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].Valid) { + continue; + } + for (Stack =3D 0; Stack < NELEMENTS (mPciPrivateData.PciRootBridgeIo= [Socket]); Stack ++) { + if (mPciPrivateData.PciRootBridgeIo[Socket][Stack] =3D=3D NULL) { + continue; + } + PciTreeTraverse (Socket, Stack, CpuCsrAccessVarPtr->StackBus[Socke= t][Stack]); + } + } + PciPlatformPostInit (); + break; + + default: + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatfor= m/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/PciPl= atformHooks.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/PciPlatfor= m/PciSupportLib.c b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciSupportLib.c new file mode 100644 index 0000000000..7b5d45711d --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSu= pportLib.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 com= ment +// 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 =3D 0xFFFFFFFF; + // + // Create PCI address map in terms of Bus, Device and Func + // + Address =3D EFI_PCI_ADDRESS (Bus, Device, Func, 0); + + // + // Read the Vendor Id register + // + Status =3D PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + Pci + ); + if ((Pci->Hdr).VendorId =3D=3D 0xFFFF) { + // + // The PCIe card could have been assigned a temporary bus number earli= er in + // the boot flow. Performing a write cycle can be used to cause the PC= Ie + // card to latch the new bus number. Try to writing the Vendor Id regi= ster, + // then recheck if the card is present. + // + Status =3D PciRootBridgeIo->Pci.Write( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + &Dummy + ); + + // + // Retry the previous read after the PCI write cycle. + // + Status =3D PciRootBridgeIo->Pci.Read ( + PciRootBridgeIo, + EfiPciWidthUint32, + Address, + 1, + Pci + ); + } + + if (!EFI_ERROR (Status) && (Pci->Hdr).VendorId !=3D 0xFFFF) { + // + // Read the entire config header for the device + // + Status =3D 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/PciPlatfor= m/PciSupportLib.h b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/Pci= Platform/PciSupportLib.h new file mode 100644 index 0000000000..e173125c97 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Features/Pci/Dxe/PciPlatform/PciSu= pportLib.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/PlatformV= ariable/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 overr= ide + that. The appropriate HOBs and PCDs are created to signal DXE code to up= date + the variable default values. + + @copyright + Copyright 2012 - 2021 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "PlatformVariableInitPei.h" +#include +#include + +UINT16 BoardId =3D BOARD_ID_DEFAULT; + +EFI_PEI_PPI_DESCRIPTOR mPpiListPlatformVariableInit =3D { + (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 =3D 0x%02x\n", Events)); + DEBUG((DEBUG_INFO, " DefaultId =3D 0x%04x\n", DefaultId)); + + // + // Assume success up front. This will be overwritten if errors occur. + // + ReturnStatus =3D EFI_SUCCESS; + + // + // Send the bitmap of events to the platform variable DXE driver. + // + Hob =3D BuildGuidDataHob(&gPlatformVariableHobGuid, &Events, sizeof(Even= ts)); + if (Hob =3D=3D NULL) { + DEBUG((DEBUG_ERROR, "Create platform var event HOB: %r!\n", EFI_OUT_OF= _RESOURCES)); + ReturnStatus =3D EFI_OUT_OF_RESOURCES; + } + + // + // Locate variable default data in FFS and send it to the core variable = DXE + // driver to write. + // + Status =3D CreateDefaultVariableHob(DefaultId, BoardId); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "create default var HOB: %r!\n", Status)); + ReturnStatus =3D Status; + } + + // + // Set the PCD SKU ID. + // + LibPcdSetSku(BoardId); + + // + // Set the PCD default store ID. + // + Status =3D PcdSet16S(PcdSetNvStoreDefaultId, DefaultId); + if (EFI_ERROR(Status)) { + DEBUG((DEBUG_ERROR, "setNVstore default ID PCD: %r!\n", Status)); + ReturnStatus =3D Status; + } + + return ReturnStatus; +} + +/** +Perform the default variable initializations after variable service is rea= dy. + +@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 =3D PcdGetPtr(PcdSetupVariableGuid); + Events =3D 0; + DefaultId =3D EFI_HII_DEFAULT_CLASS_STANDARD; + + if (PlatformVariableHookForHobGeneration(Interface, &Events, &DefaultId)= ) { + // + // Use events bitmap and default ID returned by PlatformVariableHook. + // + ApplyDefaults =3D TRUE; + } + else { + // + // If the setup variable does not exist (yet), defaults should be appl= ied. + // + VariableServices =3D (EFI_PEI_READ_ONLY_VARIABLE2_PPI *)Interface; + SystemConfiguration =3D NULL; + DataSize =3D 0; + Status =3D VariableServices->GetVariable( + VariableServices, + PLATFORM_SETUP_VARIABLE_NAME, + SystemConfigurationGuid, + NULL, + &DataSize, + SystemConfiguration + ); + // + // Setup variable is not found. So, set the default setting. + // + if (Status =3D=3D EFI_NOT_FOUND) { + Events =3D NULL_VARIABLE_EVENT; + DefaultId =3D EFI_HII_DEFAULT_CLASS_STANDARD; + ApplyDefaults =3D TRUE; + } + else { + ApplyDefaults =3D FALSE; + } + } + + + if (ApplyDefaults) { + Status =3D ApplyPlatformVariableDefaults(Events, DefaultId); + } + else { + // + // Normal case boot flow + // + Events =3D 0; // no events occurred + BuildGuidDataHob (&gPlatformVariableHobGuid, &Events, sizeof (UINT8)); + + // + // Patch RP variable value with PC variable in the begining of PEI + // + Status =3D CreateRPVariableHob (EFI_HII_DEFAULT_CLASS_STANDARD, BoardI= d); + } + + 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 =3D 0; + DefaultId =3D EFI_HII_DEFAULT_CLASS_STANDARD; + ApplyDefaults =3D FALSE; + + // + // Certain boot modes require defaults to be (re-)applied. + // + Status =3D PeiServicesGetBootMode(&BootMode); + ASSERT_EFI_ERROR(Status); + if (EFI_ERROR(Status)) { + BootMode =3D BOOT_WITH_DEFAULT_SETTINGS; + } + if (BootMode =3D=3D BOOT_WITH_MFG_MODE_SETTINGS) { + Events =3D MFG_MODE_EVENT; + DefaultId =3D EFI_HII_DEFAULT_CLASS_MANUFACTURING; + ApplyDefaults =3D TRUE; + } + else if (BootMode =3D=3D BOOT_IN_RECOVERY_MODE) { + Events =3D RECOVERY_MODE_EVENT; + DefaultId =3D EFI_HII_DEFAULT_CLASS_STANDARD; + ApplyDefaults =3D TRUE; + } + else if (BootMode =3D=3D BOOT_WITH_DEFAULT_SETTINGS) { + Events =3D CMOS_CLEAR_EVENT; + DefaultId =3D EFI_HII_DEFAULT_CLASS_STANDARD; + ApplyDefaults =3D TRUE; + } + if (ApplyDefaults) { + Status =3D ApplyPlatformVariableDefaults(Events, DefaultId); + } + return Status; +} + +EFI_PEI_NOTIFY_DESCRIPTOR mVariableNotifyList[] =3D { + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK), + &gEfiPeiReadOnlyVariable2PpiGuid, + PlatformVariablePeiInit + }, + { + (EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMI= NATE_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 read= y. + // + Status =3D PeiServicesNotifyPpi(&mVariableNotifyList[0]); + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Features/Variable/PlatformV= ariable/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 overr= ide + that. The appropriate HOBs and PCDs are created to signal DXE code to up= date + 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/PlatformV= ariable/Pei/PlatformVariableInitPei.inf b/Platform/Intel/WhitleyOpenBoardPk= g/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 overr= ide +# that. The appropriate HOBs and PCDs are created to signal DXE code to up= date +# the variable default values. +# +# @copyright +# Copyright 2012 - 2021 Intel Corporation.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION =3D 0x00010005 + BASE_NAME =3D PlatformVariableInitPei + FILE_GUID =3D B88303F6-2E0E-41cc-8510-F5892BF1D9D9 + MODULE_TYPE =3D PEIM + ENTRY_POINT =3D 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_CONSU= MES ## NOTIFY + gUpdateBootModePpiGuid ## CONSUMES + +[Depex] + TRUE --=20 2.27.0.windows.1 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#77716): https://edk2.groups.io/g/devel/message/77716 Mute This Topic: https://groups.io/mt/84168630/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-