From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga06.intel.com (mga06.intel.com [134.134.136.31]) by mx.groups.io with SMTP id smtpd.web12.859.1646952111350461854 for ; Thu, 10 Mar 2022 14:41:53 -0800 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=dHShmNr9; spf=pass (domain: intel.com, ip: 134.134.136.31, mailfrom: isaac.w.oram@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1646952112; x=1678488112; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=NISS96DD9QfsZzJ1+lR0Ly32AA2PnBfXd8NLAtUlJmw=; b=dHShmNr9I6NvmBosqRc4UiaxwN4eNOB90/uHN75AldNcxSEs0GzC+2tO Zeu1M5yx20ghbhlVRFQ22UuvabVmytB+DOP0em5HPZ4V58r+zJ53oVZja rdai5AwsCSRMGMe3aB551l2lRxlA3pLL5LUX+ZLNVUpx3kD9sQ0/U7BVN sWT8JxNZkMNvyRCaIY5yxyzEOCqQzx/pPRuGiFbqsf9FRUiTwHkouhdfj 52c5A0hOwzalrSudXCyS6rsLYv9805yN/ZU4fv4+mri6AkQ4LAw0Hec0o mI2YlgNNHXTDlyRCsZAPFsdZGBrMYlKSz5rTn0qSDR1OWbkzOkoxM4fc4 g==; X-IronPort-AV: E=McAfee;i="6200,9189,10282"; a="316121255" X-IronPort-AV: E=Sophos;i="5.90,171,1643702400"; d="scan'208";a="316121255" Received: from orsmga004.jf.intel.com ([10.7.209.38]) by orsmga104.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Mar 2022 14:41:35 -0800 X-IronPort-AV: E=Sophos;i="5.90,171,1643702400"; d="scan'208";a="644643385" Received: from iworam-desk.amr.corp.intel.com ([10.7.150.60]) by orsmga004-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 10 Mar 2022 14:41:34 -0800 From: "Oram, Isaac W" To: devel@edk2.groups.io Cc: Nate DeSimone , Chasel Chiu Subject: [edk2-devel][edk2-platforms][PATCH V1 7/9] WhitleyOpenBoardPkg/AcpiTablesLib: Add library for AcpiPlatform driver Date: Thu, 10 Mar 2022 14:41:12 -0800 Message-Id: <1a58840461a312b2263e0680c0c158c04ff5b359.1646951441.git.isaac.w.oram@intel.com> X-Mailer: git-send-email 2.27.0.windows.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit AcpiTablesLib allows for board specific updates to ACPI tables. Cc: Nate DeSimone Cc: Chasel Chiu Signed-off-by: Isaac Oram --- Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c | 534 ++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf | 127 ++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c | 735 +++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c | 1574 ++++++++++++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c | 673 ++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c | 75 + Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c | 1710 ++++++++++++++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h | 441 +++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c | 134 ++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c | 69 + Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c | 101 ++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c | 45 + Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c | 42 + Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c | 267 +++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c | 1153 +++++++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c | 952 +++++++++++ Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c | 1004 ++++++++++++ Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec | 5 + Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc | 1 + 19 files changed, 9642 insertions(+) diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c new file mode 100644 index 0000000000..f321c73a51 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.c @@ -0,0 +1,534 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include +#include +#include +#include +#include + +extern BIOS_ACPI_PARAM *mAcpiParameter; + +EFI_PLATFORM_INFO *mPlatformInfo; +EFI_CPU_CSR_ACCESS_PROTOCOL *mCpuCsrAccess; +EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; + + +UINT32 mNumOfBitShift; +BOOLEAN mX2ApicEnabled; + +SYSTEM_MEMORY_MAP_HOB *mSystemMemoryMap; + +SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration; +SOCKET_MP_LINK_CONFIGURATION mSocketMpLinkConfiguration; +SOCKET_IIO_CONFIGURATION mSocketIioConfiguration; +SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration; +SOCKET_COMMONRC_CONFIGURATION mSocketCommonRcConfiguration; +SOCKET_PROCESSORCORE_CONFIGURATION mSocketProcessorCoreConfiguration; + +CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigContextBuffer = NULL; + +EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *mSpcrTable = NULL; + +/** + The constructor function of AcpiPlatormL Library. + + The constructor function caches the value of PCD entry + + @param ImageHandle The firmware allocated handle for the EFI image. + @param SystemTable A pointer to the EFI System Table. + + @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS. + +**/ +EFI_STATUS +EFIAPI +AcpiPlatformLibConstructor ( + VOID + ) +{ + EFI_STATUS Status; + EFI_HOB_GUID_TYPE *GuidHob; + + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; + + mCpuConfigLibConfigContextBuffer = (CPU_CONFIG_CONTEXT_BUFFER *) (UINTN) PcdGet64 (PcdCpuConfigContextBuffer); + if (mCpuConfigLibConfigContextBuffer == NULL) { + ASSERT_EFI_ERROR (RETURN_NOT_FOUND); + return RETURN_NOT_FOUND; + } + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + GuidHob = GetFirstGuidHob (&gEfiPlatformInfoGuid); + if (GuidHob == NULL) { + ASSERT (GuidHob != NULL); + return EFI_NOT_FOUND; + } + mPlatformInfo = GET_GUID_HOB_DATA (GuidHob); + + // + // Locate the IIO Protocol Interface + // + Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = gBS->LocateProtocol (&gEfiCpuCsrAccessGuid, NULL, &mCpuCsrAccess); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + mCpuCsrAccessVarPtr = DynamicSiLibraryProtocol->GetSysCpuCsrAccessVar (); + mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData (); + ASSERT (mSystemMemoryMap != NULL); + + mMpService = NULL; + + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, &mMpService); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // + // Determine the number of processors + // + mMpService->GetNumberOfProcessors ( + mMpService, + &mNumberOfCPUs, + &mNumberOfEnabledCPUs + ); + ASSERT (mNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1); + if (mNumberOfCPUs > MAX_CPU_NUM) { + mNumberOfCPUs = MAX_CPU_NUM; + } + + Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, &mAcpiTable); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + return EFI_SUCCESS; +} + + +/** + Platform hook to initialize Platform Specific ACPI Parameters + + @retval EFI_SUCCESS Platform specific parameters in mAcpiParameter + initialized successfully. + @retval EFI_INVALID_PARAMETER mAcpiParameter global was NULL. +**/ +EFI_STATUS +PlatformHookAfterAcpiParamInit ( + VOID + ) +{ + EFI_STATUS Status; + + Status = EFI_SUCCESS; + + if (mAcpiParameter == NULL) { + ASSERT (mAcpiParameter != NULL); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "ACPI Parameter Block Address: 0x%X\n", mAcpiParameter)); + + + // + // Call for Local APIC ID Reorder + // + Status = SortCpuLocalApicInTable (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: SortCpuLocalApicInTable failed: %r\n", Status)); + return Status; + } + + return Status; +} + + +EFI_STATUS +AcpiPlatformHooksIsActiveTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_NFIT_TABLE_UPDATE_PROTOCOL *NfitTableUpdateProtocol; + EFI_ACPI_DESCRIPTION_HEADER *TableHeader; + EFI_STATUS Status; + SETUP_DATA SetupData; + SYSTEM_CONFIGURATION SystemConfiguration; + UINT8 *OemSkuAcpiName; + + Status = GetEntireConfig (&SetupData); + ASSERT_EFI_ERROR (Status); + CopyMem (&SystemConfiguration, &(SetupData.SystemConfig), sizeof(SYSTEM_CONFIGURATION)); + + if (mSystemMemoryMap == NULL) { + + ASSERT (FALSE); + return EFI_NOT_FOUND; + } + TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; + if (TableHeader->Signature == ACPI_PMTT_TABLE_SIGNATURE) { + if (!mSystemMemoryMap->DcpmmPresent) { + return EFI_NOT_FOUND; + } + } + + if (TableHeader->Signature == EFI_BDAT_TABLE_SIGNATURE) { + if (mSocketMemoryConfiguration.bdatEn == 0) { + return EFI_NOT_FOUND; + } + } + + if (TableHeader->Signature == NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE) { + if (mSystemMemoryMap->DcpmmPresent == 0) { + return EFI_NOT_FOUND; + } + } + + if (TableHeader->Signature == NVDIMM_FW_INTERFACE_TABLE_SIGNATURE) { + Status = gBS->LocateProtocol (&gEfiNfitTableUpdateProtocolGuid, NULL, &NfitTableUpdateProtocol); + if (EFI_ERROR (Status)){ + // If NfitTableUpdateProtocol is not found we assume no NVDIMM is present - it means don't publish NFIT + DEBUG ((DEBUG_ERROR, "NfitTableUpdateProtocol is not installed.\n")); + return EFI_NOT_FOUND; + } + } + if (TableHeader->Signature == EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE) { + // + // Initialize the SPCR table pointer. + // SPCR table is not ready yet, update it before booting. + // + mSpcrTable = (EFI_ACPI_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE *) Table; + return EFI_NOT_READY; + } + + if ((TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE) || + (TableHeader->Signature == EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE) || + (TableHeader->Signature == EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE) || + TableHeader->Signature == EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE) { + // + // Only publish SRAT/SLIT/MSCT/HMAT if NUMA is enabled in setup. + // + if (!mSocketCommonRcConfiguration.NumaEn) { + + DEBUG ((DEBUG_INFO, "[ACPI] NUMA disabled, do not publish '%c%c%c%c' table\n", + ((CHAR8*)&TableHeader->Signature)[0], ((CHAR8*)&TableHeader->Signature)[1], + ((CHAR8*)&TableHeader->Signature)[2], ((CHAR8*)&TableHeader->Signature)[3])); + return EFI_NOT_FOUND; + } + } + + if (TableHeader->Signature == EFI_ACPI_6_2_DEBUG_PORT_2_TABLE_SIGNATURE) { + return EFI_NOT_FOUND; + } + + if (TableHeader->Signature == EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) { + OemSkuAcpiName = PcdGetPtr (PcdOemSkuAcpiName); + if (OemSkuAcpiName == NULL) { + return EFI_UNSUPPORTED; + } + if ( (0 == CompareMem (&(TableHeader->OemTableId), OemSkuAcpiName, 8)) ) { + Status = PlatformGetAcpiFixTableDataPointer (&mAmlOffsetTablePointer); + if (!EFI_ERROR(Status)) { + DEBUG((DEBUG_INFO, "[ACPI] Platform DSDT Fixup table found\n")); + DEBUG((DEBUG_INFO, "[ACPI] Platform SRP: Using %a DSDT\n", OemSkuAcpiName)); + return EFI_SUCCESS; + } else { + DEBUG((DEBUG_ERROR, "[ACPI] Platform DSDT Fixup table not found.\n")); + return EFI_UNSUPPORTED; + } + } else { + DEBUG ((DEBUG_INFO, "[ACPI] Platform DSDT OemSkuAcpiName '%c%c%c%c%c%c%c%c':\n", + ((CHAR8*)OemSkuAcpiName)[0], ((CHAR8*)OemSkuAcpiName)[1], + ((CHAR8*)OemSkuAcpiName)[2], ((CHAR8*)OemSkuAcpiName)[3], + ((CHAR8*)OemSkuAcpiName)[4], ((CHAR8*)OemSkuAcpiName)[5], + ((CHAR8*)OemSkuAcpiName)[6], ((CHAR8*)OemSkuAcpiName)[7])); + + DEBUG ((DEBUG_INFO, " no match for OemTableId '%c%c%c%c%c%c%c%c' from FwVol.\n", + ((CHAR8*)&TableHeader->OemTableId)[0], ((CHAR8*)&TableHeader->OemTableId)[1], + ((CHAR8*)&TableHeader->OemTableId)[2], ((CHAR8*)&TableHeader->OemTableId)[3], + ((CHAR8*)&TableHeader->OemTableId)[4], ((CHAR8*)&TableHeader->OemTableId)[5], + ((CHAR8*)&TableHeader->OemTableId)[6], ((CHAR8*)&TableHeader->OemTableId)[7])); + + return EFI_UNSUPPORTED; + } + } + + // + // Hooks for checking additional platform ACPI Table is active or not. + // If ACPI Table is not in list, it should be reported and returned EFI_SUCCESS. + // + return PlatformAcpiReportHooksTableIsActive (Table); +} + + +/** + This function will update any runtime platform specific information. + This currently includes: + Setting OEM table values, ID, table ID, creator ID and creator revision. + Enabling the proper processor entries in the APIC tables. + + @param Table - The table to update + + @retval EFI_SUCCESS - The function completed successfully. +**/ +EFI_STATUS +PlatformUpdateTables ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN OUT EFI_ACPI_TABLE_VERSION *Version + ) +{ + EFI_ACPI_DESCRIPTION_HEADER *TableHeader; + EFI_STATUS Status; + ACPI_APIC_STRUCTURE_PTR *ProcessorLocalApicEntry; + UINT64 TempOemTableId; + UINT32 Data32; + + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + TableHeader = NULL; + + ProcessorLocalApicEntry = NULL; + Status = EFI_SUCCESS; + + // + // By default, a table belongs in all ACPI table versions published. + // Some tables will override this because they have different versions of the table. + // + *Version = EFI_ACPI_TABLE_VERSION_2_0; + + if (Table->Signature != EFI_ACPI_6_2_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE && + Table->Signature != EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE && + Table->Signature != SIGNATURE_32('N', 'F', 'I', 'T') && + Table->Signature != SIGNATURE_32('P', 'C', 'A', 'T') && + Table->Signature != SIGNATURE_32('O', 'E', 'M', '1') && + Table->Signature != SIGNATURE_32('O', 'E', 'M', '2') && + Table->Signature != SIGNATURE_32('O', 'E', 'M', '3') && + Table->Signature != SIGNATURE_32('O', 'E', 'M', '4')) + { + TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; + // + // Update the OEMID and OEM Table ID. + // + TempOemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + + CopyMem (TableHeader->OemId, PcdGetPtr(PcdAcpiDefaultOemId), sizeof(TableHeader->OemId)); + CopyMem (&TableHeader->OemTableId, &TempOemTableId, sizeof(TableHeader->OemTableId)); + + // + // Update the creator ID + // + TableHeader->CreatorId = EFI_ACPI_CREATOR_ID; + + // + // Update the creator revision + // + TableHeader->CreatorRevision = EFI_ACPI_CREATOR_REVISION; + } + // + // Complete this function + // + + //ASSERT (mMaxNumberOfCPUs <= MAX_CPU_NUM && mNumberOfEnabledCPUs >= 1); + + // + // Assign a invalid intial value for update + // + // + // Update the processors in the APIC table + // + DEBUG ((DEBUG_INFO, "[ACPI] Patching '%c%c%c%c' table...\n", + ((CHAR8*)&Table->Signature)[0], ((CHAR8*)&Table->Signature)[1], + ((CHAR8*)&Table->Signature)[2], ((CHAR8*)&Table->Signature)[3])); + switch (Table->Signature) { + + // + // Do not allow a prebuilt MADT, since it is built dynamically. + // + case EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE: + DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: Prebuilt MADT found\n")); + Status = EFI_INVALID_PARAMETER; + ASSERT_EFI_ERROR (Status); + break; + + case EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE: + Status = PatchFadtTable (Table); + break; + + case EFI_ACPI_6_2_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: + // + // Patch the memory resource + // + Status = PatchDsdtTable (Table); + break; + + case EFI_ACPI_6_2_SECONDARY_SYSTEM_DESCRIPTION_TABLE_SIGNATURE: + Status = PatchSsdtTable (Table,Version); + break; + + case EFI_ACPI_6_2_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE: + // + // Adjust HPET Table to correct the Base Address + // Get the address bits in RCRB that configure HPET MMIO space + // and create an offset to the pre-defined HEPT base address + // + DynamicSiLibraryProtocol2->PchHpetBaseGet (&Data32); + // + // Add the offset to the base address and copy into HPET DSDT table + // + ((EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *) Table)->BaseAddressLower32Bit.Address = Data32; + break; + + case EFI_ACPI_6_2_PCI_EXPRESS_MEMORY_MAPPED_CONFIGURATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE: + Status = PatchMcfgAcpiTable (Table); + break; + + case EFI_ACPI_6_2_SERIAL_PORT_CONSOLE_REDIRECTION_TABLE_SIGNATURE: + Status = PatchSpcrAcpiTable (Table); + break; + + case ACPI_PMTT_TABLE_SIGNATURE: + if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { + Status = PatchPlatformMemoryTopologyTable (Table); + } + break; + + case EFI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_SIGNATURE: + if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { + Status = PatchHmatAcpiTable (Table); + } + break; + + case EFI_ACPI_6_2_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE_SIGNATURE: + if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { + Status = PatchMsctAcpiTable (Table); + } + break; + + case EFI_MIGT_ACPI_TABLE_SIGNATURE: + if (!PcdGetBool (PcdPlatformNotSupportAcpiTable)) { + if (PcdGetBool (ReservedB)) { + Status = PatchMigtAcpiTable (Table); + } + } + break; + + case EFI_BDAT_TABLE_SIGNATURE: + if (!PcdGetBool (PcdPlatformNotSupportAcpiBdatTable)) { + Status = PatchBdatAcpiTable (Table); + } + break; + + case NVDIMM_FW_INTERFACE_TABLE_SIGNATURE: + Status = UpdateNfitTable (Table); + break; + + case NVDIMM_PLATFORM_CONFIG_ATTRIBUTE_TABLE_SIGNATURE: + Status = UpdatePcatTable (Table); + break; + + //Patch Dynamic OEM SSDT table + case OEM1_SSDT_TABLE_SIGNATURE: + Status = PatchOem1SsdtTable (Table); //CPU EIST + break; + + case OEM2_SSDT_TABLE_SIGNATURE: + Status = PatchOem2SsdtTable (Table); //CPU HWP + break; + + case OEM3_SSDT_TABLE_SIGNATURE: + Status = PatchOem3SsdtTable (Table); //CPU TST + break; + + case OEM4_SSDT_TABLE_SIGNATURE: + Status = PatchOem4SsdtTable (Table); //CPU CST + break; + case ACPI_WSMT_SIGNATURE: + (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags) = (UINT32 ) (WSMT_PROTECTION_FLAG & PcdGet32(PcdWsmtProtectionFlags)); + DEBUG ((DEBUG_INFO, "[WSMT] ProtectionFlags = 0x%x\n", (((ACPI_WINDOWS_SMM_SECURITY_MITIGATIONS_TABLE *)Table)->ProtectionFlags.Flags))); + break; + + default: + // + // Hooks for Platform only table. If the ACPI Table is Platform only, add this table in below hook. then continue to update other Table. + // + Status = PatchPlatformSpecificAcpiTableHooks (Table); + break; + } + // + // + // Update the hardware signature in the FACS structure + // + // + // + return Status; +} + +/** + Give the platform a chance to build tables. + + Some tables can be built from scratch more efficiently than being prebuilt + and updated. This function builds any such tables for the platform. + + @retval EFI_SUCCESS Any platform tables were successfully built. +**/ +EFI_STATUS +PlatformBuildTables ( + VOID + ) +{ + EFI_STATUS ReturnStatus = EFI_SUCCESS; + EFI_STATUS Status; + + Status = InstallMadtFromScratch (); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + if (mSocketCommonRcConfiguration.NumaEn) { + Status = InstallSlitTable (); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + + Status = InstallSratTable (); + if (EFI_ERROR (Status)) { + ReturnStatus = Status; + } + } + // + // Return the first error code that occured, or success. + // + return ReturnStatus; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf new file mode 100644 index 0000000000..c571871930 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf @@ -0,0 +1,127 @@ +## @file +# Library functions for ACPI Table Update library. +# +# @copyright +# Copyright 2015 - 2020 Intel Corporation.
+# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +################################################################################ +# +# Defines Section - statements that will be processed to create a Makefile. +# +################################################################################ +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiPlatformTableLib + FILE_GUID = 09114814-BF6D-4B2D-BD61-C1F0668DE06E + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = AcpiPlatformTableLib + CONSTRUCTOR = AcpiPlatformLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = X64 +# + +################################################################################ +# +# Sources Section - list of files that are required for the build to succeed. +# +################################################################################ + +[Sources] + AcpiPlatformLibApic.c + AcpiPlatformLibBdat.c + AcpiPlatformLibDsdt.c + AcpiPlatformLibFadt.c + AcpiPlatformLibMcfg.c + AcpiPlatformLibMsct.c + AcpiPlatformLib.c + AcpiPlatformLibLocal.h + AcpiPlatformLibNfit.c + AcpiPlatformLibPcat.c + AcpiPlatformLibSlit.c + AcpiPlatformLibSrat.c + AcpiPlatformLibSsdt.c + AcpiPlatformLibMigt.c + AcpiPlatformLibPmtt.c + AcpiPlatformLibHmat.c + +################################################################################ +# +# Package Dependency Section - list of Package files that are required for +# this module. +# +################################################################################ + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + UefiCpuPkg/UefiCpuPkg.dec + WhitleyOpenBoardPkg/PlatformPkg.dec + WhitleySiliconPkg/SiliconPkg.dec + WhitleySiliconPkg/CpRcPkg.dec + WhitleySiliconPkg/Cpu/CpuRcPkg.dec + WhitleySiliconPkg/WhitleySiliconPkg.dec + +[LibraryClasses] + BaseLib + DebugLib + PcdLib + MemoryAllocationLib + BuildAcpiTablesLib + CrcLib + UbaPlatLib + PlatformSpecificAcpiTableLib + CompressDxeLib + UefiDecompressLib + +[Protocols] + gDxePchPlatformPolicyProtocolGuid + gEfiNfitTableUpdateProtocolGuid + gSmbiosMemInfoProtocolGuid + gAcpiPlatformProtocolGuid + gEfiSmbiosProtocolGuid + gEfiCpuCsrAccessGuid + gDynamicSiLibraryProtocolGuid ## CONSUMES + gDynamicSiLibraryProtocol2Guid ## CONSUMES + +[Guids] + gEfiPlatformInfoGuid + gFpgaSocketVariableGuid + gEwlBdatSchemaGuid + gSpdBdatSchemaGuid + gSpdVersion1Guid + gSpdVariableGuid + gMemTrainingDataBdatSchemaGuid + gMemTrainingDataVersion1Guid + gMemTrainingDataHobGuid + +[Pcd] + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision + gPlatformTokenSpaceGuid.ReservedB + gSiPkgTokenSpaceGuid.PcdAcpiBaseAddress + gOemSkuTokenSpaceGuid.PcdOemSkuAcpiName + gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiTable + gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiBdatTable + gPlatformModuleTokenSpaceGuid.PcdWsmtProtectionFlags + gPlatformTokenSpaceGuid.PcdHalfWidth + gCpuPkgTokenSpaceGuid.PcdCpuConfigContextBuffer ## CONSUMES + +[FixedPcd] + gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuSocketCount + gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuCoreCount + gEfiCpRcPkgTokenSpaceGuid.PcdMaxCpuThreadCount + gEfiCpRcPkgTokenSpaceGuid.SaveSpdToBdat + gEfiCpRcPkgTokenSpaceGuid.SaveMrcTrainingDataToBdat + +[Depex] + gDynamicSiLibraryProtocolGuid AND + gDynamicSiLibraryProtocol2Guid diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c new file mode 100644 index 0000000000..0718e81682 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibApic.c @@ -0,0 +1,735 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +extern EFI_PLATFORM_INFO *mPlatformInfo; +extern BIOS_ACPI_PARAM *mAcpiParameter; +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; +EFI_IIO_UDS_PROTOCOL *mIioUds = NULL; + +extern UINT32 mNumOfBitShift; + +extern BOOLEAN mX2ApicEnabled; +BOOLEAN mCpuOrderSorted = FALSE; + +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; +EFI_MP_SERVICES_PROTOCOL *mMpService; +CPU_ID_ORDER_MAP mCpuApicIdOrderTable[MAX_CPU_NUM]; +UINTN mNumberOfCPUs = 0; +UINTN mNumberOfEnabledCPUs = 0; + +UINT32 mEnabledProcessor[MAX_SOCKET]; + +extern UINT32 mCpuPCPSInfo[MAX_SOCKET]; +extern CPU_LOGICAL_THREAD_ID_TABLE mCpuThreadIdMsrTable[MAX_CPU_NUM]; + + +UINT32 mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD]; + +UINT32 mThreadCount[MAX_SOCKET] = {0}; + +typedef struct { + UINT64 EnableMask; + UINT8 Id; + UINT32 GsiBase; +} IO_APIC_DESCRIPTOR; + +STATIC CONST IO_APIC_DESCRIPTOR IoApicDescList[] = { + {PCH_IOAPIC, PCH_IOAPIC_ID, PCH_INTERRUPT_BASE}, + {PC00_IOAPIC, PC00_IOAPIC_ID, PC00_INTERRUPT_BASE}, + {PC01_IOAPIC, PC01_IOAPIC_ID, PC01_INTERRUPT_BASE}, + {PC02_IOAPIC, PC02_IOAPIC_ID, PC02_INTERRUPT_BASE}, + {PC03_IOAPIC, PC03_IOAPIC_ID, PC03_INTERRUPT_BASE}, + {PC04_IOAPIC, PC04_IOAPIC_ID, PC04_INTERRUPT_BASE}, + {PC05_IOAPIC, PC05_IOAPIC_ID, PC05_INTERRUPT_BASE}, + {PC06_IOAPIC, PC06_IOAPIC_ID, PC06_INTERRUPT_BASE}, + {PC07_IOAPIC, PC07_IOAPIC_ID, PC07_INTERRUPT_BASE}, + {PC08_IOAPIC, PC08_IOAPIC_ID, PC08_INTERRUPT_BASE}, + {PC09_IOAPIC, PC09_IOAPIC_ID, PC09_INTERRUPT_BASE}, + {PC10_IOAPIC, PC10_IOAPIC_ID, PC10_INTERRUPT_BASE}, + {PC11_IOAPIC, PC11_IOAPIC_ID, PC11_INTERRUPT_BASE}, + {PC12_IOAPIC, PC12_IOAPIC_ID, PC12_INTERRUPT_BASE}, + {PC13_IOAPIC, PC13_IOAPIC_ID, PC13_INTERRUPT_BASE}, + {PC14_IOAPIC, PC14_IOAPIC_ID, PC14_INTERRUPT_BASE}, + {PC15_IOAPIC, PC15_IOAPIC_ID, PC15_INTERRUPT_BASE}, + {PC16_IOAPIC, PC16_IOAPIC_ID, PC16_INTERRUPT_BASE}, + {PC17_IOAPIC, PC17_IOAPIC_ID, PC17_INTERRUPT_BASE}, + {PC18_IOAPIC, PC18_IOAPIC_ID, PC18_INTERRUPT_BASE}, + {PC19_IOAPIC, PC19_IOAPIC_ID, PC19_INTERRUPT_BASE}, + {PC20_IOAPIC, PC20_IOAPIC_ID, PC20_INTERRUPT_BASE}, + {PC21_IOAPIC, PC21_IOAPIC_ID, PC21_INTERRUPT_BASE}, + {PC22_IOAPIC, PC22_IOAPIC_ID, PC22_INTERRUPT_BASE}, + {PC23_IOAPIC, PC23_IOAPIC_ID, PC23_INTERRUPT_BASE}, + {PC24_IOAPIC, PC24_IOAPIC_ID, PC24_INTERRUPT_BASE}, + {PC25_IOAPIC, PC25_IOAPIC_ID, PC25_INTERRUPT_BASE}, + {PC26_IOAPIC, PC26_IOAPIC_ID, PC26_INTERRUPT_BASE}, + {PC27_IOAPIC, PC27_IOAPIC_ID, PC27_INTERRUPT_BASE}, + {PC28_IOAPIC, PC28_IOAPIC_ID, PC28_INTERRUPT_BASE}, + {PC29_IOAPIC, PC29_IOAPIC_ID, PC29_INTERRUPT_BASE}, + {PC30_IOAPIC, PC30_IOAPIC_ID, PC30_INTERRUPT_BASE}, + {PC31_IOAPIC, PC31_IOAPIC_ID, PC31_INTERRUPT_BASE}, + {PC32_IOAPIC, PC32_IOAPIC_ID, PC32_INTERRUPT_BASE}, + {PC33_IOAPIC, PC33_IOAPIC_ID, PC33_INTERRUPT_BASE}, + {PC34_IOAPIC, PC34_IOAPIC_ID, PC34_INTERRUPT_BASE}, + {PC35_IOAPIC, PC35_IOAPIC_ID, PC35_INTERRUPT_BASE}, + {PC36_IOAPIC, PC36_IOAPIC_ID, PC36_INTERRUPT_BASE}, + {PC37_IOAPIC, PC37_IOAPIC_ID, PC37_INTERRUPT_BASE}, + {PC38_IOAPIC, PC38_IOAPIC_ID, PC38_INTERRUPT_BASE}, + {PC39_IOAPIC, PC39_IOAPIC_ID, PC39_INTERRUPT_BASE}, + {PC40_IOAPIC, PC40_IOAPIC_ID, PC40_INTERRUPT_BASE}, + {PC41_IOAPIC, PC41_IOAPIC_ID, PC41_INTERRUPT_BASE}, + {PC42_IOAPIC, PC42_IOAPIC_ID, PC42_INTERRUPT_BASE}, + {PC43_IOAPIC, PC43_IOAPIC_ID, PC43_INTERRUPT_BASE}, + {PC44_IOAPIC, PC44_IOAPIC_ID, PC44_INTERRUPT_BASE}, + {PC45_IOAPIC, PC45_IOAPIC_ID, PC45_INTERRUPT_BASE}, + {PC46_IOAPIC, PC46_IOAPIC_ID, PC46_INTERRUPT_BASE}, + {PC47_IOAPIC, PC47_IOAPIC_ID, PC47_INTERRUPT_BASE} +}; + +/** + Find OrderTable index which is matching input ApicId + + @param ApicId - input ApicId + + @retval Index - OrderTable index + @retval (UINT32) -1 - Not found +**/ +UINT32 +ApicId2OrderTableIndex ( + UINT32 ApicId + ) +{ + UINT32 Index; + + for (Index = 0; Index < MAX_CPU_NUM; Index++) { + if ((mCpuApicIdOrderTable[Index].Flags == 1) && (mCpuApicIdOrderTable[Index].ApicId == ApicId)) { + return Index; + } + } + + return (UINT32) -1; +} + +/** + Display reordered Apic table for detected CPUs. + + @param None + + @retval None +**/ +VOID +DebugDisplayReOrderTable ( + VOID + ) +{ + UINT32 Index; + UINT32 TotalEnabledThreads = 0; + + DEBUG ((DEBUG_INFO, "Index AcpiProcId ApicId Flags Skt\n")); + for (Index = 0; Index < MAX_CPU_NUM; Index++) { + if (mCpuApicIdOrderTable[Index].ApicId == (UINT32) -1) { + break; + } + TotalEnabledThreads++; + DEBUG ((DEBUG_INFO, " %02d 0x%02X 0x%02X %d %d\n", + Index, mCpuApicIdOrderTable[Index].AcpiProcessorId, + mCpuApicIdOrderTable[Index].ApicId, + mCpuApicIdOrderTable[Index].Flags, + mCpuApicIdOrderTable[Index].SocketNum)); + } + DEBUG ((DEBUG_INFO, "\n:ACPI: Total Enabled Threads = %d\n\n", TotalEnabledThreads)); +} + +/** + Consolidate APIC ID order for all populated socket in mApicIdMap table + + @param None + + @retval None +**/ +VOID +UpdateApicIdMap ( + VOID + ) +{ + UINT32 SocketId; + UINT32 ThreadIndex; + UINT32 CurrProcessor; + + // + // init global mApicIdMap variable + // + SetMem32 ((VOID *)mApicIdMap, sizeof(mApicIdMap), 0xFFFFFFFF); + + for (SocketId = 0; SocketId < MAX_SOCKET; SocketId++) { + if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (1 << SocketId)) == 0) { + continue; + } + + ThreadIndex = 0; + for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) { + if (mCpuApicIdOrderTable[CurrProcessor].ApicId == (UINT32) -1) { + break; + } + + if ((mCpuApicIdOrderTable[CurrProcessor].SocketNum == SocketId) && (ThreadIndex < (MAX_CORE * MAX_THREAD))) { + mApicIdMap[SocketId][ThreadIndex] = (UINT32) mCpuApicIdOrderTable[CurrProcessor].ApicId & (UINT32) ~(SocketId<< mNumOfBitShift); + ThreadIndex++; + } + } + + if (ThreadIndex != mThreadCount[SocketId]) { + DEBUG((DEBUG_ERROR, ":: Skt: %d - Enabled ThreadCount is incorrect!!!\n")); + break; + } + } + + return; +} + +/** + Find the processor index of the thread running and obtain MSR 53 and ApicId data + to populate mCpuThreadIdMsrTable array. + + @param None + + @retval None +**/ +VOID +GetThreadIdMsrValue ( + VOID + ) +{ + UINTN ProcessorNumber; + UINT64 LogicalIdMsrValue; + + mMpService->WhoAmI (mMpService, &ProcessorNumber); + LogicalIdMsrValue = AsmReadMsr64 (0x00000053); + mCpuThreadIdMsrTable[ProcessorNumber].ThreadIdValue = (UINT32) LogicalIdMsrValue; + mCpuThreadIdMsrTable[ProcessorNumber].CollocatedChaId = (UINT32) RShiftU64(LogicalIdMsrValue, 32); + mCpuThreadIdMsrTable[ProcessorNumber].ApicId = mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[ProcessorNumber].CpuMiscData.ApicID; +} + +/** + Sort CPU Local APIC Information. + + This function gets the CPU local APIC information from the MP service + protocol into the local table structure, and sorts it based on APIC ID. + + @retval EFI_SUCCESS Local APIC information was successfully sorted. +**/ +EFI_STATUS +SortCpuLocalApicInTable ( + VOID + ) +{ + EFI_STATUS Status; + EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer; + UINTN BufferSize; + UINT32 Index; + UINT32 Socket; + UINT32 CurrProcessor; + CPU_ID_ORDER_MAP *CpuIdMapPtr; + UINT32 CoreThreadMask; + UINT32 CoreThreadCount; + UINT32 BspApicId; + UINT32 LowestApicId; + UINT32 CurrentIndex; + UINT32 TargetIndex; + CPU_ID_ORDER_MAP TempEntry; + BOOLEAN SecondThreadExistent; + + BufferSize = 0; + Index = 0; + Status = EFI_SUCCESS; + + CoreThreadMask = (UINT32) ((1 << mNumOfBitShift) - 1); + CoreThreadCount = 0; + + if (!mCpuOrderSorted) { + // + // Init ProcessorBitMask table and EnabledProcessor table + // + for (Index = 0; Index < MAX_SOCKET; Index++) { + mAcpiParameter->ProcessorBitMask[Index] = 0; + mAcpiParameter->ProcessorBitMaskHi[Index] = 0; + mEnabledProcessor[Index] = 0; + mCpuPCPSInfo[Index] = 0; + } + + Index = 0; + SecondThreadExistent = FALSE; + for (CurrProcessor = 0; CurrProcessor < mNumberOfCPUs; CurrProcessor++) { + Status = mMpService->GetProcessorInfo ( + mMpService, + CurrProcessor, + &ProcessorInfoBuffer + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + continue; + } + + + if (ProcessorInfoBuffer.ProcessorId & 1) { // secondary thread + CpuIdMapPtr = &mCpuApicIdOrderTable[(Index - 1) + MAX_CPU_NUM / 2]; + SecondThreadExistent= TRUE; + } else { // primary thread + CpuIdMapPtr = &mCpuApicIdOrderTable[Index]; + Index++; + } + + CpuIdMapPtr->ApicId = (UINT32) ProcessorInfoBuffer.ProcessorId; + CpuIdMapPtr->Flags = ((ProcessorInfoBuffer.StatusFlag & PROCESSOR_ENABLED_BIT) != 0); + CpuIdMapPtr->SocketNum = (UINT32) ProcessorInfoBuffer.Location.Package; + CpuIdMapPtr->AcpiProcessorId = (CpuIdMapPtr->SocketNum << mNumOfBitShift) + mThreadCount[CpuIdMapPtr->SocketNum]; + + mThreadCount[CpuIdMapPtr->SocketNum]++; + + if (CpuIdMapPtr->Flags == 1) { + // + // Update EnabledProcessor table + // + mEnabledProcessor[CpuIdMapPtr->SocketNum]++; + mCpuPCPSInfo[CpuIdMapPtr->SocketNum]++; // count enabled processor in current socket + + // + // Update processorbitMask + // + if (ProcessorInfoBuffer.Location.Core < 64) { + mAcpiParameter->ProcessorBitMask[CpuIdMapPtr->SocketNum] |= + LShiftU64 (1, ProcessorInfoBuffer.Location.Core); + } else { + mAcpiParameter->ProcessorBitMaskHi[CpuIdMapPtr->SocketNum] |= + LShiftU64 (1, ProcessorInfoBuffer.Location.Core - 64); + } + + if (ProcessorInfoBuffer.Location.Thread >= CoreThreadCount) { + CoreThreadCount = ProcessorInfoBuffer.Location.Thread + 1; + } + } + } //end for CurrentProcessor + + DEBUG (( + DEBUG_INFO, + "::ACPI:: APIC ID Order Table Init. CoreThreadMask = 0x%x, mNumOfBitShift = %d, CoreThreadCount = %d\n", + CoreThreadMask, + mNumOfBitShift, + CoreThreadCount + )); + + DEBUG ((DEBUG_INFO, "::ACPI:: Socket ProcessorBitMaskHi ProcessorBitMask ProcessorApicIdBase\n")); + for (Index = 0; Index < MAX_SOCKET; Index++) { + DEBUG (( + DEBUG_INFO, + "::ACPI:: %d 0x%016lx %016lx 0x%x\n", + Index, + mAcpiParameter->ProcessorBitMaskHi[Index], + mAcpiParameter->ProcessorBitMask[Index], + mAcpiParameter->ProcessorApicIdBase[Index] + )); + } + AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, NULL, NULL, &BspApicId); + + if (mCpuApicIdOrderTable[0].ApicId != BspApicId) { + // + // check to see if 1st entry is BSP, if not swap it + // + CurrentIndex = ApicId2OrderTableIndex (BspApicId); + + if (CurrentIndex >= MAX_CPU_NUM) { + DEBUG ((DEBUG_ERROR, "BSP index is out of range\n")); + ASSERT (CurrentIndex < MAX_CPU_NUM); + } else { + LowestApicId = mCpuApicIdOrderTable[0].ApicId; + TargetIndex = 0; + CopyMem (&TempEntry, &mCpuApicIdOrderTable[CurrentIndex], sizeof(TempEntry)); + CopyMem (&mCpuApicIdOrderTable[CurrentIndex], &mCpuApicIdOrderTable[TargetIndex], sizeof(TempEntry)); + CopyMem (&mCpuApicIdOrderTable[TargetIndex], &TempEntry, sizeof(TempEntry)); + + if (SecondThreadExistent) { + // + // Also swap BSP's companion thread (the second thread in same core of BSP) + // + CurrentIndex = ApicId2OrderTableIndex (BspApicId + 1); + TargetIndex = ApicId2OrderTableIndex (LowestApicId + 1); + if ((CurrentIndex < MAX_CPU_NUM) && (TargetIndex < MAX_CPU_NUM)) { + CopyMem (&TempEntry, &mCpuApicIdOrderTable[CurrentIndex], sizeof(TempEntry)); + CopyMem (&mCpuApicIdOrderTable[CurrentIndex], &mCpuApicIdOrderTable[TargetIndex], sizeof(TempEntry)); + CopyMem (&mCpuApicIdOrderTable[TargetIndex], &TempEntry, sizeof(TempEntry)); + } + } + } + } + + // + // Make sure no holes between enabled threads + // + for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) { + + if (mCpuApicIdOrderTable[CurrProcessor].Flags == 0) { + // + // make sure disabled entry has ProcId set to FFs + // + mCpuApicIdOrderTable[CurrProcessor].ApicId = (UINT32) -1; + mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = (UINT32) -1; + + for (Index = CurrProcessor + 1; Index < MAX_CPU_NUM; Index++) { + if (mCpuApicIdOrderTable[Index].Flags == 1) { + // + // move enabled entry up + // + mCpuApicIdOrderTable[CurrProcessor].Flags = 1; + mCpuApicIdOrderTable[CurrProcessor].ApicId = mCpuApicIdOrderTable[Index].ApicId; + mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = mCpuApicIdOrderTable[Index].AcpiProcessorId; + mCpuApicIdOrderTable[CurrProcessor].SocketNum = mCpuApicIdOrderTable[Index].SocketNum; + // + // disable moved entry + // + mCpuApicIdOrderTable[Index].Flags = 0; + mCpuApicIdOrderTable[Index].ApicId = (UINT32) -1; + mCpuApicIdOrderTable[Index].AcpiProcessorId = (UINT32) -1; + break; + } + } + } + } + + // + // keep for debug purpose + // + DEBUG ((DEBUG_INFO, "APIC ID Order Table ReOrdered\n")); + DebugDisplayReOrderTable (); + + // + // Re-sort AcpiProcessorId for all sockets + // + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + Index = 0; + + for (CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) { + if (mCpuApicIdOrderTable[CurrProcessor].Flags && (mCpuApicIdOrderTable[CurrProcessor].SocketNum == Socket)) { + // + // re-assign AcpiProcessorId to match MADT (socket, thread) + // + mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId = (Socket << mNumOfBitShift) + Index; + Index++; + } + } + } + + // + // keep for debug purpose + // + DEBUG ((DEBUG_INFO, "APIC ID Ord Tbl ReOrd aft Re-sort AcpiProcessorId\n")); + DebugDisplayReOrderTable (); + + // + // Update mApicIdMap according the final mCpuApicIdOrderTable + // + UpdateApicIdMap (); + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + for (Index=0; Index < (MAX_THREAD * MAX_CORE); Index++) { + if (mApicIdMap[Socket][Index] != (UINT32) -1) { + DEBUG ((DEBUG_INFO, "mApicIdMap[%d][%d] = 0x%x\n", Socket, Index, mApicIdMap[Socket][Index])); + } + } + } + + // + // Initialize with safe defaults + // + for(CurrProcessor = 0; CurrProcessor < MAX_CPU_NUM; CurrProcessor++) { + mCpuThreadIdMsrTable[CurrProcessor].ApicId = (UINT32)-1; + mCpuThreadIdMsrTable[CurrProcessor].ThreadIdValue = 0xFF; + mCpuThreadIdMsrTable[CurrProcessor].CollocatedChaId = 0xFF; + mCpuThreadIdMsrTable[CurrProcessor].SNCProximityDomain = 0; + } + // + // Collect MSR 53 value and ApicId for each thread + // + mMpService->StartupAllAPs (mMpService, (EFI_AP_PROCEDURE)GetThreadIdMsrValue, FALSE, NULL, 0, NULL, NULL); + GetThreadIdMsrValue (); + + mCpuOrderSorted = TRUE; + } + + return Status; +} + +/** + Build from scratch and install the MADT. + + @retval EFI_SUCCESS The MADT was installed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate required structures. +**/ +EFI_STATUS +InstallMadtFromScratch ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable; + UINTN TableHandle; + EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader; + EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE ProcLocalApicStruct; + EFI_ACPI_6_2_IO_APIC_STRUCTURE IoApicStruct; + EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE IntSrcOverrideStruct; + EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE LocalApciNmiStruct; + EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE ProcLocalX2ApicStruct; + EFI_ACPI_6_2_LOCAL_X2APIC_NMI_STRUCTURE LocalX2ApicNmiStruct; + STRUCTURE_HEADER **MadtStructs; + UINTN MaxMadtStructCount; + UINTN MadtStructsIndex; + + NewMadtTable = NULL; + + MaxMadtStructCount = (UINT32) ( + MAX_CPU_NUM + // processor local APIC structures + MAX_CPU_NUM + // processor local x2APIC structures + MAX_IO_APICS_10NM + // IOAPIC structures + 2 + // interrupt source override structures + 1 + // local APIC NMI structures + 1 // local x2APIC NMI structures + ); // other structures are not used + + MadtStructs = (STRUCTURE_HEADER **) AllocateZeroPool (MaxMadtStructCount * sizeof (STRUCTURE_HEADER *)); + if (MadtStructs == NULL) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) Could not allocate MADT structure pointer array\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Initialize the next index into the structure pointer array. It is + // incremented every time a structure of any type is copied to the array. + // + MadtStructsIndex = 0; + + // + // Initialize MADT Header Structure + // + Status = InitializeMadtHeader (&MadtTableHeader); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) InitializeMadtHeader failed: %r\n", Status)); + goto Done; + } + + DEBUG ((DEBUG_INFO, "[ACPI](MADT) Number of CPUs detected = %d \n", mNumberOfCPUs)); + + // + // Build Processor Local APIC Structures and Processor Local X2APIC Structures + // + ProcLocalApicStruct.Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC; + ProcLocalApicStruct.Length = sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE); + + ProcLocalX2ApicStruct.Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC; + ProcLocalX2ApicStruct.Length = sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE); + ProcLocalX2ApicStruct.Reserved[0] = 0; + ProcLocalX2ApicStruct.Reserved[1] = 0; + + for (Index = 0; Index < mNumberOfCPUs; Index++) { + // + // If x2APIC mode is not enabled, and if it is possible to express the + // APIC ID as a UINT8, use a processor local APIC structure. Otherwise, + // use a processor local x2APIC structure. + // + if (!mX2ApicEnabled && mCpuApicIdOrderTable[Index].ApicId < MAX_UINT8) { + ProcLocalApicStruct.Flags = (UINT8) mCpuApicIdOrderTable[Index].Flags; + ProcLocalApicStruct.ApicId = (UINT8) mCpuApicIdOrderTable[Index].ApicId; + ProcLocalApicStruct.AcpiProcessorUid = (UINT8) mCpuApicIdOrderTable[Index].AcpiProcessorId; + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &ProcLocalApicStruct, + &MadtStructs[MadtStructsIndex++] + ); + } else { + ProcLocalX2ApicStruct.Flags = (UINT8) mCpuApicIdOrderTable[Index].Flags; + ProcLocalX2ApicStruct.X2ApicId = mCpuApicIdOrderTable[Index].ApicId; + ProcLocalX2ApicStruct.AcpiProcessorUid = mCpuApicIdOrderTable[Index].AcpiProcessorId; + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &ProcLocalX2ApicStruct, + &MadtStructs[MadtStructsIndex++] + ); + } + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (local APIC/x2APIC) failed: %r\n", Status)); + goto Done; + } + } + + // + // Build IOAPIC Structures + // + if (mIioUds == NULL) { + Status = gBS->LocateProtocol (&gEfiIioUdsProtocolGuid,NULL,&mIioUds); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + goto Done; + } + } + + IoApicStruct.Type = EFI_ACPI_6_2_IO_APIC; + IoApicStruct.Length = sizeof (EFI_ACPI_6_2_IO_APIC_STRUCTURE); + IoApicStruct.Reserved = 0; + IoApicStruct.IoApicId = PCH_IOAPIC_ID; + IoApicStruct.IoApicAddress = mIioUds->IioUdsPtr->PlatformData.IIO_resource[0].StackRes[0].IoApicBase; + IoApicStruct.GlobalSystemInterruptBase = PCH_INTERRUPT_BASE; + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &IoApicStruct, + &MadtStructs[MadtStructsIndex++] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IOAPIC) failed: %r\n", Status)); + goto Done; + } + DEBUG ((DEBUG_INFO, "[ACPI](MADT) Add IOAPIC id %d, addr 0x%x, Interrupt base %d for PCH\n", IoApicStruct.IoApicId, IoApicStruct.IoApicAddress, IoApicStruct.GlobalSystemInterruptBase)); + + // + // Build Interrupt Source Override Structures + // + IntSrcOverrideStruct.Type = EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE; + IntSrcOverrideStruct.Length = sizeof (EFI_ACPI_6_2_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE); + + // + // IRQ0=>IRQ2 Interrupt Source Override Structure + // + IntSrcOverrideStruct.Bus = 0x0; // Bus - ISA + IntSrcOverrideStruct.Source = 0x0; // Source - IRQ0 + IntSrcOverrideStruct.GlobalSystemInterrupt = 0x2; // Global System Interrupt - IRQ2 + IntSrcOverrideStruct.Flags = 0x0; // Flags - Conforms to specifications of the bus + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &IntSrcOverrideStruct, + &MadtStructs[MadtStructsIndex++] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IRQ2 source override) failed: %r\n", Status)); + goto Done; + } + + // + // IRQ9 (SCI Active High) Interrupt Source Override Structure + // + IntSrcOverrideStruct.Bus = 0x0; // Bus - ISA + IntSrcOverrideStruct.Source = 0x9; // Source - IRQ9 + IntSrcOverrideStruct.GlobalSystemInterrupt = 0x9; // Global System Interrupt - IRQ9 + IntSrcOverrideStruct.Flags = 0xD; // Flags - Level-tiggered, Active High + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &IntSrcOverrideStruct, + &MadtStructs[MadtStructsIndex++] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (IRQ9 source override) failed: %r\n", Status)); + goto Done; + } + + // + // Build Local APIC NMI Structures + // + LocalApciNmiStruct.Type = EFI_ACPI_6_2_LOCAL_APIC_NMI; + LocalApciNmiStruct.Length = sizeof (EFI_ACPI_6_2_LOCAL_APIC_NMI_STRUCTURE); + LocalApciNmiStruct.AcpiProcessorUid = 0xFF; // Applies to all processors + LocalApciNmiStruct.Flags = POLARITY_ACTIVE_HIGH | TRIGGERMODE_EDGE; // Flags - Edge-tiggered, Active High + LocalApciNmiStruct.LocalApicLint = 0x1; + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &LocalApciNmiStruct, + &MadtStructs[MadtStructsIndex++] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (APIC NMI) failed: %r\n", Status)); + goto Done; + } + + // + // Build Local x2APIC NMI Structure + // + LocalX2ApicNmiStruct.Type = EFI_ACPI_6_2_LOCAL_X2APIC_NMI; + LocalX2ApicNmiStruct.Length = sizeof (EFI_ACPI_6_2_LOCAL_X2APIC_NMI_STRUCTURE); + LocalX2ApicNmiStruct.Flags = POLARITY_ACTIVE_HIGH | TRIGGERMODE_EDGE; // Flags - Edge-tiggered, Active High + LocalX2ApicNmiStruct.AcpiProcessorUid = 0xFFFFFFFF; // Applies to all processors + LocalX2ApicNmiStruct.LocalX2ApicLint = 0x01; + LocalX2ApicNmiStruct.Reserved[0] = 0x00; + LocalX2ApicNmiStruct.Reserved[1] = 0x00; + LocalX2ApicNmiStruct.Reserved[2] = 0x00; + + ASSERT (MadtStructsIndex < MaxMadtStructCount); + Status = CopyStructure ( + &MadtTableHeader.Header, + (STRUCTURE_HEADER *) &LocalX2ApicNmiStruct, + &MadtStructs[MadtStructsIndex++] + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) CopyMadtStructure (x2APIC NMI) failed: %r\n", Status)); + goto Done; + } + + // + // Build Madt Structure from the Madt Header and collection of pointers in MadtStructs[] + // + Status = BuildAcpiTable ( + (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader, + sizeof (EFI_ACPI_6_2_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER), + MadtStructs, + MadtStructsIndex, + (UINT8 **)&NewMadtTable + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI](MADT) BuildAcpiTable failed: %r\n", Status)); + goto Done; + } + + // + // Publish Madt Structure to ACPI + // + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + NewMadtTable, + NewMadtTable->Header.Length, + &TableHandle + ); + +Done: + // + // Free memory + // + for (MadtStructsIndex = 0; MadtStructsIndex < MaxMadtStructCount; MadtStructsIndex++) { + if (MadtStructs[MadtStructsIndex] != NULL) { + FreePool (MadtStructs[MadtStructsIndex]); + } + } + + FreePool (MadtStructs); + + if (NewMadtTable != NULL) { + FreePool (NewMadtTable); + } + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c new file mode 100644 index 0000000000..09464b4a11 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibBdat.c @@ -0,0 +1,1574 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include +#include +#include +#include +#include +#include + +extern struct SystemMemoryMapHob *mSystemMemoryMap; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; + +#include + +#ifndef MAX_HOB_ENTRY_SIZE +#define MAX_HOB_ENTRY_SIZE 60*1024 +#endif + +/** + Save BSSA results to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the BSSA result schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[in] SchemaSize - The size of the BSSA results schema. + @param[out] SchemaSpaceUsed - The numebr bytes were filled in all schema + @param[out] LastSchemaSpaceUsed - The numebr bytes were filled in the last schema + + @retval EFI_SUCCESS - BSSA BDAT scehma created successfully + @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed +**/ +EFI_STATUS +SaveBssaResultsToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + IN UINT32 SchemaSize, + OUT UINT32 *SchemaSpaceUsed, + OUT UINT32 *LastSchemaSpaceUsed + ); + +/** + Save EWL results to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the EWL schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - EWL BDAT scehma created successfully + @retval !EFI_SUCCESS - EWL BDAT scehma creation failed +**/ +EFI_STATUS +SaveEwlToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ); + +/** + Save SPD date structure to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the SPD data schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - SPD BDAT scehma created successfully + @retval !EFI_SUCCESS - SPD BDAT scehma creation failed +**/ +EFI_STATUS +SaveSpdToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ); + +/** + Save memory training date structure to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the memory training data schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - Memory training data BDAT scehma created successfully + @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed +**/ +EFI_STATUS +SaveTrainingDataToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ); + +/** + Get the size of SPD data structure not include the SPD BDAT schema header. + + @retval UINT32 - Size of SPD data structure in bytes +**/ +UINT32 +GetSpdDataSize ( + VOID + ); + +/** + Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space. + + @param[out] Address - Start Address of the buffer where the SPD entry to be filled + @param[in] Socket - Socket number + @param[in] Channel - Channel number inside the Socket + @param[in] Dimm - Dimm slot number + @param[in] MaxSpdByteOffset - The max SPD byte offset. DDR4 is 512 + + @retval EFI_SUCCESS - SPD Structure filled successfully + @retval !EFI_SUCCESS - SPD structure creation failed +**/ +EFI_STATUS +FillSpdPerDimmEntry ( + OUT EFI_PHYSICAL_ADDRESS Address, + IN UINT8 Socket, + IN UINT8 Channel, + IN UINT8 Dimm, + IN UINT16 MaxSpdByteOffset + ); + +/** + Fill the SPD data structure inside the BDAT schema space. + + @param[out] StartAddress - Start Address of the buffer where SPD data structure to be filled + @param[in] SpdDataSize - Size of SPD data structure includes the header + + @retval EFI_SUCCESS - SPD Structure filled successfully + @retval !EFI_SUCCESS - SPD structure creation failed +**/ +EFI_STATUS +FillSpdSchema ( + OUT EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT32 SpdDataSize + ); + +/** + Displays SPD content for debugging. + + @param[in] Address - The starting address of the SPD entry + + @retval N/A +**/ +VOID +DisplaySpdContents ( + IN EFI_PHYSICAL_ADDRESS Address + ); + +/** + Get Number of Schemas From BSSA HOB + + @retval UINT16 - Number of BSSA Schemas +**/ +UINT16 +GetNumberOfSchemasFromBssaHob ( + VOID + ) +{ + UINT32 GuidIdx = 0; + UINT16 NumberOfBssaSchemas = 0; + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + + if (mSystemMemoryMap == NULL) { + mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData (); + } + + ASSERT (mSystemMemoryMap != NULL); + if (mSystemMemoryMap == NULL) { + return 0; + } + + for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) { + // + // No. of HOBS per GUID added up for all GUIDs created from calls to saveToBdat () + // + NumberOfBssaSchemas += mSystemMemoryMap->Reserved7[GuidIdx]; + DEBUG ((DEBUG_VERBOSE, "GuidIdx = %d, total num hobs: %d\n", GuidIdx, mSystemMemoryMap->Reserved7[GuidIdx])); + } + return NumberOfBssaSchemas; +} + +/** + Create BDAT Header with necessary information. + Allocate memory with BdatSize and if failure return status. + If Success return the pointer address for copying the schema information + + @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] BdatSize - Size of BDAT Structure + @param[in] NumberOfSchema - Total nunber of of schema + + @retval EFI_SUCCESS - BDAT Structure created successfully + @retval !EFI_SUCCESS - BDAT structure creation failed +**/ +EFI_STATUS +CreateBdatHeader ( + OUT BDAT_STRUCTURE **BdatHeaderStructPtr, + IN UINT32 BdatSize, + IN UINT16 NumberOfSchema + ) +{ + EFI_TIME EfiTime; + UINT64 Address = 0xffffffff; + EFI_STATUS Status = EFI_SUCCESS; + + // + // Allocating RealTime Memory for BDAT. + // + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES(BdatSize), + &Address + ); + + if (EFI_ERROR (Status)) { + return Status; + } + + // + // The memory location where the HOB's are to be copied to + // + ZeroMem ((VOID *)Address, BdatSize); + + *BdatHeaderStructPtr = (BDAT_STRUCTURE *)Address; + + DEBUG ((DEBUG_VERBOSE, "\nBDAT Allocated Address = %x\n", Address)); + + // + // Create BIOS Data Signature + // + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[0] = 'B'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[1] = 'D'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[2] = 'A'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[3] = 'T'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[4] = 'H'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[5] = 'E'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[6] = 'A'; + (*BdatHeaderStructPtr)->BdatHeader.BiosDataSignature[7] = 'D'; + // + // Structure size + // + (*BdatHeaderStructPtr)->BdatHeader.BiosDataStructSize = BdatSize; + // + // Primary Version + // + (*BdatHeaderStructPtr)->BdatHeader.PrimaryVersion = BDAT_PRIMARY_VER; + // + // Secondary Version + // + (*BdatHeaderStructPtr)->BdatHeader.SecondaryVersion = BDAT_SECONDARY_VER; + // + // CRC16 value of the BDAT_STRUCTURE + // + (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0; + Status = CalculateCrc16 ( + (VOID *)(*BdatHeaderStructPtr), + BdatSize, + &(*BdatHeaderStructPtr)->BdatHeader.Crc16 + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + (*BdatHeaderStructPtr)->BdatHeader.Crc16 = 0xFFFF; + } + (*BdatHeaderStructPtr)->BdatSchemas.SchemaListLength = NumberOfSchema; + (*BdatHeaderStructPtr)->BdatSchemas.Reserved = 0; + (*BdatHeaderStructPtr)->BdatSchemas.Reserved1 = 0; + // + // Initialize the Time parameters in the SCHEMA_LIST_STRUCTURE + // + Status = gRT->GetTime (&EfiTime, NULL); + if (!EFI_ERROR (Status)) { + (*BdatHeaderStructPtr)->BdatSchemas.Year = EfiTime.Year; + (*BdatHeaderStructPtr)->BdatSchemas.Month = EfiTime.Month; + (*BdatHeaderStructPtr)->BdatSchemas.Day = EfiTime.Day; + (*BdatHeaderStructPtr)->BdatSchemas.Hour = EfiTime.Hour; + (*BdatHeaderStructPtr)->BdatSchemas.Minute = EfiTime.Minute; + (*BdatHeaderStructPtr)->BdatSchemas.Second = EfiTime.Second; + } + return Status; +} + +/** + Dump BDAT Table to serial log + + Example 1: There are 2 schema: BSSA RMT and EWL. + + Print BDAT Table + Address 0 1 2 3 4 5 6 7 8 9 A B C D E F + 00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x30 0x18 0x00 0x00 0xD7 0x7A 0x00 0x00 + 00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 00000020 0x02 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x00 0x29 0x03 0x00 0x34 0x00 0x00 0x00 + 00000030 0xFA 0x07 0x00 0x00 0x28 0xE9 0xF4 0x08 0x5F 0x0F 0xD4 0x46 0x84 0x10 0x47 0x9F + 00000040 0xDA 0x27 0x9D 0xB6 0xC6 0x07 0x00 0x00 0x57 0x7F 0x00 0x00 0x00 0x00 0x00 0xA5 + 00000050 0x98 0x88 0xFE 0x4C 0x00 0x00 0x00 0x0D 0xEB 0x7A 0x47 0x07 0xDE 0x77 0x42 0xA4 + 00000060 0xE7 0x87 0x81 0x0B 0x10 0x00 0x31 0xF1 0x98 0x88 0xFE 0xF2 0x45 0x81 0xD9 0xF4 + ... + ... + 000007F0 0x00 0x00 0x00 0x5A 0xA5 0x5A 0xA5 0x5A 0xA5 0x5A 0x2F 0x53 0xFE 0xBF 0x3B 0xCA + 00000800 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D 0x36 0x10 0x00 0x00 0x9F 0xEF + 00000810 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED 0x60 0xF2 0x82 0x48 0x6C 0xFC + 00000820 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81 0x50 0x51 0x00 0x00 0x00 0x00 + 00000830 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00 0x7E 0x07 0x17 0x18 0x01 0xFF + 00000840 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + Example 2: There is 1 schema: EWL + Address 0 1 2 3 4 5 6 7 8 9 A B C D E F + 00000000 0x42 0x44 0x41 0x54 0x48 0x45 0x41 0x44 0x66 0x10 0x00 0x00 0xA9 0x44 0x00 0x00 + 00000010 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 00000020 0x01 0x00 0x00 0x00 0xE4 0x07 0x08 0x0E 0x01 0x0F 0x2C 0x00 0x30 0x00 0x00 0x00 + 00000030 0x2F 0x53 0xFE 0xBF 0x3B 0xCA 0x6C 0x41 0xA0 0xF6 0xFF 0xE4 0xE7 0x1E 0x3A 0x0D + 00000040 0x36 0x10 0x00 0x00 0x9F 0xEF 0x70 0x33 0x71 0x75 0x05 0x38 0xB0 0x46 0x9F 0xED + 00000050 0x60 0xF2 0x82 0x48 0x6C 0xFC 0x20 0x10 0x00 0x00 0x12 0x00 0x00 0x00 0x2E 0x81 + 00000060 0x50 0x51 0x00 0x00 0x00 0x00 0x01 0x00 0x00 0x00 0x12 0x00 0x01 0x00 0x00 0x00 + 00000070 0x7E 0x07 0x17 0x18 0x01 0xFF 0xFF 0xFF 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + 00000080 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 + + @param[out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] BdatSize - Size of BDAT Structure + + @retval None +**/ +VOID +DumpBdatTable( + IN BDAT_STRUCTURE **BdatHeaderStructPtr, + IN UINT32 BdatSize +) +{ + UINT32 i = 0; + UINT8 *Table = NULL; + + Table = (UINT8 *)(*BdatHeaderStructPtr); + DEBUG ((DEBUG_VERBOSE, "\nPrint BDAT Table\n")); + + // + // Print address header + // + DEBUG ((DEBUG_VERBOSE, "Address ")); + for (i = 0; i < 16; i++) { + DEBUG ((DEBUG_VERBOSE, " %01x", i)); + } + + i = 0; + while (i < BdatSize) { + if ((i % 16) == 0) { + DEBUG ((DEBUG_VERBOSE, "\n%08x ", (i / 16) * 16)); + } else { + DEBUG ((DEBUG_VERBOSE, " ")); + } + + DEBUG ((DEBUG_VERBOSE, "0x%02x", Table[i])); + + if (i == BdatSize - 1) { + DEBUG ((DEBUG_VERBOSE, "\n")); + } + + i++; + + } + DEBUG ((DEBUG_VERBOSE, "\n")); +} + +/** + Copy BDAT Table pointer to scratchpad 5 register + + @param[in] BdatAddress - Bdat Table Address to be copied to Scratchpad 5 register + + @retval None +**/ +VOID +CopyBdatPointerToScratchPad5 ( + IN UINT64 BdatAddress + ) +{ + UINT8 Socket = 0; + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + // + // Copy BDAT base address to ScratchPad5 + // + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) { + DynamicSiLibraryProtocol->WriteScratchpad5 (Socket, (UINT32) BdatAddress); + DEBUG ((DEBUG_VERBOSE, "Scratchpad_Debug PatchBdaAcpiTable: Verify Non Sticky Scratchpad5 0x%08x\n", BdatAddress)); + } + } +} + +/** + Update the BDAT ACPI table: Multiple instances of the BDAT DATA HOB are placed into one contiguos memory range + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchBdatAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + EFI_PHYSICAL_ADDRESS Address = 0; + UINT32 Idx = 0; + UINT8 Checksum = 0; + BDAT_STRUCTURE *BdatHeaderStructPtr = NULL; + UINT32 TotalBDATstructureSize = 0; + UINT32 BdatHeaderSize = 0; + EFI_HOB_GUID_TYPE *GuidHob = NULL; + UINT16 NumberBssaSchemas = 0; + UINT16 TotalNumberSchemas = 0; + UINT32 BssaSchemaSize = 0; + EFI_BDAT_ACPI_DESCRIPTION_TABLE *BdatAcpiTable = NULL; + EWL_PRIVATE_DATA *EwlPrivateData = NULL; + EFI_GUID EWLDataGuid = EWL_ID_GUID; + UINT32 EwlSchemaSize = 0; + MEM_TRAINING_DATA_STRUCTURE *MemTrainingData = NULL; + MEM_TRAINING_DATA_HOB_HEADER *TrainingDataHobHeader = NULL; + UINT32 TrainingDataSchemaSize = 0; + UINT32 RemainingSchemaSpace = 0; + UINT32 SpdDataSize = 0; + UINT32 SpdSchemaSize = 0; + UINT8 SchemaIndex = 0; + UINT32 SpaceUsed = 0; + UINT32 LastSchemaSpaceUsed = 0; + UINT32 OffsetFromLastSchema = 0; + + BdatAcpiTable = (EFI_BDAT_ACPI_DESCRIPTION_TABLE *)Table; + DEBUG ((DEBUG_INFO, "\nPatchBdatAcpiTable Started\n")); + + // + // Gather BSSA schema info + // + NumberBssaSchemas = GetNumberOfSchemasFromBssaHob (); + + BssaSchemaSize = mSystemMemoryMap->Reserved6 + (NumberBssaSchemas * sizeof (BDAT_SCHEMA_HEADER_STRUCTURE)); //Total size of all HOBs created by SaveToBdat() + NumberBssaSchemas*headerPerSchema + DEBUG ((DEBUG_VERBOSE, "NumberBssaSchemas = %d, total BSSA schema size: %d\n", NumberBssaSchemas, BssaSchemaSize)); + + TotalNumberSchemas = NumberBssaSchemas; + + TotalBDATstructureSize += BssaSchemaSize; + + // + // Gather EWL schema info + // + GuidHob = GetFirstGuidHob (&EWLDataGuid); + if (GuidHob != NULL) { + DEBUG ((DEBUG_VERBOSE, "Found EWL with GUID %g\n", &EWLDataGuid)); + + TotalNumberSchemas += 1; + + EwlPrivateData = GET_GUID_HOB_DATA (GuidHob); + + EwlSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + EwlPrivateData->status.Header.Size; + + DEBUG ((DEBUG_VERBOSE, "EWL schema size: %d\n", EwlSchemaSize)); + + TotalBDATstructureSize += EwlSchemaSize; + } + + // + // Gather SPD schema info + // + SpdSchemaSize = 0; + if (PcdGetBool (SaveSpdToBdat)) { + SpdDataSize = GetSpdDataSize (); + + if (SpdDataSize > 0) { + TotalNumberSchemas += 1; + SpdSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + SpdDataSize; + DEBUG ((DEBUG_VERBOSE, "SPD data schema size: %d\n", SpdSchemaSize)); + + TotalBDATstructureSize += SpdSchemaSize; + } + } // PcdGetBool (SaveSpdToBdat) + + // + // Gather Memory training data schema info + // + TrainingDataSchemaSize = 0; + if (PcdGetBool (SaveMrcTrainingDataToBdat)) { + GuidHob = GetFirstGuidHob (&gMemTrainingDataHobGuid); + if (GuidHob != NULL) { + DEBUG ((DEBUG_VERBOSE, "Found memory training data HOB with GUID %g\n", &gMemTrainingDataHobGuid)); + + TotalNumberSchemas += 1; + + TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob); + + MemTrainingData = (MEM_TRAINING_DATA_STRUCTURE *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER)); + + TrainingDataSchemaSize = sizeof (BDAT_SCHEMA_HEADER_STRUCTURE) + MemTrainingData->Header.Size; + + DEBUG ((DEBUG_VERBOSE, "Memory training data schema size: %d\n", TrainingDataSchemaSize)); + + TotalBDATstructureSize += TrainingDataSchemaSize; + } + } // PcdGetBool (SaveMrcTrainingDataToBdat) + + BdatHeaderSize = sizeof (BDAT_STRUCTURE) + (TotalNumberSchemas * (sizeof (UINT32))); + TotalBDATstructureSize += BdatHeaderSize; + + // + // This variable is used to keep track the remain space in the BDAT payload (schema section) to + // prevent overflow the allocated RT BDAT buffer. + // + RemainingSchemaSpace = TotalBDATstructureSize - BdatHeaderSize; + + DEBUG ((DEBUG_INFO, "Total BDAT size:%d, BDAT header size: %d, Total schema:%d \n", TotalBDATstructureSize, BdatHeaderSize, TotalNumberSchemas)); + + Status = CreateBdatHeader (&BdatHeaderStructPtr, TotalBDATstructureSize, TotalNumberSchemas); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((DEBUG_INFO, "BdatRegionAddress = 0x%x\n", (UINT64)BdatHeaderStructPtr)); + CopyBdatPointerToScratchPad5 ((UINT64)BdatHeaderStructPtr); + + // + // Update BDAT ACPI table + // + BdatAcpiTable->BdatGas.Address = (UINT64)BdatHeaderStructPtr; + + // + // Starting address of the first schema + // + Address = (EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + BdatHeaderSize; + + // + // Saving to RT Memory BDAT Data received from HOBs generated due to BSSA call/calls to SaveToBdat() + // + SpaceUsed = 0; + + // + // The first schema starts right after the BDAT header structure + // + LastSchemaSpaceUsed = BdatHeaderSize; // It will used as the OffsetFromLastSchema for the next schema if BSSA is not available + OffsetFromLastSchema = BdatHeaderSize; + + if (BssaSchemaSize > 0) { + + Status = SaveBssaResultsToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, BssaSchemaSize, &SpaceUsed, &LastSchemaSpaceUsed); + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Faield to add BSSA result to BDAT\n")); + } + } + + // + // Update the starting address of next schema and remaining space. + // + Address += SpaceUsed; + RemainingSchemaSpace -= SpaceUsed; + OffsetFromLastSchema = LastSchemaSpaceUsed; + + // + // Saving to RT Memory BDAT Data received from EWL HOB + // + SpaceUsed = 0; + + if (EwlSchemaSize > 0) { + + if (RemainingSchemaSpace < EwlSchemaSize) { + DEBUG ((DEBUG_ERROR, "Not enough space to add EWL schema.\n")); + goto End; + } + + Status = SaveEwlToBdat (BdatHeaderStructPtr, OffsetFromLastSchema ,&Address, &SchemaIndex, &SpaceUsed); + + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Failed to add EWL to BDAT.\n")); + } + + } + + // + // Update the starting address of next schema and remaining space. + // + Address += SpaceUsed; + RemainingSchemaSpace -= SpaceUsed; + OffsetFromLastSchema = SpaceUsed; + + // + // Add SPD schema + // + SpaceUsed = 0; + + if (SpdSchemaSize > 0) { + + if (RemainingSchemaSpace < SpdSchemaSize) { + DEBUG ((DEBUG_ERROR, "Not enough space to add SPD schema.\n")); + goto End; + } + + Status = SaveSpdToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed); + + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Failed to add SPD to BDAT.\n")); + } + + } + + // + // Update the starting address of next schema and remaining space. + // + Address += SpaceUsed; + RemainingSchemaSpace -= SpaceUsed; + OffsetFromLastSchema = SpaceUsed; + + // + // Add memory training data schema + // + SpaceUsed = 0; + + if (TrainingDataSchemaSize > 0) { + + if (RemainingSchemaSpace < TrainingDataSchemaSize) { + DEBUG ((DEBUG_ERROR, "Not enough space to add memory training data schema.\n")); + goto End; + } + + Status = SaveTrainingDataToBdat (BdatHeaderStructPtr, OffsetFromLastSchema, &Address, &SchemaIndex, &SpaceUsed); + + if (Status != EFI_SUCCESS) { + DEBUG ((DEBUG_ERROR, "Failed to add memory training data to BDAT.\n")); + } + } + + // + // Update the starting address of next schema and remaining space. + // + Address += SpaceUsed; + RemainingSchemaSpace -= SpaceUsed; + OffsetFromLastSchema = SpaceUsed; + + DEBUG ((DEBUG_VERBOSE, "Final SchemaIndex:%d RemainingSchemaSpace:%d\n", SchemaIndex, RemainingSchemaSpace)); + + End: + + // + // Update checksum + // + BdatAcpiTable->Header.Checksum = 0; + Checksum = 0; + for(Idx = 0; Idx < sizeof(EFI_BDAT_ACPI_DESCRIPTION_TABLE); Idx++) { + Checksum = Checksum + (UINT8) (((UINT8 *)(BdatAcpiTable))[Idx]); + } + BdatAcpiTable->Header.Checksum = (UINT8) (0 - Checksum); + + DumpBdatTable (&BdatHeaderStructPtr, TotalBDATstructureSize); + + return Status; +} + + +/** + Displays SPD content for debugging. + + @param[in] Address - The starting address of the SPD entry + + @retval N/A +**/ +VOID +DisplaySpdContents ( + IN EFI_PHYSICAL_ADDRESS Address + ) +{ + UINT16 Index; + MEM_SPD_ENTRY_TYPE0 *EntryHeaderPtr; + + EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0 *)Address; + + // + // Print the Socket, Channel and Dimm information. + // + DEBUG ((DEBUG_VERBOSE, "START_PRINT_SPD S%dC%dD%d:\n", + EntryHeaderPtr->MemoryLocation.Socket, + EntryHeaderPtr->MemoryLocation.Channel, + EntryHeaderPtr->MemoryLocation.Dimm)); + + // + // Print the Column Number of the SPD data. + // + for (Index = 0; Index < 0x10; Index++) { + DEBUG ((DEBUG_VERBOSE, " %02x", Index)); + } + + Address += sizeof (MEM_SPD_ENTRY_TYPE0); + + for (Index = 0; Index < EntryHeaderPtr->NumberOfBytes; Index++) { + + // + // Print the Carriage Return and Byte Index of SPD data. + // + if ((Index % 0x10) == 0) { + + // + // Split the SPD data for every 256 bytes + // + if (((Index % 0x100) == 0) && (Index != 0)) { + DEBUG ((DEBUG_VERBOSE, "\n")); + } + + DEBUG ((DEBUG_VERBOSE, "\n%02x:", (UINT8) (Index & 0x00F0))); + } + + DEBUG ((DEBUG_VERBOSE, " %02x", *(UINT8 *)(Address + (EFI_PHYSICAL_ADDRESS)Index))); + } + + DEBUG ((DEBUG_VERBOSE, "\n")); + + + DEBUG ((DEBUG_VERBOSE, "STOP_PRINT_SPD\n")); + +} // DisplaySpdContents + +/** + Get the size of SPD data structure not include the SPD BDAT schema header. + + @retval UINT32 - Size of SPD data structure in bytes +**/ +UINT32 +GetSpdDataSize ( + VOID + ) +{ + UINT32 SchemaSize = 0; + UINT8 Socket; + UINT8 Channel; + UINT8 Dimm; + UINT32 SpdBytesPerDimm = 0; + UINT8 NumberOfDimmPresent = 0; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + + if (mSystemMemoryMap == NULL) { + mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData (); + } + + if (mSystemMemoryMap == NULL) { + return 0; + } + + ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4); + SpdBytesPerDimm = MAX_SPD_BYTE_DDR4; + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + for (Channel = 0; Channel < MAX_CH; Channel++) { + for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) { + if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) { + NumberOfDimmPresent += 1; + } + } + } + } + + // + // Total entries + // + SchemaSize = (SpdBytesPerDimm + sizeof (MEM_SPD_ENTRY_TYPE0)) * NumberOfDimmPresent; + + // + // Add the SPD raw data header + // + SchemaSize += sizeof (MEM_SPD_RAW_DATA_HEADER); + + return SchemaSize; + +} + + +/** + Read the SPD data for one dimm and fill up SPD entry inside SPD BDAT schema space. + + @param[out] Address - Start Address of the buffer where the SPD entry to be filled + @param[in] Socket - Socket number + @param[in] Channel - Channel number inside the Socket + @param[in] Dimm - Dimm slot number + @param[in] MaxSpdByteOffset - The max SPD byte offset. DDR4 is 512 + + @retval EFI_SUCCESS - SPD Structure filled successfully + @retval !EFI_SUCCESS - SPD structure creation failed +**/ +EFI_STATUS +FillSpdPerDimmEntry ( + OUT EFI_PHYSICAL_ADDRESS Address, + IN UINT8 Socket, + IN UINT8 Channel, + IN UINT8 Dimm, + IN UINT16 MaxSpdByteOffset + ) +{ + UINT16 SpdByteOffset = 0; + UINT8 SpdData = 0; + MEM_SPD_ENTRY_TYPE0 *EntryHeaderPtr; + EFI_STATUS Status = EFI_SUCCESS; + + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + DEBUG ((DEBUG_VERBOSE, "Fill Spd entry for Socket:%d Channel:%d Dimm:%d at location:0x%x \n", Socket, Channel, Dimm, Address)); + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + EntryHeaderPtr = (MEM_SPD_ENTRY_TYPE0 *)Address; + + // + // Add the entry header. We use type 0. + // + EntryHeaderPtr->Header.Type = MemSpdDataType0; + EntryHeaderPtr->Header.Size = sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset; + + EntryHeaderPtr->MemoryLocation.Socket = Socket; + EntryHeaderPtr->MemoryLocation.Channel = Channel; + EntryHeaderPtr->MemoryLocation.Dimm = Dimm; + + EntryHeaderPtr->NumberOfBytes = MaxSpdByteOffset; + + Address += sizeof (MEM_SPD_ENTRY_TYPE0); + + for (SpdByteOffset = 0; SpdByteOffset < MaxSpdByteOffset; SpdByteOffset++) { + Status = DynamicSiLibraryProtocol2->SpdReadByte (Socket, Channel, Dimm, SpdByteOffset, &SpdData); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d SpdByteOffset:%d Status:0x%x\n", + Socket, Channel, Dimm, SpdByteOffset, Status)); + return Status; + } + + *(UINT8 *)Address = SpdData; + Address += 1; + } // SpdByteOffset + + return Status; +} + +/** + Fill the SPD data structure inside the BDAT schema space. + + @param[out] StartAddress - Start Address of the buffer where SPD data structure to be filled + @param[in] SpdDataSize - Size of SPD data structure includes the header + + @retval EFI_SUCCESS - SPD Structure filled successfully + @retval !EFI_SUCCESS - SPD structure creation failed +**/ +EFI_STATUS +FillSpdSchema ( + OUT EFI_PHYSICAL_ADDRESS StartAddress, + IN UINT32 SpdDataSize + ) +{ + UINT8 Socket; + UINT8 Channel; + UINT8 Dimm; + UINT16 MaxSpdByteOffset = 0; + UINT32 RemainedSpace; + EFI_PHYSICAL_ADDRESS Address; + MEM_SPD_RAW_DATA_HEADER *SpdDataHeaderStructPtr; + EFI_STATUS Status = EFI_SUCCESS; + + DYNAMIC_SI_LIBARY_PROTOCOL *DynamicSiLibraryProtocol = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocolGuid, NULL, &DynamicSiLibraryProtocol); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if (mSystemMemoryMap == NULL) { + mSystemMemoryMap = DynamicSiLibraryProtocol->GetSystemMemoryMapData (); + } + + if (mSystemMemoryMap == NULL) { + return EFI_DEVICE_ERROR;; + } + if (StartAddress == 0) { + return EFI_INVALID_PARAMETER; + } + + RemainedSpace = SpdDataSize; + Address = StartAddress; + SpdDataHeaderStructPtr = (MEM_SPD_RAW_DATA_HEADER *)StartAddress; + + // + // Fill up the header of the SPD data strcuture + // + SpdDataHeaderStructPtr->MemSpdGuid = gSpdVersion1Guid; + SpdDataHeaderStructPtr->Size = SpdDataSize; + SpdDataHeaderStructPtr->Reserved = 0; + + Address += sizeof (MEM_SPD_RAW_DATA_HEADER); + RemainedSpace -= sizeof (MEM_SPD_RAW_DATA_HEADER); + + ASSERT (mSystemMemoryMap->DramType == SPD_TYPE_DDR4); + MaxSpdByteOffset = MAX_SPD_BYTE_DDR4; + + // + // Iterate through all populated DIMMs and add them + // + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + for (Channel = 0; Channel < MAX_CH; Channel++) { + for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) { + + if (mSystemMemoryMap->Socket[Socket].ChannelInfo[Channel].DimmInfo[Dimm].Present != 0) { + + if (RemainedSpace < sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset) { + DEBUG ((DEBUG_ERROR, "Run out of allocated SPD data space. RemainedSpace:%d required space:%d\n", + RemainedSpace, sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset)); + return RETURN_OUT_OF_RESOURCES; + } + + Status = FillSpdPerDimmEntry (Address, Socket, Channel, Dimm, MaxSpdByteOffset); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to read SPD data at Socket:%d Channel:%d Dimm:%d Status:0x%x.\n", Socket, Channel, Dimm, Status)); + return Status; + } + + DisplaySpdContents (Address); + + Address += sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset; + RemainedSpace -= sizeof (MEM_SPD_ENTRY_TYPE0) + MaxSpdByteOffset; + + } + } // Dimm + } // Channel + } // Socket + + // + // Update CRC + // + SpdDataHeaderStructPtr->Crc = 0; + SpdDataHeaderStructPtr->Crc = CalculateCrc32 ((VOID *) SpdDataHeaderStructPtr, SpdDataHeaderStructPtr->Size); + + return EFI_SUCCESS; + +} + +/** + Save BSSA results to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the BSSA result schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[in] SchemaSize - The size of the BSSA results schema. + @param[out] SchemaSpaceUsed - The numebr bytes were filled in all schema + @param[out] LastSchemaSpaceUsed - The numebr bytes were filled in the last schema + + @retval EFI_SUCCESS - BSSA BDAT scehma created successfully + @retval !EFI_SUCCESS - BSSA BDAT scehma creation failed +**/ +EFI_STATUS +SaveBssaResultsToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + IN UINT32 SchemaSize, + OUT UINT32 *SchemaSpaceUsed, + OUT UINT32 *LastSchemaSpaceUsed + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 *SchemaAddrLocationArray = NULL; + UINT32 CurrentHobSize = 0; + EFI_HOB_GUID_TYPE *GuidHob = NULL; + VOID *HobData = NULL; + UINT32 PreviousSchemaSize = 0; + EFI_GUID gEfiMemoryMapDataHobBdatBssaGuid = {0}; + UINT32 GuidIdx = 0; + UINT32 HobIdx = 0; + UINT32 RemainingHobSizeBssaSchema = 0; + BDAT_SCHEMA_HEADER_STRUCTURE *BssaSchemaHeaderPtr = NULL; + EFI_PHYSICAL_ADDRESS Address = 0; + + if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + RemainingHobSizeBssaSchema = SchemaSize; + Address = *SchemaStartAddress; + *SchemaSpaceUsed = 0; + + // + // Update the schema offset array for its first BSSA schema + // + SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE)); + + if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) { + if (*SchemaIndex == 0) { + SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema; + } + else { + SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema; + } + } + + for (GuidIdx = 0; GuidIdx < mSystemMemoryMap->Reserved9; GuidIdx++) { + + gEfiMemoryMapDataHobBdatBssaGuid = mSystemMemoryMap->Reserved8[GuidIdx]; //get first GUID instance + GuidHob = GetFirstGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid); + + for (HobIdx = 0; HobIdx < mSystemMemoryMap->Reserved7[GuidIdx]; HobIdx++) { //looping through all HOBs linked to that GUID + + ASSERT (GuidHob != NULL); + if (GuidHob == NULL) { + return EFI_NOT_FOUND; + } + + HobData = GET_GUID_HOB_DATA (GuidHob); + CurrentHobSize = GET_GUID_HOB_DATA_SIZE (GuidHob); + DEBUG ((DEBUG_VERBOSE, "Initial HOB size %d; remaining HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema)); + + // + // Setting the header first + // + if (RemainingHobSizeBssaSchema < sizeof(BDAT_SCHEMA_HEADER_STRUCTURE)) { + // + // Nothing we can do, break execution + // + DEBUG ((DEBUG_WARN, "Not enough space to add schema header to BIOS SSA result\n")); + RemainingHobSizeBssaSchema = 0; + break; + } + + // + // Each HOB has a header added to it (BDAT_SCHEMA_HEADER_STRUCTURE) + // + Address = Address + (EFI_PHYSICAL_ADDRESS)PreviousSchemaSize; + + BssaSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address; + BssaSchemaHeaderPtr->SchemaId = gEfiMemoryMapDataHobBdatBssaGuid; + RemainingHobSizeBssaSchema -= sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE + // + BssaSchemaHeaderPtr->Crc16 = 0; + Status = CalculateCrc16 ( + (VOID *) BssaSchemaHeaderPtr, + sizeof (BDAT_SCHEMA_HEADER_STRUCTURE), + &BssaSchemaHeaderPtr->Crc16 + ); + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + BssaSchemaHeaderPtr->Crc16 = 0xFFFF; + } + + if (RemainingHobSizeBssaSchema < CurrentHobSize) { + DEBUG ((DEBUG_WARN, "Not enough space to add complete BIOS SSA result\n")); + CurrentHobSize = RemainingHobSizeBssaSchema; + } + + // + // HOB size won't overflow a UINT32. + // + BssaSchemaHeaderPtr->DataSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + DEBUG ((DEBUG_VERBOSE, "Setting schema %g size to %d\n", &(BssaSchemaHeaderPtr->SchemaId), BssaSchemaHeaderPtr->DataSize)); + // + // HOB size won't overflow a UINT32. + // + PreviousSchemaSize = (UINT32)CurrentHobSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // Copy HOB to RT Memory + // + CopyMem ((VOID *)Address, (VOID *)HobData, (UINT32)CurrentHobSize); + // + // HOB size won't overflow a UINT32. + // + DEBUG ((DEBUG_VERBOSE, "HOB size %d; remaining SSA HOB size %d\n", CurrentHobSize, RemainingHobSizeBssaSchema)); + RemainingHobSizeBssaSchema -= (UINT32)CurrentHobSize; + *SchemaSpaceUsed = *SchemaSpaceUsed + (UINT32)CurrentHobSize; + + *SchemaIndex = *SchemaIndex + 1; + + if (RemainingHobSizeBssaSchema == 0) { + break; + } + + GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB + GuidHob = GetNextGuidHob (&gEfiMemoryMapDataHobBdatBssaGuid, GuidHob); // Now search for next instance of the BDAT HOB + if (GuidHob == NULL) { + break; + } + + // + // Update the schema offset arrary + // + if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) { + SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + PreviousSchemaSize; + } + } + + if (RemainingHobSizeBssaSchema == 0) { + break; + } + + } + + *LastSchemaSpaceUsed = PreviousSchemaSize; + + return EFI_SUCCESS; +} // SaveBssaResultsToBdat + + +/** + Save EWL results to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the EWL schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - EWL BDAT scehma created successfully + @retval !EFI_SUCCESS - EWL BDAT scehma creation failed +**/ +EFI_STATUS +SaveEwlToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 *SchemaAddrLocationArray = NULL; + EFI_HOB_GUID_TYPE *GuidHob = NULL; + EFI_PHYSICAL_ADDRESS Address = 0; + EWL_PRIVATE_DATA *EwlPrivateData = NULL; + EFI_GUID EWLDataGuid = EWL_ID_GUID; + BDAT_SCHEMA_HEADER_STRUCTURE *EwlSchemaHeaderPtr = NULL; + UINT32 EwlSize = 0; + + if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Address = *SchemaStartAddress; + *SchemaSpaceUsed = 0; + + DEBUG ((DEBUG_VERBOSE, "\nStarting to copy EWL schema at Address = 0x%x\n", Address)); + + // + // Update the schema offset arrary + // + SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE)); + + if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) { + if (*SchemaIndex == 0) { + SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema; + } + else { + SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema; + } + } + + EwlSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address; + EwlSchemaHeaderPtr->SchemaId = gEwlBdatSchemaGuid; + *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE + // + EwlSchemaHeaderPtr->Crc16 = 0; + Status = CalculateCrc16 ( + (VOID *)EwlSchemaHeaderPtr, + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE), + &EwlSchemaHeaderPtr->Crc16 + ); + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + EwlSchemaHeaderPtr->Crc16 = 0xFFFF; + } + + GuidHob = GetFirstGuidHob (&EWLDataGuid); + EwlPrivateData = GET_GUID_HOB_DATA (GuidHob); + + EwlSize = EwlPrivateData->status.Header.Size; + + EwlSchemaHeaderPtr->DataSize = EwlSize + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // Copy EWL HOB to RT Memory + // + Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + CopyMem ((VOID *)Address, (VOID *)&(EwlPrivateData->status), EwlSize); + *SchemaSpaceUsed = *SchemaSpaceUsed + EwlSize; + + *SchemaIndex = *SchemaIndex + 1; + + return EFI_SUCCESS; +} //SaveEwlToBdat + +/** + Check if current boot is slow boot or not + + @retval TRUE - Slow boot path + @retval FALSE - not slow boot path + **/ +BOOLEAN +IsSlowBoot ( + VOID + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return TRUE; + } + + return DynamicSiLibraryProtocol2->IsSlowBoot (); +} // IsSlowBoot + +/** + Save SPD date structure to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the SPD data schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - SPD BDAT scehma created successfully + @retval !EFI_SUCCESS - SPD BDAT scehma creation failed +**/ +EFI_STATUS +SaveSpdToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 *SchemaAddrLocationArray = NULL; + UINT32 SpdDataSize = 0; + EFI_PHYSICAL_ADDRESS Address = 0; + BDAT_SCHEMA_HEADER_STRUCTURE *SpdSchemaHeaderPtr = NULL; +// UINT16 *SpdVariableName = L"SpdData"; + VOID *VariableData = NULL; + BOOLEAN SaveToVariable = TRUE; + UINTN CompareValue; + + if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Address = *SchemaStartAddress; + *SchemaSpaceUsed = 0; + + // + // Add SPD schema + // + DEBUG ((DEBUG_VERBOSE, "\nStarting to add SPD schema at Address = 0x%x\n", Address)); + + // + // Update the schema offset arrary + // + SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE)); + + if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) { + if (*SchemaIndex == 0) { + SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema; + } + else { + SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema; + } + } + + SpdSchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address; + SpdSchemaHeaderPtr->SchemaId = gSpdBdatSchemaGuid; + + // + // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE + // + SpdSchemaHeaderPtr->Crc16 = 0; + Status = CalculateCrc16 ( + (VOID *)SpdSchemaHeaderPtr, + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE), + &SpdSchemaHeaderPtr->Crc16 + ); + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + SpdSchemaHeaderPtr->Crc16 = 0xFFFF; + } + + Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + SpdDataSize = GetSpdDataSize (); + + if (IsSlowBoot ()) { + // + // Read SPD via Smbus, fill up the SPD data structure. + // + FillSpdSchema (Address, SpdDataSize); + + // + // Save the SPD data structure to EFI variables to save fast boot time + // + // Before save variable, read and comapre to current data. If they are the same, then + // don't save it. + // If fail to read the variable(the variable doesn't exist), save variable. + // + + SaveToVariable = TRUE; + + VariableData = AllocatePool (SpdDataSize); + if (VariableData == NULL) { + DEBUG ((DEBUG_ERROR, "Not able to allocate space to store SPD variable data.\n")); + Status = EFI_OUT_OF_RESOURCES; + goto End; + } + +// Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, VariableData, SpdDataSize); + + if (!EFI_ERROR (Status)) { + CompareValue = CompareMem ((VOID *)Address, VariableData, SpdDataSize); + if (CompareValue == 0) { + SaveToVariable = FALSE; + DEBUG ((DEBUG_VERBOSE, "No change to the SPD data, don't save variable.\n")); + } + } + + if (SaveToVariable) { +// Status = CompressAndSaveToVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize); + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to save SPD data to variable.\n")); + goto End; + } + + DEBUG ((DEBUG_VERBOSE, "Save SPD data to EFI variable.\n")); + } + } else { + // + // Fast boot, read the SPD data from vaiable + // +// Status = LoadCompressedVariable (SpdVariableName, gSpdVariableGuid, (VOID *)Address, SpdDataSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to load SPD data from variable.\n")); + goto End; + } + DEBUG ((DEBUG_VERBOSE, "Fill with SPD data from EFI variable.\n")); + } + + End: + + if (VariableData != NULL) { + FreePool (VariableData); + } + + SpdSchemaHeaderPtr->DataSize = SpdDataSize + sizeof (BDAT_SCHEMA_HEADER_STRUCTURE); + *SchemaSpaceUsed = *SchemaSpaceUsed + SpdDataSize; + + *SchemaIndex = *SchemaIndex + 1; + return Status; +} //SaveSpdToBdat + +/** + Save memory training date structure to BDAT + + @param[in,out] BdatHeaderStructPtr - Pointer to BDAT Structure + @param[in] OffsetFromLastSchema- Offset (in bytes) from the last schema. Need it to update the schema offsets array. + @param[in] SchemaStartAddress - Starting address where the memory training data schema will be added + @param[in, out] SchemaIndex - Current schema index inside the BDAT. Need it to update the schema offsets array. + @param[out] SchemaSpaceUsed - The numebr bytes were filled + + @retval EFI_SUCCESS - Memory training data BDAT scehma created successfully + @retval !EFI_SUCCESS - Memory training data BDAT scehma creation failed +**/ +EFI_STATUS +SaveTrainingDataToBdat ( + IN OUT BDAT_STRUCTURE *BdatHeaderStructPtr, + IN UINT32 OffsetFromLastSchema, + IN EFI_PHYSICAL_ADDRESS *SchemaStartAddress, + IN OUT UINT8 *SchemaIndex, + OUT UINT32 *SchemaSpaceUsed + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + UINT32 *SchemaAddrLocationArray = NULL; + EFI_HOB_GUID_TYPE *GuidHob = NULL; + EFI_PHYSICAL_ADDRESS Address = 0; + MEM_TRAINING_DATA_HEADER *TrainingDataHeader = NULL; + MEM_TRAINING_DATA_HOB_HEADER *TrainingDataHobHeader = NULL; + EFI_GUID TrainingDataGuid = gMemTrainingDataHobGuid; + BDAT_SCHEMA_HEADER_STRUCTURE *SchemaHeaderPtr = NULL; + INT32 RemainingDataSize = 0; + UINT32 HobSize = 0; + UINT32 TrainingDataSize = 0; + UINT8 HobIndex = 0; + + if ((BdatHeaderStructPtr == NULL) || (SchemaStartAddress == NULL) || (SchemaIndex == NULL) || (SchemaSpaceUsed == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Address = *SchemaStartAddress; + *SchemaSpaceUsed = 0; + + DEBUG ((DEBUG_VERBOSE, "\nStarting to copy memory training data schema at Address = 0x%x\n", Address)); + + // + // Update the schema offset arrary + // + SchemaAddrLocationArray = (UINT32 *)((EFI_PHYSICAL_ADDRESS)BdatHeaderStructPtr + sizeof(BDAT_STRUCTURE)); + + if (*SchemaIndex < BdatHeaderStructPtr->BdatSchemas.SchemaListLength) { + if (*SchemaIndex == 0) { + SchemaAddrLocationArray[*SchemaIndex] = OffsetFromLastSchema; + } + else { + SchemaAddrLocationArray[*SchemaIndex] = SchemaAddrLocationArray[*SchemaIndex - 1] + OffsetFromLastSchema; + } + } + + SchemaHeaderPtr = (BDAT_SCHEMA_HEADER_STRUCTURE *)Address; + SchemaHeaderPtr->SchemaId = gMemTrainingDataBdatSchemaGuid; + *SchemaSpaceUsed = *SchemaSpaceUsed + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // CRC16 value of the BDAT_SCHEMA_HEADER_STRUCTURE + // + SchemaHeaderPtr->Crc16 = 0; + Status = CalculateCrc16 ( + (VOID *)SchemaHeaderPtr, + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE), + &SchemaHeaderPtr->Crc16 + ); + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + SchemaHeaderPtr->Crc16 = 0xFFFF; + } + + GuidHob = GetFirstGuidHob (&TrainingDataGuid); + + ASSERT (GuidHob != NULL); + if (GuidHob == NULL) { + DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid)); + return EFI_NOT_FOUND; + } + + TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob); + TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory. + + TrainingDataHeader = (MEM_TRAINING_DATA_HEADER *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER)); + + HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob); + ASSERT (TrainingDataSize <= HobSize); + + HobIndex += 1; + DEBUG ((DEBUG_VERBOSE, "Memory training data structre size:%d\n", TrainingDataHeader->Size)); + SchemaHeaderPtr->DataSize = TrainingDataHeader->Size + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + + // + // This is the total data size in the training data structure. + // + RemainingDataSize = (INT32) TrainingDataHeader->Size; + + DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d\n", RemainingDataSize)); + // + // Copy training data HOBs to RT Memory + // + Address = Address + sizeof(BDAT_SCHEMA_HEADER_STRUCTURE); + CopyMem ((VOID *)Address, (VOID *)TrainingDataHeader, TrainingDataSize); + + *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize; + + Address = Address + TrainingDataSize; + RemainingDataSize -= TrainingDataSize; + + while (RemainingDataSize > 0) { + + GuidHob = GET_NEXT_HOB (GuidHob); // Increment to next HOB + GuidHob = GetNextGuidHob (&TrainingDataGuid, GuidHob); // Now search for next instance of the BDAT HOB + + ASSERT (GuidHob != NULL); + if (GuidHob == NULL) { + DEBUG ((DEBUG_ERROR, "Not found training data HOB with GUID:%g\n", &TrainingDataGuid)); + return EFI_NOT_FOUND; + } + + TrainingDataHobHeader = GET_GUID_HOB_DATA (GuidHob); + TrainingDataSize = TrainingDataHobHeader->Size - sizeof (MEM_TRAINING_DATA_HOB_HEADER); // This is the size of data to copy to the RT memory. + + HobSize = GET_GUID_HOB_DATA_SIZE (GuidHob); + ASSERT (TrainingDataSize <= HobSize); + + HobIndex += 1; + + // + // Copy training data HOBs to RT Memory + // + CopyMem ((VOID *)Address, (VOID *)((EFI_PHYSICAL_ADDRESS)TrainingDataHobHeader + sizeof (MEM_TRAINING_DATA_HOB_HEADER)), TrainingDataSize); + + *SchemaSpaceUsed = *SchemaSpaceUsed + TrainingDataSize; + + Address = Address + TrainingDataSize; + RemainingDataSize -= TrainingDataSize; + DEBUG ((DEBUG_VERBOSE, "Remaining training data:%d after copying Hob:%d \n", RemainingDataSize, HobIndex)); + } + + // + // Update training data header structure CRC, after all the training data were copied from HOBs to a RT contiguous memory region. + // + TrainingDataHeader->Crc = 0; + TrainingDataHeader->Crc = CalculateCrc32 ((VOID *) TrainingDataHeader, TrainingDataHeader->Size); + + *SchemaIndex = *SchemaIndex + 1; + + return EFI_SUCCESS; +} //SaveTrainingDataToBdat diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c new file mode 100644 index 0000000000..29722c1269 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibDsdt.c @@ -0,0 +1,673 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + + +#define CPM_MMIO_SIZE 0x100000000 // 4G MMIO resource for CPM +#define HQM_MMIO_SIZE 0x400000000 // 16G MMIO resource for HQM + +extern BIOS_ACPI_PARAM *mAcpiParameter; +extern struct SystemMemoryMapHob *mSystemMemoryMap; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; + +extern SOCKET_MP_LINK_CONFIGURATION mSocketMpLinkConfiguration; +extern SOCKET_IIO_CONFIGURATION mSocketIioConfiguration; +extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration; + +extern BOOLEAN mCpuOrderSorted; +extern UINT32 mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD]; +extern UINT32 mNumOfBitShift; +extern CPU_ID_ORDER_MAP mCpuApicIdOrderTable[MAX_CPU_NUM]; + + +AML_OFFSET_TABLE_ENTRY *mAmlOffsetTablePointer = NULL; + +/** + Check current thread status + + @param ApicId - current thread ApicId + + @retval EFI_SUCCESS Returns Success if current thread is active + @retval EFI_UNSUPPORTED Table is not supported +**/ +EFI_STATUS +CheckCurrentThreadStatus ( + UINT32 ApicId + ) +{ + UINT32 Index; + + for (Index = 0; Index < MAX_CPU_NUM; Index++) { + if ((mCpuApicIdOrderTable[Index].Flags == 1) && (mCpuApicIdOrderTable[Index].ApicId == ApicId)) { + return EFI_SUCCESS; + } + } + return EFI_UNSUPPORTED; +} + + +/** + Get socket, stack and optionaly port index from PCI device path. + + The PCI device path is typically: + '_SB_.PCxy.FIXz' for PCIe stack object + '_SB_.UCxy.FIXz' for UBOX stack object + '_SB_.PCxy.RPya' for PCIe bridge root port object + where x and y are hex digits, and 'a' is a letter like 'A', 'B',..,'H'. + + NOTE: 'xy' is decimal number of subsequent PCIe stack, not including UBOX. + For UBOX UCxy, 'x' is socket, 'y' is stack. + + @param[in] DevPathPtr - PCI device path, e.g. '_SB_.PC00.FIX1' + @param[out] SocketPtr - Buffer for socket index. + @param[out] StackPtr - Buffer for stack index. + @param[out] PortkPtr - Buffer for port index. +**/ +VOID +AcpiPciDevPath2SktStkPort ( + IN CHAR8 *DevPathPtr, + OUT UINT8 *SocketPtr, + OUT UINT8 *StackPtr, + OUT UINT8 *PortPtr + ) +{ + UINT16 SysStackNo; + UINT8 SocketNo = 0xFF; + UINT8 StackNo = 0xFF; + UINT8 PortNo = 0xFF; + + if (PortPtr != NULL) { + // + // Device path should contain bridge root port object, let's verify. + // + if (AsciiStrLen (DevPathPtr) < 3*4 + 2 || + DevPathPtr[10] != 'R' || DevPathPtr[12] != 'P' || DevPathPtr[13] < 'A' || DevPathPtr[13] > 'H') { + + goto ErrExit; + } + PortNo = DevPathPtr[13] - 'A'; + } + if (AsciiStrLen (DevPathPtr) < 2*4 + 1 || DevPathPtr[7] < '0' || DevPathPtr[8] < '0') { + + goto ErrExit; + } + switch (DevPathPtr[5] << 8 | DevPathPtr[6]) { + + case ('P' << 8 | 'C'): + if (DevPathPtr[7] > '9' || DevPathPtr[8] > '9') { + + goto ErrExit; + } + SysStackNo = (DevPathPtr[7] - '0') * 10; + SysStackNo += DevPathPtr[8] - '0'; + SocketNo = (UINT8)(SysStackNo / MAX_IIO_STACK); + StackNo = (UINT8)(SysStackNo % MAX_IIO_STACK); + break; + + case ('U' << 8 | 'C'): + if (DevPathPtr[7] <= '9') { + + SocketNo = DevPathPtr[7] - '0'; + + } else if (DevPathPtr[7] <= 'F') { + + if (DevPathPtr[7] < 'A') { + + goto ErrExit; + } + SocketNo = 10 + DevPathPtr[7] - 'A'; + + } else if (DevPathPtr[7] <= 'f') { + + if (DevPathPtr[7] < 'a') { + + goto ErrExit; + } + SocketNo = 10 + DevPathPtr[7] - 'a'; + + } else { + goto ErrExit; + } + if (DevPathPtr[8] <= '9') { + + StackNo = DevPathPtr[8] - '0'; + + } else if (DevPathPtr[8] <= 'F') { + + if (DevPathPtr[8] < 'A') { + + goto ErrExit; + } + StackNo = 10 + DevPathPtr[8] - 'A'; + + } else { + goto ErrExit; + } + break; + + default: + ErrExit: + DEBUG ((DEBUG_ERROR, "[ACPI] ERROR: String '%a' is not valid PCI stack name, ", DevPathPtr)); + DEBUG ((DEBUG_ERROR, "expect _SB_.PCxy.FIXz, or _SB_.UCxv.FIXz, or _SB_.PCxy.RPya\n")); + break; + } + if (SocketPtr != NULL) { + *SocketPtr = SocketNo; + } + if (StackPtr != NULL) { + *StackPtr = StackNo; + } + if (PortPtr != NULL) { + *PortPtr = PortNo; + } + return; +} + + +/** + Update the DSDT table + + @param[in,out] *Table - The table to be set + + @retval EFI_SUCCESS - DSDT updated + @retval EFI_INVALID_PARAMETER - DSDT not updated +**/ +EFI_STATUS +PatchDsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status; + UINT8 *DsdtPointer; + UINT32 *Signature; + UINT32 *Signature2; + UINT32 Fixes; + UINT32 NodeIndex; + UINT8 Counter; + UINT16 i; // DSDT_PLATEXRP_OffsetTable LUT entries extends beyond 256! + UINT8 BusBase = 0, BusLimit = 0; + UINT16 IoBase = 0, IoLimit = 0; + UINT32 MemBase32 = 0, MemLimit32 = 0; + UINT64 MemBase64 = 0, MemLimit64 = 0; + AML_RESOURCE_ADDRESS16 *AmlResourceAddress16Pointer; + AML_RESOURCE_ADDRESS32 *AmlResourceAddress32Pointer; + AML_RESOURCE_ADDRESS64 *AmlResourceAddress64Pointer; + EFI_ACPI_DESCRIPTION_HEADER *TableHeader; + UINT32 AdjustSize = 0; + UINT32 CpuSkt = 0; + UINT32 CpuIndex = 0; + ACPI_NAMEPACK_DWORD *NamePtr; + UINT8 *CurrPtr; + UINT8 *EndPtr; + const UINT32 *ApicMapPtr; + UINT8 Socket; + UINT8 Stack; + UINT8 UboxStack; + UINT8 PropagateSerrOption; + UINT8 PropagatePerrOption; + + Status = GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CONFIGURATION, PropagateSerr), &PropagateSerrOption, sizeof(PropagateSerrOption)); + if (EFI_ERROR (Status)) { + mAcpiParameter->PropagateSerrOption = 1; + } else { + mAcpiParameter->PropagateSerrOption = PropagateSerrOption; + } + + Status = GetOptionData (&gEfiSetupVariableGuid, OFFSET_OF(SYSTEM_CONFIGURATION, PropagatePerr), &PropagatePerrOption, sizeof(PropagatePerrOption)); + if (EFI_ERROR (Status)) { + mAcpiParameter->PropagatePerrOption = 1; + } else { + mAcpiParameter->PropagatePerrOption = PropagatePerrOption; + } + + TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Table; + + if (mAmlOffsetTablePointer == NULL) { + return EFI_INVALID_PARAMETER; + } + + mAcpiParameter->SocketBitMask = mCpuCsrAccessVarPtr->socketPresentBitMap; + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if (!mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) { + mAcpiParameter->IioPresentBitMask[Socket] = 0; + continue; + } + mAcpiParameter->IioPresentBitMask[Socket] = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].stackPresentBitmap; + for (Stack = 0; Stack < MAX_LOGIC_IIO_STACK; Stack++) { + + mAcpiParameter->BusBase[Socket][Stack] = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusBase; + DEBUG ((DEBUG_INFO, "[ACPI](DSDT) [%d.%d] BusBase: 0x%02X\n", Socket, Stack, mAcpiParameter->BusBase[Socket][Stack])); + } + } // for (Socket...) + + // + // Update IIO PCIe Root Port PCIe Capability offset + // for 10nm process CPUs with PCIe GEN4/GEN5 controller, PCIe Capability offset is at 0x40 + // + mAcpiParameter->IioPcieRpCapOffset = 0x40; + + // + // Initialize TsegSize - 1MB aligned. + // + Fixes = 0; + // + // Loop through the AML looking for values that we must fix up. + // + for (i = 0; mAmlOffsetTablePointer[i].Pathname != 0; i++) { + // + // Point to offset in DSDT for current item in AmlOffsetTable. + // + DsdtPointer = (UINT8 *) (TableHeader) + mAmlOffsetTablePointer[i].Offset; + + if (mAmlOffsetTablePointer[i].Opcode == AML_DWORD_PREFIX) { + // + // If Opcode is 0x0C, then operator is Name() or OperationRegion(). + // (TableHeader + AmlOffsetTable.Offset) is at offset for value to change. + // + // The assert below confirms that AML structure matches the offsets table. + // If not then patching the AML would just corrupt it and result in OS failure. + // If you encounter this assert something went wrong in *.offset.h files + // generation. Remove the files and rebuild. + // + ASSERT (DsdtPointer[-1] == mAmlOffsetTablePointer[i].Opcode); + // + // AmlOffsetTable.Value has FIX tag, so check that to decide what to modify. + // + Signature = (UINT32 *) (&mAmlOffsetTablePointer[i].Value); + switch (*Signature) { + // + // Due to iASL compiler change and DSDT patch design change, if these items need support + // then the ASI files will need to conform to the format requires for iASL to add the items + // to the offset table, and we will need to filter them out when iASL is executed. + // + // "FIX0" OperationRegion() in Acpi\AcpiTables\Dsdt\CommonPlatform.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '0')): + *(UINT32*)DsdtPointer = (UINT32)(UINTN)mAcpiParameter; + Fixes++; + break; + + default: + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n", + mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode)); + break; + } + } else if (mAmlOffsetTablePointer[i].Opcode == AML_INDEX_OP) { + // + // If Opcode is 0x88, then operator is WORDBusNumber() or WORDIO(). + // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS16 to change values. + // + AmlResourceAddress16Pointer = (AML_RESOURCE_ADDRESS16 *) (DsdtPointer); + // + // The assert below confirms that AML structure matches the offsets table. + // If not then patching the AML would just corrupt it and result in OS failure. + // If you encounter this assert something went wrong in *.offset.h files + // generation. Remove the files and rebuild. + // + ASSERT (AmlResourceAddress16Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode); + + // + // Last 4 chars of AmlOffsetTable.Pathname has FIX tag. + // + Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4); + Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9); + switch (*Signature) { + // + // "FIX1" BUS resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '1')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + + BusBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusBase; + BusLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].BusLimit; + + AmlResourceAddress16Pointer->Granularity = 0; + if ((BusLimit > BusBase)) { + AmlResourceAddress16Pointer->Minimum = (UINT16) BusBase; + AmlResourceAddress16Pointer->Maximum = (UINT16) BusLimit; + AmlResourceAddress16Pointer->AddressLength = (UINT16) (BusLimit - BusBase + 1); + } + + Fixes++; + break; + + // + // "FIXB" BUS resource for FpgaKtiXX in Acpi\AcpiTables\Dsdt\FpgaKtiXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', 'B')): + break; + + // + // "FIX2" IO resource for for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '2')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + + IoBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoBase; + IoLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceIoLimit; + if (IoLimit > IoBase) { + AmlResourceAddress16Pointer->Minimum = (UINT16) IoBase; + AmlResourceAddress16Pointer->Maximum = (UINT16) IoLimit; + AmlResourceAddress16Pointer->AddressLength = (UINT16) (IoLimit - IoBase + 1); + } + AmlResourceAddress16Pointer->Granularity = 0; + + Fixes++; + break; + + // + // "FIX9" BUS resource for UNXX in Acpi\AcpiTables\Dsdt\Uncore.asi + // + case (SIGNATURE_32('F', 'I', 'X', '9')) : + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + UboxStack = UBOX_STACK; + BusBase = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].BusBase; + BusLimit = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].BusLimit; + if (mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].Personality != TYPE_UBOX || + BusBase > BusLimit) { + + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) ERROR: Stack [%d.%d] of type %d is not UBOX, '%a' not patched\n", + Socket, UboxStack, mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[UboxStack].Personality, + mAmlOffsetTablePointer[i].Pathname)); + break; + } + AmlResourceAddress16Pointer->Granularity = 0; + if (Stack & 1) { + AmlResourceAddress16Pointer->Minimum = BusLimit; + AmlResourceAddress16Pointer->Maximum = BusLimit; + } else { + AmlResourceAddress16Pointer->Minimum = BusBase; + AmlResourceAddress16Pointer->Maximum = BusBase; + } + AmlResourceAddress16Pointer->AddressLength = 1; + mAcpiParameter->BusBase[Socket][Stack] = (UINT8)AmlResourceAddress16Pointer->Minimum; + mAcpiParameter->IioPresentBitMask[Socket] |= 1 << Stack; + Fixes++; + break; + + // + // "FIX6" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '6')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + AmlResourceAddress16Pointer->Granularity = 0; + if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) && + (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)){ + + AmlResourceAddress16Pointer->Minimum = (UINT16) 0x03b0; + AmlResourceAddress16Pointer->Maximum = (UINT16) 0x03bb; + AmlResourceAddress16Pointer->AddressLength = (UINT16) 0x000C; + } + Fixes++; + break; + + // + // "FIX7" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '7')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + AmlResourceAddress16Pointer->Granularity = 0; + if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) && + (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)) { + + AmlResourceAddress16Pointer->Minimum = (UINT16) 0x03c0; + AmlResourceAddress16Pointer->Maximum = (UINT16) 0x03df; + AmlResourceAddress16Pointer->AddressLength = (UINT16) 0x0020; + } + Fixes++; + break; + + default: + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n", + mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode)); + break; + } + } else if (mAmlOffsetTablePointer[i].Opcode == AML_SIZE_OF_OP) { + // + // If Opcode is 0x87, then operator is DWORDMemory(). + // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS32 to change values. + // + AmlResourceAddress32Pointer = (AML_RESOURCE_ADDRESS32 *) (DsdtPointer); + // + // The assert below confirms that AML structure matches the offsets table. + // If not then patching the AML would just corrupt it and result in OS failure. + // If you encounter this assert something went wrong in *.offset.h files + // generation. Remove the files and rebuild. + // + ASSERT (AmlResourceAddress32Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode); + // + // Last 4 chars of AmlOffsetTable.Pathname has FIX tag. + // + Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4); + Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9); + switch (*Signature) { + // + // "FIX3" PCI32 resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '3')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + + MemBase32 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Base; + MemLimit32 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem32Limit; + + if (MemLimit32 > MemBase32) { + AmlResourceAddress32Pointer->Minimum = (UINT32) MemBase32; + AmlResourceAddress32Pointer->Maximum = (UINT32) MemLimit32; + AmlResourceAddress32Pointer->AddressLength = (UINT32) (MemLimit32 - MemBase32 + 1); + } + AmlResourceAddress32Pointer->Granularity = 0; + + Fixes++; + break; + + // + // "FIX5" IO resource for PCXX in Acpi\AcpiTables\Dsdt\PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '5')): + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + AmlResourceAddress32Pointer->Granularity = 0; + if ((mSocketMpLinkConfiguration.LegacyVgaSoc == Socket) && + (mSocketMpLinkConfiguration.LegacyVgaStack == Stack)) { + AmlResourceAddress32Pointer->Minimum = 0x000a0000; + AmlResourceAddress32Pointer->Maximum = 0x000bffff; + AmlResourceAddress32Pointer->AddressLength = 0x00020000; + } + Fixes++; + break; + + // + // "FIXZ" IO resource for FpgaBusXX in Acpi\AcpiTables\Dsdt\FpgaBusXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', 'Z')): + break; + + default: + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n", + mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode)); + break; + } + } else if (mAmlOffsetTablePointer[i].Opcode == AML_CREATE_DWORD_FIELD_OP) { + // + // If Opcode is 0x8A, then operator is QWORDMemory(). + // (TableHeader + AmlOffsetTable.Offset) must be cast to AML_RESOURCE_ADDRESS64 to change values. + // + AmlResourceAddress64Pointer = (AML_RESOURCE_ADDRESS64 *) (DsdtPointer); + // + // The assert below confirms that AML structure matches the offsets table. + // If not then patching the AML would just corrupt it and result in OS failure. + // If you encounter this assert something went wrong in *.offset.h files + // generation. Remove the files and rebuild. + // + ASSERT (AmlResourceAddress64Pointer->DescriptorType == mAmlOffsetTablePointer[i].Opcode); + // + // Last 4 chars of AmlOffsetTable.Pathname has FIX tag. + // + Signature = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 4); + Signature2 = (UINT32 *) (mAmlOffsetTablePointer[i].Pathname + AsciiStrLen(mAmlOffsetTablePointer[i].Pathname) - 9); + switch (*Signature) { + // + // "FIX4" PCI64 resource for PCXX in Acpi\AcpiTables\Dsdt\SysBus.asi and PCXX.asi + // + case (SIGNATURE_32 ('F', 'I', 'X', '4')): + if (mSocketIioConfiguration.Pci64BitResourceAllocation) { + + AcpiPciDevPath2SktStkPort (mAmlOffsetTablePointer[i].Pathname, &Socket, &Stack, NULL); + MemBase64 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Base; + MemLimit64 = mIioUds->IioUdsPtr->PlatformData.IIO_resource[Socket].StackRes[Stack].PciResourceMem64Limit; + if (MemLimit64 > MemBase64) { + AmlResourceAddress64Pointer->Granularity = 0; + AmlResourceAddress64Pointer->Minimum = (UINT64) MemBase64; + AmlResourceAddress64Pointer->Maximum = (UINT64) MemLimit64; + AmlResourceAddress64Pointer->AddressLength = (UINT64) (MemLimit64 - MemBase64 + 1); + } + + Fixes++; + } + break; + + default: + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n", + mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode)); + break; + } + } else { + DEBUG ((DEBUG_ERROR, "[ACPI](DSDT) WARNING: Object '%a' with opcode 0x%02X not patched\n", + mAmlOffsetTablePointer[i].Pathname, mAmlOffsetTablePointer[i].Opcode)); + } + } + + // CurrPtr = beginning of table + // + CurrPtr = (UINT8 *) TableHeader; + + // EndPtr = beginning of table + length of table + // + EndPtr = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); + + // Subtract from End Ptr the largest data item we read from table + // so we don't try to access data beyond end of table + // + EndPtr -= 9; + + for (DsdtPointer = CurrPtr; DsdtPointer <= EndPtr; DsdtPointer++) { + + // + // fix CpuMemHp.asi, force no same ASL code string as it... + // + if ((DsdtPointer[0] == 'C') && (DsdtPointer[6] == 0x4) && (DsdtPointer[5] == 0x10)) { + if (mCpuOrderSorted) { + CpuSkt = (UINT32) DsdtPointer[4]; + AdjustSize = 0; + if ((DsdtPointer[1] > '0') && (DsdtPointer[1] <= '9')) { + AdjustSize = (UINT32) ((DsdtPointer[1] -'0') * 0x100); + } else if ((DsdtPointer[1] >= 'A') && (DsdtPointer[1] <= 'F')) { + AdjustSize = (UINT32) ((DsdtPointer[1] -'A' + 10) * 0x100); + } + + CpuIndex = AdjustSize; + + AdjustSize = 0; + if ((DsdtPointer[2] > '0') && (DsdtPointer[2] <= '9')) { + AdjustSize = (UINT32) ((DsdtPointer[2] -'0') * 0x10); + } else if ((DsdtPointer[2] >= 'A') && (DsdtPointer[2] <= 'F')) { + AdjustSize = (UINT32) ((DsdtPointer[2] -'A' + 10) * 0x10); + } + + CpuIndex += AdjustSize; + + AdjustSize = 0; + if ((DsdtPointer[3] > '0') && (DsdtPointer[3] <= '9')) { + AdjustSize = (UINT32) (DsdtPointer[3] -'0'); + } else if ((DsdtPointer[3] >= 'A') && (DsdtPointer[3] <= 'F')) { + AdjustSize = (UINT32) (DsdtPointer[3] -'A' + 10); + } + + CpuIndex += AdjustSize; + + NodeIndex = (UINT32) (CpuSkt << mNumOfBitShift) + mApicIdMap[CpuSkt][CpuIndex] ; + + DsdtPointer[4] = (UINT8) 0xFF; + if (((mCpuCsrAccessVarPtr->socketPresentBitMap >> CpuSkt) & BIT0) == 1) { + if (CheckCurrentThreadStatus (NodeIndex) == EFI_SUCCESS) { + DsdtPointer[4] = (UINT8) (NodeIndex & 0xFF); + } + } + + // + // Update IO Address + // + *(UINT16 *)(DsdtPointer+5) = (UINT16)(PM_BASE_ADDRESS + 0x10); + } + } + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + + if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << Socket)) == 0) { + continue; + } + // + // Find APT##socket name + // + if ((DsdtPointer[0] == 'A') && (DsdtPointer[1] == 'P') && (DsdtPointer[2] == 'T') && (DsdtPointer[3] == '0' + Socket)) { + NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer); + ApicMapPtr = mApicIdMap[Socket]; + if (NamePtr->StartByte != AML_NAME_OP) { + continue; + } + + Counter = DsdtPointer[8]; + ASSERT (Counter >= (UINT32) (MAX_THREAD * MAX_CORE)); + DEBUG ((DEBUG_INFO, "\n::ACPI:: Found 'APT%x'...Counter = DsdtPointer[7] = %x\n\n", Socket, Counter)); + for (i = 0; i < (MAX_THREAD * MAX_CORE); i++) { + DEBUG ((DEBUG_VERBOSE, "Before override, DsdtPointer[%x] = %x, ", i, DsdtPointer[i+9])); + DsdtPointer[i+9] = (UINT8)ApicMapPtr[i]; + DEBUG ((DEBUG_VERBOSE, "Then override value = %x \n", DsdtPointer[i+9])); + } + } + } + // + // Fix up _S3 + // + if ((DsdtPointer[0] == '_') && (DsdtPointer[1] == 'S') && (DsdtPointer[2] == '3')) { + NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer); + if (NamePtr->StartByte != AML_NAME_OP) { + continue; + } + + if (!mSocketPowermanagementConfiguration.AcpiS3Enable) { + // + // S3 disabled + // + DsdtPointer[0] = 'D'; + } + } + // + // Fix up _S4 + // + if ((DsdtPointer[0] == '_') && (DsdtPointer[1] == 'S') && (DsdtPointer[2] == '4')) { + NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (DsdtPointer); + if (NamePtr->StartByte != AML_NAME_OP) { + continue; + } + if (!mSocketPowermanagementConfiguration.AcpiS4Enable) { + // + // S4 disabled + // + DsdtPointer[0] = 'D'; + } + } + } + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c new file mode 100644 index 0000000000..4cdb540a6a --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibFadt.c @@ -0,0 +1,75 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2018 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include + +extern UINT8 mKBPresent; +extern UINT8 mMousePresent; +extern SOCKET_PROCESSORCORE_CONFIGURATION mSocketProcessorCoreConfiguration; +extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration; + + +EFI_STATUS +PatchFadtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT16 LegacyDevice; + EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader; + EFI_STATUS Status; + UINT8 PcieGlobalAspm; + + Status = GetOptionData (&gEfiSocketIioVariableGuid, OFFSET_OF(SOCKET_IIO_CONFIGURATION, PcieGlobalAspm), &PcieGlobalAspm, sizeof(UINT8)); + if (EFI_ERROR (Status)) { + PcieGlobalAspm = 0x2; + } + + // + // Patch FADT for legacy free + // + LegacyDevice = 0; + FadtHeader = (EFI_ACPI_6_2_FIXED_ACPI_DESCRIPTION_TABLE *) Table; + + // + // Control of setting ASPM disabled bit in FADT + // + switch (mSocketPowermanagementConfiguration.NativeAspmEnable) { + + case 0: + LegacyDevice |= (1 << 4); + break; + + case 1: + LegacyDevice &= ~(1 << 4); + break; + + case 2: + if (PcieGlobalAspm == 0) { + LegacyDevice |= (1 << 4); + } else { + LegacyDevice &= ~(1 << 4); + } + break; + + default: + LegacyDevice &= ~(1 << 4); + DEBUG ((DEBUG_ERROR, "\n Native ASPM = %d is not valid (expected values are 0, 1, 2). \n", mSocketPowermanagementConfiguration.NativeAspmEnable )); + ASSERT (0); + break; + } + + FadtHeader->IaPcBootArch = LegacyDevice; + FadtHeader->Flags |= (mSocketProcessorCoreConfiguration.ForcePhysicalModeEnable) ? EFI_ACPI_6_2_FORCE_APIC_PHYSICAL_DESTINATION_MODE : 0; + + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c new file mode 100644 index 0000000000..277c956196 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibHmat.c @@ -0,0 +1,1710 @@ +/** @file + ACPI Platform Library HMAT + + @copyright + Copyright 2016 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include +#include +#include + +// +// The represented latency/bandwidth in 'System Locality Latency and Bandwidth +// Information Structure' is expressed in multiples of Entry Base Unit. +// Unit of latency is picoseconds and bandwidth is megabytes per second +// Below #defines are be base units and values for calcualting the latency/bandwidth +// For example: read latency of DDRT is 180ns which is 180000 picoseconds. +// This is expressed as DDRT_LATENCY_BASE_UNIT of 1000 and DDRT_READ_LATENCY of 180 +// + +#define MEMORY_LATENCY_BASE_UNIT 100 +#define MEMORY_BANDWIDTH_BASE_UNIT 1 +#define DDR2LMCACHE_LATENCY_BASE_UNIT 100 +#define DDR2LMCACHE_BANDWIDTH_BASE_UNIT 1 + +#define XSOCKET_LATENCY_BASE_UNIT 100 +#define XSOCKET_BANDWIDTH_BASE_UNIT 1 + +// +// DDRT values +// +#define DDRT_ACCESS_LATENCY 0 +#define DDRT_1LM_READ_LATENCY 2535 +#define DDRT_2LM_READ_LATENCY 3285 +#define DDRT_1LM_WRITE_LATENCY 2535 +#define DDRT_2LM_WRITE_LATENCY 3285 +#define DDRT_ACCESS_BANDWIDTH 0 +#define DDRT_1LM_READ_BANDWIDTH 4625 +#define DDRT_2LM_READ_BANDWIDTH 4625 +#define DDRT_1LM_WRITE_BANDWIDTH 1375 +#define DDRT_2LM_WRITE_BANDWIDTH 1375 + +// +// X-SOCKET values +// +#define XSOCKET_DDRT_1LM_ACCESS_LATENCY 0 +#define XSOCKET_DDRT_1LM_READ_LATENCY 3160 +#define XSOCKET_DDRT_1LM_WRITE_LATENCY 3160 +#define XSOCKET_DDRT_1LM_ACCESS_BANDWIDTH 0 +#define XSOCKET_DDRT_1LM_READ_BANDWIDTH 4625 +#define XSOCKET_DDRT_1LM_WRITE_BANDWIDTH 1375 + +#define XSOCKET_DDRT_2LM_ACCESS_LATENCY 0 +#define XSOCKET_DDRT_2LM_READ_LATENCY 3885 +#define XSOCKET_DDRT_2LM_WRITE_LATENCY 3885 +#define XSOCKET_DDRT_2LM_ACCESS_BANDWIDTH 0 +#define XSOCKET_DDRT_2LM_READ_BANDWIDTH 4625 +#define XSOCKET_DDRT_2LM_WRITE_BANDWIDTH 1375 + +// +// DDR values 1LM or flat mode +// +#define DDR_ACCESS_LATENCY 0 +#define DDR_READ_LATENCY 760 +#define DDR_WRITE_LATENCY 760 +#define DDR_ACCESS_BANDWIDTH 0 +#define DDR_READ_BANDWIDTH 17900 +#define DDR_WRITE_BANDWIDTH 19100 + +// +// X-Socket DDR values 1LM or flat mode +// +#define XSOCKET_DDR_ACCESS_LATENCY 0 +#define XSOCKET_DDR_READ_LATENCY 1356 +#define XSOCKET_DDR_WRITE_LATENCY 1356 +#define XSOCKET_DDR_ACCESS_BANDWIDTH 0 +#define XSOCKET_DDR_READ_BANDWIDTH 17900 +#define XSOCKET_DDR_WRITE_BANDWIDTH 19100 + +// +// DDR/X-Socket DDR values 2LM when acting as cache +// +#define DDR2LMCACHE_ACCESS_LATENCY 0 +#define DDR2LMCACHE_READ_LATENCY 760 +#define DDR2LMCACHE_WRITE_LATENCY 760 +#define DDR2LMCACHE_ACCESS_BANDWIDTH 0 +#define DDR2LMCACHE_READ_BANDWIDTH 17900 +#define DDR2LMCACHE_WRITE_BANDWIDTH 12691 + + +extern struct SystemMemoryMapHob *mSystemMemoryMap; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +extern SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration; +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; + +UINT8 SkippedEntries = 0; + +typedef enum { + DDR = 0x00, + DDRT, + DDR2LMCACHE +} MemoryType; + + +/** + Dump HMAT Header + + @param [in] HdrPtr Pointer to HMAT Header + + @retval None +**/ +VOID +DumpHeader ( + EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER *HdrPtr + ) +{ + DEBUG ((DEBUG_INFO, "=========== HMAT header ==========\n")); + DEBUG ((DEBUG_INFO, " Signature: %.4a\n", (CHAR8 *)&HdrPtr->Header.Signature)); + DEBUG ((DEBUG_INFO, " Length: %d\n", HdrPtr->Header.Length)); + DEBUG ((DEBUG_INFO, " Revision: %Xh\n", HdrPtr->Header.Revision)); + DEBUG ((DEBUG_INFO, " Checksum: N/A - CHECKSUM ADDED LATER\n")); + DEBUG ((DEBUG_INFO, " OemId: %.6a\n", HdrPtr->Header.OemId)); + DEBUG ((DEBUG_INFO, " OemTableId: %.8a\n", (CHAR8 *)&HdrPtr->Header.OemTableId)); + DEBUG ((DEBUG_INFO, " OemRevision: %Xh\n", HdrPtr->Header.OemRevision)); + DEBUG ((DEBUG_INFO, " CreatorId: %.4a\n", (CHAR8 *)&HdrPtr->Header.CreatorId)); + DEBUG ((DEBUG_INFO, " CreatorRevision: %Xh\n", HdrPtr->Header.CreatorRevision)); + DEBUG ((DEBUG_INFO, "==================================\n")); + DEBUG ((DEBUG_INFO, "\n")); +} + +/** + Dump MSARS Structure + + @param [in] MsarsPtr Pointer to MSARS Structure + + @retval None +**/ +VOID +DumpMsars ( + MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *MsarsPtr + ) +{ + DEBUG ((DEBUG_INFO, "=========== MSARS Table =============================\n")); + DEBUG ((DEBUG_INFO, " Type: %d\n", MsarsPtr->Type)); + DEBUG ((DEBUG_INFO, " Length: %d\n", MsarsPtr->Length)); + DEBUG ((DEBUG_INFO, " ProcessorDomainValid: %d\n", MsarsPtr->Flags.Bits.ProcessorDomainValid)); + DEBUG ((DEBUG_INFO, " MemoryDomainValid: %d\n", MsarsPtr->Flags.Bits.MemoryDomainValid)); + DEBUG ((DEBUG_INFO, " ReservationHint: %d\n", MsarsPtr->Flags.Bits.ReservationHint)); + DEBUG ((DEBUG_INFO, " ProcessorProximityDomain: %Xh\n", MsarsPtr->ProcessorProximityDomain)); + DEBUG ((DEBUG_INFO, " MemoryProximityDomain: %Xh\n", MsarsPtr->MemoryProximityDomain)); + DEBUG ((DEBUG_INFO, " SystemPhysicalAddressRangeBase: %llXh\n", MsarsPtr->AddrBase)); + DEBUG ((DEBUG_INFO, " SystemPhysicalAddressRangeLength: %llXh\n", MsarsPtr->AddrLength)); + DEBUG ((DEBUG_INFO, "=====================================================\n")); + DEBUG ((DEBUG_INFO, "\n")); +} + +/** + Dump HSCIS Structure + + @param [in] MscisPtr Pointer to HSCIS Structure + + @retval None +**/ +VOID +DumpMscis ( + MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE *MscisPtr + ) +{ + UINT8 SmbiosHandleIndex; + + DEBUG ((DEBUG_INFO, "=========== MSCIS Table =============================\n")); + DEBUG ((DEBUG_INFO, " Type: %d\n", MscisPtr->Type)); + DEBUG ((DEBUG_INFO, " Length: %d\n", MscisPtr->Length)); + DEBUG ((DEBUG_INFO, " MemoryProximityDomain: %Xh\n", MscisPtr->MemoryProximityDomain)); + DEBUG ((DEBUG_INFO, " MemorySideCacheSize: %llXh\n", MscisPtr->MemorySideCacheSize)); + DEBUG ((DEBUG_INFO, " TotalCacheLevels: %d\n", MscisPtr->CacheAttributes.Bits.TotalCacheLevels)); + DEBUG ((DEBUG_INFO, " CacheLevel: %d\n", MscisPtr->CacheAttributes.Bits.CacheLevel)); + DEBUG ((DEBUG_INFO, " CacheAssociativity: %d\n", MscisPtr->CacheAttributes.Bits.CacheAssociativity)); + DEBUG ((DEBUG_INFO, " WritePolicy: %d\n", MscisPtr->CacheAttributes.Bits.WritePolicy)); + DEBUG ((DEBUG_INFO, " CacheLineSize: %d\n", MscisPtr->CacheAttributes.Bits.CacheLineSize)); + DEBUG ((DEBUG_INFO, " NumSmbiosHandles: %d\n", MscisPtr->NumSmbiosHandles)); + + for (SmbiosHandleIndex = 0; SmbiosHandleIndex < MscisPtr->NumSmbiosHandles; SmbiosHandleIndex++) { + DEBUG ((DEBUG_INFO, " SmbiosHandle[%d]: %xh\n", SmbiosHandleIndex + 1 ,MscisPtr->SmbiosHandles[SmbiosHandleIndex])); + } + DEBUG ((DEBUG_INFO, "=====================================================\n")); + DEBUG ((DEBUG_INFO, "\n")); +} + +/** + Dump LBIS Structure + + @param [in] LbisPtr Pointer to LBIS Structure + + @retval None +**/ +VOID +DumpLbis ( + LATENCY_BANDWIDTH_INFO_STRUCTURE *LbisPtr + ) +{ + UINTN Index, Index1; + UINT32 *TargetProximityDomainList; + UINT16 *Entry; + + DEBUG ((DEBUG_INFO, "=========== MLBIS Table =============================\n")); + DEBUG ((DEBUG_INFO, " Type: %d\n", LbisPtr->Type)); + DEBUG ((DEBUG_INFO, " Length: %d\n", LbisPtr->Length)); + DEBUG ((DEBUG_INFO, " Flags: %d\n", LbisPtr->Flags)); + DEBUG ((DEBUG_INFO, " DataType: %d\n", LbisPtr->DataType)); + DEBUG ((DEBUG_INFO, " InitiatorProximityDomainsNumber: %d\n", LbisPtr->InitiatorProximityDomainsNumber)); + DEBUG ((DEBUG_INFO, " TargetProximityDomainsNumber: %d\n", LbisPtr->TargetProximityDomainsNumber)); + DEBUG ((DEBUG_INFO, " EntryBaseUnit: %lXh\n", LbisPtr->EntryBaseUnit)); + DEBUG ((DEBUG_INFO, " InitiatorProximityDomainList:\n")); + + for (Index = 0; Index < LbisPtr->InitiatorProximityDomainsNumber; Index++) { + DEBUG ((DEBUG_INFO, " %d ", LbisPtr->InitiatorProximityDomainList[Index])); + } + TargetProximityDomainList = (UINT32*)&(LbisPtr->InitiatorProximityDomainList[Index]); + DEBUG ((DEBUG_INFO, "\n")); + + DEBUG ((DEBUG_INFO, " TargetProximityDomainList:\n")); + for (Index = 0; Index < LbisPtr->TargetProximityDomainsNumber; Index++) { + DEBUG ((DEBUG_INFO, " %d ", TargetProximityDomainList[Index])); + } + Entry = (UINT16*)(TargetProximityDomainList + Index); + DEBUG ((DEBUG_INFO, "\n")); + + DEBUG ((DEBUG_INFO, "RelativeDistanceEntry:\n")); + for (Index = 0; Index < LbisPtr->InitiatorProximityDomainsNumber; Index++) { + for (Index1 = 0; Index1 < LbisPtr->TargetProximityDomainsNumber; Index1++) { + DEBUG ((DEBUG_INFO, " %d ", *(Entry + (Index * LbisPtr->TargetProximityDomainsNumber) + Index1))); + } + DEBUG ((DEBUG_INFO, "\n")); + } + DEBUG ((DEBUG_INFO, "\n")); + DEBUG ((DEBUG_INFO, "=====================================================\n")); + DEBUG ((DEBUG_INFO, "\n")); +} + + +/** + Dump HMAT table + + @param [in] HmatAcpiTable Pointer to HMAT table. + + @retval None +**/ +VOID +DumpHmat ( + EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *HmatAcpiTable + ) +{ + UINT32 TotalLength = HmatAcpiTable->HmatHeader.Header.Length; + UINT8 *Table = (UINT8 *)HmatAcpiTable; + UINT32 Length; + UINT16 Type; + + DumpHeader (&HmatAcpiTable->HmatHeader); + Length = sizeof (EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE_HEADER); + + Table += Length; + TotalLength -= Length; + + // + // Dump tables + // + while (TotalLength) { + Type = ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table)->Type; + // + // For HBM will need to add LBIS structure + // + if (Type == MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE_TYPE) { + DumpMsars ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table); + } else if (Type == MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE_TYPE) { + DumpMscis ((MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE *)Table); + } else { + DumpLbis ((LATENCY_BANDWIDTH_INFO_STRUCTURE *)Table); + } + + // + // Goto next entry + // + Length = ((MEMORY_SUBSYSTEM_ADDRESS_RANGE_STRUCTURE *)Table)->Length; + Table += Length; + TotalLength -= Length; + } +} + +/** + Update SMBIOS handles and number of SMBIOS handles which is related to specified NodeId to MEMORY_DOMAIN_LIST_INFO + + SMBIOS Type 17 handles are formed in sequence order. First handle is S0 C0 D0, Second handle is S0 C0 D1 and so on. + So we loop in this order to find the handles of DDR which is part of the specific 2LM cache memory. + + @param [in] HmatData Points to HMAT structure + @param [in] NodeId SMBIOS handles related to this NodeId will be retrieved + + @retval None +**/ +VOID +UpdateSmbiosHandles( + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData, + IN UINT32 NodeId, + IN UINT8 Socket, + IN UINT32 ImcBitMap + ) +{ + EFI_STATUS Status; + STATIC EFI_SMBIOS_PROTOCOL *Smbios = NULL; + SMBIOS_TABLE_TYPE17 *Type17Record; + EFI_SMBIOS_TABLE_HEADER *SmbiosRecord; + EFI_SMBIOS_HANDLE SmbiosHandle; + EFI_SMBIOS_TYPE SmbiosType; + UINT8 Loop = 1; + UINT8 SlotsPerImc = MAX_DIMM * MAX_MC_CH; + UINT8 DimmsPerImc = 0; + + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, &Smbios); + if (EFI_ERROR (Status)) { + return ; + } + + SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED; + SmbiosType = 17; + + // + // Adjust ImcBitMap according to the socket number + // + if (Socket != 0) { + ImcBitMap <<= (Socket * SlotsPerImc); + } + + if (!PcdGetBool (PcdHalfWidth)) { + DimmsPerImc = SlotsPerImc; + } else { + DimmsPerImc = SlotsPerImc - 1; + } + + do { + Status = Smbios->GetNext(Smbios, &SmbiosHandle, &SmbiosType, &SmbiosRecord, NULL); + if (!EFI_ERROR (Status) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED)) { + Type17Record = (SMBIOS_TABLE_TYPE17 *)SmbiosRecord; + + // + // 1) check whether the Memory device of this record is cache capable(ie, 2LM DDR cache) and + // 2) this memory handle is to the current looping IMC + // + if ((Type17Record->TypeDetail.CacheDram) && (ImcBitMap & BIT0)) { + HmatData->MemoryDomainList[NodeId].SmbiosHandles[HmatData->MemoryDomainList[NodeId].NumSmbiosHandles] = Type17Record->Hdr.Handle ; + HmatData->MemoryDomainList[NodeId].NumSmbiosHandles++; + } + } + // + // if loop done for this IMC then move for next + // + if (Loop % DimmsPerImc == 0) { + ImcBitMap >>= 1; + } + ++Loop; + } while (!EFI_ERROR (Status) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) && (ImcBitMap != 0)); +} + +/** + Remove slack by moving this substructure lower which removes unused memory. + + @param [in] SlackSize Points to cumulative unused memory size + @param [in] Src Points to memory to move + @param [in] SrcLen Size of memory to move + + @retval None +**/ +VOID +RemoveSlack ( + IN UINTN *SlackSize, + IN VOID *Src, + IN UINTN SrcLen + ) +{ + VOID *Dst; + + Dst = (UINT8 *)Src - (*SlackSize); + CopyMem (Dst, Src, SrcLen); +} + +/** + Calculate the Memory Proximity Domain Number and generate its associate list. + + @param [in, out] HmatData Pointer to HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be filled + + @retval None. +**/ +VOID +GetMemoryDomains ( + IN OUT HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData +) +{ + UINT64 MemorySideCacheSize; + UINT32 NodeId; + UINT32 LastDomainId = 0; + UINT8 Index; + UINT8 PrevIndex; + UINT8 LastIndex = 0; + UINT8 Mc; + UINT8 Socket; + UINT8 McBitmap[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS]; + UINT32 PmemEntry[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS]; + UINT64 MemoryAddressStore[EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS]; + UINT64 MemoryAddress; + UINT8 MaxEnabledImc = 0; + UINTN ImcIndex; + UINT8 MemSocketBitmap = 0; + UINT8 NoMemSocketBitmap; + BOOLEAN SkipEntry; + BOOLEAN UpdateSmbiosHandle = FALSE; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + HmatData->MemoryDomainNumber = 0; + + ZeroMem (McBitmap, sizeof(McBitmap)); + ZeroMem (MemoryAddressStore, sizeof(MemoryAddressStore)); + + // + // Memory Proximity Domain must match the Domain in the SRAT Memory Affinity structure + // + for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) { + // + // Skip any memory region marked reserved + // + if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) { + continue; + } + + if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) { + // + // Skip all non volatile regions + // + PmemEntry[SkippedEntries] = Index; + SkippedEntries++; + continue; + } + + SkipEntry = FALSE; + + MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[Index].BaseAddress, MEM_ADDR_SHFT_VAL); + + // + // Skip duplicate entries + // + if (Index) { + for (PrevIndex = 0; PrevIndex < Index; PrevIndex++) { + if (MemoryAddress == MemoryAddressStore[PrevIndex]) { + SkipEntry = TRUE; + break; + } + } + } + if (SkipEntry) { + continue; + } + + MemoryAddressStore[Index] = MemoryAddress; + LastIndex = Index; + + for (ImcIndex = 0, MaxEnabledImc = 0; ImcIndex < MAX_IMC; ImcIndex++) { + if (mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imcEnabled[ImcIndex] != 0) { + MaxEnabledImc ++; + } + } + + // + // Update bitmap for sockets with memory populated + // + MemSocketBitmap |= BIT0 << mSystemMemoryMap->Element[Index].SocketId; + + // + // Get memory domain (must match SRAT memory domain) + // + NodeId = ProximityDomainOf ( + mSystemMemoryMap->Element[Index].SocketId, + mSystemMemoryMap->Element[Index].Type, + MaxEnabledImc, + HmatData->SncEnabled, + HmatData->SncNumOfCluster, + mSystemMemoryMap->Element[Index].ImcInterBitmap, + mSystemMemoryMap->volMemMode, + LastDomainId + ); + + NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster); + + if (LastDomainId < NodeId) { + LastDomainId = NodeId; + } + + if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) { + DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Memory Proximity Domain (0x%x)\n", NodeId)); + ASSERT (FALSE); + } + + // + // Update map of indexes included in this memory domain + // + HmatData->MemoryDomainList[NodeId].MemMapIndexMap |= LShiftU64 (BIT0, Index); + + // + // Update Memory domain count and set domain to valid + // Prevent counting repeated entries with the same Proximity Domain ID + // + if ((Index == 0) || (HmatData->MemoryDomainList[NodeId].Valid == 0)) { + HmatData->MemoryDomainNumber++; + HmatData->MemoryDomainList[NodeId].PhysicalSocketId = mSystemMemoryMap->Element[Index].SocketId; + HmatData->MemoryDomainList[NodeId].Valid = 1; + McBitmap[NodeId] = 0; + } + + if (HmatData->MemoryDomainList[NodeId].Valid) { + if (mSystemMemoryMap->Element[Index].Type == MemType2lmDdrCacheMemoryMode) { + // + // Set up side cache info for 2LM + // + HmatData->MemoryDomainList[NodeId].Cacheable = 1; + + // + // Calculate MemorySideCacheSize + // MemorySideCacheSize for each MC is the DDR4 memSize + // + MemorySideCacheSize = 0; + UpdateSmbiosHandle = FALSE; + + for (Mc = 0; Mc < MAX_IMC; Mc++) { + if ((mSystemMemoryMap->Element[Index].ImcInterBitmap & (BIT0 << Mc)) && !(McBitmap[NodeId] & (BIT0 << Mc))) { + UpdateSmbiosHandle = TRUE; + if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) { + MemorySideCacheSize += mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imc[Mc].MemSize; + } else{ // VOL_MEM_MODE_MIX_1LM2LM + MemorySideCacheSize += mSystemMemoryMap->DdrCacheSize[mSystemMemoryMap->Element[Index].SocketId][Mc]; + } + } + } + + if (UpdateSmbiosHandle) { + UpdateSmbiosHandles ( + HmatData, + NodeId, + mSystemMemoryMap->Element[Index].SocketId, + mSystemMemoryMap->Element[Index].ImcInterBitmap + ); + } + HmatData->MemoryDomainList[NodeId].MemorySideCacheSize += MemorySideCacheSize; + } + McBitmap[NodeId] |= mSystemMemoryMap->Element[Index].ImcInterBitmap; + } + + DEBUG ((DEBUG_INFO, "MemoryDomainList[%x] Valid = %x Cacheable = %x MemorySideCacheSize = %x\n", + NodeId, + HmatData->MemoryDomainList[NodeId].Valid, + HmatData->MemoryDomainList[NodeId].Cacheable, + HmatData->MemoryDomainList[NodeId].MemorySideCacheSize + )); + } + + // + // Update LastDomainId for enabled sockets with no memory + // + NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap; + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if ((BIT0 << Socket) & NoMemSocketBitmap) { + LastDomainId += HmatData->SncNumOfCluster; + } + } + + // + // Add skipped entries + // + for (Index = 0; Index < SkippedEntries; Index++) { + SkipEntry = FALSE; + MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[PmemEntry[Index]].BaseAddress, MEM_ADDR_SHFT_VAL); + + // + // Skip duplicate entries + // + for (PrevIndex = 0; PrevIndex < LastIndex; PrevIndex++) { + if (MemoryAddress == MemoryAddressStore[PrevIndex]) { + SkipEntry = TRUE; + break; + } + } + if (SkipEntry) { + continue; + } + + MemoryAddressStore[LastIndex++] = MemoryAddress; + + // + // Get memory domain (must match SRAT memory domain) + // + NodeId = ProximityDomainOf ( + mSystemMemoryMap->Element[PmemEntry[Index]].SocketId, + mSystemMemoryMap->Element[PmemEntry[Index]].Type, + MaxEnabledImc, + HmatData->SncEnabled, + HmatData->SncNumOfCluster, + mSystemMemoryMap->Element[PmemEntry[Index]].ImcInterBitmap, + mSystemMemoryMap->volMemMode, + LastDomainId + ); + NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster); + + if (LastDomainId < NodeId) { + LastDomainId = NodeId; + } + + if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) { + DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Memory Proximity Domain (0x%x)\n", NodeId)); + ASSERT (FALSE); + } + + // + // Update map of indexes included in this memory domain + // + HmatData->MemoryDomainList[NodeId].MemMapIndexMap |= LShiftU64 (BIT0, PmemEntry[Index]); + + // + // Update Memory domain count and set domain to valid + // Prevent counting repeated entries with the same Proximity Domain ID + // + if ((PmemEntry[Index] == 0) || (HmatData->MemoryDomainList[NodeId].Valid == 0)) { + HmatData->MemoryDomainNumber++; + HmatData->MemoryDomainList[NodeId].PhysicalSocketId = mSystemMemoryMap->Element[PmemEntry[Index]].SocketId; + HmatData->MemoryDomainList[NodeId].Valid = 1; + } + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MemoryDomainList[%x] Valid = %x Cacheable = %x MemorySideCacheSize = %x\n", + NodeId, + HmatData->MemoryDomainList[NodeId].Valid, + HmatData->MemoryDomainList[NodeId].Cacheable, + HmatData->MemoryDomainList[NodeId].MemorySideCacheSize + )); + } +} + +/** + Calculate the Processor Proximity Domain Number and generate its associate list. + + @param [in, out] HmatData Pointer to HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be filled + + @retval None. +**/ +VOID +GetProcessorDomains ( + IN OUT HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData + ) +{ + UINT32 NodeId; + UINT8 Index; + INTN FirstImc; + UINT8 SocketId; + UINT8 SocketLogicalId; + UINT8 MemSocketBitmap; + UINT8 NoMemSocketBitmap; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + MemSocketBitmap = 0; + NoMemSocketBitmap = 0; + HmatData->ProcessorDomainNumber = 0; + + // + // Processor Proximity Domain must match the Domain in the SRAT APIC or X2APIC Affinity Structure + // + for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) { + // + // Skip any memory region marked reserved or FPGA + // + if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type) || DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) { + continue; + } + + SocketId = mSystemMemoryMap->Element[Index].SocketId; + SocketLogicalId = GetSocketLogicalId (SocketId); + + // + // Get processor proximity domain + // + if (HmatData->SncEnabled || HmatData->VirtualNumaEnabled) { + FirstImc = LowBitSet32 (mSystemMemoryMap->Element[Index].ImcInterBitmap); + if (FirstImc == -1) { + FirstImc = 0; + } + // + // Find the 1st IMC according the interbitmap + // + if (MAX_IMC <= HmatData->SncNumOfCluster) { + NodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + (UINT32)FirstImc; + } else { + NodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + ((UINT32)FirstImc) / HmatData->SncNumOfCluster; + } + + NodeId = (NodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster); + + DEBUG ((DEBUG_INFO, "%a: SocketId: 0x%x SncNumOfCluster: 0x%x ImcInterBitmap:0x%x and NodeId:0x%x\n", + __FUNCTION__, mSystemMemoryMap->Element[Index].SocketId, HmatData->SncNumOfCluster, mSystemMemoryMap->Element[Index].ImcInterBitmap, NodeId)); + } else { + NodeId = SocketLogicalId; + } + + if (NodeId >= EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS) { + DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Invalid Processor Proximity Domain (0x%x)\n", NodeId)); + return; + } + + // + // Update processor domain count and set domain to valid + // Prevent counting repeated entries with the same Proximity Domain ID + // + if ((Index == 0) || (HmatData->ProcessorDomainList[NodeId] == 0)) { + HmatData->ProcessorDomainNumber++; + HmatData->ProcessorDomainSocketIdList[NodeId] = SocketId; + HmatData->ProcessorDomainList[NodeId] = 1; // Domain is valid + MemSocketBitmap |= (BIT0 << mSystemMemoryMap->Element[Index].SocketId); + } + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) ProcessorDomainList[%x] Valid = %x\n", NodeId, HmatData->ProcessorDomainList[NodeId])); + } + + // + // Update processor domain for enabled sockets without memory + // + NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap; + for (SocketId = 0; SocketId < MAX_SOCKET; SocketId++) { + if ((BIT0 << SocketId) & NoMemSocketBitmap) { + for (Index = 0; Index < (HmatData->SncNumOfCluster * HmatData->VirtualNumOfCluster); Index++) { + NodeId = GetSocketLogicalId (SocketId) * HmatData->SncNumOfCluster * HmatData->VirtualNumOfCluster + Index; + HmatData->ProcessorDomainNumber++; + HmatData->ProcessorDomainSocketIdList[NodeId] = SocketId; + HmatData->ProcessorDomainList[NodeId] = 1; + } + } + } +} + +/** + Initialize HMAT Data to be consumed when populating tables. + This Functions allocates buffer for HMAT Data, so it is caller responsibility to free it. + + @param None. + + @retval Pointer to allocated HMAT Data if it was initialized correctly. + @retval NULL if not allocated and not initialized correctly. +**/ +UINTN * +InitializeHmatData ( + VOID +) +{ + HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData = NULL; + + HmatData = AllocateZeroPool (sizeof (HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE)); + if (HmatData == NULL) { + DEBUG ((DEBUG_ERROR, "[ACPI] (HMAT) ERROR: Could not allocate HmatData structure pointer\n")); + return (UINTN *) HmatData; + } + + if (mIioUds->IioUdsPtr->SystemStatus.OutSncEn) { + HmatData->SncEnabled = 1; + HmatData->SncNumOfCluster = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster; + } else { + HmatData->SncNumOfCluster = 1; + } + + if (mSystemMemoryMap->VirtualNumaEnable) { + HmatData->VirtualNumaEnabled = 1; + HmatData->VirtualNumOfCluster = mSystemMemoryMap->VirtualNumOfCluster; + } else { + HmatData->VirtualNumOfCluster = 1; + } + + GetProcessorDomains (HmatData); + GetMemoryDomains (HmatData); + + return (UINTN *)HmatData; +} + +/** + Patch HMAT MSARS substructure. + + @param [in, out] HmatAcpiTable Points to HMAT table to be modified + @param [in, out] SlackSize Points to cumulative slack size + @param [in] HmatData HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed + + @retval None +**/ +VOID +PatchHmatMsars ( + IN OUT EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *HmatAcpiTable, + IN OUT UINTN *SlackSize, + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData + ) +{ + UINT32 Index; + UINT32 PrevIndex; + UINT32 MemoryNodeId; + UINT32 ProcessorNodeId; + UINT32 Count = 0; + UINT32 UnusedCount; + UINT8 MemoryNodeValid; + UINT16 ProcessorNodeValid; + UINT64 MemoryAddress; + BOOLEAN SkipEntry; + INTN FirstImc; + UINT8 SocketLogicalId; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating Memory Subsystem Address Range Structure\n")); + for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++) { + // + // Skip any memory region marked reserved + // + DEBUG ((DEBUG_INFO, "[ACPI] mSystemMemoryMap->Element[%d].Type = 0x%x\n",Index, mSystemMemoryMap->Element[Index].Type)); + if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) { + continue; + } + + if (Count >= EFI_ACPI_HMAT_MSARS_COUNT) { + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Invalid MSARS entry with Index = 0x%x\n", Count)); + ASSERT (FALSE); + break; + } + + SkipEntry = FALSE; + + // + // Skip duplicate entries + // + MemoryAddress = LShiftU64 (mSystemMemoryMap->Element[Index].BaseAddress, MEM_ADDR_SHFT_VAL); + if (Count) { + for (PrevIndex = 0; PrevIndex < Count; PrevIndex++) { + if (MemoryAddress == HmatAcpiTable->Msars[PrevIndex].AddrBase) { + SkipEntry = TRUE; + break; + } + } + } + if (SkipEntry) { + continue; + } + + // + // Find memory domain for this index + // + for (MemoryNodeId = 0; MemoryNodeId < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; MemoryNodeId++) { + if (HmatData->MemoryDomainList[MemoryNodeId].MemMapIndexMap & LShiftU64(BIT0, Index)) { + break; + } + } + + // + // Fill in valid field + // + if (MemoryNodeId < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS) { + MemoryNodeValid = HmatData->MemoryDomainList[MemoryNodeId].Valid; + } else { + MemoryNodeValid = 0; + } + + // + // Get processor domain for this index + // + if (DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) { + ProcessorNodeValid = 0; // There is no processor for FPGA. + ProcessorNodeId = 0; // This field will be ingored for FPGA. + } else { + SocketLogicalId = GetSocketLogicalId (mSystemMemoryMap->Element[Index].SocketId); + if (HmatData->SncEnabled || HmatData->VirtualNumaEnabled) { + FirstImc = LowBitSet32 (mSystemMemoryMap->Element[Index].ImcInterBitmap); + if (FirstImc == -1) { + FirstImc = 0; + } + // + // Find the 1st IMC according the interbitmap + // + if (MAX_IMC <= HmatData->SncNumOfCluster) { + ProcessorNodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + (UINT32)FirstImc; + } else { + ProcessorNodeId = (SocketLogicalId * HmatData->SncNumOfCluster) + ((UINT32)FirstImc) / HmatData->SncNumOfCluster; + } + ProcessorNodeId = (ProcessorNodeId * HmatData->VirtualNumOfCluster) + (Index % HmatData->VirtualNumOfCluster); + DEBUG ((DEBUG_INFO, "%a: SocketId: 0x%x SncNumOfCluster: 0x%x ImcInterBitmap:0x%x and NodeId:0x%x \n", + __FUNCTION__, mSystemMemoryMap->Element[Index].SocketId, HmatData->SncNumOfCluster, mSystemMemoryMap->Element[Index].ImcInterBitmap, ProcessorNodeId)); + } else { + ProcessorNodeId = SocketLogicalId; + } + + // + // Fill in valid field + // + if (ProcessorNodeId < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS) { + ProcessorNodeValid = HmatData->ProcessorDomainList[ProcessorNodeId]; + } else { + ProcessorNodeValid = 0; + } + } + + // + // The HOB has base addr in 64 MB chunks + // + HmatAcpiTable->Msars[Count].AddrBase = MemoryAddress; + HmatAcpiTable->Msars[Count].AddrLength = LShiftU64 (mSystemMemoryMap->Element[Index].ElementSize, MEM_ADDR_SHFT_VAL); + + HmatAcpiTable->Msars[Count].Flags.Value = 0; + + // + // Fill in Proximity Domains + // + HmatAcpiTable->Msars[Count].ProcessorProximityDomain = ProcessorNodeId; + HmatAcpiTable->Msars[Count].Flags.Bits.ProcessorDomainValid = ProcessorNodeValid; + HmatAcpiTable->Msars[Count].MemoryProximityDomain = MemoryNodeId; + HmatAcpiTable->Msars[Count].Flags.Bits.MemoryDomainValid = MemoryNodeValid; + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MSARS[%x] AddrBase = 0x%lx, AddrLength = 0x%lx, MemDomain = %x, ProcDomain = %x\n", + Count, + HmatAcpiTable->Msars[Count].AddrBase, + HmatAcpiTable->Msars[Count].AddrLength, + MemoryNodeId, + ProcessorNodeId + )); + Count++; + } + + // + // Update SlackSize for unused MSARS entries + // + UnusedCount = EFI_ACPI_HMAT_MSARS_COUNT - Count; + *SlackSize += UnusedCount * sizeof(HmatAcpiTable->Msars[0]); +} + +/** + Prints HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE for debug purposes. + + @param [in] Lbis Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be printed. + + @retval None. +**/ +VOID +PrintLbisHmat ( + IN LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis + ) +{ + UINT32 Row = 0; + UINT32 Col = 0; + UINT32 RowBaseIndex = 0; + UINT16 *Entry; + + Entry = (UINT16 *) Lbis->RelativeDistanceEntry; + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) SLLBIS Data: ")); + DEBUG ((DEBUG_INFO, "InitiatorNumber = %d, TargetNumber = %d. ", Lbis->InitiatorProximityDomainsNumber, Lbis->TargetProximityDomainsNumber)); + DEBUG ((DEBUG_INFO, "Entry Base Unit = %d \n", Lbis->EntryBaseUnit)); + + DEBUG ((DEBUG_INFO, " ")); + for (Col = 0; Col < Lbis->TargetProximityDomainsNumber; Col++) { + DEBUG ((DEBUG_INFO, "%02d ", Lbis->TargetProximityDomainList[Col])); + } + DEBUG ((DEBUG_INFO, "\n")); + for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) { + RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber; + DEBUG ((DEBUG_INFO, "%02d ", Lbis->InitiatorProximityDomainList[Row])); + for (Col = 0; Col < Lbis->TargetProximityDomainsNumber; Col++) { + DEBUG ((DEBUG_INFO, "%08d ", Entry[RowBaseIndex + Col])); + } + DEBUG ((DEBUG_INFO, "\n")); + } +} + +/** + Get the Read/Write/Access bandwidth value of the memory type. + + @param [in] DataType Type of bandwidth value that is required. (Read/Write/Access) + @param [in] Type Type of memory for which Bandwidth is required. (DDR/DDRT) + + @retval Value of the bandwidth associated with memory type. + @retval 0xFF Input parameters are invalid. +**/ + +UINT16 +GetMemoryBandWidth ( + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode + ) +{ + if (Type == DDRT) { // MemoryType == DDRT + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH : + return DDRT_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH : + if (volMemMode == VOL_MEM_MODE_1LM) { + return DDRT_1LM_READ_BANDWIDTH; + } else { + return DDRT_2LM_READ_BANDWIDTH; + } + case EFI_ACPI_HMAT_WRITE_BANDWIDTH : + if (volMemMode == VOL_MEM_MODE_1LM) { + return DDRT_1LM_WRITE_BANDWIDTH; + } else { + return DDRT_2LM_WRITE_BANDWIDTH; + } + default: + return 0xFF; + } + } else if (Type == DDR2LMCACHE) { + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH : + return DDR2LMCACHE_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH : + return DDR2LMCACHE_READ_BANDWIDTH; + case EFI_ACPI_HMAT_WRITE_BANDWIDTH : + return DDR2LMCACHE_WRITE_BANDWIDTH; + default: + return 0xFF; + } + } else { + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH : + return DDR_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH : + return DDR_READ_BANDWIDTH; + case EFI_ACPI_HMAT_WRITE_BANDWIDTH : + return DDR_WRITE_BANDWIDTH; + default: + return 0xFF; + } + } +} + +/** + Get the Read/Write/Access bandwidth value of the memory type across sockets. + + @param [in] DataType Type of bandwidth value that is required. (Read/Write/Access) + @param [in] Type Type of memory for which Bandwidth is required. (DDR/DDRT) + + @retval Value of the bandwidth associated with memory type. + @retval 0xFF Input parameters are invalid. +**/ +UINT16 +GetXSocketMemoryBandWidth ( + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode +) +{ + if (Type == DDRT) { // MemoryType == DDRT + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH: + return DDRT_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH: + if (volMemMode == VOL_MEM_MODE_1LM) { + return XSOCKET_DDRT_1LM_READ_BANDWIDTH; + } else { + return XSOCKET_DDRT_2LM_READ_BANDWIDTH; + } + case EFI_ACPI_HMAT_WRITE_BANDWIDTH: + if (volMemMode == VOL_MEM_MODE_1LM) { + return XSOCKET_DDRT_1LM_WRITE_BANDWIDTH; + } else { + return XSOCKET_DDRT_2LM_WRITE_BANDWIDTH; + } + default: + return 0xFF; + } + } else if (Type == DDR2LMCACHE) { + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH: + return DDR2LMCACHE_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH: + return DDR2LMCACHE_READ_BANDWIDTH; + case EFI_ACPI_HMAT_WRITE_BANDWIDTH: + return DDR2LMCACHE_WRITE_BANDWIDTH; + default: + return 0xFF; + } + } else { + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_BANDWIDTH: + return XSOCKET_DDR_ACCESS_BANDWIDTH; + case EFI_ACPI_HMAT_READ_BANDWIDTH: + return XSOCKET_DDR_READ_BANDWIDTH; + case EFI_ACPI_HMAT_WRITE_BANDWIDTH: + return XSOCKET_DDR_WRITE_BANDWIDTH; + default: + return 0xFF; + } + } +} + +/** + Get the Read/Write/Access Latency value of the memory type. + + @param [in] DataType Type of latency value that is required (Read/Write/Access) + @param [in] Type Type of memory for which Latency is required. (DDR/DDRT) + + @retval Value of the Latency associated with memory type. + @retval 0xFF Input parameters are invalid. +**/ +UINT16 +GetMemoryLatency ( + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode + ) +{ + if (Type == DDRT) { // MemoryType == DDRT + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return DDRT_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + if (volMemMode == VOL_MEM_MODE_1LM) { + return DDRT_1LM_READ_LATENCY; + } else { + return DDRT_2LM_READ_LATENCY; + } + + case EFI_ACPI_HMAT_WRITE_LATENCY : + if (volMemMode == VOL_MEM_MODE_1LM) { + return DDRT_1LM_WRITE_LATENCY; + } else { + return DDRT_2LM_WRITE_LATENCY; + } + + default: + return 0xFF; + } + } else if (Type == DDR2LMCACHE){ + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return DDR2LMCACHE_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + return DDR2LMCACHE_READ_LATENCY; + + case EFI_ACPI_HMAT_WRITE_LATENCY : + return DDR2LMCACHE_WRITE_LATENCY; + + default: + return 0xFF; + } + } else { + switch (DataType) { + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return DDR_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + return DDR_READ_LATENCY; + + case EFI_ACPI_HMAT_WRITE_LATENCY : + return DDR_WRITE_LATENCY; + + default: + return 0xFF; + } + } +} + +/** + Get the Read/Write/Access Latency value of the memory type between sockets. + + @param [in] DataType Type of latency value that is required (Read/Write/Access) + @param [in] Type Type of memory for which Latency is required. (DDR/DDRT) + + @retval Value of the Latency associated with memory type. + @retval 0xFF Input parameters are invalid. +**/ +UINT16 +GetXSocketMemoryLatency ( + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode + ) +{ + if (Type == DDRT) { // MemoryType == DDRT + switch (DataType) { + + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return DDRT_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + if (volMemMode == VOL_MEM_MODE_1LM) { + return XSOCKET_DDRT_1LM_READ_LATENCY; + } else { + return XSOCKET_DDRT_2LM_READ_LATENCY; + } + + case EFI_ACPI_HMAT_WRITE_LATENCY : + if (volMemMode == VOL_MEM_MODE_1LM) { + return XSOCKET_DDRT_1LM_WRITE_LATENCY; + } else { + return XSOCKET_DDRT_2LM_WRITE_LATENCY; + } + + default: + return 0xFF; + } + } else if (Type == DDR2LMCACHE){ + switch (DataType) { + + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return DDR2LMCACHE_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + return DDR2LMCACHE_READ_LATENCY; + + case EFI_ACPI_HMAT_WRITE_LATENCY : + return DDR2LMCACHE_WRITE_LATENCY; + + default: + return 0xFF; + } + } else { + switch (DataType) { + + case EFI_ACPI_HMAT_ACCESS_LATENCY : + return XSOCKET_DDR_ACCESS_LATENCY; + + case EFI_ACPI_HMAT_READ_LATENCY : + return XSOCKET_DDR_READ_LATENCY; + + case EFI_ACPI_HMAT_WRITE_LATENCY : + return XSOCKET_DDR_WRITE_LATENCY; + + default: + return 0xFF; + } + } +} + +/** + Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure. + + @param [in] Lbis Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified + @param [in, out] LibsSlackSize Points to cummulative LIBS slack size + @param [in] HmatData HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed + + @retval None +**/ +VOID +PatchBandWidthLbis ( + IN LATENCY_BANDWIDTH_INFO_STRUCTURE **LbisPtr, + IN OUT UINTN *LibsSlackSize, + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData, + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode + ) +{ + UINT32 Row = 0; + UINT32 Col = 0; + UINT32 RowSocketId = 0; + UINT32 ColSocketId = 0; + UINT32 RowBaseIndex = 0; + UINT32 StructSize = 0; + UINT32 InitiatorIndex = 0; + UINT32 TargetIndex = 0; + LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis = *LbisPtr; + UINT32 *InitiatorProximityDomainList = (UINT32*)Lbis; + UINT32 *TargetProximityDomainList = (UINT32*)Lbis; + UINT16 *RelativeDistanceEntry = (UINT16*)Lbis; + + Lbis->Type = SYSTEM_LOCALITY_LATENCY_BANDWIDTH_INFORMATION_STRUCTURE_TYPE; + Lbis->DataType = DataType; + Lbis->InitiatorProximityDomainsNumber = HmatData->ProcessorDomainNumber; + Lbis->TargetProximityDomainsNumber = HmatData->MemoryDomainNumber; + + switch (Type) { + + case DDR2LMCACHE: + Lbis->EntryBaseUnit = DDR2LMCACHE_BANDWIDTH_BASE_UNIT; + Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_LAST_LEVEL_MEMORY; + break; + + default: + Lbis->EntryBaseUnit = MEMORY_BANDWIDTH_BASE_UNIT; + Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_MEMORY; + } + + InitiatorProximityDomainList = (UINT32*)&(Lbis->InitiatorProximityDomainList[0]); + StructSize = (UINT32)((UINT8*)InitiatorProximityDomainList - (UINT8*)Lbis); + StructSize += (Lbis->InitiatorProximityDomainsNumber * (sizeof (UINT32))); + TargetProximityDomainList = (UINT32*)((UINT8*)TargetProximityDomainList + StructSize); + StructSize += (Lbis->TargetProximityDomainsNumber * (sizeof (UINT32))); + RelativeDistanceEntry = (UINT16*)((UINT8*)RelativeDistanceEntry + StructSize); + StructSize += (Lbis->InitiatorProximityDomainsNumber * Lbis->TargetProximityDomainsNumber * (sizeof (UINT16))); + + Lbis->Length = StructSize; + + for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) { + *(InitiatorProximityDomainList + Row) = Row; + } + for (Row = 0; Row < Lbis->TargetProximityDomainsNumber; Row++) { + *(TargetProximityDomainList + Row) = Row; + } + Row = 0; + for (InitiatorIndex = 0; InitiatorIndex < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS; InitiatorIndex++) { + if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) { + RowSocketId = HmatData->ProcessorDomainSocketIdList[InitiatorIndex]; + RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber; + Col = 0; + for (TargetIndex = 0; TargetIndex < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; TargetIndex++) { + if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) { + ColSocketId = HmatData->MemoryDomainList[TargetIndex].PhysicalSocketId; + if (Type == DDR2LMCACHE) { + // + // DDR acting as cache for DDRT + //SocketsLinked + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, Type, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, Type, volMemMode); + } + } else if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) { + // + // Add only details for DDRT as entire DDR is acting as Cache + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDRT, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDRT, volMemMode); + } + } else { + // + // Neither cache nor 2LM, we need to add details for both DDR and DDRT + // + if ((Col / (HmatData->MemoryDomainNumber- SkippedEntries)) == 0) { + // + // DDR entries + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDR, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDR, volMemMode); + } + } else { + // + // DDRT entries + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryBandWidth (DataType, DDRT, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryBandWidth (DataType, DDRT, volMemMode); + } + } + } + Col++; + } //if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) + } // for (TargetIndex) + Row++; + } // if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) + } //for (InitiatorIndex) + + *LibsSlackSize += StructSize; + *LbisPtr = (LATENCY_BANDWIDTH_INFO_STRUCTURE *)((UINT8*)Lbis + StructSize); +} + +/** + Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure. + + @param [in] Lbis Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified + @param [in, out] LibsSlackSize Points to cumulative LIBS slack size + @param [in] HmatData HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed + + @retval None +**/ +VOID +PatchMemoryLatencyLbis ( + IN LATENCY_BANDWIDTH_INFO_STRUCTURE **LbisPtr, + IN OUT UINTN *LibsSlackSize, + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData, + IN UINT8 DataType, + IN MemoryType Type, + IN UINT8 volMemMode + ) +{ + UINT32 Row = 0; + UINT32 Col = 0; + UINT32 RowSocketId = 0; + UINT32 ColSocketId = 0; + UINT32 RowBaseIndex = 0; + UINT32 StructSize = 0; + UINT32 InitiatorIndex = 0; + UINT32 TargetIndex = 0; + LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis = *LbisPtr; + UINT32 *InitiatorProximityDomainList = (UINT32*)Lbis; + UINT32 *TargetProximityDomainList = (UINT32*)Lbis; + UINT16 *RelativeDistanceEntry = (UINT16*)Lbis; + + Lbis->Type = SYSTEM_LOCALITY_LATENCY_BANDWIDTH_INFORMATION_STRUCTURE_TYPE; + Lbis->DataType = DataType; + Lbis->InitiatorProximityDomainsNumber = HmatData->ProcessorDomainNumber; + Lbis->TargetProximityDomainsNumber = HmatData->MemoryDomainNumber; + + switch (Type) { + + case DDR2LMCACHE: + Lbis->EntryBaseUnit = DDR2LMCACHE_BANDWIDTH_BASE_UNIT; + Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_LAST_LEVEL_MEMORY; + break; + + default: + Lbis->EntryBaseUnit = MEMORY_LATENCY_BASE_UNIT; + Lbis->Flags = EFI_ACPI_HMAT_MEMORY_HIERACHY_MEMORY; + } + + InitiatorProximityDomainList = (UINT32*)&(Lbis->InitiatorProximityDomainList[0]); + StructSize = (UINT32)((UINT8*)InitiatorProximityDomainList - (UINT8*)Lbis); + StructSize += (Lbis->InitiatorProximityDomainsNumber * (sizeof (UINT32))); + TargetProximityDomainList = (UINT32*)((UINT8*)TargetProximityDomainList + StructSize); + StructSize += (Lbis->TargetProximityDomainsNumber * (sizeof (UINT32))); + RelativeDistanceEntry = (UINT16*)((UINT8*)RelativeDistanceEntry + StructSize); + StructSize += (Lbis->InitiatorProximityDomainsNumber * Lbis->TargetProximityDomainsNumber * (sizeof (UINT16))); + + Lbis->Length = StructSize; + + for (Row = 0; Row < Lbis->InitiatorProximityDomainsNumber; Row++) { + *(InitiatorProximityDomainList + Row) = Row; + } + for (Row = 0; Row < Lbis->TargetProximityDomainsNumber; Row++) { + *(TargetProximityDomainList + Row) = Row; + } + Row = 0; + for (InitiatorIndex = 0; InitiatorIndex < EFI_ACPI_HMAT_NUMBER_OF_PROCESSOR_DOMAINS; InitiatorIndex++) { + if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) { + RowSocketId = HmatData->ProcessorDomainSocketIdList[InitiatorIndex]; + RowBaseIndex = Row * Lbis->TargetProximityDomainsNumber; + Col = 0; + for (TargetIndex = 0; TargetIndex < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; TargetIndex++) { + if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) { + ColSocketId = HmatData->MemoryDomainList[TargetIndex].PhysicalSocketId; + if (Type == DDR2LMCACHE) { + // + // DDR acting as cache for DDRT + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, Type, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, Type, volMemMode); + } + } else if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_2LM) { + // + // Add only details for DDRT as entire DDR is acting as Cache + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDRT, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDRT, volMemMode); + } + } else { + // + // Neither cache nor 2LM, we need to add details for both DDR and DDRT + // + if ((Col / (HmatData->MemoryDomainNumber - SkippedEntries)) == 0) { + // + // DDR entries + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDR, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDR, volMemMode); + } + } else { + // + // DDRT entries + // + if (SocketsLinked (RowSocketId, ColSocketId)) { + RelativeDistanceEntry[RowBaseIndex + Col] = GetXSocketMemoryLatency (DataType, DDRT, volMemMode); + } else { + RelativeDistanceEntry[RowBaseIndex + Col] = GetMemoryLatency (DataType, DDRT, volMemMode); + } + } + } + Col++; + } //if (HmatData->MemoryDomainList[TargetIndex].Valid == 1) + } // for (TargetIndex) + Row++; + } // if (HmatData->ProcessorDomainList[InitiatorIndex] == 1) + } //for (InitiatorIndex) + + *LibsSlackSize += StructSize; + *LbisPtr = (LATENCY_BANDWIDTH_INFO_STRUCTURE *)((UINT8*)Lbis + StructSize); +} + +/** + Patch HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE structure. + + @param [in] Lbis Points to HMAT LATENCY_BANDWIDTH_INFO_STRUCTURE to be modified + @param [in, out] SlackSize Points to cummulative slack size + @param [in] HmatData HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed + + @retval None +**/ +VOID +PatchHmatLbis ( + IN LATENCY_BANDWIDTH_INFO_STRUCTURE *Lbis, + IN OUT UINTN *SlackSize, + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData + ) +{ + UINTN LibsStructSize=0; + UINT8 volMemMode; + LATENCY_BANDWIDTH_INFO_STRUCTURE *OrginalLbis = Lbis; + + volMemMode = mSystemMemoryMap->volMemMode; + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating System Locality Latency and Bandwidth Information Structure\n")); + + PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_LATENCY, DDR, volMemMode); + PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_LATENCY, DDR, volMemMode); + PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_BANDWIDTH, DDR, volMemMode); + PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_BANDWIDTH, DDR, volMemMode); + + if (mSystemMemoryMap->volMemMode != VOL_MEM_MODE_1LM) { + PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_LATENCY, DDR2LMCACHE, volMemMode); + PatchMemoryLatencyLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_LATENCY, DDR2LMCACHE, volMemMode); + PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_READ_BANDWIDTH, DDR2LMCACHE, volMemMode); + PatchBandWidthLbis (&Lbis, &LibsStructSize, HmatData, EFI_ACPI_HMAT_WRITE_BANDWIDTH, DDR2LMCACHE, volMemMode); + } + + RemoveSlack (SlackSize, OrginalLbis, LibsStructSize); + *SlackSize += EFI_ACPI_HMAT_LBIS_COUNT * sizeof(Lbis[0]) - LibsStructSize; +} + +/** + Get Type 17 Handles for HBM devices used as cache. + + @param [in, out] SmbiosHandles Points to SmbiosHandles array to be modified + @param [in] NumaNode Value for NUMA Node whose memory is being cached for the specific HBM devices + @retval None +**/ +VOID +GetHbmCacheHandles ( + IN UINT16 *SmbiosHandles, + IN UINT8 NumaNode + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + SMBIOS_TABLE_TYPE17 *SmbiosType17Record; + EFI_SMBIOS_HANDLE SmbiosHandle = 0; + EFI_SMBIOS_PROTOCOL *mSmbios; + EFI_SMBIOS_TYPE SmbiosType = EFI_SMBIOS_TYPE_MEMORY_DEVICE; + EFI_SMBIOS_TABLE_HEADER *SmbiosRecord; + UINT8 HbmHandleCount = 0; + + Status = gBS->LocateProtocol (&gEfiSmbiosProtocolGuid, NULL, (VOID **) &mSmbios); + if (!(EFI_ERROR (Status))) { + while ((!(EFI_ERROR (Status))) && (SmbiosHandle != SMBIOS_HANDLE_PI_RESERVED) ){ + Status = mSmbios->GetNext (mSmbios, &SmbiosHandle, &SmbiosType, &SmbiosRecord, NULL); + SmbiosType17Record = (SMBIOS_TABLE_TYPE17 *) SmbiosRecord; + if ((SmbiosType17Record->TypeDetail.CacheDram == 1) && (SmbiosType17Record->DeviceSet == NumaNode) ) { + SmbiosHandles[HbmHandleCount] = SmbiosType17Record->Hdr.Handle; + HbmHandleCount++; + } + } + } +} + +/** + Patch HMAT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE substructure. + + @param [in, out] Mscis Points to HMAT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE to be modified + @param [in, out] SlackSize Points to cumulative slack size + @param [in] HmatData HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE to be consumed + + @retval None +**/ +VOID +PatchHmatMscis ( + IN OUT MEMORY_SIDE_CACHE_INFORMATION_STRUCTURE *Mscis, + IN OUT UINTN *SlackSize, + IN HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData + ) +{ + UINT32 Index; + UINT32 Count = 0; + UINT32 UnusedCount; + UINT8 SmbiosHandleIndex; + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) Populating Memory Side Cache Information Structure\n")); + + for (Index = 0; Index < EFI_ACPI_HMAT_NUMBER_OF_MEMORY_DOMAINS; Index++) { + if ((HmatData->MemoryDomainList[Index].Valid == 0) || (HmatData->MemoryDomainList[Index].Cacheable == 0)) { + continue; + } + + // + // Fill in fields for Cached Memory Domains + // + Mscis[Count].MemoryProximityDomain = Index; + Mscis[Count].CacheAttributes.Bits.TotalCacheLevels = EFI_ACPI_HMAT_ONE_LEVEL_CACHE; + Mscis[Count].CacheAttributes.Bits.CacheLevel = EFI_ACPI_HMAT_ONE_LEVEL_CACHE; + Mscis[Count].CacheAttributes.Bits.CacheLineSize = DDR4_CACHE_LINE_SIZE; + Mscis[Count].CacheAttributes.Bits.CacheAssociativity = EFI_ACPI_HMAT_CACHE_ASSOCIATIVITY_DIRECT_MAPPED; + Mscis[Count].CacheAttributes.Bits.WritePolicy = EFI_ACPI_HMAT_WRITE_POLICY_WB; + Mscis[Count].MemorySideCacheSize = LShiftU64 (HmatData->MemoryDomainList[Index].MemorySideCacheSize, MEM_ADDR_SHFT_VAL); + Mscis[Count].NumSmbiosHandles = HmatData->MemoryDomainList[Index].NumSmbiosHandles; + for(SmbiosHandleIndex = 0 ; SmbiosHandleIndex < HmatData->MemoryDomainList[Index].NumSmbiosHandles; SmbiosHandleIndex++){ + Mscis[Count].SmbiosHandles[SmbiosHandleIndex] = HmatData->MemoryDomainList[Index].SmbiosHandles[SmbiosHandleIndex]; + } + + DEBUG ((DEBUG_INFO, "[ACPI] (HMAT) MSCIS[%x] MemorySideCacheSize = 0x%lx, ProximityDomain = %x\n", Count, Mscis[Count].MemorySideCacheSize, Index)); + + Count++; + } + + // + // Move MSCIS entries up to replace removed MSARS entries + // + if (*SlackSize && Count) { + RemoveSlack (SlackSize, Mscis, Count * sizeof(Mscis[0])); + } + + // + // Update SlackSize for unused MSCIS entries + // + UnusedCount = EFI_ACPI_HMAT_MSCIS_COUNT - Count; + *SlackSize += UnusedCount * sizeof(Mscis[0]); +} + +/** + Update the HMAT table. + + @param [in, out] HmatAcpiTable The table to be set. + + @retval EFI SUCCESS Procedure returned successfully. +**/ +EFI_STATUS +PatchHmatAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINTN SlackSize = 0; + HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *HmatData = NULL; + EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *HmatAcpiTable; + + if (mSystemMemoryMap == NULL) { + + ASSERT (FALSE); + return EFI_UNSUPPORTED; + } + + HmatAcpiTable = (EFI_ACPI_HETEROGENEOUS_MEMORY_ATTRIBUTE_TABLE *)Table; + + HmatData = (HMAT_PROXIMITY_DOMAIN_DATA_STRUCTURE *) InitializeHmatData (); + if (HmatData == NULL) { + DEBUG ((DEBUG_ERROR, "ACPI (HMAT) HMAT Data could not be initialized... skipping HMAT Patch\n")); + return EFI_OUT_OF_RESOURCES; + } + + // + // Patch the MSARS, SLLBIS, and MSCIS Structure from HMAT Table. + // + PatchHmatMsars (HmatAcpiTable, &SlackSize, HmatData); + PatchHmatLbis (HmatAcpiTable->Lbis, &SlackSize, HmatData); + PatchHmatMscis (HmatAcpiTable->MemSideCache, &SlackSize, HmatData); + + if (HmatData != NULL) { + FreePool (HmatData); + } + + // + // Update HMAT table size + // + HmatAcpiTable->HmatHeader.Header.Length -= (UINT32)SlackSize; + + // + // Dump HMAT + // + DumpHmat (HmatAcpiTable); + + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h new file mode 100644 index 0000000000..4e0d9eaa8f --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibLocal.h @@ -0,0 +1,441 @@ +/** @file + + @copyright + Copyright 1999 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef _ACPI_PLATFORM__LIB_LOCAL_H_ +#define _ACPI_PLATFORM__LIB_LOCAL_H_ + +// +// Statements that include other header files +// +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // came from https://acpica.org/downloads/source_code.php acpica-win-20130214.zip/source/include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#define OEM1_SSDT_TABLE_SIGNATURE SIGNATURE_32('O', 'E', 'M', '1') +#define OEM2_SSDT_TABLE_SIGNATURE SIGNATURE_32('O', 'E', 'M', '2') +#define OEM3_SSDT_TABLE_SIGNATURE SIGNATURE_32('O', 'E', 'M', '3') +#define OEM4_SSDT_TABLE_SIGNATURE SIGNATURE_32('O', 'E', 'M', '4') + +#define AML_NAME_OP 0x08 +#define AML_NAME_PREFIX_SIZE 0x06 +#define AML_NAME_DWORD_SIZE 0x0C + +#ifndef AML_EXTERNAL_OP +#define AML_EXTERNAL_OP 0x15 /* ACPI 6.0 */ +#endif + +#define GPSS_FVID_MAX_STATES 40 // Greater Than 16 p-state support + +// +// mCpuPCPSInfo usage +// +#define B_PCPS_DISABLE (1 << 17) // Bit 17 +#define B_PCPS_HT_ENABLE (1 << 16) // Bit 16 +#define PCIE_BUS_0 0x00 +#define PCIE_BUS_1 0x01 +#define PCIE_BUS_2 0x02 +#define PCIE_BUS_3 0x03 +#define PCIE_BUS_4 0x04 +#define PCIE_BUS_5 0x05 + +#define PCIE_PORT_ALL_FUNC 0x00 + +#define PCIE_PORT_0_DEV 0x00 + +#define PCIE_PORT_1A_DEV 0x00 +#define PCIE_PORT_1B_DEV 0x01 +#define PCIE_PORT_1C_DEV 0x02 +#define PCIE_PORT_1D_DEV 0x03 + +#define PCIE_PORT_2A_DEV 0x00 +#define PCIE_PORT_2B_DEV 0x01 +#define PCIE_PORT_2C_DEV 0x02 +#define PCIE_PORT_2D_DEV 0x03 + +#define PCIE_PORT_3A_DEV 0x00 +#define PCIE_PORT_3B_DEV 0x01 +#define PCIE_PORT_3C_DEV 0x02 +#define PCIE_PORT_3D_DEV 0x03 + +#define PCIE_PORT_4A_DEV 0x00 +#define PCIE_PORT_4B_DEV 0x01 +#define PCIE_PORT_4C_DEV 0x02 +#define PCIE_PORT_4D_DEV 0x03 + +#define PCIE_PORT_5_DEV 0x00 + +#define MAX_IO_APICS_10NM 1 + +// +// Define flag bits +// +#define POLARITY_ACTIVE_HIGH 0x01 +#define POLARITY_ACTIVE_LOW 0x03 +#define TRIGGERMODE_EDGE 0x04 +#define TRIGGERMODE_LEVEL 0x0C + +#pragma pack(1) +typedef struct { + UINT32 AcpiProcessorId; + UINT32 ApicId; + UINT32 Flags; + UINT32 SocketNum; +} CPU_ID_ORDER_MAP; + +typedef struct { + UINT8 AcpiProcessorId; + UINT8 ApicId; + UINT16 Flags; +} CPU_ID_MAP; + +typedef struct { + UINT8 StartByte; + UINT32 NameStr; + UINT8 Size; + UINT32 Value; +} ACPI_NAMEPACK_DWORD; + +typedef struct { + UINT8 StartByte; + UINT32 NameStr; + UINT8 OpCode; + UINT16 Size; // Hardcode to 16bit width because the table we use is fixed size + UINT8 NumEntries; +} ACPI_NAME_COMMAND; + +typedef struct { + UINT8 PackageOp; + UINT8 PkgLeadByte; + UINT8 NumEntries; + UINT8 DwordPrefix0; + UINT32 CoreFreq; + UINT8 DwordPrefix1; + UINT32 Power; + UINT8 DwordPrefix2; + UINT32 TransLatency; + UINT8 DwordPrefix3; + UINT32 BMLatency; + UINT8 DwordPrefix4; + UINT32 Control; + UINT8 DwordPrefix5; + UINT32 Status; +} PSS_PACKAGE; + +typedef struct { + UINT8 NameOp; // 08h ;First opcode is a NameOp. + UINT32 PackageName; // PSDC/PSDE + UINT8 Length; + UINT8 DwordPrefix1; + UINT8 Revision; + UINT8 PackageOp; + UINT8 PackageLen; + UINT8 PackLen; + UINT16 WordValue1; + UINT16 WordValue2; + UINT8 BytePrefix2; + UINT32 Domain; + UINT8 BytePrefix3; + UINT8 CoordType; // 0xFC(SW_ALL), 0xFE(HW_ALL) + UINT8 BytePrefix4; + UINT32 NumProcessors; +} PSD_PACKAGE_LAYOUT; + +struct CpcRegPack { + UINT8 ResourceOp; // 11h + UINT8 Length; // 14h + UINT32 FFixedHW; + UINT32 RegisterBitsUsage; + UINT32 RegisterBitsShift; + UINT32 RegisterOffset; + UINT32 RegisterByteSize; +}; + +typedef struct { + UINT8 ExternalOp; + UINT8 RootChar; + UINT8 MultiNamePrefix; + UINT8 SegCount; + UINT32 NameStr[0]; +} EXTERNAL_OBJECT_DECL; + +#define ACPI_NAME_COMMAND_FROM_NAME_STR(a) BASE_CR (a, ACPI_NAME_COMMAND, NameStr) +#define ACPI_NAME_COMMAND_FROM_NAMEPACK_STR(a) BASE_CR (a, ACPI_NAMEPACK_DWORD, NameStr) +#define ACPI_EXTERNAL_OBJECT_DECL_FROM_NAME_STR(a) BASE_CR (a, EXTERNAL_OBJECT_DECL, NameStr) + +// +// Private Driver Data +// +// +// Define Union of IO APIC & Local APIC structure; +// +typedef union { + EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic; + EFI_ACPI_6_2_IO_APIC_STRUCTURE AcpiIoApic; + EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic; + struct { + UINT8 Type; + UINT8 Length; + } AcpiApicCommon; +} ACPI_APIC_STRUCTURE_PTR; + +#pragma pack() + +EFI_STATUS +PatchBdatAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +/** + Build from scratch and install the MADT. + + @retval EFI_SUCCESS The MADT was installed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate required structures. +**/ +EFI_STATUS +InstallMadtFromScratch ( + VOID + ); + +EFI_STATUS +InstallSratTable ( + VOID + ); + +EFI_STATUS +PatchFadtTable( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchDsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchMcfgAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchSLitTable( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +InstallSlitTable( + VOID + ); + +/** + Finds the Proximity Domain which the element in the Memory Map belongs to. + + @param [in] SocketId SocketId which the element belongs to. + @param [in] MemType MemType of the element. + @param [in] SncEnabled Bit to indicate if SNC is enabled in the setup options. + @param [in] ImcInterBitmap IMC interleave bitmap for this element. + @param [in] MemMode Current memory mode. 1LM, 2LM etc. + @param [in] LastDomainId Last Domain ID. + + @retval Proximity Domain. + +**/ +UINT32 +ProximityDomainOf ( + UINT8 SocketId, + UINT16 MemType, + UINT8 MaxEnabledImc, + UINT8 SncEnabled, + UINT8 SncNumOfCluster, + UINT8 ImcInterBitmap, + UINT8 MemMode, + UINT32 LastDomainId + ); + +EFI_STATUS +PatchSratTable ( + IN OUT STATIC_RESOURCE_AFFINITY_TABLE *Table + ); + +EFI_STATUS +PatchSsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN OUT EFI_ACPI_TABLE_VERSION *Version + ); + +EFI_STATUS +PatchCpuPmSsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchOem1SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchOem2SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchOem3SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +PatchOem4SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +UpdateNfitTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +EFI_STATUS +UpdatePcatTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ); + +/** + Detect the APICID map and initialize the module global pointer. +**/ +VOID +DetectApicIdMap ( + VOID + ); + +/** + Sort CPU Local APIC Information. + + This function gets the CPU local APIC information from the MP service + protocol into the local table structure, and sorts it based on APIC ID. + + @retval EFI_SUCCESS Local APIC information was successfully sorted. +**/ +EFI_STATUS +SortCpuLocalApicInTable ( + VOID + ); + +/** + Get the socket logical index. + + This function convert the socket physical index to logical index (0 based). + If the specified physical socket is not enabled, an invalid logical index 0xff + will be returned. The socket physical index and logical index will be the same + if the indexes of enabled sockets are continuous. + + @param[in] SocketPhysicalId Socket physical index. + + @retval Socket logical index. +**/ +UINT8 +GetSocketLogicalId ( + IN UINT8 SocketPhysicalId + ); + +/** + Get the socket physical index. + + This function convert the socket logical index to physical index (0 based). + If the specified logical socket does not exist, an invalid physical index 0xff + will be returned. The socket physical index and logical index will be the same + if the indexes of enabled sockets are continuous. + + @param[in] SocketLogicalId Socket logical index. + + @retval Socket physical index. +**/ +UINT8 +GetSocketPhysicalId ( + IN UINT8 SocketlogicId + ); + +/** + Verifies whether sockets are linked + + @param[in] SourceSocket Source Socket ID + @param[in] TargetSocket Targer Socket ID + + @retval TRUE link between source socket and target socket was found + FALSE otherwise + +**/ +BOOLEAN +SocketsLinked ( + IN UINT32 SourceSocket, + IN UINT32 TargetSocket + ); + +// +// AcpiPlatformTableLib private share +// +extern EFI_MP_SERVICES_PROTOCOL *mMpService; +extern BOOLEAN mCpuOrderSorted; +extern CPU_ID_ORDER_MAP mCpuApicIdOrderTable[]; +extern UINTN mNumberOfCPUs; +extern UINTN mNumberOfEnabledCPUs; +extern AML_OFFSET_TABLE_ENTRY *mAmlOffsetTablePointer; +extern CPU_CONFIG_CONTEXT_BUFFER *mCpuConfigLibConfigContextBuffer; + + +#endif diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c new file mode 100644 index 0000000000..dfe2425648 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMcfg.c @@ -0,0 +1,134 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2015 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + + +extern BIOS_ACPI_PARAM *mAcpiParameter; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; +extern SYSTEM_CONFIGURATION mSystemConfiguration; + +EFI_STATUS +PatchMcfgAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT8 NodeId; + UINT8 NodeCount; + EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *McfgTable; + + McfgTable = (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE *)Table; + + // + // mAcpiParameter memory buffer has been zero'ed out, so mAcpiParameter->PcieSegNum[] are 0's + // Patch \_SB.PSYS.SGEN with User Setup Option data + // + // + // dynamically allow multi-seg support + // + mAcpiParameter->PcieMultiSegSupport = 0; + for (NodeId = 0; NodeId < MAX_SOCKET; NodeId++) { + if ((UINT16) (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment) > 0) { + mAcpiParameter->PcieMultiSegSupport = 1; + break; + } + } + + // + // Update MCFG table entries (segment number, base addr and start/end bus numbers) + // + if (mAcpiParameter->PcieMultiSegSupport == 0) { + + // + // Original code for single PCIe segment start + // + McfgTable->Segment[0].BaseAddress = mIioUds->IioUdsPtr->PlatformData.PciExpressBase; + McfgTable->Segment[0].EndBusNumber = (UINT8)RShiftU64 (mIioUds->IioUdsPtr->PlatformData.PciExpressSize, 20) - 1; + // + // Original code for single PCIe segment end + // + + // + // Single segment with segment number as 0 + // + McfgTable->Segment[0].PciSegmentGroupNumber = 0; + NodeCount = 1; + + } else { + // + // PCIe Multi-Segment handling - Assume each CPU socket as a segment, and copy Segement info from IioUds HOB to MCFG table entries + // + + // + // Segment count = 0 + // + NodeCount = 0; + + for (NodeId = 0; NodeId < MAX_SOCKET; NodeId++) { + + // + // Skip a socket if it does not exist or does not contain valid bus range data + // + if ( (UINT8)(mCpuCsrAccessVarPtr->SocketLastBus[NodeId]) == + (UINT8)(mCpuCsrAccessVarPtr->SocketFirstBus[NodeId]) ) { + continue; + } + + // + // Copy PCIe Segement info from IioUds HOB to MCFG table entries + // + McfgTable->Segment[NodeCount].PciSegmentGroupNumber = (UINT16)(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment); + + McfgTable->Segment[NodeCount].BaseAddress = \ + LShiftU64 (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].SegMmcfgBase.hi, 32) + \ + (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].SegMmcfgBase.lo); + + McfgTable->Segment[NodeCount].StartBusNumber = (UINT8)(mCpuCsrAccessVarPtr->SocketFirstBus[NodeId]); + + McfgTable->Segment[NodeCount].EndBusNumber = (UINT8)(mCpuCsrAccessVarPtr->SocketLastBus[NodeId]); + + // + // Update segment number returned by AML _SEG() . It resides in mAcpiParameter region now. + // + mAcpiParameter->PcieSegNum[NodeId] = (UINT8)(mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[NodeId].PcieSegment); + + // + // Update count of valid segments + // + NodeCount++; + } + } + + // + // Set MCFG table "Length" field based on the number of PCIe segments enumerated so far + // + McfgTable->Header.Header.Length = \ + sizeof (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER) + \ + sizeof (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCATION_STRUCTURE) * NodeCount; + + // + // Debug dump of MCFG table + // + DEBUG ((DEBUG_ERROR, "ACPI MCFG table @ address 0x%x\n", Table )); + DEBUG ((DEBUG_ERROR, " Multi-Seg Support = %x\n", mAcpiParameter->PcieMultiSegSupport)); + DEBUG ((DEBUG_ERROR, " Number of Segments (sockets): %2d\n", NodeCount )); + DEBUG ((DEBUG_ERROR, " Table Length = 0x%x\n\n", McfgTable->Header.Header.Length )); + for (NodeId = 0; NodeId < NodeCount; NodeId ++) { + DEBUG ((DEBUG_ERROR, " Segment[%2d].BaseAddress = %x\n", NodeId, McfgTable->Segment[NodeId].BaseAddress)); + DEBUG ((DEBUG_ERROR, " Segment[%2d].PciSegmentGroupNumber = %x\n", NodeId, McfgTable->Segment[NodeId].PciSegmentGroupNumber)); + DEBUG ((DEBUG_ERROR, " Segment[%2d].StartBusNumber = %x\n", NodeId, McfgTable->Segment[NodeId].StartBusNumber)); + DEBUG ((DEBUG_ERROR, " Segment[%2d].EndBusNumber = %x\n\n", NodeId, McfgTable->Segment[NodeId].EndBusNumber)); + } + + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c new file mode 100644 index 0000000000..603fe57cec --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMigt.c @@ -0,0 +1,69 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2018 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +extern BIOS_ACPI_PARAM *mAcpiParameter; + +/** + Update the MIGT ACPI table + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchMigtAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status; + UINT64 Address; + UINTN idx; + UINT8 checksum; + EFI_MIGT_ACPI_DESCRIPTION_TABLE *MigtAcpiTable; + + MigtAcpiTable = (EFI_MIGT_ACPI_DESCRIPTION_TABLE *)Table; + Address = 0xffffffff; + + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + 1, //page + &Address + ); + + if (EFI_ERROR (Status)) { + return Status; + } + // + // update MIGT ACPI table + // + MigtAcpiTable->ActionRegion.Address = Address; + + // + // update checksum + // + MigtAcpiTable->Header.Checksum = 0; + checksum = 0; + for(idx = 0; idx < sizeof(EFI_MIGT_ACPI_DESCRIPTION_TABLE); idx++) { + checksum = checksum + (UINT8) (((UINT8 *)(MigtAcpiTable))[idx]); + } + MigtAcpiTable->Header.Checksum = (UINT8) (0 - checksum); + + // + // Update Migration Action Region GAS address + // + mAcpiParameter->MigrationActionRegionAddress = Address; + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c new file mode 100644 index 0000000000..1755325d61 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibMsct.c @@ -0,0 +1,101 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +/** + Update the MSCT ACPI table + + @param *MsctAcpiTable - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchMsctAcpiTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINTN idx; + UINT8 checksum; + UINT32 MaxPhysicalAddressBit; + EFI_CPUID_REGISTER CpuidLeafInfo; + EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE *MsctAcpiTable = NULL; + UINT32 MaxThreadCapacity; + UINT32 MaxSocketCount; + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + MsctAcpiTable = (EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE *)Table; + + // + // If SNC is enabled set the Maximum number of Proximity domains accordingly + // + MaxSocketCount = FixedPcdGet32 (PcdMaxCpuSocketCount); + + if (DynamicSiLibraryProtocol2->GetNumOfClusterPerSystem () != 0) { + MsctAcpiTable->MaxNumProxDom = MaxSocketCount * DynamicSiLibraryProtocol2->GetNumOfClusterPerSystem () - 1; + } + + // + // Update Maximum Physical Address + // Get the number of address lines; Maximum Physical Address is 2^MaxPhysicalAddressBit - 1. + // If CPUID does not support reporting the max physical address, then use a max value of 36 as per SDM 3A, 4.1.4. + // + AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuidLeafInfo.RegEax, NULL, NULL, NULL); + MaxPhysicalAddressBit = 36; + if (CpuidLeafInfo.RegEax >= (UINT32) CPUID_VIR_PHY_ADDRESS_SIZE) { + AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &CpuidLeafInfo.RegEax, NULL, NULL, NULL); + MaxPhysicalAddressBit = (UINT8) CpuidLeafInfo.RegEax; + } + + MsctAcpiTable->MaxPhysicalAddress = (LShiftU64 (0x01, MaxPhysicalAddressBit) - 1); + + MaxPhysicalAddressBit = DynamicSiLibraryProtocol2->GetMaxPhysicalAddrBits (); + + MsctAcpiTable->MaxPhysicalAddress = (LShiftU64 (0x01, MaxPhysicalAddressBit) - 1); + + // + // First Proximity Domain Information Structure reports characteristics for all proximity domains, + // since the characteristics are the same for all proximity domains. + // + MsctAcpiTable->ProxDomInfoStructure[0].ProxDomRangeLow = 0; + MsctAcpiTable->ProxDomInfoStructure[0].ProxDomRangeHigh = MsctAcpiTable->MaxNumProxDom; + + // + // Max Number of Threads that the processor can have MaxThreadCapacity + // + AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, NULL, &MaxThreadCapacity, NULL, NULL); + MsctAcpiTable->ProxDomInfoStructure[0].MaxProcessorCapacity = MaxThreadCapacity; + + // + // Max Memory capacity per proximity domain + // + MsctAcpiTable->ProxDomInfoStructure[0].MaxMemoryCapacity = MsctAcpiTable->MaxPhysicalAddress; + + // + // Update Checksum + // + MsctAcpiTable->Header.Checksum = 0; + checksum = 0; + for(idx = 0; idx < sizeof(EFI_ACPI_MAXIMUM_SYSTEM_CHARACTERISTICS_TABLE); idx++) { + checksum = checksum + (UINT8) (((UINT8 *)(MsctAcpiTable))[idx]); + } + MsctAcpiTable->Header.Checksum = (UINT8) (0 - checksum); + + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c new file mode 100644 index 0000000000..cc65d575c3 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibNfit.c @@ -0,0 +1,45 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2019 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +/** + This function locates the CrystalRidge protocol and JedecNvdimm protocol + and calls the update ACPI tables functions defined there to update/build + the NVDIMM F/W Interface Table (NFIT). It builds the NFIT table which gets + published in ACPI XSDT. + + @param[in,out] Table Pointer to NFIT which will be build in + CR Protocol and will be publised in ACPI XSDT. + + @retval EFI_SUCCESS Table successfully updated. + @retval EFI_UNSUPPORTED Table not updated. +**/ +EFI_STATUS +UpdateNfitTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_NFIT_TABLE_UPDATE_PROTOCOL *NfitTableUpdateProtocol = NULL; + EFI_STATUS Status; + + Status = gBS->LocateProtocol (&gEfiNfitTableUpdateProtocolGuid, NULL, &NfitTableUpdateProtocol); + + if (!EFI_ERROR (Status)) { + Status = NfitTableUpdateProtocol->UpdateAcpiTable ((UINT64*) Table); + } else { + DEBUG ((DEBUG_ERROR, "Cannot find NfitTableUpdateProtocol\n")); + } + DEBUG ((DEBUG_INFO, "NFIT Update Status: 0x%x\n", Status)); + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c new file mode 100644 index 0000000000..515e8ffd1d --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPcat.c @@ -0,0 +1,42 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2016 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +/** + This function locates the CrystalRidge Protocol and calls + into one of its interface function (UpdateAcpiPcatTable) to + update/build the PCAT (Platform Capability Attribute Table). + And this table gets published in ACPI XSDT. + + @param *Table - Pointer to PCAT table which will be + build in CR Protocol and will be publised in ACPI + XSDT. + @retval Status - Return Status +**/ +EFI_STATUS +UpdatePcatTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = DynamicSiLibraryProtocol2->UpdatePcatTable (Table); + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c new file mode 100644 index 0000000000..dd9807c899 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibPmtt.c @@ -0,0 +1,267 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 2016 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include "AcpiPlatformLibLocal.h" +#include + +extern struct SystemMemoryMapHob *mSystemMemoryMap; + +/****************************************************************************** + * Definitions. + ******************************************************************************/ +//#define PMTTDEBUG_ENABLED 1 +#if PMTTDEBUG_ENABLED +#define PMTTDEBUG(Expr) _DEBUG(Expr) +#else +#define PMTTDEBUG(Expr) +#endif +#ifndef NELEMENTS +#define NELEMENTS(Array) (sizeof(Array)/sizeof((Array)[0])) +#endif + + +// +// PMTT GUID variables +// +const EFI_GUID gEfiPmttTypeDieGuid = PMTT_TYPE_DIE_GUID; +const EFI_GUID gEfiPmttTypeChannelGuid = PMTT_TYPE_CHANNEL_GUID; +const EFI_GUID gEfiPmttTypeSlotGuid = PMTT_TYPE_SLOT_GUID; + +/****************************************************************************** + * Functions. + ******************************************************************************/ + +EFI_STATUS +PatchPlatformMemoryTopologyTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT8 Socket; + UINT8 Die; + UINT8 Imc; + UINT8 Channel; + UINT8 ChannelIndex; + UINT8 Dimm; + SMBIOS_DIMM_INFO DimmInfo; + SMBIOS_MEM_INFO_PROTOCOL *SmbiosInfoProtocol; + EFI_STATUS Status; + ACPI_PLATFORM_MEMORY_TOPOLOGY_TABLE *PmttTable = (ACPI_PLATFORM_MEMORY_TOPOLOGY_TABLE*)Table; + UINT8 MaxImc; + UINT8 MaxChPerImc; + UINT8 DieCnt; + + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + MaxImc = DynamicSiLibraryProtocol2->GetMaxImc (); + MaxChPerImc = DynamicSiLibraryProtocol2->GetNumChannelPerMc (); + + ASSERT (PmttTable->Header.Signature == ACPI_PMTT_TABLE_SIGNATURE); + + Status = gBS->LocateProtocol (&gSmbiosMemInfoProtocolGuid, NULL, (VOID**)&SmbiosInfoProtocol); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "[ACPI] (PMTT) Cannot locate SmbiosMemInfoProtocol! (%r)\n", Status)); + ASSERT_EFI_ERROR (Status); + SmbiosInfoProtocol = NULL; + } + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + + PmttTable->Socket[Socket].Type = ACPI_TOP_LEVEL_SOCKET; + PmttTable->Socket[Socket].SckIdent = Socket; + PmttTable->Socket[Socket].Length = sizeof(PmttTable->Socket[Socket]) - sizeof(ACPI_PMTT_DIE_DEVICE); + PmttTable->Socket[Socket].Flag = 0; + PmttTable->Socket[Socket].NumOfMemoryDevices = 0; + + if (mSystemMemoryMap->Socket[Socket].SocketEnabled) { + PmttTable->Socket[Socket].Flag |= (PMTT_TOP_LEVEL_AGGREGATOR_DEVICE | PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY); + PmttTable->NumOfMemoryDevices++; + } else { + continue; + } + + DieCnt = DynamicSiLibraryProtocol2->GetAcpiDieCount (Socket); + for (Die = 0; Die < DieCnt; Die++) { + + PmttTable->Socket[Socket].Die[Die].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE; + PmttTable->Socket[Socket].Die[Die].Length = sizeof(PmttTable->Socket[Socket].Die[Die]) - MAX_IMC * sizeof(ACPI_PMTT_IMC_DEVICE); + PmttTable->Socket[Socket].Die[Die].Flag = 0; + PmttTable->Socket[Socket].Die[Die].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY; + PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices = 0; + PmttTable->Socket[Socket].Die[Die].DieId = Die; + CopyGuid (&PmttTable->Socket[Socket].Die[Die].TypeUuid, &gEfiPmttTypeDieGuid); + + PmttTable->Socket[Socket].NumOfMemoryDevices++; + + for (Imc = 0; Imc < MaxImc; Imc++) { + + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Type = ACPI_TOP_LEVEL_IMC; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc]) - MAX_MC_CH * sizeof(ACPI_PMTT_CHANNEL_DEVICE); + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag = 0; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices = 0; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].ImcId = Imc; + + if (mSystemMemoryMap->Socket[Socket].imcEnabled[Imc]) { + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY; + PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices++; + } else { + continue; + } + + for (Channel = 0; Channel < MaxChPerImc; Channel++) { + + ChannelIndex = MEM_IMCCH_TO_SKTCH(Imc, Channel); + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel]) - MAX_DIMM * sizeof(ACPI_PMTT_SLOT_DEVICE); + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag = 0; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices = 0; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].ChannelId = Channel; + CopyGuid (&(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].TypeUuid), &gEfiPmttTypeChannelGuid); + + if (mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].Enabled) { + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices++; + } else { + continue; + } + + for (Dimm = 0; Dimm < MAX_DIMM; Dimm++) { + // + // Looping through the each DIMM on the IMC. + // + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Type = ACPI_TOP_LEVEL_VENDOR_SPECIFIC_DEVICE; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm]) - sizeof(ACPI_PMTT_DIMM_DEVICE); + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices = 0; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].SlotId = Dimm; + CopyGuid (&PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].TypeUuid, &gEfiPmttTypeSlotGuid); + + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Type = PHYSICAL_COMPONENT_IDENTIFIER_TYPE_DIMM; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Length = sizeof(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm); + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.NumOfMemoryDevices = 0; + + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag = 0; + + if (!mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].Present) { + continue; + } + + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag |= PMTT_PHYSICAL_ELEMENT_OF_TOPOLOGY; + + if (mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].DcpmmPresent) { + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag |= PMTT_AEP_DIMM; + } + // + // Get SMBIOS handle for the DIMM. If handle not found use FFFFFFFFh. + // + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle = (UINT32)-1; + if (SmbiosInfoProtocol != NULL) { + + DimmInfo.Socket = Socket; + DimmInfo.Imc = Imc; + DimmInfo.Channel = Channel; + DimmInfo.Dimm = Dimm; + Status = SmbiosInfoProtocol->SmbiosGetDimmByLocation (SmbiosInfoProtocol, &DimmInfo); + if (!EFI_ERROR (Status)) { + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle = DimmInfo.Type17Handle; + } + } + + if (!mSystemMemoryMap->Socket[Socket].ChannelInfo[ChannelIndex].DimmInfo[Dimm].Enabled) { + continue; + } + + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices++; + PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices++; + } // for (Dimm...) + } // for (Channel...) + } // for (Imc...) + } // for (Die...) + } // for (Skt...) + // + // Dump the strucutre for debug purpose + // + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Signature: 0x%08X\n", PmttTable->Header.Signature)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Length: %d\n", PmttTable->Header.Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Revision: %d\n", PmttTable->Header.Revision)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) Checksum: %d\n", PmttTable->Header.Checksum)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemId: '%c%c%c%c%c%c'\n", + PmttTable->Header.OemId[0], PmttTable->Header.OemId[1], PmttTable->Header.OemId[2], + PmttTable->Header.OemId[3], PmttTable->Header.OemId[4], PmttTable->Header.OemId[5])); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemTableId: 0x%08X\n", PmttTable->Header.OemTableId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) OemRevision: %d\n", PmttTable->Header.OemRevision)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) CreatorId: 0x%08X\n", PmttTable->Header.CreatorId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) CreatorRevision: %d\n", PmttTable->Header.OemRevision)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) NumOfMemoryDevices: %d\n", PmttTable->NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "\n")); + for (Socket = 0; Socket < NELEMENTS (PmttTable->Socket); Socket++) { + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Type: 0x%02X\n", Socket, PmttTable->Socket[Socket].Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Length: %d\n", Socket, PmttTable->Socket[Socket].Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] Flags: 0x%04X\n", Socket, PmttTable->Socket[Socket].Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] SocketId: %d\n", Socket, PmttTable->Socket[Socket].SckIdent)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d] NumOfMemoryDevices: %d\n", Socket, PmttTable->Socket[Socket].NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "\n")); + for (Die = 0; Die < NELEMENTS(PmttTable->Socket[Socket].Die); Die++) { + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Type: 0x%02X\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Length: %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] Flags: 0x%04X\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] DieId: %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].DieId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] TypeUuid: %g\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].TypeUuid)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d] NumOfMemoryDevices: %d\n", Socket, Die, PmttTable->Socket[Socket].Die[Die].NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "\n")); + for (Imc = 0; Imc < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc); Imc++) { + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Type: 0x%02X\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Length: %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] Flags: 0x%04X\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] ImcId: %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].ImcId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d] NumOfMemoryDevices: %d\n", Socket, Die, Imc, PmttTable->Socket[Socket].Die[Die].Imc[Imc].NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "\n")); + for (Channel = 0; Channel < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel); Channel++) { + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Type: 0x%02X\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Length: %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] Flags: 0x%04X\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] ChannelId: %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].ChannelId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] TypeUuid: %g\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].TypeUuid)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d] NumOfMemoryDevices: %d\n", Socket, Die, Imc, Channel, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "\n")); + for (Dimm = 0; Dimm < NELEMENTS(PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot); Dimm++) { + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Type: 0x%02X\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Length: %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] Flags: 0x%04X\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] SlotId: %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].SlotId)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] TypeUuid: %g\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].TypeUuid)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d] NumOfMemoryDevices: %d\n", Socket, Die, Imc, Channel, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].NumOfMemoryDevices)); + + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Type: 0x%02X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Type)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Length: %d\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Length)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] Flags: 0x%04X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.Flag)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] SmbiosHandle: 0x%08X\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.SmbiosHandle)); + PMTTDEBUG ((DEBUG_INFO, "[ACPI] (PMTT) [%d][%d][%d][%d][%d][%d] NumOfMemoryDevices: %d\n", Socket, Die, Imc, Channel, Dimm, Dimm, PmttTable->Socket[Socket].Die[Die].Imc[Imc].Channel[Channel].Slot[Dimm].Dimm.NumOfMemoryDevices)); + } // for (Dimm...) + } // for (Channel...) + } // for (Imc...) + } // for (Die...) + } // for (Skt...) + return EFI_SUCCESS; +} // PatchPlatformMemoryTopologyTable () diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c new file mode 100644 index 0000000000..a8ac046aea --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSlit.c @@ -0,0 +1,1153 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" + +extern SYSTEM_MEMORY_MAP_HOB *mSystemMemoryMap; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; + +EFI_ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE_PMEM_INFO mSlitPmemInfo[EFI_ACPI_SLIT_PMEM_INFO_CNT]; + + +/** + Displays System Locality Distance Information Table (SLIT) + + @param None + + @retval None +**/ +VOID +DisplayEntries ( + IN ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr + ) +{ + UINT16 EntryIdx = 0; + UINT16 MaxTableEntries; + UINT8 NodeCount; + + if (SlitPtr == NULL) { + + ASSERT (SlitPtr != NULL); + return; + } + NodeCount = (UINT8)SlitPtr->Header.NumberOfSystemLocalities; + MaxTableEntries = NodeCount * NodeCount; + + DEBUG ((DEBUG_INFO, "SLIT: Dump table (size %d):\n", NodeCount)); + + while (EntryIdx < MaxTableEntries) { + + DEBUG ((DEBUG_INFO, "%02X ", SlitPtr->NumSlit[EntryIdx].Entry)); + if ((EntryIdx % NodeCount) == (NodeCount - 1)) { + DEBUG ((DEBUG_INFO, "\n")); + } + EntryIdx++; + } +} + + +/** + Stores correlation between AEP PMEM NUMA node and socket + + @param[in] Pmem AEP PMEM NUMA node number + @param[in] Socket Socket number + + @retval None + +**/ +VOID +SavePmemInfo ( + IN UINT8 Pmem, + IN UINT8 Socket, + MEM_TYPE Type + ) +{ + if (Pmem < EFI_ACPI_SLIT_PMEM_INFO_CNT) { + + DEBUG ((DEBUG_INFO, "SLIT: Found PMem %d at socket %d (mem type 0x%X)\n", Pmem, Socket, Type)); + mSlitPmemInfo[Pmem].Pmem = Pmem; + mSlitPmemInfo[Pmem].Socket = Socket; + mSlitPmemInfo[Pmem].Valid = TRUE; + return; + } + + DEBUG ((DEBUG_ERROR, "SLIT: Error - Number of PMem nodes (%d) exceed PMem info data table size (%d)\n", + Pmem, EFI_ACPI_SLIT_PMEM_INFO_CNT)); + ASSERT (FALSE); +} + +/** + Retrieves socket correlated with given AEP PMEM NUMA node + + @param[in] Pmem AEP PMEM Numa node + + @retval Socket correlated with given AEP PMEM NUMA node + +**/ +UINT8 +GetSocketForPmem ( + IN UINT8 Pmem + ) +{ + UINT8 PmemInfoEntry; + + for (PmemInfoEntry = 0; PmemInfoEntry < EFI_ACPI_SLIT_PMEM_INFO_CNT; PmemInfoEntry++) { + if (mSlitPmemInfo[PmemInfoEntry].Valid && mSlitPmemInfo[PmemInfoEntry].Pmem == Pmem) { + return mSlitPmemInfo[PmemInfoEntry].Socket; + } + } + + DEBUG ((DEBUG_ERROR, "SLIT: Error - PMem node (%d) is not associated with any socket\n", Pmem)); + ASSERT (FALSE); + return PMEM_INVALID_SOCKET; +} + +/** + This function gets the physical node index for given FPGA NUMA node. + If the given FPGA NUMA node doesn't exist, an invalid physical node + index 0xff will be returned. + + @param[in] FpgaNumaNodeId FPGA NUMA node index (0 based). + + @retval Physical node index of given FPGA NUMA node (0 based). + +**/ +UINT8 +GetPhyNodeIdForFpga ( + IN UINT8 FpgaNumaNodeId + ) +{ + UINT32 FpgaPresentBitMap; + UINT8 PhyNodeId; + + PhyNodeId = 0; + FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap; + + while ((FpgaNumaNodeId != (UINT8) -1) && (FpgaPresentBitMap != 0)) { + if ((FpgaPresentBitMap & BIT0) != 0) { + FpgaNumaNodeId--; + } + FpgaPresentBitMap >>= 1; + PhyNodeId++; + } + + if ((FpgaPresentBitMap == 0) && (FpgaNumaNodeId != (UINT8) -1)) { + return (UINT8) -1; + } + + return PhyNodeId - 1; +} + +/** + Retrieves number of FPGA Presents + + @retval Number of FPGA Presents in the system + +**/ +UINT8 +GetFpgaCount ( + VOID) +{ + UINT8 FpgaCount = 0; + UINT32 FpgaPresentBitMap = mCpuCsrAccessVarPtr->FpgaPresentBitMap; + + while (FpgaPresentBitMap) { + if (FpgaPresentBitMap & BIT0) { + FpgaCount++; + } + FpgaPresentBitMap >>= 1; + } + return FpgaCount; +} + +/** + Retrieves number of AEP PMEM NUMA nodes + + @retval Number of AEP PMEM NUMA nodes + +**/ +UINT8 +GetPmemNodeCount ( + VOID + ) +{ + UINT8 Socket; + UINT8 SadRule; + UINT8 PmemNodeCount = 0; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return 0; + } + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << Socket)) == 0) { + continue; + } + for (SadRule = 0; SadRule < MAX_SAD_RULES; SadRule++) { + // + // Only local SADs of PMEM type should be taken into consideration. + // Skip any memory region marked reserved. + // + if (mSystemMemoryMap->Socket[Socket].SAD[SadRule].local && + DynamicSiLibraryProtocol2->IsMemTypeAppDirect (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type) && + !DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Socket[Socket].SAD[SadRule].type)) { + + SavePmemInfo (PmemNodeCount++, Socket, mSystemMemoryMap->Socket[Socket].SAD[SadRule].type); + } + } + } + + return PmemNodeCount; +} + +/** + Retrieves number of clusters in the system if system is in SNC mode. If system is not + in SNC mode, the return 1. + + @return Number of clusters in the system in SNC mode or 1 if system is not in SNC mode. + +**/ +UINT8 +GetNumClusters ( + VOID + ) +{ + UINT8 NumClusters; + + NumClusters = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster; + if ((NumClusters == 0) || (mIioUds->IioUdsPtr->SystemStatus.OutSncEn == 0)) { + NumClusters = 1; // For non-SNC mode, we should also return 1. + } + if (mSystemMemoryMap->VirtualNumaEnable) { + NumClusters = NumClusters * mSystemMemoryMap->VirtualNumOfCluster; + } + + return NumClusters; +} + +/** + Retrieves number of enabled CPUs in the system + + @param None + + @retval Number of enabled CPUs in the system + +**/ +UINT8 +GetNumCpus ( + VOID + ) +{ + return mIioUds->IioUdsPtr->SystemStatus.numCpus; +} + +/** + Calculates total number of nodes + + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + + @retval Total number of nodes + +**/ +UINT8 +GetNodeCount ( + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount + ) +{ + UINT8 NodeCount; + + if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) { + NodeCount = ((NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT) + PmemNodeCount + FpgaCount); + } else { + NodeCount = ((NumCpus * NumClusters) + PmemNodeCount + FpgaCount); + } + if ((NodeCount * NodeCount) < EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT) { + return NodeCount; + } + + DEBUG ((DEBUG_ERROR, "SLIT: Error - Nodes distances info data size (%d) exceed SLIT distances info table size (%d)\n", + (NodeCount * NodeCount), EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT)); + ASSERT (FALSE); + return 0; +} + +/** + Verifies whether sockets are linked + + @param[in] SourceSocket Source Socket ID + @param[in] TargetSocket Targer Socket ID + + @retval TRUE link between source socket and target socket was found + FALSE otherwise + +**/ +BOOLEAN +SocketsLinked ( + IN UINT32 SourceSocket, + IN UINT32 TargetSocket + ) +{ + UINT8 PeerSocket; + UINT8 LinkValid; + UINT8 PeerSocId; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return FALSE; + } + + // + // Validate sockets ids + // + if ((SourceSocket < MAX_SOCKET) && (TargetSocket < MAX_SOCKET)) { + // + // Do not process when source socket is the same as target socket + // + if (SourceSocket != TargetSocket) { + for (PeerSocket = 0; PeerSocket < (DynamicSiLibraryProtocol2->GetKtiPortCnt()); PeerSocket++) { + LinkValid = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].Valid; + PeerSocId = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SourceSocket].PeerInfo[PeerSocket].PeerSocId; + if (LinkValid && (PeerSocId == TargetSocket)) { + // + // Link found + // + return TRUE; + } + } + } + // + // Link not found + // + return FALSE; + } + + DEBUG ((DEBUG_ERROR, "SLIT: Error when checking if sockets are linked (source socket id %d, target socket id %d)\n", SourceSocket, TargetSocket)); + return FALSE; +} + +/** + Initializes SLIT Table entries + + @param[in,out] Table Pointer to SLIT ACPI tables + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +InitEntries ( + IN OUT ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitPtr + ) +{ + if (SlitPtr == NULL) { + ASSERT (SlitPtr != NULL); + return EFI_INVALID_PARAMETER; + } + SetMem (&SlitPtr->NumSlit[0].Entry, EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT, 0xFF); + + return EFI_SUCCESS; +} + +/** + Processes socket nodes + + @param[in,out] Table Pointer to SLIT ACPI tables + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + @param[in] FpgaCount Number of FPGA NUMA nodes + @param[in] NodeCount Number of all nodes + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessSockets ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 EntryIdx; + UINT8 SourceNode; + UINT8 SourceSocket; + UINT8 SourceCluster; + UINT8 TargetSocket; + UINT8 TargetCluster; + UINT8 VirtualNumaFactor; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket\n")); + return EFI_INVALID_PARAMETER; + } + VirtualNumaFactor = 1; + if (mSystemMemoryMap->VirtualNumaEnable) { + VirtualNumaFactor = mSystemMemoryMap->VirtualNumOfCluster; + } + + DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) { + SourceSocket = SourceNode / NumClusters; + SourceCluster = SourceNode % NumClusters; + for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) { + for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) { + if (SourceSocket == TargetSocket) { + EntryIdx = (SourceNode * (NodeCount)) + (TargetSocket * NumClusters) + TargetCluster; + // + // Source and target are nodes on same socket + // + if ((SourceCluster / VirtualNumaFactor) == (TargetCluster / VirtualNumaFactor)) { + // + // a) Same socket same physical cluster + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_HOP; + } else { + // + // b) Same socket different cluster + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = ZERO_ONE; + } + } + } + } + } + + return EFI_SUCCESS; +} + +/** + Processes socket nodes + + @param[in,out] Table Pointer to SLIT ACPI tables + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + @param[in] FpgaCount Number of FPGA NUMA nodes + @param[in] NodeCount Number of all nodes + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessMixedModeSockets ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 EntryIdx1LM; + UINT16 EntryIdx2LM; + UINT8 SourceNode; + UINT8 SourceSocket; + UINT8 SourceCluster; + UINT8 TargetSocket; + UINT8 TargetCluster; + BOOLEAN Is2LM; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in SLIT update with data about nodes on same socket for Mixed Mode\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "SLIT: Update with data about nodes on same socket for Mixed Mode\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount) ; SourceNode++) { + Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE; + SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters; + SourceCluster = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) % NumClusters; + + TargetSocket = SourceSocket; + for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) { + EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster); + EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters; + + if ((SourceCluster == TargetCluster) && (Is2LM == FALSE)) { + // + // CPU -> 1LM at the same socket, the same cluster + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_HOP; + // + // CPU -> 2LM at the same socket, the same cluster + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_ONE; + } else if ((SourceCluster == TargetCluster) && (Is2LM == TRUE)) { + // + // CPU -> 2LM at the same socket, the same cluster + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE; + // + // not effective + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_HOP; + } else if ((SourceCluster != TargetCluster) && (Is2LM == FALSE)) { + // + // CPU -> 1LM at the same socket, different cluster + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_ONE; + // + // CPU -> 2LM at the same socket, different cluster + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO; + } else { + // + // branch condition: ((SourceCluster != TargetCluster) && (Is2LM == TRUE)) + // CPU -> 2LM at the same socket, different cluster + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ZERO_TWO; + // + // not effective + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ZERO_TWO; + } + } + } + + return EFI_SUCCESS; +} + +/** + Processes connections between sockets to retrieve valid distances + + @param[in,out] Table Pointer to SLIT ACPI tables + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + @param[in] FpgaCount Number of FPGA NUMA nodes + @param[in] NodeCount Number of all nodes + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessSocketsLinks ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT8 SourceNode; + UINT8 SourceSocket; + UINT8 SourceCluster; + UINT8 TargetSocket; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) { + SourceSocket = SourceNode / NumClusters; + SourceCluster = SourceNode % NumClusters; + for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) { + if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) { + SetMem (&SlitAcpiTable->NumSlit[(SourceNode * NodeCount) + (TargetSocket * NumClusters)].Entry, + NumClusters, ONE_HOP); + } + } + } + + return EFI_SUCCESS; +} + +/** + Processes connections between sockets to retrieve valid distances + + @param[in,out] Table Pointer to SLIT ACPI tables + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + @param[in] FpgaCount Number of FPGA NUMA nodes + @param[in] NodeCount Number of all nodes + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessMixedModeSocketsLinks ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 EntryIdx1LM; + UINT16 EntryIdx2LM; + UINT8 SourceNode; + UINT8 SourceSocket; + UINT8 SourceCluster; + UINT8 TargetSocket; + UINT8 TargetCluster; + BOOLEAN Is2LM; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in processing links between sockets in Mixed Mode\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "SLIT: Update table with links between sockets in Mixed Mode\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) { + Is2LM = (SourceNode >= NumCpus * NumClusters) ? TRUE : FALSE; + SourceSocket = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) / NumClusters; + SourceCluster = (SourceNode - NumCpus * NumClusters * (Is2LM ? 1 : 0)) % NumClusters; + + for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) { + if (SocketsLinked (GetSocketPhysicalId (SourceSocket), GetSocketPhysicalId (TargetSocket))) { + // + // If both sockets are linked by KTI and not the same socket. + // + for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) { + EntryIdx1LM = (UINT16)((SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster); + EntryIdx2LM = EntryIdx1LM + NumCpus * NumClusters; + + if (Is2LM == FALSE) { + // + // CPU -> 1LM at different socket + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_HOP; + // + // CPU -> 2LM at different socket + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_ONE; + } else { + // + // branch condition: (Is2LM == TRUE) + // CPU -> 2LM at different socket + // + SlitAcpiTable->NumSlit[EntryIdx1LM].Entry = ONE_ONE; + // + // not effective + // + SlitAcpiTable->NumSlit[EntryIdx2LM].Entry = ONE_TWO; + } + } + } + } + } + + return EFI_SUCCESS; +} + +/** + Processes all AEP PMEM NUMA nodes + + @param[in,out] Table Pointer to SLIT ACPI tables + @param[in] NumCpus Number of CPUs + @param[in] NumClusters Number of clusters + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes + @param[in] FpgaCount Number of FPGA NUMA nodes + @param[in] NodeCount Number of all nodes + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessPmems ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumCpus, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 EntryIdx; + UINT8 SourceNode; + UINT8 TargetNode; + UINT8 SourceSocket; + UINT8 TargetCluster; + UINT8 TargetSocket; + UINT8 SourcePmem; + UINT8 TargetPmem; + UINT8 SourcePmemSocket; + UINT8 TargetPmemSocket; + UINT8 TotalVolMemNodes; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in processing PMems\n")); + return EFI_INVALID_PARAMETER; + } + + if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) { + TotalVolMemNodes = NumCpus * NumClusters * EFI_ACPI_SLIT_DOMAINS_NODES_MAX_CNT; + } else { + TotalVolMemNodes = NumCpus * NumClusters; + } + + DEBUG ((DEBUG_INFO, "SLIT: Include PMem NUMA nodes\n")); + + if (PmemNodeCount > 0) { + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + // + // 1) AEP PMEM nodes to AEP PMEM nodes distances + // + for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) { + SourcePmem = SourceNode - TotalVolMemNodes; + for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) { + TargetNode = TargetPmem + TotalVolMemNodes; + EntryIdx = (SourceNode * NodeCount) + TargetNode; + if (SourcePmem == TargetPmem) { + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ZERO_HOP; + } else { + // + // Retrieve sockets associated with PMEMs + // + SourcePmemSocket = GetSocketForPmem (SourcePmem); + TargetPmemSocket = GetSocketForPmem (TargetPmem); + + if (SourcePmemSocket == TargetPmemSocket) { + // + // PMEMs are on the same socket + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE; + } else { + // + // Assign 2 hop and process with PeerInfo checking + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP; + + // + // Examine PeerInfo to look for link between AEP PMEM source socket and AEP PMEM target socket + // + if (SocketsLinked (SourcePmemSocket, TargetPmemSocket)) { + // + // Link found assign 1 hop + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP; + } + } + } + } + } + + // + // 2) Sockets to AEP PMEM nodes distances + // + for (SourceNode = 0; SourceNode < (NodeCount - PmemNodeCount - FpgaCount); SourceNode++) { + SourceSocket = GetSocketPhysicalId (SourceNode / NumClusters); + for (TargetPmem = 0; TargetPmem < PmemNodeCount; TargetPmem++) { + TargetPmemSocket = GetSocketForPmem (TargetPmem); + TargetNode = TargetPmem + TotalVolMemNodes; + EntryIdx = (SourceNode * NodeCount) + TargetNode; + if (SourceSocket == TargetPmemSocket) { + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE; + } else { + // + // Assign 2 hop and process with PeerInfo checking + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP; + + // + // Examine PeerInfo to look for link between source socket and AEP PMEM socket + // + if (SocketsLinked (SourceSocket, TargetPmemSocket)) { + // + // Link found assign 1 hop + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP; + } + } + } + } + + // + // 3) AEP PMEM nodes to sockets distances + // + for (SourceNode = (NodeCount - PmemNodeCount - FpgaCount); SourceNode < (NodeCount - FpgaCount); SourceNode++) { + SourcePmem = SourceNode - TotalVolMemNodes; + SourcePmemSocket = GetSocketForPmem (SourcePmem); + for (TargetSocket = 0; TargetSocket < NumCpus; TargetSocket++) { + for (TargetCluster = 0; TargetCluster < NumClusters; TargetCluster++) { + EntryIdx = (SourceNode * NodeCount) + (TargetSocket * NumClusters) + TargetCluster; + if(SourcePmemSocket == GetSocketPhysicalId (TargetSocket)) { + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_ONE; + } else { + // + // Assign 2 hop and process with PeerInfo checking + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_TWO_HOP; + + // + // Examine PeerInfo to look for link between source socket and AEP PMEM socket + // + if (SocketsLinked (SourcePmemSocket, GetSocketPhysicalId (TargetSocket))) { + // + // Link found assign 1 hop + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = PMEM_ONE_HOP; + } + } + } + } + } + } else { + DEBUG ((DEBUG_INFO, "SLIT: PMem NUMA nodes not present\n")); + } + + return EFI_SUCCESS; +} + +/** + This function processes all FPGA NUMA nodes. + + @param[in,out] Table Pointer to SLIT ACPI tables. + @param[in] NumClusters Number of clusters. + @param[in] PmemNodeCount Number of AEP PMEM NUMA nodes. + @param[in] FpgaCount Number of FPGA NUMA nodes. + @param[in] NodeCount Number of all nodes. + + @retval EFI_SUCCESS This function is executed successfully. + @retval EFI_INVALID_PARAMETER Some of input parameters are invalid. +**/ +EFI_STATUS +ProcessFpgaNodes ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN UINT8 NumClusters, + IN UINT8 PmemNodeCount, + IN UINT8 FpgaCount, + IN UINT8 NodeCount + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT8 SourceNode; + UINT8 TargetNode; + UINT8 SourceSocket; + UINT8 TargetSocket; + + if (Table == NULL) { + DEBUG ((DEBUG_ERROR, "SLIT: Error in processing FPGA nodes\n")); + return EFI_INVALID_PARAMETER; + } + + if (FpgaCount == 0) { + return EFI_SUCCESS; + } + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + for (SourceNode = (NodeCount - FpgaCount); SourceNode < NodeCount; SourceNode++) { + SourceSocket = GetPhyNodeIdForFpga (SourceNode - (NodeCount - FpgaCount)); + + for (TargetNode = 0; TargetNode < NodeCount; TargetNode++) { + if (TargetNode < (NodeCount- PmemNodeCount - FpgaCount)) { + TargetSocket = GetSocketPhysicalId (TargetNode / NumClusters); // Normal nodes + } else if (TargetNode < (NodeCount - FpgaCount)) { + TargetSocket = GetSocketForPmem (TargetNode - (NodeCount - PmemNodeCount - FpgaCount)); // PMEM nodes + } else { + TargetSocket = GetPhyNodeIdForFpga (TargetNode - (NodeCount - FpgaCount)); // FPGA nodes + } + + if (SourceSocket == TargetSocket) { + SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ZERO_HOP; + } else if (SocketsLinked (SourceSocket, TargetSocket)) { + SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = ONE_HOP; + SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = ONE_HOP; + } else { + SlitAcpiTable->NumSlit[SourceNode * NodeCount + TargetNode].Entry = TWO_HOP; + SlitAcpiTable->NumSlit[TargetNode * NodeCount + SourceNode].Entry = TWO_HOP; + } + } + } + + return EFI_SUCCESS; +} + +/** + Processes all remaining valid SLIT nodes + + @param[in,out] Table pointer to SLIT ACPI tables + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessRemainingNodes ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 EntryIdx = 0; + UINT16 MaxTableEntries; + UINT8 NodeCount; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error while processing remaining valid nodes\n")); + return EFI_INVALID_PARAMETER; + } + + DEBUG ((DEBUG_INFO, "SLIT: Fill in the rest of the SLIT table\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities; + MaxTableEntries = NodeCount * NodeCount; + + while (EntryIdx < MaxTableEntries) { + if (SlitAcpiTable->NumSlit[EntryIdx].Entry == 0xFF) { + // + // This entry has not been filled yet, assign 2 hop to this table entry + // + SlitAcpiTable->NumSlit[EntryIdx].Entry = TWO_HOP; + } + + if ((EntryIdx % NodeCount) == 0) { + DEBUG ((DEBUG_INFO, "[%2d - %2d] ", EntryIdx/NodeCount, EntryIdx%NodeCount)); + } + EntryIdx++; + } + + return EFI_SUCCESS; +} + +/** + Processes unused SLIT nodes + + @param[in,out] Table pointer to SLIT ACPI tables + + @retval EFI_SUCCESS operation completed successfully + +**/ +EFI_STATUS +ProcessUnusedNodes ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + UINT16 MaxTableEntries; + UINT8 NodeCount; + + if (NULL == Table) { + DEBUG ((DEBUG_ERROR, "SLIT: Error while processing unused nodes\n")); + return EFI_INVALID_PARAMETER; + + } + + DEBUG ((DEBUG_INFO, "SLIT: Zero out the unused nodes\n")); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + + NodeCount = (UINT8)SlitAcpiTable->Header.NumberOfSystemLocalities; + MaxTableEntries = NodeCount * NodeCount; + + SetMem (&SlitAcpiTable->NumSlit[MaxTableEntries], + (UINTN)&SlitAcpiTable->NumSlit[EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT] - (UINTN)&SlitAcpiTable->NumSlit[MaxTableEntries], 0); + + return EFI_SUCCESS; +} + +/** + Updates System Locality Distance Information Table (SLIT) + + @param[in,out] Table pointer to SLIT ACPI tables + + @retval EFI_SUCCESS operation completed successfully + @retval EFI_ABORTED operation not completed due to processing error + +**/ +EFI_STATUS +PatchSLitTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *SlitAcpiTable; + EFI_STATUS Status; + UINT8 NodeCount; + UINT8 NumCpus; + UINT8 NumClusters; + UINT8 PmemNodeCount; + UINT8 FpgaCount; + + NumCpus = GetNumCpus (); + NumClusters = GetNumClusters (); + PmemNodeCount = GetPmemNodeCount (); + FpgaCount = GetFpgaCount(); + NodeCount = GetNodeCount (NumCpus, NumClusters, PmemNodeCount, FpgaCount); + + DEBUG ((DEBUG_INFO, "SLIT: NumCpus %d, NumClusters %d, PmemNodeCount %d -> NodeCount %d FpgaCount %d\n", + NumCpus, NumClusters, PmemNodeCount, NodeCount,FpgaCount)); + + SlitAcpiTable = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *)Table; + SlitAcpiTable->Header.NumberOfSystemLocalities = NodeCount; + + // + // 1) Initialize all entries to 0xFF + // + Status = InitEntries (SlitAcpiTable); + + // + // 2) Update SLIT table with data about nodes on same socket + // + if (!EFI_ERROR(Status)) { + if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) { + Status = ProcessMixedModeSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } else { + Status = ProcessSockets (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } + } + + // + // 3) Update table with links between sockets by examining PeerInfo structure + // + if (!EFI_ERROR (Status)) { + if (mSystemMemoryMap->volMemMode == VOL_MEM_MODE_MIX_1LM2LM) { + Status = ProcessMixedModeSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } else { + Status = ProcessSocketsLinks (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } + } + + // + // 4) Update table with PMEMs + // + if (!EFI_ERROR (Status)) { + Status = ProcessPmems (Table, NumCpus, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } + + // + // 5 Update table with FPGA + // + if (!EFI_ERROR (Status)) { + Status = ProcessFpgaNodes (Table, NumClusters, PmemNodeCount, FpgaCount, NodeCount); + } + + // + // 6) Fill in the rest of the Slit table, 2 hops between any remaining valid nodes + // + if (!EFI_ERROR (Status)) { + Status = ProcessRemainingNodes (Table); + } + + // + // 7) Zero out the unused nodes + // + if (!EFI_ERROR (Status)) { + Status = ProcessUnusedNodes (Table); + } + + // + // 8) Print the entire SLIT table + // + if (!EFI_ERROR (Status)) { + DisplayEntries (SlitAcpiTable); + } + + ASSERT_EFI_ERROR (Status); + return Status; +} + +/** + Allocate memory and fill SLIT information to this buffer, then + install this table to ACPI table. + + @retval EFI_SUCCESS Install table success. + @retval EFI_OUT_OF_RESOURCES Out of memory. + +**/ +EFI_STATUS +InstallSlitTable ( + VOID + ) +{ + ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *Table; + UINTN TableSize; + UINT8 NumClusters; + UINTN TableHandle = 0; + EFI_STATUS Status; + + NumClusters = GetNumClusters (); + + TableSize = sizeof (EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_HEADER) + + sizeof (ACPI_SYSTEM_LOCALITIES_STRUCTURE) * EFI_ACPI_SYSTEM_LOCALITIES_ENTRY_COUNT; + + Table = (ACPI_SYSTEM_LOCALITY_INFORMATION_TABLE *) AllocateZeroPool (TableSize); + if (Table == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Table->Header.Header.Signature = EFI_ACPI_6_2_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE; + Table->Header.Header.Length = (UINT32) TableSize; + Table->Header.Header.Revision = EFI_ACPI_6_2_SYSTEM_LOCALITY_DISTANCE_INFORMATION_TABLE_REVISION; + Table->Header.Header.OemRevision = EFI_ACPI_OEM_SLIT_REVISION; + CopyMem (Table->Header.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->Header.Header.OemId)); + Table->Header.Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + Table->Header.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + Table->Header.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + // + // All node init with 0 before pass to patcher + // + PatchSLitTable ((EFI_ACPI_COMMON_HEADER *)&Table->Header.Header); + + // + // Publish SLIT Structure to ACPI + // + + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + Table, + Table->Header.Header.Length, + &TableHandle + ); + + // + // Free memory + // + if (Table != NULL) { + FreePool (Table); + } + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c new file mode 100644 index 0000000000..c19c942274 --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSrat.c @@ -0,0 +1,952 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include +#include +#include +#include + +extern BOOLEAN mX2ApicEnabled; +extern struct SystemMemoryMapHob *mSystemMemoryMap; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; +extern SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration; +extern UINT32 mNumOfBitShift; +extern UINT32 mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD]; +extern UINTN mNumberOfCPUs; +extern CPU_ID_ORDER_MAP mCpuApicIdOrderTable[]; +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTable; +extern CPU_CSR_ACCESS_VAR *mCpuCsrAccessVarPtr; + +UINT32 mPackageChaTotal[MAX_SOCKET]; + +CPU_LOGICAL_THREAD_ID_TABLE mCpuThreadIdMsrTable[MAX_CPU_NUM]; + +static ACPI_PLATFORM_PROTOCOL mAcpiPlatformProtocol; + +struct _ACPI_PLATFORM_UTILS_MEM_AFF_DATA { + EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE AcpiMemAffData[MEMORY_AFFINITY_STRUCTURE_COUNT]; + BOOLEAN AcpiMemAffDataValid; +} mAcpiPlatformMemAffData; + + +VOID +CollectThreadIdMsrData ( + IN UINT8 SncEnabled, + IN UINT8 SncNumOfCluster + ); + +UINT32 +GetProximityDomainForSNC ( + UINT32 ApicId + ); + + +/** + This function counts the number of bits set in a 32-bit unsigned integer. + + @param[in] Value The 32-bit unsigned integer to count. + + @retval The number of set bits. +**/ +UINT8 +BitCount32 ( + IN UINT32 Value + ) +{ + UINT8 Count; + + Count = 0; + while (Value != 0) { + Value &= Value - 1; + Count++; + } + + return Count; +} + +/** + Get the socket logical index. + + This function convert the socket physical index to logical index (0 based). + If the specified physical socket is not enabled, an invalid logical index 0xff + will be returned. The socket physical index and logical index will be the same + if the indexes of enabled sockets are continuous. + + @param[in] SocketPhysicalId Socket physical index. + + @retval Socket logical index. +**/ +UINT8 +GetSocketLogicalId ( + IN UINT8 SocketPhysicalId + ) +{ + UINT32 SocketBitMap; + + if ((mCpuCsrAccessVarPtr->socketPresentBitMap & (BIT0 << SocketPhysicalId)) == 0) { + return (UINT8) -1; + } + + SocketBitMap = mCpuCsrAccessVarPtr->socketPresentBitMap & ((BIT0 << SocketPhysicalId) - 1); + return BitCount32 (SocketBitMap); +} + +/** + Get the socket physical index. + + This function convert the socket logical index to physical index (0 based). + If the specified logical socket does not exist, an invalid physical index 0xff + will be returned. The socket physical index and logical index will be the same + if the indexes of enabled sockets are continuous. + + @param[in] SocketLogicalId Socket logical index. + + @retval Socket physical index. +**/ +UINT8 +GetSocketPhysicalId ( + IN UINT8 SocketlogicId + ) +{ + UINT32 SocketBitMap; + + SocketBitMap = mCpuCsrAccessVarPtr->socketPresentBitMap; + + while (SocketlogicId != 0) { + SocketBitMap &= SocketBitMap - 1; + SocketlogicId--; + } + + if (SocketBitMap == 0) { + return (UINT8) -1; + } + + return BitCount32 (SocketBitMap ^ (SocketBitMap - 1)) - 1; +} + +/** + + Update the SRAT APIC IDs. + + @param *SRAAcpiTable - The table to be set + + @retval EFI_SUCCESS - Returns Success + +**/ +EFI_STATUS +PatchSratAllApicIds( + IN OUT STATIC_RESOURCE_AFFINITY_TABLE *SRAAcpiTable + ) +{ + UINT16 ThreadIndex; // Support more than 256 threads (8S case) + UINT8 *ApicTablePtr; + UINT8 socket; + UINT8 Index; + + ThreadIndex = 0; + for (socket = 0; socket < MAX_SOCKET; socket++) { + ApicTablePtr = (UINT8*)mApicIdMap[socket]; + // + // Even IDs must be list first + // + for (Index = 0; Index < MAX_CORE * MAX_THREAD; Index += 2) { + SRAAcpiTable->Apic[ThreadIndex].ApicId = (UINT8)ApicTablePtr[Index] + (socket << mNumOfBitShift); + SRAAcpiTable->Apic[ThreadIndex].ProximityDomain7To0 = socket; //as ProxDomain are all 0, or we can come up some algorithm if there is any dependency + if ((UINT8)ApicTablePtr[Index] != 0xff) { + SRAAcpiTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED; + } + ThreadIndex++; + } //end of for coreThreadIndex + } //end for socket + + for (socket = 0; socket < MAX_SOCKET; socket++) { + // + // for odd APICID and must be after all even APICIDs + // + ApicTablePtr = (UINT8*)mApicIdMap[socket]; + for (Index = 1; Index < MAX_CORE * MAX_THREAD; Index += 2) { + SRAAcpiTable->Apic[ThreadIndex].ApicId = (UINT8)ApicTablePtr[Index] + (socket << mNumOfBitShift); + SRAAcpiTable->Apic[ThreadIndex].ProximityDomain7To0 = socket; //as ProxDomain are all 0, or we can come up some algorithm if there is any dependency + if ((UINT8)ApicTablePtr[Index] != 0xff) { + SRAAcpiTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED; + } + ThreadIndex++; + } + } //end of for coreThreadIndex + ASSERT (ThreadIndex == MAX_CPU_NUM); + return EFI_SUCCESS; +} + +UINT32 +ProximityDomainOf ( + UINT8 SocketId, + UINT16 MemType, + UINT8 MaxEnabledImc, + UINT8 SncEnabled, + UINT8 SncNumOfCluster, + UINT8 ImcInterBitmap, + UINT8 MemMode, + UINT32 LastDomainId + ) +{ + UINT32 DomainId = (UINT16)~0; + INTN FirstImc; + UINT8 ImcPerCluster; + UINT8 NumSockets = mIioUds->IioUdsPtr->SystemStatus.numCpus; + UINT8 SocketLogicalId; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + + if (SncEnabled == 0) { + SncNumOfCluster = 1; + } + + if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (MemType)) { + // + // Persistent memory nodes and FPGA nodes are just pending behinds volatile memories + // + DomainId = LastDomainId + 1; + } else { + SocketLogicalId = GetSocketLogicalId (SocketId); + // + // Process volatile memory nodes + // + if (SncEnabled == 0) { + DomainId = SocketLogicalId; + } else { + // + // Find the cluster ID using ImcInterBitmap + // + ImcPerCluster = MAX_IMC / SncNumOfCluster; + FirstImc = LowBitSet32 (ImcInterBitmap); + if (FirstImc == -1) { + FirstImc = 0; + } + if (MaxEnabledImc <= SncNumOfCluster) { + DomainId = (SocketLogicalId * SncNumOfCluster) + (UINT32) (FirstImc / ImcPerCluster); + } else { + DomainId = (SocketLogicalId * SncNumOfCluster) + ((UINT32) FirstImc) / ImcPerCluster; + } + } + if (MemMode == VOL_MEM_MODE_MIX_1LM2LM) { + // + // 2LM nodes follow the completion of iteration of all 1LM nodes + // + DomainId += (UINT32)((DynamicSiLibraryProtocol2->IsMemType2lm (MemType) ? 1 : 0) * NumSockets * SncNumOfCluster); + } + } + + DEBUG ((DEBUG_INFO, "SocketId = %d, SncEnabled = %d, SncNumOfCluster = %d, ImcInterBitmap = 0x%x, ", + SocketId, SncEnabled, SncNumOfCluster, ImcInterBitmap)); + + DEBUG ((DEBUG_INFO, "MemType = %d, MemMode = %d, Physical DomainId = %d\n", + MemType, MemMode, DomainId)); + + return DomainId; +} + +VOID +PatchMemorySratEntries ( + IN OUT STATIC_RESOURCE_AFFINITY_TABLE *SratTable, + UINT8 SncEnabled, + UINT8 SncNumOfCluster, + UINT8 *LastIndexUsed + ) +{ + UINT8 LegacyNodeId; + UINT8 NodeId; + UINT8 Index; + UINT8 TableIndex = 0; + UINT8 Socket; + UINT32 LastDomainId = 0; + UINT64 MemoryAddress; + UINT64 MemorySize; + UINT8 Pass; + UINT8 PrevIndex; + BOOLEAN SkipEntry; + UINT8 MaxEnabledImc = 0; + UINTN ImcIndex; + UINT8 MemSocketBitmap = 0; + UINT8 NoMemSocketBitmap; + UINT32 ProximityDomain; + UINT8 PhysicalClusters; + UINT8 VirtualClusters; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + LegacyNodeId = 0xFF; + DEBUG ((DEBUG_INFO, "\nSRAT: Updating SRAT memory information!\n")); + DEBUG ((DEBUG_INFO, "Idx Base Length Proximity Flags\n")); + + if (mSystemMemoryMap->VirtualNumaEnable) { + PhysicalClusters = SncNumOfCluster / mSystemMemoryMap->VirtualNumOfCluster; + VirtualClusters = mSystemMemoryMap->VirtualNumOfCluster; + } else { + PhysicalClusters = SncNumOfCluster; + VirtualClusters = 1; + } + + // + // Looping the System Memory Map elements twice + // Fist loop creates domains for all volatile regions based on socket + // The second loop creates domains for all persistent memory ranges + // + for (Pass = 1; Pass < 3; Pass++ ) { + TableIndex = 0; + for (Index = 0; Index < mSystemMemoryMap->numberEntries; Index++ ) { + SkipEntry = FALSE; + NodeId = mSystemMemoryMap->Element[Index].NodeId; + ASSERT (NodeId < MC_MAX_NODE); + + if (TableIndex >= MEMORY_AFFINITY_STRUCTURE_COUNT) { + ASSERT (0); + break; + } + + // + // Skip any memory region marked reserved + // + if (DynamicSiLibraryProtocol2->IsMemTypeReserved (mSystemMemoryMap->Element[Index].Type)) { + continue; + } + + // + // As the HOB has base addr in 64 MB chunks + // + MemoryAddress = ((UINT64)mSystemMemoryMap->Element[Index].BaseAddress << MEM_ADDR_SHFT_VAL); + + // + // Skip duplicate entries if applicable + // + if (TableIndex) { + for (PrevIndex = 0; PrevIndex < TableIndex; PrevIndex++) { + if (MemoryAddress == ((UINT64)SratTable->Memory[PrevIndex].AddressBaseHigh << 32) + SratTable->Memory[PrevIndex].AddressBaseLow) { + SkipEntry = TRUE; + break; + } + } + } + if (SkipEntry) { + continue; + } + + // + // Update bitmap for sockets with memory populated + // + if (DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) { + MemSocketBitmap |= BIT0 << mSystemMemoryMap->Element[Index].SocketId; + } + + SratTable->Memory[TableIndex].AddressBaseLow = (UINT32)(MemoryAddress & 0xFFFFFFFF); + SratTable->Memory[TableIndex].AddressBaseHigh = (UINT32)((UINTN)MemoryAddress >> 32); + + // + // As the HOB has Length in 64 MB chunks + // + MemorySize = ((UINT64)mSystemMemoryMap->Element[Index].ElementSize << MEM_ADDR_SHFT_VAL); + SratTable->Memory[TableIndex].LengthLow = (UINT32)(MemorySize & 0xFFFFFFFF); + SratTable->Memory[TableIndex].LengthHigh = (UINT32)((UINTN)MemorySize >> 32); + + if ((Pass == 2) || DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type)) { + + // + // Get max enabled IMC for this socket + // + for (ImcIndex = 0, MaxEnabledImc = 0; ImcIndex < MAX_IMC; ImcIndex++) { + if (mSystemMemoryMap->Socket[mSystemMemoryMap->Element[Index].SocketId].imcEnabled[ImcIndex] != 0) { + MaxEnabledImc ++; + } + } + + ProximityDomain = ProximityDomainOf ( + mSystemMemoryMap->Element[Index].SocketId, + mSystemMemoryMap->Element[Index].Type, + MaxEnabledImc, + SncEnabled, + PhysicalClusters, + mSystemMemoryMap->Element[Index].ImcInterBitmap, + mSystemMemoryMap->volMemMode, + LastDomainId + ); + SratTable->Memory[TableIndex].ProximityDomain = (ProximityDomain * VirtualClusters) + (Index % VirtualClusters); + if (LastDomainId < SratTable->Memory[TableIndex].ProximityDomain) { + LastDomainId = SratTable->Memory[TableIndex].ProximityDomain; + } + if ((MemoryAddress == 0) && (MemorySize > 0)) { + LegacyNodeId = NodeId; + } + + // + // Enable the Memory structure + // + if ((LegacyNodeId == NodeId) || (!mSocketMemoryConfiguration.SratMemoryHotPlug) ) { + SratTable->Memory[TableIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED; + } else { + SratTable->Memory[TableIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED | EFI_ACPI_6_2_MEMORY_HOT_PLUGGABLE; + } + if (!DynamicSiLibraryProtocol2->IsMemTypeVolatile (mSystemMemoryMap->Element[Index].Type) && + !DynamicSiLibraryProtocol2->IsMemTypeFpga (mSystemMemoryMap->Element[Index].Type)) { + SratTable->Memory[TableIndex].Flags |= EFI_ACPI_6_2_MEMORY_NONVOLATILE; + } + + if (Pass == 2) { + DEBUG ((DEBUG_INFO, "%3d %08x%08x, %08x%08x %2x %x\n", + TableIndex, + SratTable->Memory[TableIndex].AddressBaseHigh, + SratTable->Memory[TableIndex].AddressBaseLow, + SratTable->Memory[TableIndex].LengthHigh, + SratTable->Memory[TableIndex].LengthLow, + SratTable->Memory[TableIndex].ProximityDomain, + SratTable->Memory[TableIndex].Flags)); + } + } + TableIndex++; + } + // + // Update LastDomainId for enabled sockets with no memory + // + NoMemSocketBitmap = mCpuCsrAccessVarPtr->socketPresentBitMap & ~MemSocketBitmap; + if (Pass == 1) { + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if ((BIT0 << Socket) & NoMemSocketBitmap) { + LastDomainId += SncNumOfCluster; + } + } + } + } + + *LastIndexUsed = TableIndex; +} + +EFI_STATUS +PatchSratTable ( + IN OUT STATIC_RESOURCE_AFFINITY_TABLE *SratTable + ) +{ + UINT8 Index; + UINT8 NewIndex; + UINT16 ThreadIndex; // Support more than 256 threads (8S case) + UINT8 NodeId; + UINTN HighTopMemory; + UINTN HotPlugBase; + UINTN HotPlugLen; + UINT8 SncEnabled; + UINT8 SncNumOfCluster; + + SncEnabled = mIioUds->IioUdsPtr->SystemStatus.OutSncEn; + SncNumOfCluster = mIioUds->IioUdsPtr->SystemStatus.OutNumOfCluster; + + if (mSystemMemoryMap != NULL) { + if (mSystemMemoryMap->VirtualNumaEnable) { + if (SncEnabled) { + SncNumOfCluster = SncNumOfCluster * mSystemMemoryMap->VirtualNumOfCluster; + } else { + // + // If Virtual NUMA enabled without SNC, use the number of Virtual NUMA clusters. + // Do not multiply by "OutNumOfCluster" if the system is in a UMA Based Clustering mode (e.g. Hemisphere). + // + SncNumOfCluster = mSystemMemoryMap->VirtualNumOfCluster; + SncEnabled = 1; + } + } + } + + if (SncNumOfCluster == 0) { + SncNumOfCluster = 1; + } + + CollectThreadIdMsrData (SncEnabled, SncNumOfCluster); + + if (mSocketMemoryConfiguration.SratCpuHotPlug) { + PatchSratAllApicIds (SratTable); + } else { + DEBUG (( DEBUG_INFO, "-------- SRAT TABLE ---------- %x\n", PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT)); + + for (ThreadIndex = 0; ThreadIndex < PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT; ThreadIndex++) { + if (ThreadIndex < mNumberOfCPUs) { + + // + // Use mCpuThreadIdMsrTable.ApicId by sorting SRAT sequentially to fix proximity domain grouping of threads in OSes + // + if (mX2ApicEnabled) { + SratTable->x2Apic[ThreadIndex].ProximityDomain = GetProximityDomainForSNC (mCpuThreadIdMsrTable[ThreadIndex].ApicId); + SratTable->x2Apic[ThreadIndex].X2ApicId = mCpuThreadIdMsrTable[ThreadIndex].ApicId; + SratTable->x2Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED; + } else { + // + // If SNC is enabled and 2 clusters, there is 1 extra Proximity Domain per socket + // SNC cannot exist unless all HA's have memory + // + SratTable->Apic[ThreadIndex].ProximityDomain7To0 = (UINT8)GetProximityDomainForSNC (mCpuThreadIdMsrTable[ThreadIndex].ApicId); + SratTable->Apic[ThreadIndex].ApicId = (UINT8)mCpuThreadIdMsrTable[ThreadIndex].ApicId; + SratTable->Apic[ThreadIndex].Flags = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_ENABLED; + } + } else { + if (mX2ApicEnabled) { + SratTable->x2Apic[ThreadIndex].X2ApicId = (UINT32)-1; + } else { + SratTable->Apic[ThreadIndex].ApicId = 0xFF; + } + } + if (mX2ApicEnabled) { + DEBUG (( DEBUG_INFO, "\nSRAT: CpuThreadIndex\t%x, ApicId\t%x, Flags\t%x!\n", + ThreadIndex, SratTable->x2Apic[ThreadIndex].X2ApicId, SratTable->x2Apic[ThreadIndex].Flags)); + } else { + DEBUG (( DEBUG_INFO, "\nSRAT: CpuThreadIndex\t%x, ApicId\t%x, Flags\t%x, ProximityDomain\t%x!\n", + ThreadIndex, SratTable->Apic[ThreadIndex].ApicId, SratTable->Apic[ThreadIndex].Flags, + SratTable->Apic[ThreadIndex].ProximityDomain7To0)); + } + } + } + + if (mSystemMemoryMap != NULL) { + + PatchMemorySratEntries (SratTable, SncEnabled, SncNumOfCluster, &Index); + + HotPlugBase = 0x100; + if (mSocketMemoryConfiguration.MemoryHotPlugBase == 0) { // Auto + // + // Read the actual TOHM and set it as the hot memory base + // + HighTopMemory = (UINT64)mIioUds->IioUdsPtr->SystemStatus.tohmLimit << 26; + HotPlugBase = (HighTopMemory >> 32); + if ((UINT32)HighTopMemory > 0) { + HotPlugBase++; + } + } else if (mSocketMemoryConfiguration.MemoryHotPlugBase) { // Number + HotPlugBase = mSocketMemoryConfiguration.MemoryHotPlugBase * 0x80; + } + HotPlugLen = (mSocketMemoryConfiguration.MemoryHotPlugLen + 1) * 0x10; + + if (mSocketMemoryConfiguration.SratMemoryHotPlug) { + DEBUG (( DEBUG_INFO, "SRAT: Updating SRAT hotplug memory information!\n" )); + for (NodeId = 0; NodeId < MC_MAX_NODE; NodeId++) { + NewIndex = Index + NodeId; + if (NewIndex >= MEMORY_AFFINITY_STRUCTURE_COUNT) { + ASSERT (0); + break; + } + // + // As the HOB has base addr in 1 GB chunks + // + SratTable->Memory[NewIndex].ProximityDomain = (NodeId >> 1); + SratTable->Memory[NewIndex].AddressBaseLow = 0; + SratTable->Memory[NewIndex].AddressBaseHigh = (UINT32)(HotPlugBase + NodeId * HotPlugLen); + SratTable->Memory[NewIndex].LengthLow = 0; + SratTable->Memory[NewIndex].LengthHigh = (UINT32)HotPlugLen; + SratTable->Memory[NewIndex].Flags = EFI_ACPI_6_2_MEMORY_ENABLED | EFI_ACPI_6_2_MEMORY_HOT_PLUGGABLE; + + DEBUG ((DEBUG_INFO, "%3d %08x%08x %08x%08x %x %x\n", NewIndex, + SratTable->Memory[Index].AddressBaseHigh, + SratTable->Memory[Index].AddressBaseLow, + SratTable->Memory[Index].LengthHigh, + SratTable->Memory[Index].LengthLow, + SratTable->Memory[Index].ProximityDomain, + SratTable->Memory[NewIndex].Flags)); + } + } + // + // Copy SRAT memory affinity data to ACPI platform protocol + // + DEBUG ((DEBUG_INFO, "ACPI Platform Protocol - Memory Affinity Data updated\n")); + ZeroMem (&mAcpiPlatformMemAffData, sizeof (mAcpiPlatformMemAffData)); + CopyMem (&mAcpiPlatformMemAffData.AcpiMemAffData[0], &SratTable->Memory[0], sizeof (mAcpiPlatformMemAffData.AcpiMemAffData)); + mAcpiPlatformMemAffData.AcpiMemAffDataValid = TRUE; + } + return EFI_SUCCESS; +} + + +/** + Routine Description: + Collect ThreadIdMsr Value for all the AP's and sorts it by the ThreadIdMsr Value. + The Sorted Table, for every socket the first half of the threads will be Mapped to 1st HA + The second half f threads in every socket will mapped to 2nd HA. + + Arguments: + NONE + + Returns: + NONE +**/ +VOID +CollectThreadIdMsrData ( + IN UINT8 SncEnabled, + IN UINT8 SncNumOfCluster + ) +{ + UINT32 SocketIndex; + UINT32 ThreadIndex; + UINTN NumOfChaPerCluster; + BOOLEAN CollocatedChaIdPresent; + UINT32 NumberOfThreads; + UINT8 SocketLogicalId; + + NumOfChaPerCluster = 0; + CollocatedChaIdPresent = FALSE; + AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &NumberOfThreads, NULL, NULL); + + // + // Get total number of CHAs per socket + // + for(SocketIndex = 0; SocketIndex < MAX_SOCKET; SocketIndex++) { + mPackageChaTotal[SocketIndex] = mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[SocketIndex].TotCha; + } + + // + // Determine whether collocated CHA ID is encoded in upper 32 bits of MSR 0x53 LOGICAL_THREAD_ID + // + if (SncEnabled) { + for(ThreadIndex = 0; ThreadIndex < (MAX_CORE * MAX_THREAD); ThreadIndex++) { + if (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId != 0) { + if (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId != 0xFF) { + CollocatedChaIdPresent = TRUE; + } + break; + } + } + if (!CollocatedChaIdPresent) { + DEBUG ((DEBUG_WARN, "ERROR: Collocated CHA ID is not found! Correct SNC Proximity Domain programming not guaranteed.\n")); + } + } + + // + // Set SNC Proximity Domain variables for each thread + // + for(ThreadIndex = 0; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) { + if (mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue == 0xff) { + continue; + } + + // + // We divide cores in group by number of clusters. + // CHA number is used instead of active threads to account for when cores or + // threads are disabled. + // + SocketIndex = mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[ThreadIndex].ProcessorLocation.Package; + SocketLogicalId = GetSocketLogicalId ((UINT8) SocketIndex); + if (!SncEnabled) { + mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = SocketLogicalId; + } else { + NumOfChaPerCluster = mPackageChaTotal[SocketIndex]/SncNumOfCluster; + if (CollocatedChaIdPresent) { + mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = (UINT32)((SocketLogicalId * SncNumOfCluster) + (mCpuThreadIdMsrTable[ThreadIndex].CollocatedChaId / (NumOfChaPerCluster))); + } else { + mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain = (UINT32)((SocketLogicalId * SncNumOfCluster) + (mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue / (NumOfChaPerCluster*NumberOfThreads))); + } + DEBUG ((DEBUG_INFO, "ThreadIndex=%x, SncNumOfCluster=%x, NumOfChaPerCluster=%x, SNCProximityDomain=%x\n", ThreadIndex, SncNumOfCluster, NumOfChaPerCluster, mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain)); + DEBUG ((DEBUG_INFO, "ThreadIdValue=%x\n", mCpuThreadIdMsrTable[ThreadIndex].ThreadIdValue)); + } + } +} + +/** + Return the Domain Flag value of the specific APICID + Proximity Domain Flag + 0 Denotes upper half of the sorted thread needs to be mapped to 1st HA. + 1 Denotes lower half and mapped to 2nd HA + + @retval Proximity Domain Value for the thread within a Socket. +**/ +UINT32 +GetProximityDomainForSNC ( + IN UINT32 ApicId + ) +{ + UINT32 ThreadIndex = 0; + static UINT32 SncIndex = 0; + + // + // The ApicIds are in order. Saving the index will reduce loop iterations + // + for (ThreadIndex = SncIndex; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) { + if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == ApicId){ + SncIndex = ThreadIndex + 1; + return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain; + } else if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == (UINT32) -1) { + // + // We have reached the end of the populated threads + // + break; + } + } + + // + // Start again from the beginning if we made it to the end of the array + // + for (ThreadIndex = 0; ThreadIndex < MAX_CPU_NUM; ThreadIndex++) { + if (mCpuThreadIdMsrTable[ThreadIndex].ApicId == ApicId){ + SncIndex = ThreadIndex + 1; + return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain; + } + } + + DEBUG ((DEBUG_ERROR, "APICID not found in CpuThreadIdMsrValueTable\n")); + ASSERT (FALSE); + ThreadIndex--; + return mCpuThreadIdMsrTable[ThreadIndex].SNCProximityDomain; +} + +/** + Function retrieves selected data of ACPI SRAT Memory Affinity Structures + (please note that data will not be available until SRAT table installation) + + @param[out] *MemAffData ACPI Memory Affinity Data + @param[out] *MemAffDataLength ACPI Memory Affinity Data Length + + @retval EFI_SUCCESS ACPI Memory Affinity Data retrieved successfully + @retval EFI_NOT_FOUND ACPI Memory Affinity Data not found (SRAT ACPI table was not published) + @retval EFI_INVALID_PARAMETER One or more of input arguments is NULL +**/ +EFI_STATUS +GetAcpiMemoryAffinityData ( + OUT ACPI_MEMORY_AFFINITY_DATA **MemAffData, + OUT UINTN *MemAffDataLength + ) +{ + if (MemAffData == NULL || MemAffDataLength == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (!mAcpiPlatformMemAffData.AcpiMemAffDataValid) { + return EFI_NOT_FOUND; + } + + *MemAffData = mAcpiPlatformMemAffData.AcpiMemAffData; + *MemAffDataLength = (UINT8)MEMORY_AFFINITY_STRUCTURE_COUNT; + + return EFI_SUCCESS; +} + +/** + Function initialize and install ACPI Platform Protocol + + @param None + + @retval EFI_SUCCESS Operation completed successfully +**/ +EFI_STATUS +InstallAcpiPlatformProtocol ( + VOID + ) +{ + EFI_HANDLE Handle = NULL; + + ZeroMem (&mAcpiPlatformProtocol, sizeof(mAcpiPlatformProtocol)); + mAcpiPlatformProtocol.GetAcpiMemoryAffinityData = GetAcpiMemoryAffinityData; + + return gBS->InstallProtocolInterface (&Handle, &gAcpiPlatformProtocolGuid, EFI_NATIVE_INTERFACE, &mAcpiPlatformProtocol); +} + +VOID +PrintSratTable ( + IN EFI_ACPI_DESCRIPTION_HEADER *Header + ) +{ + EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *Table; + EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *SubType; + UINTN TotalLength; + UINT8 *TempPtr; + EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *ApicType; + EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE *MemType; + EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *x2ApicType; + UINTN TempLength; + + Table = (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *) Header; + if (Table->Header.Signature != EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE) { + DEBUG ((DEBUG_ERROR, "[SRAT] Not SRAT table, skip!\n")); + return; + } + + TotalLength = Table->Header.Length; + + DEBUG ((DEBUG_INFO, "----------------------------[SRAT Table] --------------------\n")); + DEBUG ((DEBUG_INFO, "----Header-----\n")); + DEBUG ((DEBUG_INFO, "Length : %d\n", Table->Header.Length)); + DEBUG ((DEBUG_INFO, "Revision : %d\n", Table->Header.Revision)); + DEBUG ((DEBUG_INFO, "Checksum : %2X\n", Table->Header.Checksum)); + DEBUG ((DEBUG_INFO, "OemTableId : %X\n", Table->Header.OemTableId)); + DEBUG ((DEBUG_INFO, "OemRevision : %d\n", Table->Header.OemRevision)); + DEBUG ((DEBUG_INFO, "CreatorId : %X\n", Table->Header.CreatorId)); + DEBUG ((DEBUG_INFO, "CreatorRevision : %X\n", Table->Header.CreatorRevision)); + DEBUG ((DEBUG_INFO, "\n")); + + TempPtr = (UINT8 *)Table; + TempPtr += sizeof(EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER); + TempLength = ((EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) TempPtr)->Length; + while (TempPtr < ((UINT8 *)Table + TotalLength)){ + SubType = (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) TempPtr; + if (SubType->Type == EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY) { + ApicType = SubType; + DEBUG ((DEBUG_INFO, "APIC Type : %d\n", ApicType->Type)); + DEBUG ((DEBUG_INFO, "Length : %d\n", ApicType->Length)); + DEBUG ((DEBUG_INFO, "ProximityDomain7To0 : %d\n", ApicType->ProximityDomain7To0)); + DEBUG ((DEBUG_INFO, "ApicId : %X\n", ApicType->ApicId)); + DEBUG ((DEBUG_INFO, "Flags : %X\n", ApicType->Flags)); + DEBUG ((DEBUG_INFO, "LocalSapicEid : %d\n", ApicType->LocalSapicEid)); + DEBUG ((DEBUG_INFO, "ProximityDomain31To8 : %d\n", (*(UINT32 *)ApicType->ProximityDomain31To8) & 0xFFFFFF)); + DEBUG ((DEBUG_INFO, "ClockDomain : %d\n", ApicType->ClockDomain)); + + } else if (SubType->Type == EFI_ACPI_6_2_MEMORY_AFFINITY) { + MemType = (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE *)SubType; + DEBUG ((DEBUG_INFO, "Mem Type : %d\n", MemType->Type)); + DEBUG ((DEBUG_INFO, "Length : %d\n", MemType->Length)); + DEBUG ((DEBUG_INFO, "ProximityDomain : %d\n", MemType->ProximityDomain)); + DEBUG ((DEBUG_INFO, "AddressBaseLow : %X\n", MemType->AddressBaseLow)); + DEBUG ((DEBUG_INFO, "AddressBaseHigh : %X\n", MemType->AddressBaseHigh)); + DEBUG ((DEBUG_INFO, "LengthLow : %X\n", MemType->LengthLow)); + DEBUG ((DEBUG_INFO, "LengthHigh : %X\n", MemType->LengthHigh)); + DEBUG ((DEBUG_INFO, "Flags : %X\n", MemType->Flags)); + + } else if (SubType->Type == EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY) { + x2ApicType = (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *) SubType; + DEBUG ((DEBUG_INFO, "x2APIC Type : %d\n", x2ApicType->Type)); + DEBUG ((DEBUG_INFO, "Length : %d\n", x2ApicType->Length)); + DEBUG ((DEBUG_INFO, "ProximityDomain : %d\n", x2ApicType->ProximityDomain)); + DEBUG ((DEBUG_INFO, "X2ApicId : %X\n", x2ApicType->X2ApicId)); + DEBUG ((DEBUG_INFO, "Flags : %X\n", x2ApicType->Flags)); + DEBUG ((DEBUG_INFO, "ClockDomain : %d\n", x2ApicType->ClockDomain)); + + } else { + DEBUG ((DEBUG_INFO, "Unknown Type : %d\n", SubType->Type)); + DEBUG ((DEBUG_INFO, "Length : %d\n", SubType->Length)); + } + if (SubType->Length < 10) { + DEBUG ((DEBUG_ERROR, "Error in Length %d, try previous length.\n", SubType->Length)); + TempPtr += TempLength; + } else { + TempPtr += SubType->Length; + TempLength = SubType->Length; + } + DEBUG ((DEBUG_INFO, "\n")); + } +} + +/** + Build from scratch and install the SRAT. + + @retval EFI_SUCCESS The SRAT was installed successfully. + @retval EFI_OUT_OF_RESOURCES Could not allocate required structures. +**/ +EFI_STATUS +InstallSratTable ( + VOID + ) +{ + EFI_STATUS Status; + UINTN Index; + UINTN TableHandle; + UINTN TableSize; + STATIC_RESOURCE_AFFINITY_TABLE *SratTable; + + Status = EFI_SUCCESS; + TableHandle = 0; + + if (mSocketMemoryConfiguration.Srat == 0) { + return EFI_SUCCESS; + } + + if (mSystemMemoryMap == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + SratTable = (STATIC_RESOURCE_AFFINITY_TABLE *) AllocateZeroPool (sizeof(STATIC_RESOURCE_AFFINITY_TABLE)); + if (SratTable == NULL) { + DEBUG ((DEBUG_ERROR, "InstallSratTable: allocate SRAT table failed \n")); + return EFI_OUT_OF_RESOURCES; + } + + TableSize = sizeof (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER) + + sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE) * PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT + + sizeof (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE) * MEMORY_AFFINITY_STRUCTURE_COUNT + + sizeof (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE) * X2APIC_AFFINITY_STRUCTURE_COUNT ; + + SratTable->SratHeader = (EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER *) AllocateZeroPool (TableSize); + if (SratTable->SratHeader == NULL) { + DEBUG ((DEBUG_ERROR, "InstallSratTable: Create SratHeader has failed \n")); + return EFI_OUT_OF_RESOURCES; + } + + SratTable->Apic = (EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->SratHeader + + (UINTN)sizeof(EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_HEADER)); + + SratTable->Memory = (EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->Apic + + (UINTN)sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE) * PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT); + + SratTable->x2Apic = (EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE *) (UINTN)((UINTN)SratTable->Memory + + (UINTN)sizeof(EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE)* MEMORY_AFFINITY_STRUCTURE_COUNT); + + + SratTable->SratHeader->Header.Signature = EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE; + SratTable->SratHeader->Header.Length = (UINT32) TableSize; + SratTable->SratHeader->Header.Revision = EFI_ACPI_6_2_SYSTEM_RESOURCE_AFFINITY_TABLE_REVISION; + CopyMem (SratTable->SratHeader->Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (SratTable->SratHeader->Header.OemId)); + SratTable->SratHeader->Header.OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId); + SratTable->SratHeader->Header.OemRevision = EFI_ACPI_OEM_SRAT_REVISION; + SratTable->SratHeader->Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + SratTable->SratHeader->Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + SratTable->SratHeader->Reserved1 = EFI_ACPI_SRAT_RESERVED_FOR_BACKWARD_COMPATIBILITY; + SratTable->SratHeader->Reserved2 = EFI_ACPI_RESERVED_QWORD; + + for (Index = 0; Index < PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE_COUNT; Index++) { + SratTable->Apic[Index].Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY; + SratTable->Apic[Index].Length = sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_APIC_SAPIC_AFFINITY_STRUCTURE); + SratTable->Apic[Index].ApicId = 0xFF; + } + + for (Index = 0; Index < MEMORY_AFFINITY_STRUCTURE_COUNT; Index++) { + SratTable->Memory[Index].Type = EFI_ACPI_6_2_MEMORY_AFFINITY; + SratTable->Memory[Index].Length = sizeof(EFI_ACPI_6_2_MEMORY_AFFINITY_STRUCTURE); + } + + for (Index = 0; Index < X2APIC_AFFINITY_STRUCTURE_COUNT; Index++) { + SratTable->x2Apic[Index].Type = EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY; + SratTable->x2Apic[Index].Length = sizeof(EFI_ACPI_6_2_PROCESSOR_LOCAL_X2APIC_AFFINITY_STRUCTURE); + SratTable->x2Apic[Index].X2ApicId = 0xFFFFFFFF; + } + + PatchSratTable (SratTable); + PrintSratTable (&SratTable->SratHeader->Header); + + // + // Publish SRAT Structure to ACPI + // + Status = mAcpiTable->InstallAcpiTable ( + mAcpiTable, + SratTable->SratHeader, + SratTable->SratHeader->Header.Length, + &TableHandle + ); + + + FreePool (SratTable->SratHeader); + FreePool (SratTable); + + InstallAcpiPlatformProtocol (); + + return Status; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c new file mode 100644 index 0000000000..cb8b2b24be --- /dev/null +++ b/Platform/Intel/WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLibSsdt.c @@ -0,0 +1,1004 @@ +/** @file + ACPI Platform Driver Hooks + + @copyright + Copyright 1996 - 2020 Intel Corporation.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +// +// Statements that include other files +// +#include "AcpiPlatformLibLocal.h" +#include + +extern BIOS_ACPI_PARAM *mAcpiParameter; +extern EFI_IIO_UDS_PROTOCOL *mIioUds; + +extern SOCKET_MEMORY_CONFIGURATION mSocketMemoryConfiguration; +extern SOCKET_POWERMANAGEMENT_CONFIGURATION mSocketPowermanagementConfiguration; + +extern BOOLEAN mCpuOrderSorted; +extern UINT32 mApicIdMap[MAX_SOCKET][MAX_CORE * MAX_THREAD]; +extern UINT32 mNumOfBitShift; + +extern UINT32 mEnabledProcessor[MAX_SOCKET]; + +extern EFI_CPU_CSR_ACCESS_PROTOCOL *mCpuCsrAccess; +UINT32 mCpuPCPSInfo[MAX_SOCKET]; +UINT32 mNcpuValue[MAX_SOCKET]; + +extern CPU_ID_ORDER_MAP mCpuApicIdOrderTable[]; +extern UINT8 mPStateEnable; + +#ifndef MSR_MISC_ENABLES +#define MSR_MISC_ENABLES 0x01A0 +#endif + +/** + This function detects PCPS Info + + mCpuPCPSInfo usage: + Bit[15:0]: Enabled processors in current socket + Bit[16]: Hyperthreading enable + Bit[17]: PCPS disable in system + + @param None + + @retval VOID + +**/ +VOID +DetectPcpsInfo ( + VOID + ) +{ + UINT8 Socket; + UINT32 CpuPCPSInfo = 0; + UINT32 SmtDisable = 0; + UINT32 Csr; + + EFI_STATUS Status = EFI_SUCCESS; + DYNAMIC_SI_LIBARY_PROTOCOL2 *DynamicSiLibraryProtocol2 = NULL; + + Status = gBS->LocateProtocol (&gDynamicSiLibraryProtocol2Guid, NULL, &DynamicSiLibraryProtocol2); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return; + } + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if (mIioUds->IioUdsPtr->PlatformData.CpuQpiInfo[Socket].Valid) { + SmtDisable = DynamicSiLibraryProtocol2->PcuGetDesiredCoreSmtDis (Socket); + + Csr = mCpuCsrAccess->ReadCpuCsr (Socket, 0, 0x04320084); + + if (!SmtDisable && !(Csr & (1 << 12))) { + mCpuPCPSInfo[Socket] |= B_PCPS_HT_ENABLE; + } + CpuPCPSInfo = mCpuPCPSInfo[Socket]; + + // + // Update NCPU + // + mNcpuValue[Socket] = mCpuPCPSInfo[Socket] & 0xFF; + + if (((CpuPCPSInfo & B_PCPS_DISABLE) == 0)) { + if (CpuPCPSInfo & B_PCPS_HT_ENABLE) { + mNcpuValue[Socket] = 2; + } else { + mNcpuValue[Socket] = 1; + } + } + } + } + + for (Socket = 0; Socket < MAX_SOCKET; Socket++) { + if (mCpuPCPSInfo[Socket] == 0) { + mCpuPCPSInfo[Socket] = CpuPCPSInfo; + mNcpuValue[Socket] = mNcpuValue[0]; + } + } +} + +/** + Find APICID in mCpuApicIdOrderTable + + @param SocketIndex - In: Acpi thread number + @param ThreadIndex - In: Acpi thread number + + @retval APICID - If not found, return 0xFFFFFFFF +**/ +UINT32 +LocateApicIdInfo ( + IN UINT32 SocketIndex, + IN UINT32 ThreadIndex + ) +{ + if (mApicIdMap[SocketIndex][ThreadIndex] == (UINT32) -1) { + return (UINT32) -1; + } + + return (mApicIdMap[SocketIndex][ThreadIndex] + (SocketIndex << mNumOfBitShift)); +} + +/** + Gather the EIST information + + @param ThreadId - In: Acpi thread number + @param CpuMiscData - In/Out: Pointer to thread's CPU_MISC_DTAT struct + + @retval EFI_SUCCESS - EIST info retrieved +**/ +EFI_STATUS +LocateCpuEistInfo ( + IN UINT32 CpuIndex, + OUT CPU_MISC_DATA **CpuMiscData + ) +{ + UINTN Index; + UINT32 Socket; + UINT32 ApicId; + const UINT32 *ApicMapPtr; + + Socket = CpuIndex / (MAX_CORE * MAX_THREAD); + Index = CpuIndex % (MAX_CORE * MAX_THREAD); + ApicMapPtr = mApicIdMap[Socket]; + + ApicId = mAcpiParameter->ProcessorApicIdBase[Socket] + ApicMapPtr[Index]; + + for (Index = 0; Index < mCpuConfigLibConfigContextBuffer->NumberOfProcessors; ++Index) { + if (mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[Index].CpuMiscData.ApicID == ApicId) { + *CpuMiscData = &mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[Index].CpuMiscData; + break; + } + } + + if (*CpuMiscData == NULL) { //use SBSP's data + *CpuMiscData = &mCpuConfigLibConfigContextBuffer->CollectedDataBuffer[0].CpuMiscData; + } + + return EFI_SUCCESS; +} + +/** + Determine turbo mode status + + @param None + + @retval TRUE if turbo enabled, FALSE if disabled +**/ +BOOLEAN +IsTurboModeEnabled ( + VOID + ) +{ + EFI_CPUID_REGISTER CpuidRegisters; + BOOLEAN Status; + UINT64 MiscEnable; + + Status = FALSE; + AsmCpuid (CPUID_THERMAL_POWER_MANAGEMENT, &CpuidRegisters.RegEax, &CpuidRegisters.RegEbx, &CpuidRegisters.RegEcx, &CpuidRegisters.RegEdx); + if (((CPUID_THERMAL_POWER_MANAGEMENT_EAX*)&CpuidRegisters.RegEax)->Bits.TurboBoostTechnology != 0) { + // + // Turbo mode is supported on this processor (Available) + // + + MiscEnable = AsmReadMsr64 (MSR_MISC_ENABLES); + if ((RShiftU64 (MiscEnable, 38) & 1) == 0) { // Bit 38 is TurboModeDisable + // + // Turbo mode is supported on this processor (Available) + // + Status = TRUE; + } + } + + return Status; +} + +/** + Finds the actual beginning of a CPU SSDT table, skips the If(Zero) { External() ... } opcode + auto-generated by the iASL 6.1 compiler + + From iASL/6.1/changes.txt + "Completed full support for the ACPI 6.0 External() AML opcode. The + compiler emits an external AML opcode for each ASL External statement. + This opcode is used by the disassembler to assist with the disassembly of + external control methods by specifying the required number of arguments + for the method. AML interpreters do not use this opcode. To ensure that + interpreters do not even see the opcode, a block of one or more external + opcodes is surrounded by an "If(0)" construct. As this feature becomes + commonly deployed in BIOS code, the ability of disassemblers to correctly + disassemble AML code will be greatly improved." + + The AML code contains external (_SB_SCKxCyyy) opcodes within a If(Zero) statement; + we have to ignore this opcodes and start patching from the actual table begin marker, i.e., "TBST" + + @param[in] BeginPtr a pointer to the begin of a SSDT table + @param[in] EndPtr a pointer to the end of a SSDT table + + @retval beginning of the part of SSDT table past external _SB_ opcodes +**/ +static inline +UINT8 * +SkipExternalSbOpcodes( + IN UINT8 *BeginPtr, + IN UINT8 *EndPtr, + IN UINT32 ExternSbExpected + ) +{ + UINT8 *CurPtr = BeginPtr; + UINT32 ExternSbFound = 0; + + ASSERT (BeginPtr < EndPtr); + + DEBUG ((DEBUG_VERBOSE, "SkipExternalSbOpcodes start\n")); + + for (CurPtr = BeginPtr; CurPtr < EndPtr; ++CurPtr) { + UINT32 Signature = *(UINT32 *) CurPtr; + + if (SIGNATURE_32 ('_', 'S', 'B', '_') == Signature) { + CONST EXTERNAL_OBJECT_DECL *ExternDecl = ACPI_EXTERNAL_OBJECT_DECL_FROM_NAME_STR (CurPtr); + + ASSERT (BeginPtr < (UINT8 *)ExternDecl); + + if ((AML_EXTERNAL_OP == ExternDecl->ExternalOp ) && + (AML_ROOT_CHAR == ExternDecl->RootChar) && + (AML_MULTI_NAME_PREFIX == ExternDecl->MultiNamePrefix) && + (0x3 <= ExternDecl->SegCount)) { + ++ExternSbFound; + } else { + break; + } + } + } + + DEBUG ((DEBUG_ERROR, "ExternSbExpected: %d, ExternSbFound: %d\n")); + + ASSERT ((ExternSbFound % ExternSbExpected) == 0); + + DEBUG ((DEBUG_VERBOSE, "SkipExternalSbOpcodes end\n")); + + return CurPtr; +} + +/** + Update the CPU PM SSDT table + + @param[in,out] TableHeader The table to be set + + @retval EFI_SUCCESS Returns Success + @retval EFI_UNSUPPORTED Table is not supported +**/ +EFI_STATUS +PatchCpuPmSsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT8 *CurrPtr; + UINT8 *EndPtr; + UINT8 *SsdtPointer; + UINT32 Signature; + UINT32 CpuFixes; + UINT32 CpuSkt; + UINT32 CpuIndex; + UINT32 ThreadIndex; + UINT32 AdjustSize; + ACPI_NAMEPACK_DWORD *NamePtr; + UINT32 DomnValue; + ACPI_NAME_COMMAND *PsdPackage; + PSD_PACKAGE_LAYOUT *PsdPackageItemPtr; + CPU_MISC_DATA *CpuMiscData; + + DEBUG ((DEBUG_INFO, "Patching SSDT PatchCpuPmSsdtTable\n")); + + // + // Loop through the ASL looking for values that we must fix up. + // + DomnValue = 0; + CpuFixes = 0; + CpuSkt = 0; + CpuIndex = 0; + ThreadIndex = 0; + CurrPtr = (UINT8 *) Table; + EndPtr = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); + CpuMiscData = NULL; + + DetectPcpsInfo (); + + // + // CurrPtr = beginning of table to search + // + CurrPtr = SkipExternalSbOpcodes (CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM); + + // + // Subtract 11 from EndPtr - this is the size of the largest data item we will search for + // so that we do not try to read past the end of the table + // + EndPtr -= 11; + + for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) { + Signature = *(UINT32 *) SsdtPointer; + CpuIndex = 0; + AdjustSize = 0; + + switch (Signature) { + + // + // The AML code contains strings in the form of _SB_SCKxCyyy where x is the socket number + // and yyy is the thread number in hexadecimal, this first case parses that string and saves + // the socket number into CpuSkt and the thread number into CpuIndex. + // + case SIGNATURE_32 ('_', 'S', 'B', '_'): + // + // SKTX + // + CpuSkt = *(SsdtPointer + 7); + if ((CpuSkt < '0') || ((CpuSkt - '0') > MAX_SOCKET)) { + CpuSkt = '0'; + } + CpuSkt -= '0'; + + if ((*(SsdtPointer + 8) != 'C')) { + continue; + } + + if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) { + CpuIndex = (*(SsdtPointer + 11) -'0'); + } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) { + CpuIndex = (*(SsdtPointer + 11) -'A' + 10); + } + + if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) { + AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10; + } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) { + AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10; + } + + CpuIndex += AdjustSize; + AdjustSize = 0; + + if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) { + AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100; + } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) { + AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100; + } + + CpuIndex += AdjustSize; + ThreadIndex = CpuIndex; + + // + // PCPS - Update DOMN + // + DomnValue = (UINT8) CpuSkt; + + if ((mCpuPCPSInfo[CpuSkt] & B_PCPS_DISABLE) == 0) { + DomnValue = LocateApicIdInfo (CpuSkt, ThreadIndex); + + if (mNcpuValue[CpuSkt] == 2) { + DomnValue = (DomnValue >> 1); + } + } + + DEBUG (( + DEBUG_INFO, + ":ACPI: PatchCpuPmSsdtTable(): CpuSkt: %d ThreadIndex: %d, NcpuValue: %d, DomnValue: %d\n", + CpuSkt, + ThreadIndex, + mNcpuValue[CpuSkt], + DomnValue + )); + ++CpuFixes; + CpuMiscData = NULL; + LocateCpuEistInfo (0, &CpuMiscData); // use CPU0 for update NPSS and SPSS + break; + + case SIGNATURE_32 ('D', 'O', 'M', 'N'): + NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer); + if (NamePtr->StartByte != AML_NAME_OP) { + continue; + } + + if (NamePtr->Size != AML_NAME_DWORD_SIZE) { + continue; + } + + NamePtr->Value = DomnValue; + break; + + case SIGNATURE_32 ('N', 'C', 'P', 'U'): + NamePtr = ACPI_NAME_COMMAND_FROM_NAMEPACK_STR (SsdtPointer); + if (NamePtr->StartByte != AML_NAME_OP) { + continue; + } + + if (NamePtr->Size != AML_NAME_DWORD_SIZE) { + continue; + } + + NamePtr->Value = (UINT32) mNcpuValue[CpuSkt]; + break; + + case SIGNATURE_32 ('P', 'S', 'D', 'C'): + case SIGNATURE_32 ('P', 'S', 'D', 'E'): + PsdPackage = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer); + if (PsdPackage->StartByte != AML_NAME_OP) { + continue; + } + + PsdPackageItemPtr = (PSD_PACKAGE_LAYOUT *) ((UINT8 *) PsdPackage); + DEBUG (( + DEBUG_VERBOSE, + "PatchCpuPmSsdtTable(): PsdPackageItemPtr table: %x is detected...\n", + PsdPackage->NameStr + )); + DEBUG (( + DEBUG_VERBOSE, + " Initial Values: Domain = %x, CoordType = %x, NumProcessors = %x\n", + PsdPackageItemPtr->Domain, + PsdPackageItemPtr->CoordType, + PsdPackageItemPtr->NumProcessors + )); + + PsdPackageItemPtr->Domain = DomnValue; + PsdPackageItemPtr->NumProcessors = (UINT32) mNcpuValue[CpuSkt]; + DEBUG (( + DEBUG_VERBOSE, + " PsdPackage = %x, PsdPackageItemPtr = %x, SsdtPointer = %x\n", + (UINT8 *)PsdPackage, + (UINT8 *)PsdPackageItemPtr, + (UINT8 *)SsdtPointer + )); + DEBUG (( + DEBUG_VERBOSE, + " Updated PSD Domain = %x, CoordType = %x, NumProcessors = %x\n", + PsdPackageItemPtr->Domain, + PsdPackageItemPtr->CoordType, + PsdPackageItemPtr->NumProcessors + )); + break; + + default: + break; + } // switch + } // for + + // + // N fixes together currently + // + ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM); + + return EFI_SUCCESS; +} + +/** + + Update the OEM1 P-State SSDT table (EIST) + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success + +**/ +EFI_STATUS +PatchOem1SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status; + UINT8 *CurrPtr; + UINT8 *EndPtr; + UINT8 *SsdtPointer; + UINT32 Signature; + UINT32 CpuFixes; + UINT32 NpssFixes; + UINT32 GpssFixes; + UINT32 CpuSkt; + UINT32 CpuIndex; + UINT32 ThreadIndex; + UINT32 PackageSize; + UINT32 NewPackageSize; + UINT32 AdjustSize; + UINTN TableIndex; + ACPI_NAME_COMMAND *PssTable; + PSS_PACKAGE *PssTableItemPtr; + CPU_MISC_DATA *CpuMiscData; + FVID_ENTRY *PssState; + + DEBUG ((DEBUG_INFO, "Patching SSDT PatchOem1SsdtTable\n")); + + // + // Loop through the ASL looking for values that we must fix up. + // + NpssFixes = 0; + GpssFixes = 0; + CpuFixes = 0; + CpuSkt = 0; + CpuIndex = 0; + ThreadIndex = 0; + CurrPtr = (UINT8 *) Table; + EndPtr = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); + CpuMiscData = NULL; + + Status = LocateCpuEistInfo (0, &CpuMiscData); // get BSP's data + if( (EFI_ERROR (Status)) || (CpuMiscData == NULL ) ){ + DEBUG ((DEBUG_WARN, " PatchGv3SsdtTable - EIST info for BSP index not found \n")); + return Status; + } + + mPStateEnable = 1; + + // + // CurrPtr = beginning of table to search + // + CurrPtr = SkipExternalSbOpcodes (CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM); + + // + // Subtract 11 from EndPtr - this is the size of the larget data item we will search for + // so that we do not try to read past the end of the table + // + EndPtr -= 11; + + for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) { + Signature = *(UINT32 *) SsdtPointer; + CpuIndex = 0; + AdjustSize = 0; + + switch (Signature) { + case SIGNATURE_32 ('_', 'S', 'B', '_'): + // + // SKTX + // + CpuSkt = *(SsdtPointer + 7); + if ((CpuSkt < '0') || ((CpuSkt - '0') > MAX_SOCKET)) { + CpuSkt = '0'; + } + + CpuSkt -= '0'; + + if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) { + CpuIndex = (*(SsdtPointer + 11) -'0'); + } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) { + CpuIndex = (*(SsdtPointer + 11) -'A' + 10); + } + + if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) { + AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10; + } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) { + AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10; + } + + CpuIndex += AdjustSize; + AdjustSize = 0; + + if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) { + AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100; + } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) { + AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100; + } + + CpuIndex += AdjustSize; + ThreadIndex = CpuIndex; + + ++CpuFixes; + CpuMiscData = NULL; + LocateCpuEistInfo (0, &CpuMiscData); // use CPU0 for update NPSS and SPSS + break; + + case SIGNATURE_32 ('N', 'P', 'S', 'S'): + case SIGNATURE_32 ('S', 'P', 'S', 'S'): + + PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer); + if (PssTable->StartByte != AML_NAME_OP) { + continue; + } + + ASSERT (CpuMiscData != NULL); + PssState = CpuMiscData->FvidTable; + + AdjustSize = PssTable->NumEntries * sizeof (PSS_PACKAGE); + AdjustSize -= (UINT32)(CpuMiscData->NumberOfPStates * sizeof (PSS_PACKAGE)); + PackageSize = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4); + NewPackageSize = PackageSize - AdjustSize; + PssTable->Size = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4)); + + // + // Set most significant two bits of byte zero to 01, meaning two bytes used + // + PssTable->Size |= 0x40; + + // + // Set unused table to Noop Code + // + SetMem ( + (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE, + AdjustSize, + AML_NOOP_OP + ); + PssTable->NumEntries = (UINT8) CpuMiscData->NumberOfPStates; + PssTableItemPtr = (PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (ACPI_NAME_COMMAND)); + + // + // Update the size + // + + if (CpuMiscData->NumberOfPStates == 1) { + mPStateEnable = 0; + } + + for (TableIndex = 0; TableIndex < CpuMiscData->NumberOfPStates; ++TableIndex) { + PssTableItemPtr->CoreFreq = (UINT32) (CpuMiscData->IntendedFsbFrequency * PssState[TableIndex].Ratio); + if (mSocketPowermanagementConfiguration.TurboMode && (TableIndex == 0) && IsTurboModeEnabled ()) { + PssTableItemPtr->CoreFreq = (UINT32)((CpuMiscData->IntendedFsbFrequency * PssState[TableIndex + 1].Ratio) + 1); + } + + + PssTableItemPtr->Power = (UINT32)(PssState[TableIndex].Power); // when calulate Tdp already make it mW; + if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) { + PssTableItemPtr->TransLatency = (UINT32)(PssState[TableIndex].TransitionLatency); + PssTableItemPtr->Control = (UINT32)(PssState[TableIndex].Ratio << 8); + PssTableItemPtr->Status = (UINT32)(PssState[TableIndex].Ratio << 8); + } else { + // + // This method should be supported by SMM PPM Handler + // + // Status is simply the state number. + // Use the state number w/ OS command value so that the + // legacy interface may be used. Latency for SMM is 100 + BM latency. + PssTableItemPtr->Status = (UINT32)TableIndex; + PssTableItemPtr->TransLatency = (UINT32)(100 + PssState[TableIndex].TransitionLatency); + PssTableItemPtr->Control = (UINT32)(SW_SMI_OS_REQUEST | (TableIndex << 8)); + } + + PssTableItemPtr->BMLatency = (UINT32)(PssState[TableIndex].BusMasterLatency); + + ++PssTableItemPtr; + } + + if (PssTable->NameStr == SIGNATURE_32 ('N', 'P', 'S', 'S')) { + ++NpssFixes; + } + + SsdtPointer = (UINT8 *) PssTable + PackageSize; + break; + + case SIGNATURE_32 ('G', 'P', 'S', 'S'): + + PssTable = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer); + if (PssTable->StartByte != AML_NAME_OP) { + continue; + } + + ASSERT (CpuMiscData != NULL); + PssState = CpuMiscData->GreaterFvidTable; + + ASSERT (CpuMiscData->GreaterNumberOfPStates <= GPSS_FVID_MAX_STATES); + if (CpuMiscData->GreaterNumberOfPStates > GPSS_FVID_MAX_STATES) { + continue; + } + + AdjustSize = PssTable->NumEntries * sizeof (PSS_PACKAGE); + AdjustSize -= (UINT32)(CpuMiscData->GreaterNumberOfPStates * sizeof (PSS_PACKAGE)); + PackageSize = (PssTable->Size & 0xF) + ((PssTable->Size & 0xFF00) >> 4); + NewPackageSize = PackageSize - AdjustSize; + PssTable->Size = (UINT16) ((NewPackageSize & 0xF) + ((NewPackageSize & 0x0FF0) << 4)); + + // + // Set most significant two bits of byte zero to 01, meaning two bytes used + // + PssTable->Size |= 0x40; + + // + // Set unused table to Noop Code + // + SetMem ( + (UINT8 *) PssTable + NewPackageSize + AML_NAME_PREFIX_SIZE, + AdjustSize, + AML_NOOP_OP + ); + PssTable->NumEntries = (UINT8) CpuMiscData->GreaterNumberOfPStates; + PssTableItemPtr = (PSS_PACKAGE *) ((UINT8 *) PssTable + sizeof (ACPI_NAME_COMMAND)); + + // + // Update the size + // + for (TableIndex = 0; TableIndex < CpuMiscData->GreaterNumberOfPStates; ++TableIndex) { + PssTableItemPtr->CoreFreq = (UINT32) (CpuMiscData->IntendedFsbFrequency * PssState[TableIndex].Ratio); + if (mSocketPowermanagementConfiguration.TurboMode && (TableIndex == 0) && IsTurboModeEnabled()) { + PssTableItemPtr->CoreFreq = (UINT32)((CpuMiscData->IntendedFsbFrequency * PssState[TableIndex + 1].Ratio) + 1); + } + + // + // If Turbo mode is supported, add one to the Max Non-Turbo frequency + // + PssTableItemPtr->Power = (UINT32)(PssState[TableIndex].Power); // when calulate Tdp already make it mW; + if (PssTable->NameStr == SIGNATURE_32 ('G', 'P', 'S', 'S')) { + PssTableItemPtr->TransLatency = (UINT32)(PssState[TableIndex].TransitionLatency); + PssTableItemPtr->Control = (UINT32)(PssState[TableIndex].Ratio << 8); + PssTableItemPtr->Status = (UINT32)(PssState[TableIndex].Ratio << 8); + } else { + // + // This method should be supported by SMM PPM Handler + // + // Status is simply the state number. + // Use the state number w/ OS command value so that the + // legacy interface may be used. Latency for SMM is 100 + BM latency. + // + PssTableItemPtr->Status = (UINT32)TableIndex; + PssTableItemPtr->TransLatency = (UINT32)(100 + PssState[TableIndex].TransitionLatency); + PssTableItemPtr->Control = (UINT32)(SW_SMI_OS_REQUEST | (TableIndex << 8)); + } + + PssTableItemPtr->BMLatency = (UINT32)(PssState[TableIndex].BusMasterLatency); + + ++PssTableItemPtr; + } + + if (PssTable->NameStr == SIGNATURE_32 ('G', 'P', 'S', 'S')) { + ++GpssFixes; + } + + SsdtPointer = (UINT8 *) PssTable + PackageSize; + break; + + default: + break; + } // switch + } // for + + // + // N fixes together currently + // + ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM); + + if (!mPStateEnable || !mSocketPowermanagementConfiguration.ProcessorEistEnable || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable > HWP_MODE_NATIVE) ) { + Status = EFI_UNSUPPORTED; //CPU EIST + return Status; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +PatchSsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table, + IN OUT EFI_ACPI_TABLE_VERSION *Version + ) +{ + EFI_STATUS Status; + EFI_ACPI_DESCRIPTION_HEADER *TableHeader; + + Status = EFI_SUCCESS; + TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *)Table; + + // + // Do not load the xHCI table. It is handled by separate function. + // + TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table; + if (CompareMem (&TableHeader->OemTableId, "xh_", 3) == 0) { + DEBUG ((DEBUG_ERROR,"Xhci TableHeader->OemTableId = %x\n ", TableHeader->OemTableId)); + *Version = EFI_ACPI_TABLE_VERSION_NONE; + } + + if (TableHeader->OemTableId == SIGNATURE_64 ('S', 'S', 'D', 'T', ' ', ' ', 'P', 'M')) { + PatchCpuPmSsdtTable (Table); //CPU PM + } + + return Status; +} + +/** + Update the OEM2 HWP SSDT table if needed + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchOem2SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + if ((mSocketPowermanagementConfiguration.ProcessorHWPMEnable == 0) || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable == HWP_MODE_OOB)) { + Status = EFI_UNSUPPORTED; + } + + return Status; +} + +/** + Update the OEM3 T-State SSDT table (TST) + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchOem3SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + UINT8 *CurrPtr; + UINT8 *EndPtr; + UINT8 *SsdtPointer; + UINT32 Signature; + UINT32 CpuFixes; + UINT32 CpuSkt; + UINT32 CpuIndex; + UINT32 ThreadIndex; + UINT32 AdjustSize; + UINT32 DomnValue; + ACPI_NAME_COMMAND *PsdPackage; + PSD_PACKAGE_LAYOUT *PsdPackageItemPtr; + + DEBUG ((DEBUG_INFO, "Patching SSDT PatchOem3SsdtTable\n")); + + if (!mSocketPowermanagementConfiguration.TStateEnable || (mSocketPowermanagementConfiguration.ProcessorHWPMEnable > HWP_MODE_NATIVE) ) { + return EFI_UNSUPPORTED; + } + + // + // Loop through the ASL looking for values that we must fix up. + // + DomnValue = 0; + CpuFixes = 0; + CpuSkt = 0; + ThreadIndex = 0; + CurrPtr = (UINT8 *) Table; + EndPtr = (CurrPtr + ((EFI_ACPI_COMMON_HEADER *) CurrPtr)->Length); + + // + // CurrPtr = beginning of table we want to search + // + CurrPtr = SkipExternalSbOpcodes(CurrPtr, EndPtr, (UINT32) MAX_CPU_NUM); + + // + // Subtract 11 from EndPtr - this is the size of the larget data item we will read + // so that we don't read beyond the end of the table + // + EndPtr -= 11; + + for (SsdtPointer = CurrPtr; SsdtPointer <= EndPtr; ++SsdtPointer) { + Signature = *(UINT32 *) SsdtPointer; + CpuIndex = 0; + AdjustSize = 0; + + switch (Signature) { + + case SIGNATURE_32 ('_', 'S', 'B', '_'): + // + // SKTX + // + CpuSkt = *(SsdtPointer + 7); + CpuSkt -= '0'; + + if ((*(SsdtPointer + 8) != 'C')) { + continue; + } + + if ((*(SsdtPointer + 11) > '0') && (*(SsdtPointer + 11) <= '9')) { + CpuIndex = (*(SsdtPointer + 11) -'0'); + } else if ((*(SsdtPointer + 11) >= 'A') && (*(SsdtPointer + 11) <= 'F')) { + CpuIndex = (*(SsdtPointer + 11) -'A' + 10); + } + + if ((*(SsdtPointer + 10) > '0') && ( *(SsdtPointer + 10) <= '9')) { + AdjustSize = (*(SsdtPointer + 10) -'0') * 0x10; + } else if ((*(SsdtPointer + 10) >= 'A') && (*(SsdtPointer + 10) <= 'F')) { + AdjustSize = (*(SsdtPointer + 10) -'A' + 10) * 0x10; + } + + CpuIndex += AdjustSize; + AdjustSize = 0; + + if ((*(SsdtPointer + 9) > '0') && (*(SsdtPointer + 9) <= '9')) { + AdjustSize = (*(SsdtPointer + 9) -'0') * 0x100; + } else if ((*(SsdtPointer + 9) >= 'A') && (*(SsdtPointer + 9) <= 'F')) { + AdjustSize = (*(SsdtPointer + 9) -'A' + 10) * 0x100; + } + + CpuIndex += AdjustSize; + ThreadIndex = CpuIndex; + + // + // PCPS - Update DOMN + // + DomnValue = (UINT8) CpuSkt; + + if ((mCpuPCPSInfo[CpuSkt] & B_PCPS_DISABLE) == 0) { + DomnValue = LocateApicIdInfo (CpuSkt, ThreadIndex); + + if (mNcpuValue[CpuSkt] == 2) { + DomnValue = (DomnValue >> 1); + } + } + + DEBUG (( + DEBUG_VERBOSE, + "PatchOem3SsdtTable(): CpuIndex: 0x%x ThreadIndex: 0x%x CpuFixes: 0x%x (%d)\n", + CpuIndex, + ThreadIndex, + CpuFixes, + CpuFixes + )); + + DEBUG (( + DEBUG_INFO, + "PatchOem3SsdtTable(): CpuSkt: %d CpuIndex: 0x%x, NcpuValue = 0x%x, DomnValue = 0x%x\n", + CpuSkt, + CpuIndex, + mNcpuValue[CpuSkt], + DomnValue + )); + ++CpuFixes; + break; + + case SIGNATURE_32 ('T', 'S', 'D', 'C'): + case SIGNATURE_32 ('T', 'S', 'D', 'D'): + PsdPackage = ACPI_NAME_COMMAND_FROM_NAME_STR (SsdtPointer); + if (PsdPackage->StartByte != AML_NAME_OP) { + continue; + } + + PsdPackageItemPtr = (PSD_PACKAGE_LAYOUT *) ((UINT8 *) PsdPackage); + DEBUG (( + DEBUG_VERBOSE, + "TSDC: PsdPackageItemPtr table: %x is detected...\n", + PsdPackage->NameStr + )); + DEBUG (( + DEBUG_VERBOSE, + " Initial Values: Domain = %x, CoordType = %x, NumProcessors = %x\n", + PsdPackageItemPtr->Domain, + PsdPackageItemPtr->CoordType, + PsdPackageItemPtr->NumProcessors + )); + + PsdPackageItemPtr->Domain = DomnValue; + PsdPackageItemPtr->NumProcessors = mNcpuValue[CpuSkt]; + DEBUG (( + DEBUG_VERBOSE, + " PsdPackage = %x, PsdPackageItemPtr = %x, SsdtPointer = %x\n", + (UINT8 *)PsdPackage, + (UINT8 *)PsdPackageItemPtr, + (UINT8 *)SsdtPointer + )); + DEBUG (( + DEBUG_VERBOSE, + " Updated TSD Domain = %x, CoordType = %x, NumProcessors = %x\n", + PsdPackageItemPtr->Domain, + PsdPackageItemPtr->CoordType, + PsdPackageItemPtr->NumProcessors + )); + break; + + default: + break; + } // switch + } // for + + // + // N fixes together currently + // + ASSERT (CpuFixes == (UINT32) MAX_CPU_NUM); + + return EFI_SUCCESS; +} + +/** + Update the OEM4 C State SSDT table (CST) + + @param *TableHeader - The table to be set + + @retval EFI_SUCCESS - Returns Success +**/ +EFI_STATUS +PatchOem4SsdtTable ( + IN OUT EFI_ACPI_COMMON_HEADER *Table + ) +{ + return EFI_SUCCESS; +} diff --git a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec index 4d416325ae..a80472e73c 100644 --- a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec +++ b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dec @@ -398,6 +398,11 @@ ## gPlatformModuleTokenSpaceGuid.PcdEnableHighSpeedUart|FALSE|BOOLEAN|0x0000002C + ## Platform Not support Acpi Table + # + gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiTable|FALSE|BOOLEAN|0x40000012 + gPlatformTokenSpaceGuid.PcdPlatformNotSupportAcpiBdatTable|FALSE|BOOLEAN|0x40000013 + [PcdsFixedAtBuild, PcdsPatchableInModule, PcdsDynamicEx] ## MemoryCheck value for checking memory before boot OS. # To save the boot performance, the default MemoryCheck is set to 0. diff --git a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc index 39b93d9289..5dfee0eeb5 100644 --- a/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc +++ b/Platform/Intel/WhitleyOpenBoardPkg/PlatformPkg.dsc @@ -621,6 +621,7 @@ CrcLib|WhitleyOpenBoardPkg/Library/BaseCrcLib/BaseCrcLib.inf PlatformSpecificAcpiTableLib|WhitleyOpenBoardPkg/Library/PlatformSpecificAcpiTableLibNull/PlatformSpecificAcpiTableLibNull.inf BuildAcpiTablesLib|WhitleyOpenBoardPkg/Library/BuildAcpiTablesLib/DxeBuildAcpiTablesLib.inf + AcpiPlatformTableLib|WhitleyOpenBoardPkg/Library/AcpiPlatformTableLib/AcpiPlatformLib.inf [LibraryClasses.Common.SEC, LibraryClasses.Common.PEI_CORE, LibraryClasses.Common.PEIM] FspWrapperApiLib|IntelFsp2WrapperPkg/Library/BaseFspWrapperApiLib/BaseFspWrapperApiLib.inf -- 2.27.0.windows.1