Adds ACPI common driver which generates. Generates CPU topology SSDT table. Generates PCIe topology SSDT table. Generates SPMI table.
Cc: Abner Chang <abner.ch...@amd.com> Cc: Paul Grimes <paul.gri...@amd.com> Signed-off-by: Abdul Lateef Attar <abdullateef.at...@amd.com> --- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dec | 13 +- .../AMD/AmdPlatformPkg/AmdPlatformPkg.dsc | 7 +- .../Universal/Acpi/AcpiCommon/AcpiCommon.c | 226 +++ .../Universal/Acpi/AcpiCommon/AcpiCommon.h | 118 ++ .../Universal/Acpi/AcpiCommon/AcpiCommon.inf | 74 + .../Universal/Acpi/AcpiCommon/CpuSsdt.c | 345 ++++ .../Universal/Acpi/AcpiCommon/PciSsdt.c | 1381 +++++++++++++++++ .../Universal/Acpi/AcpiCommon/Spmi.c | 111 ++ 8 files changed, 2273 insertions(+), 2 deletions(-) create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c create mode 100644 Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec index 4cb66d2a36..83f57f6d0a 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dec @@ -1,7 +1,7 @@ ## @file # AMD Platform common Package DEC file # This is the package provides the AMD edk2 common platform drivers -# and libraries for AMD Server, Clinet and Gaming console platforms. +# and libraries for AMD Server, Client and Gaming console platforms. # # Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -31,3 +31,14 @@ # Platform DSC can set this value to another event GUID. # gAmdPlatformPkgTokenSpaceGuid.PcdAmdDisplayLogoEventGuid|{0xdc, 0xd5, 0xb3, 0x8e, 0xe7, 0xf4, 0x57, 0x4b, 0xa9, 0xe7, 0x27, 0x39, 0x10, 0xf2, 0x18, 0x9f}|VOID*|0x00010001 + +[PcdsFixedAtBuild] + # + # IPMI Interface Type + # + # 0 - Unknown + # 1 - KCS + # 2 - SMIC + # 3 - BT + # 4 - SSIF + gAmdPlatformPkgTokenSpaceGuid.PcdIpmiInterfaceType|0|UINT8|0x00020001 diff --git a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc index 40ed5ea07c..99dd5b341f 100644 --- a/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc +++ b/Platform/AMD/AmdPlatformPkg/AmdPlatformPkg.dsc @@ -1,7 +1,7 @@ ## @file # AMD Platform common Package DSC file # This is the package provides the AMD edk2 common platform drivers -# and libraries for AMD Server, Clinet and Gaming console platforms. +# and libraries for AMD Server, Client and Gaming console platforms. # # Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved.<BR> # SPDX-License-Identifier: BSD-2-Clause-Patent @@ -24,6 +24,8 @@ !include MdePkg/MdeLibs.dsc.inc [LibraryClasses.Common] + AmlLib|DynamicTablesPkg/Library/Common/AmlLib/AmlLib.inf + AcpiHelperLib|DynamicTablesPkg/Library/Common/AcpiHelperLib/AcpiHelperLib.inf AlwaysFalseDepexLib|AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf BaseCryptLib|CryptoPkg/Library/BaseCryptLib/BaseCryptLib.inf BaseLib|MdePkg/Library/BaseLib/BaseLib.inf @@ -33,6 +35,7 @@ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf IntrinsicLib|CryptoPkg/Library/IntrinsicLib/IntrinsicLib.inf + IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf OpensslLib|CryptoPkg/Library/OpensslLib/OpensslLib.inf PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf PlatformPKProtectionLib|SecurityPkg/Library/PlatformPKProtectionLibVarPolicy/PlatformPKProtectionLibVarPolicy.inf @@ -41,6 +44,7 @@ SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf SecureBootVariableProvisionLib|SecurityPkg/Library/SecureBootVariableProvisionLib/SecureBootVariableProvisionLib.inf SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf + SortLib|MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf @@ -62,6 +66,7 @@ AmdPlatformPkg/Library/BaseAlwaysFalseDepexLib/BaseAlwaysFalseDepexLib.inf AmdPlatformPkg/Library/DxePlatformSocLib/DxePlatformSocLibNull.inf AmdPlatformPkg/Library/SimulatorSerialPortLibPort80/SimulatorSerialPortLibPort80.inf + AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf AmdPlatformPkg/Universal/SecureBoot/SecureBootDefaultKeysInit/SecureBootDefaultKeysInit.inf AmdPlatformPkg/Universal/HiiConfigRouting/AmdConfigRouting.inf AmdPlatformPkg/Universal/LogoDxe/JpegLogoDxe.inf # Server platform JPEG logo driver diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c new file mode 100644 index 0000000000..f373115a5f --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.c @@ -0,0 +1,226 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023-2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ + +#include "AcpiCommon.h" + +EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol; +EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; + +/** + Locates an existing ACPI Table + + @param[in] Signature - The Acpi table signature + @param[in] OemTableId - The Acpi table OEM Table ID. Ignored if 0 + @param[out] Table - Table if Found or NULL + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +GetExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemTableId, + OUT EFI_ACPI_SDT_HEADER **Table + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_SDT_HEADER *LocalTable; + EFI_ACPI_TABLE_VERSION LocalVersion; + UINTN LocalTableKey; + + Status = EFI_NOT_FOUND; + *Table = NULL; + + for (Index = 0; ; Index++) { + Status = mAcpiSdtProtocol->GetAcpiTable (Index, &LocalTable, &LocalVersion, &LocalTableKey); + if (EFI_ERROR (Status)) { + return Status; + } + + if (!(LocalTable->Signature == Signature)) { + continue; + } + + // Accept table if OemTableId is zero. + if ((OemTableId == 0) || + (CompareMem (&LocalTable->OemTableId, &OemTableId, 8) == 0)) + { + *Table = LocalTable; + return EFI_SUCCESS; + } + } +} + +/** + Appends generated AML to an existing ACPI Table + + 1. Locate the existing ACPI table + 2. Allocate pool for original table plus new data size + 3. Copy original table to new buffer + 4. Append new data to buffer + 5. Update Table header length (Checksum will be calculated on install) + 6. Uninstall original ACPI table + 7. Install appended table + 8. Free new table buffer since ACPI made a copy. + + @param[in] Signature - The Acpi table signature + @param[in] OemId - The Acpi table OEM ID + @param[in] AmlData - The AML data to append + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +AppendExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemId, + IN EFI_ACPI_DESCRIPTION_HEADER *AmlData + ) +{ + EFI_STATUS Status; + UINTN Index; + EFI_ACPI_SDT_HEADER *Table; + EFI_ACPI_TABLE_VERSION Version; + UINTN TableKey; + EFI_ACPI_SDT_HEADER *ReplacementAcpiTable; + UINT32 ReplacementAcpiTableLength; + UINTN TableHandle; + + for (Index = 0; ; Index++) { + Status = mAcpiSdtProtocol->GetAcpiTable (Index, &Table, &Version, &TableKey); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: ACPI table not found with signature=0x%X\n", Signature)); + return Status; + } + + if ((Table->Signature == Signature) && + (CompareMem (&Table->OemTableId, &OemId, 8) == 0)) + { + break; + } + } + + // Calculate new DSDT Length and allocate space + ReplacementAcpiTableLength = Table->Length + (UINT32)(AmlData->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)); + ReplacementAcpiTable = AllocatePool (ReplacementAcpiTableLength); + if (ReplacementAcpiTable == NULL) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to allocate Replacement Table space.\n")); + return EFI_OUT_OF_RESOURCES; + } + + // Copy the old DSDT to the new buffer + CopyMem (ReplacementAcpiTable, Table, Table->Length); + // Append new data to DSDT + CopyMem ( + (UINT8 *)ReplacementAcpiTable + Table->Length, + (UINT8 *)AmlData + sizeof (EFI_ACPI_DESCRIPTION_HEADER), + AmlData->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER) + ); + ReplacementAcpiTable->Length = ReplacementAcpiTableLength; + + // Uninstall the original DSDT + Status = mAcpiTableProtocol->UninstallAcpiTable ( + mAcpiTableProtocol, + TableKey + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to uninstall original ACPI Table signature=0x%X\n", Signature)); + } else { + // Install ACPI table + Status = mAcpiTableProtocol->InstallAcpiTable ( + mAcpiTableProtocol, + ReplacementAcpiTable, + ReplacementAcpiTableLength, + &TableHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "ERROR: Unable to re-install ACPI Table signature=0x%X\n", Signature)); + } + } + + // Release this copy of table + FreePool (ReplacementAcpiTable); + return Status; +} + +/** + Install common platform SSDTs and DSDT additions + + Place to install all generically identifiable SSDT tables. These tables will + be programmatically created from UEFI or other resources and should cover + many different Processor Family IPs. + + Might need to split this driver into LibraryClasses for each + functionality/SSDT while keeping a single driver to reduce the AmlLib overhead. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallAllAcpiTables ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__)); + + // Get Acpi Table Protocol + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&mAcpiTableProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Get Acpi SDT Protocol + Status = gBS->LocateProtocol ( + &gEfiAcpiSdtProtocolGuid, + NULL, + (VOID **)&mAcpiSdtProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = InstallCpuAcpi (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: CPU SSDT install error: Status=%r\n", + __FUNCTION__, + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InstallPciAcpi (ImageHandle, SystemTable); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "%a: PCI SSDT install error: Status=%r\n", + __FUNCTION__, + Status + )); + ASSERT_EFI_ERROR (Status); + return Status; + } + + InstallAcpiSpmiTable (); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h new file mode 100644 index 0000000000..b9db33ac76 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.h @@ -0,0 +1,118 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023-2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ + +#ifndef ACPI_COMMON_H_ +#define ACPI_COMMON_H_ + +#include <IndustryStandard/Acpi.h> +#include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> +#include <Library/DebugLib.h> +#include <Library/MemoryAllocationLib.h> +#include <Library/PcdLib.h> +#include <Library/PrintLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/AcpiSystemDescriptionTable.h> +#include <Protocol/AcpiTable.h> +#include <Uefi.h> + +#define AMD_DSDT_OEMID SIGNATURE_64 ('A', 'm', 'd', 'T','a','b','l','e') +#define CREATOR_REVISION 2 +#define MAX_LOCAL_STRING_SIZE 20 +#define OEM_REVISION_NUMBER 0 +#define CXL_EARLY_DISCOVERY_TABLE_SIGNATURE SIGNATURE_32 ('C', 'E', 'D', 'T') /// "CEDT" CXL Early Discovery Table + +extern EFI_ACPI_TABLE_PROTOCOL *mAcpiTableProtocol; +extern EFI_ACPI_SDT_PROTOCOL *mAcpiSdtProtocol; + +/** + Locates an existing ACPI Table + + @param[in] Signature - The Acpi table signature + @param[in] OemTableId - The Acpi table OEM Table ID. Ignored if 0 + @param[out] Table - Table if Found or NULL + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +GetExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemTableId, + OUT EFI_ACPI_SDT_HEADER **Table + ); + +/** + Appends generated AML to an existing ACPI Table + + 1. Locate the existing ACPI table + 2. Allocate pool for original table plus new data size + 3. Copy original table to new buffer + 4. Append new data to buffer + 5. Update Table header length (Checksum will be calculated on install) + 6. Uninstall original ACPI table + 7. Install appended table + 8. Free new table buffer since ACPI made a copy. + + @param[in] Signature - The Acpi table signature + @param[in] OemId - The Acpi table OEM ID + @param[in] AmlData - The AML data to append + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +AppendExistingAcpiTable ( + IN UINT32 Signature, + IN UINT64 OemId, + IN EFI_ACPI_DESCRIPTION_HEADER *AmlData + ); + +/** + Install CPU devices scoped under \_SB into DSDT + + Determine all the CPU threads and create ACPI Device nodes for each thread. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallCpuAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +/** + Install PCI devices scoped under \_SB into DSDT + + Determine all the PCI Root Bridges and PCI root ports and install resources + including needed _HID, _CID, _UID, _ADR, _CRS and _PRT Nodes. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallPciAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ); + +VOID +EFIAPI +InstallAcpiSpmiTable ( + VOID + ); + +#endif // ACPI_COMMON_H__ diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf new file mode 100644 index 0000000000..2c17dbb500 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/AcpiCommon.inf @@ -0,0 +1,74 @@ +## @file +# Creates ACPI tables for AMD platforms. +# +# Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = AcpiCommon + FILE_GUID = 66838F31-1062-415C-957A-CC2871D9E6B7 + MODULE_TYPE = DXE_DRIVER + VERSION_STRING = 1.0 + ENTRY_POINT = InstallAllAcpiTables + +[Sources.common] + AcpiCommon.c + AcpiCommon.h + CpuSsdt.c + PciSsdt.c + Spmi.c + +[Packages] + AmdPlatformPkg/AmdPlatformPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + MdeModulePkg/MdeModulePkg.dec + MdePkg/MdePkg.dec + MinPlatformPkg/MinPlatformPkg.dec + PcAtChipsetPkg/PcAtChipsetPkg.dec + +[LibraryClasses] + AmlLib + BaseLib + BaseMemoryLib + DebugLib + HobLib + IoLib + MemoryAllocationLib + PcdLib + PlatformSocLib + SortLib + UefiDriverEntryPoint + +[Protocols] + gEfiAcpiSdtProtocolGuid ## CONSUMES + gEfiAcpiTableProtocolGuid ## CONSUMES + gEfiMpServiceProtocolGuid ## CONSUMES + gEfiPciRootBridgeIoProtocolGuid ## CONSUMES + +[Pcd] + gAmdPlatformPkgTokenSpaceGuid.PcdIpmiInterfaceType ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES + gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdIpmiKcsIoBaseAddress ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES + gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseSize ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdIoApicAddress ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdMaxCpuSocketCount ## CONSUMES + gMinPlatformPkgTokenSpaceGuid.PcdPcIoApicAddressBase + +[Guids] + gEfiHobListGuid + +[Depex] + gEfiMpServiceProtocolGuid AND + gEfiAcpiTableProtocolGuid AND + gEfiPciRootBridgeIoProtocolGuid AND + gEfiPciEnumerationCompleteProtocolGuid + diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c new file mode 100644 index 0000000000..345fb4f8c9 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/CpuSsdt.c @@ -0,0 +1,345 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include "AcpiCommon.h" + +#include <Library/AmlLib/AmlLib.h> +#include <Library/SortLib.h> +#include <Protocol/MpService.h> +#include <Register/Intel/Cpuid.h> // for CPUID_EXTENDED_TOPOLOGY + +#define AMD_CPUID_EXTENDED_TOPOLOGY_V2 0x26 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCD 0x04 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_CCX 0x03 +#define AMD_CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE 0x05 +#define CREATOR_REVISION 2 +#define DEVICE_BATTERY_BIT 0x0010// Control Method Battery Device Only +#define DEVICE_ENABLED_BIT 0x0002 +#define DEVICE_HEALTH_BIT 0x0008 +#define DEVICE_IN_UI_BIT 0x0004 +#define DEVICE_PRESENT_BIT 0x0001 +#define MAX_TEST_CPU_STRING_SIZE 20 +#define OEM_REVISION_NUMBER 0 + +EFI_PROCESSOR_INFORMATION *mApicIdtoUidMap = NULL; +UINT32 mCcdOrder[16] = { 0, 4, 8, 12, 2, 6, 10, 14, 3, 7, 11, 15, 1, 5, 9, 13 }; +UINTN mNumberOfCpus = 0; +UINTN mNumberOfEnabledCPUs = 0; + +/** + Callback compare function. + Compares CCD number of provided arguments. + + @param[in] LocalX2ApicLeft Pointer to Left Buffer. + @param[in] LocalX2ApicRight Pointer to Right Buffer. + @return 0 If both are same + -1 If left value is less than righ value. + 1 If left value is greater than righ value. + +**/ +INTN +EFIAPI +SortByCcd ( + IN CONST VOID *LocalX2ApicLeft, + IN CONST VOID *LocalX2ApicRight + ) +{ + EFI_PROCESSOR_INFORMATION *Left; + EFI_PROCESSOR_INFORMATION *Right; + UINT32 Index; + UINT32 LeftCcdIndex; + UINT32 RightCcdIndex; + + Left = (EFI_PROCESSOR_INFORMATION *)LocalX2ApicLeft; + Right = (EFI_PROCESSOR_INFORMATION *)LocalX2ApicRight; + + // Get the CCD Index number + LeftCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (Left->ExtendedInformation.Location2.Die == mCcdOrder[Index]) { + LeftCcdIndex = Index; + break; + } + } + + RightCcdIndex = MAX_UINT32; + for (Index = 0; Index < ARRAY_SIZE (mCcdOrder); Index++) { + if (Right->ExtendedInformation.Location2.Die == mCcdOrder[Index]) { + RightCcdIndex = Index; + break; + } + } + + // Now compare for quick sort + if (LeftCcdIndex < RightCcdIndex) { + return -1; + } + + if (LeftCcdIndex > RightCcdIndex) { + return 1; + } + + return 0; +} + +/** + Generate ApicId to Processor UID map. + + @retval EFI_SUCCESS - ApicId to Processor UID map generated successfully. + @retval EFI_NOT_FOUND - MP Service Protocol not found. + @retval EFI_OUT_OF_RESOURCES - Memory allocation failed. +**/ +EFI_STATUS +GenerateApicIdtoUidMap ( + VOID + ) +{ + EFI_MP_SERVICES_PROTOCOL *MpService; + EFI_STATUS Status; + UINTN Index; + + // Get MP service + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpService); + if (EFI_ERROR (Status) || (MpService == NULL)) { + return EFI_NOT_FOUND; + } + + // Load MpServices + Status = MpService->GetNumberOfProcessors (MpService, &mNumberOfCpus, &mNumberOfEnabledCPUs); + if (EFI_ERROR (Status)) { + return Status; + } + + DEBUG ((DEBUG_ERROR, "%a: NumberOfCpus = %d mNumberOfEnabledCPUs = %d\n", __func__, mNumberOfCpus, mNumberOfEnabledCPUs)); + + mApicIdtoUidMap = AllocateZeroPool (mNumberOfCpus * sizeof (EFI_PROCESSOR_INFORMATION)); + if (mApicIdtoUidMap == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < mNumberOfCpus; Index++) { + Status = MpService->GetProcessorInfo ( + MpService, + Index | CPU_V2_EXTENDED_TOPOLOGY, + &mApicIdtoUidMap[Index] + ); + } + + if (FixedPcdGet32 (PcdMaxCpuSocketCount) > 1) { + /// Sort by CCD location + PerformQuickSort (mApicIdtoUidMap, mNumberOfCpus/2, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + PerformQuickSort (mApicIdtoUidMap+(mNumberOfCpus/2), mNumberOfCpus/2, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + } else { + /// Sort by CCD location + PerformQuickSort (mApicIdtoUidMap, mNumberOfCpus, sizeof (EFI_PROCESSOR_INFORMATION), SortByCcd); + } + + // Now allocate the Uid + for (Index = 0; Index < mNumberOfCpus; Index++) { + // Now make Processor as Uid + mApicIdtoUidMap[Index].ProcessorId = Index; + } + + return EFI_SUCCESS; +} + +/** + Install CPU devices scoped under \_SB into DSDT + + Determine all the CPU threads and create ACPI Device nodes for each thread. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallCpuAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + AML_OBJECT_NODE_HANDLE CpuInstanceNode; + AML_OBJECT_NODE_HANDLE CpuNode; + AML_OBJECT_NODE_HANDLE ScopeNode; + AML_ROOT_NODE_HANDLE RootNode; + CHAR8 *String; + CHAR8 Identifier[MAX_TEST_CPU_STRING_SIZE]; + EFI_ACPI_DESCRIPTION_HEADER *Table; + EFI_MP_SERVICES_PROTOCOL *MpServices; + EFI_STATUS Status; + EFI_STATUS Status1; + UINTN DeviceStatus; + UINTN Index; + UINTN NumberOfEnabledProcessors; + UINTN NumberOfLogicProcessors; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__)); + + String = &Identifier[0]; + + // Get MP service + MpServices = NULL; + Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices); + if (EFI_ERROR (Status) || (MpServices == NULL)) { + return EFI_NOT_FOUND; + } + + // Generate ACPI UID Map + Status = GenerateApicIdtoUidMap (); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: Could not generate ApicId to ProcessorUid map.\n", __func__)); + return EFI_NOT_FOUND; + } + + // Load MpServices + Status = MpServices->GetNumberOfProcessors (MpServices, &NumberOfLogicProcessors, &NumberOfEnabledProcessors); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = AmlCodeGenDefinitionBlock ( + "SSDT", + "AMD ", + "SSDTPROC", + 0x00, + &RootNode + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenScope ("\\_SB_", RootNode, &ScopeNode); // START: Scope (\_SB) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + CpuNode = ScopeNode; + + for (Index = 0; Index < NumberOfLogicProcessors; Index++) { + // Check for valid Processor under the current socket + if (!mApicIdtoUidMap[Index].StatusFlag) { + continue; + } + + AsciiSPrint (String, MAX_TEST_CPU_STRING_SIZE, "C%03X", Index); + Status = AmlCodeGenDevice (String, CpuNode, &CpuInstanceNode); // START: Device (CXXX) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _HID + Status = AmlCodeGenNameString ("_HID", "ACPI0007", CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + DeviceStatus = DEVICE_PRESENT_BIT | DEVICE_IN_UI_BIT; + if (mApicIdtoUidMap[Index].StatusFlag & PROCESSOR_ENABLED_BIT) { + DeviceStatus |= DEVICE_ENABLED_BIT; + } + + if (mApicIdtoUidMap[Index].StatusFlag & PROCESSOR_HEALTH_STATUS_BIT) { + DeviceStatus |= DEVICE_HEALTH_BIT; + } + + // _UID - Must match ACPI Processor UID in MADT + Status = AmlCodeGenNameInteger ("_UID", mApicIdtoUidMap[Index].ProcessorId, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _STA - As defined by 6.3.7 + Status = AmlCodeGenMethodRetInteger ("_STA", DeviceStatus, 0, FALSE, 0, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // PACK -> Package + Status = AmlCodeGenNameInteger ("PACK", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Package, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CCD_ -> Ccd + Status = AmlCodeGenNameInteger ("CCD_", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Die, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CCX_ -> Ccx + Status = AmlCodeGenNameInteger ("CCX_", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Module, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // CORE -> Core Number + Status = AmlCodeGenNameInteger ("CORE", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Core, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // THRD -> Thread + Status = AmlCodeGenNameInteger ("THRD", mApicIdtoUidMap[Index].ExtendedInformation.Location2.Thread, CpuInstanceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + Table = NULL; + // Serialize the tree. + Status = AmlSerializeDefinitionBlock ( + RootNode, + &Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data." + " Status = %r\n", + Status + )); + return (Status); + } + + // Cleanup + Status1 = AmlDeleteTree (RootNode); + if (EFI_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to cleanup AML tree." + " Status = %r\n", + Status1 + )); + // If Status was success but we failed to delete the AML Tree + // return Status1 else return the original error code, i.e. Status. + if (!EFI_ERROR (Status)) { + return Status1; + } + } + + Status = AppendExistingAcpiTable ( + EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + AMD_DSDT_OEMID, + Table + ); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c new file mode 100644 index 0000000000..a9d3c83a5e --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/PciSsdt.c @@ -0,0 +1,1381 @@ +/** @file + Creates SSDT table for PCIe devices + + Copyright (C) 2023 - 2024 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include <Library/AcpiHelperLib.h> +#include <Library/AmdPlatformSocLib.h> +#include <Library/AmlLib/AmlLib.h> +#include <Library/DebugLib.h> +#include <Library/IoLib.h> +#include <Library/PcdLib.h> +#include <Library/UefiBootServicesTableLib.h> +#include <Protocol/PciRootBridgeIo.h> +#include <Register/IoApic.h> +#include <Uefi/UefiSpec.h> +#include "AcpiCommon.h" + +#define MAX_PCI_BUS_NUMBER_PER_SEGMENT 0x100 + +EFI_HANDLE mDriverHandle; + +/** + Collect and sort the root bridge devices + + Does not include the Root Bridge resources + + @param[in, out] RootBridge - RootBridge information pointer + @param[in, out] RootBridgeCount - Number of root bridges + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalCollectSortedRootBridges ( + IN OUT AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE **RootBridge, + IN OUT UINTN *RootBridgeCount + ) +{ + UINTN Index; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *LocalRootBridge; // do not free + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *SortedRb; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *UnsortedRb; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE TempRootBridge; + UINTN LocalRootBridgeCount; + UINTN SortedIndex; + UINTN UnsortedIndex; + EFI_STATUS Status; + + if ((RootBridge == NULL) || (RootBridgeCount == NULL)) { + return EFI_INVALID_PARAMETER; + } + + LocalRootBridge = NULL; + LocalRootBridgeCount = 0; + Status = GetPcieInfo (&LocalRootBridge, &LocalRootBridgeCount); + if (EFI_ERROR (Status) || (LocalRootBridge == NULL) || (LocalRootBridgeCount == 0)) { + DEBUG ((DEBUG_ERROR, "%a:%d Cannot obtain Platform PCIe configuration information.\n", __func__, __LINE__)); + return EFI_NOT_FOUND; + } + + // Sort by PCIe bus number + for (SortedIndex = 0, SortedRb = LocalRootBridge; SortedIndex < LocalRootBridgeCount; SortedIndex++, SortedRb++) { + for (UnsortedIndex = 0, UnsortedRb = LocalRootBridge; UnsortedIndex < LocalRootBridgeCount; UnsortedIndex++, UnsortedRb++) { + if (SortedRb->Object->BaseBusNumber < UnsortedRb->Object->BaseBusNumber) { + CopyMem (&TempRootBridge, UnsortedRb, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + CopyMem (UnsortedRb, SortedRb, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + CopyMem (SortedRb, &TempRootBridge, sizeof (AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE)); + } + } + } + + for (Index = 0; Index < LocalRootBridgeCount; Index++) { + // Assign Uid values + LocalRootBridge[Index].Uid = Index; + } + + *RootBridge = LocalRootBridge; + *RootBridgeCount = LocalRootBridgeCount; + return EFI_SUCCESS; +} + +/** + Insert Root Bridge interrupts into AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in, out] GlobalInterruptBase - Global interrupt base + @param[in, out] PciNode - AML tree node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootBridgeInterrupts ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN OUT UINTN *GlobalInterruptBase, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + AML_OBJECT_NODE_HANDLE PrtNode; + EFI_STATUS Status; + UINTN Index; + + Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode); + ASSERT_EFI_ERROR (Status); + + if ((RootBridge->Object->BaseBusNumber == 0) && (RootBridge->Object->Segment == 0)) { + // Package () {0x0014FFFF, 0, 0, 16}, // 0 + 16 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 0, + NULL, + 16, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 1, 0, 17}, // 0 + 17 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 1, + NULL, + 17, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 2, 0, 18}, // 0 + 18 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 2, + NULL, + 18, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + // Package () {0x0014FFFF, 3, 0, 19}, // 0 + 19 + Status = AmlAddPrtEntry ( + 0x0014FFFF, + 3, + NULL, + 19, + PrtNode + ); + ASSERT_EFI_ERROR (Status); + } + + /// Add interrupt for Device 0 function 3 (generic to all function) + /// Value is taken from CRB BIOS + /// Fix the "pcie port 0000:XX:XX.3: can't derive routing for PCI INT A" error + Status = AmlAddPrtEntry ( + 0xFFFF, + 0, + NULL, + (UINT32)(RootBridge->GlobalInterruptStart + 1), + PrtNode + ); + ASSERT_EFI_ERROR (Status); + + for (Index = 1; Index <= RootBridge->RootPortCount; Index++) { + if ((RootBridge->RootPort[Index]->PortPresent == 0) && (RootBridge->RootPort[Index]->Enabled == 0)) { + continue; + } + + // Only insert for Functions 1 - 4 (minus 1) + if (((RootBridge->RootPort[Index]->Function - 1) & ~0x3) == 0) { + Status = AmlAddPrtEntry ( + (UINT32)((RootBridge->RootPort[Index]->Device << 16) | 0x0000FFFF), + (UINT8)(RootBridge->RootPort[Index]->Function - 1), + NULL, + (UINT32)(RootBridge->GlobalInterruptStart + RootBridge->RootPort[Index]->EndpointInterruptArray[RootBridge->RootPort[Index]->Function - 1]), + PrtNode + ); + ASSERT_EFI_ERROR (Status); + } + } + + // Attach the _PRT entry. + Status = AmlAttachNode (PciNode, PrtNode); + if (EFI_ERROR (Status)) { + AmlDeleteTree (PrtNode); + ASSERT_EFI_ERROR (Status); + } + + PrtNode = NULL; + + if (EFI_ERROR (Status)) { + return EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Insert Root Bridge resources into AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in, out] CrsNode - AML tree node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootBridgeResources ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN OUT AML_OBJECT_NODE_HANDLE CrsNode + ) +{ + EFI_STATUS Status; + EFI_HANDLE *HandleBuffer; + UINTN NumHandles; + EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL *Io; + UINTN Index; + VOID *Configuration; // Never free this buffer + EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR *LocalBuffer; + UINTN BaseBusNumber; + + BaseBusNumber = ~(UINTN)0; + // Get EFI Pci Root Bridge I/O Protocols + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciRootBridgeIoProtocolGuid, + NULL, + &NumHandles, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // Locate the Root Bridge IO protocol for this root bridge. + LocalBuffer = NULL; + Configuration = NULL; + for (Index = 0; Index < NumHandles; Index++) { + Status = gBS->OpenProtocol ( + HandleBuffer[Index], + &gEfiPciRootBridgeIoProtocolGuid, + (VOID **)&Io, + mDriverHandle, + NULL, + EFI_OPEN_PROTOCOL_GET_PROTOCOL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Io->SegmentNumber == RootBridge->Object->Segment) { + Status = Io->Configuration (Io, &Configuration); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Retrieve Root Bridge Configuration failed\n", __func__)); + return Status; + } + + LocalBuffer = Configuration; + while (TRUE) { + if (LocalBuffer->Header.Header.Byte == ACPI_END_TAG_DESCRIPTOR) { + LocalBuffer = NULL; + break; + } else if (LocalBuffer->Header.Header.Byte == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) { + if ((LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) && + (LocalBuffer->AddrRangeMin == RootBridge->Object->BaseBusNumber)) + { + BaseBusNumber = LocalBuffer->AddrRangeMin; + break; + } + } + + LocalBuffer++; + } + + if (BaseBusNumber == RootBridge->Object->BaseBusNumber) { + break; + } + } + } + + if ((Configuration == NULL) || (LocalBuffer == NULL)) { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Retrieve Root Bridge Configuration failed\n", __func__)); + return EFI_NOT_FOUND; + } + + LocalBuffer = Configuration; + + // All Elements are sizeof (EFI_ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) except + // for the End Tag + // Parse through Root Bridge resources and insert them in the ACPI Table + while (TRUE) { + if (LocalBuffer->Header.Header.Byte == ACPI_END_TAG_DESCRIPTOR) { + break; + } else if (LocalBuffer->Header.Header.Byte == ACPI_QWORD_ADDRESS_SPACE_DESCRIPTOR) { + if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_BUS) { + BaseBusNumber = LocalBuffer->AddrRangeMin; + Status = AmlCodeGenRdWordBusNumber ( + FALSE, + TRUE, + TRUE, + TRUE, + 0, + (UINT16)LocalBuffer->AddrRangeMin, + (UINT16)LocalBuffer->AddrRangeMax, + (UINT16)LocalBuffer->AddrTranslationOffset, + (UINT16)LocalBuffer->AddrLen, + 0, + NULL, + CrsNode, + NULL + ); + } else if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_IO) { + Status = AmlCodeGenRdWordIo ( + FALSE, + TRUE, + TRUE, + TRUE, + 3, // entire ranges + 0, + (UINT16)LocalBuffer->AddrRangeMin, + (UINT16)LocalBuffer->AddrRangeMax, + (UINT16)LocalBuffer->AddrTranslationOffset, + (UINT16)LocalBuffer->AddrLen, + 0, + NULL, + TRUE, + TRUE, + CrsNode, + NULL + ); + } else if (LocalBuffer->ResType == ACPI_ADDRESS_SPACE_TYPE_MEM) { + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + LocalBuffer->AddrRangeMin, + LocalBuffer->AddrRangeMax, + LocalBuffer->AddrTranslationOffset, + LocalBuffer->AddrLen, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + } + } else { + DEBUG ((DEBUG_ERROR, "%a: ERROR: Invalid Configuration Entry\n", __func__)); + return EFI_NOT_FOUND; + } + + LocalBuffer++; + } + + if ((RootBridge->Object->Segment == 0) && (BaseBusNumber == 0)) { + Status = AmlCodeGenRdWordIo ( + FALSE, + TRUE, + TRUE, + FALSE, + 3, // entire ranges + 0, + 0, + 0x0FFF, + 0, + 0x1000, + 0, + NULL, + TRUE, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + PcdGet32 (PcdPcIoApicAddressBase), + 0xFED3FFFF, + 0x0, + 0x140000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFED45000, + 0xFEDC1FFF, + 0x0, + 0x7D000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEDC7000, + 0xFEDCAFFF, + 0x0, + 0x4000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEDCC000, + 0xFEDFFFFF, + 0x0, + 0x34000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0, + 0xFEE01000, + 0xFEFFFFFF, + 0x0, + 0x1FF000, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + } + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + return Status; + } + + return EFI_SUCCESS; +} + +/** + Insert Root Port into the AML table + + @param[in] RootBridge - Single Root Bridge instance + @param[in] GlobalInterruptBase - Base to add to IOAPIC interrupt offset + @param[in,out] PciNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertRootPorts ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge, + IN UINTN GlobalInterruptBase, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + EFI_STATUS Status; + CHAR8 NameSeg[5]; + CHAR8 RpName[15]; + UINTN RPIndex; + UINTN Index; + AML_OBJECT_NODE_HANDLE DeviceNode; + AML_OBJECT_NODE_HANDLE PrtNode; + AML_OBJECT_NODE_HANDLE DsmMethod; + AML_OBJECT_NODE_HANDLE OstMethod; + AML_METHOD_PARAM MethodParam[7]; + + for (RPIndex = 1; RPIndex <= RootBridge->RootPortCount; RPIndex++) { + if ((RootBridge->RootPort[RPIndex]->PortPresent == 0) && (RootBridge->RootPort[RPIndex]->Enabled == 0)) { + continue; + } + + CopyMem (NameSeg, "RPxx", AML_NAME_SEG_SIZE + 1); + NameSeg[AML_NAME_SEG_SIZE - 2] = AsciiFromHex (RootBridge->RootPort[RPIndex]->Device & 0xF); + NameSeg[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (RootBridge->RootPort[RPIndex]->Function & 0xF); + + Status = AmlCodeGenDevice (NameSeg, PciNode, &DeviceNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ( + "_ADR", + (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Insert Slot User Number _SUN Record. + if (RootBridge->RootPort[RPIndex]->SlotNum != 0) { + Status = AmlCodeGenNameInteger ( + "_SUN", + RootBridge->RootPort[RPIndex]->SlotNum, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // _DSM and _OST, handling for root port EDR feature. + // Device 1 to 4 are external PCIe ports, only include them. + if ((RootBridge->RootPort[RPIndex]->Device > 0) && (RootBridge->RootPort[RPIndex]->Device < 5)) { + DEBUG (( + DEBUG_INFO, + "%a:Add EDR support for Uid 0x%x Addr 0x%x\n", + __func__, + RootBridge->Uid, + ((RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function) + )); + + AsciiSPrint ( + RpName, + 5, + "P%01X%01X%01X", + RootBridge->Uid, + RootBridge->RootPort[RPIndex]->Device, + RootBridge->RootPort[RPIndex]->Function + ); + + Status = AmlCodeGenNameString ( + "RSTR", + RpName, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ( + "BRB_", + RootBridge->Object->BaseBusNumber, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create a _DSM method for the root port + Status = AmlCodeGenMethodRetNameString ( + "_DSM", + NULL, + 4, + TRUE, + 0, + DeviceNode, + &DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// fill the AML_METHOD_PARAM structure to call the \\_SB.HDSM method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + MethodParam[4].Type = AmlMethodParamTypeInteger; + MethodParam[4].Data.Integer = RootBridge->Object->BaseBusNumber; + MethodParam[5].Type = AmlMethodParamTypeInteger; + MethodParam[5].Data.Integer = (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function; + MethodParam[6].Type = AmlMethodParamTypeString; + MethodParam[6].Data.Buffer = RpName; + /// Call the \\_SB.HDSM method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HDSM", + 7, + MethodParam, + DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create a _OST method for the root port + Status = AmlCodeGenMethodRetNameString ( + "_OST", + NULL, + 3, + TRUE, + 0, + DeviceNode, + &OstMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB._OST method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeInteger; + MethodParam[2].Data.Integer = RootBridge->Object->BaseBusNumber; + MethodParam[3].Type = AmlMethodParamTypeInteger; + MethodParam[3].Data.Integer = (RootBridge->RootPort[RPIndex]->Device << 16) + RootBridge->RootPort[RPIndex]->Function; + // call the \\_SB._OST method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HOST", + 4, + MethodParam, + OstMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // Build Root Port _PRT entry and insert in main ACPI Object list + Status = AmlCodeGenNamePackage ("_PRT", NULL, &PrtNode); + ASSERT_EFI_ERROR (Status); + + for (Index = 0; Index <= 3; Index++) { + Status = AmlAddPrtEntry ( + 0x0000FFFF, + (UINT8)Index, + NULL, + (UINT32)(GlobalInterruptBase + RootBridge->RootPort[RPIndex]->EndpointInterruptArray[Index]), + PrtNode + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + } + + // Attach the _PRT entry. + Status = AmlAttachNode (DeviceNode, PrtNode); + if (EFI_ERROR (Status)) { + AmlDeleteTree (PrtNode); + ASSERT_EFI_ERROR (Status); + } + + PrtNode = NULL; + } + + if (EFI_ERROR (Status)) { + Status = EFI_DEVICE_ERROR; + } + + return Status; +} + +/** + Insert CXL Root Bridge into the AML table + + @param[in] RootBridgeHead - RootBridge information pointer + @param[in] RootBridgeCount - Number of root bridges + @param[in,out] PciNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertCxlRootBridge ( + IN AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridgeHead, + IN UINTN RootBridgeCount, + IN OUT AML_OBJECT_NODE_HANDLE PciNode + ) +{ + AMD_PCI_ADDR PciAddr; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge; + AML_OBJECT_NODE_HANDLE CrsNode; + AML_OBJECT_NODE_HANDLE DeviceNode; + AML_OBJECT_NODE_HANDLE PackageNode; + CHAR8 NameSeg[5]; + EFI_STATUS Status; + UINT32 EisaId; + UINT8 DevIndex; + UINT8 Index; + AML_METHOD_PARAM MethodParam[7]; + AML_OBJECT_NODE_HANDLE OscMethod; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + ZeroMem ((VOID *)&PciAddr, sizeof (PciAddr)); + + // + // Populate the data structure for the CXL devices in the system to add to + // the ACPI Table + // + DevIndex = 0; + for (Index = 0, RootBridge = RootBridgeHead; Index < RootBridgeCount; Index++, RootBridge++) { + if ((RootBridge->CxlCount == 0) || (RootBridge->CxlPortInfo.IsCxl2 == TRUE)) { + continue; + } + + DevIndex++; + + CopyMem (NameSeg, "CXLx", AML_NAME_SEG_SIZE + 1); + if (DevIndex < 0x10) { + NameSeg[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (DevIndex); + } else { + NameSeg[AML_NAME_SEG_SIZE - 2] = AsciiFromHex (DevIndex); + } + + Status = AmlCodeGenDevice (NameSeg, PciNode, &DeviceNode); // RootBridge + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameString ("_HID", "ACPI0016", DeviceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNamePackage ("_CID", DeviceNode, &PackageNode); + ASSERT_EFI_ERROR (Status); + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_ADR, <address>) + Status = AmlCodeGenNameInteger ( + "_ADR", + (RootBridge->CxlPortInfo.EndPointBDF.Address.Device << 16) + RootBridge->CxlPortInfo.EndPointBDF.Address.Function, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", DevIndex, DeviceNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_BBN, <base bus number>) + Status = AmlCodeGenNameInteger ( + "_BBN", + RootBridge->CxlPortInfo.EndPointBDF.Address.Bus, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_SEG, <segment number>) + Status = AmlCodeGenNameInteger ( + "_SEG", + RootBridge->Object->BaseBusNumber / MAX_PCI_BUS_NUMBER_PER_SEGMENT, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PXM, <RootBridge->SocketId>) + PciAddr.Address.Bus = (UINT32)RootBridge->Object->BaseBusNumber; + PciAddr.Address.Segment = (UINT32)RootBridge->Object->Segment; + + Status = AmlCodeGenNameInteger ( + "_PXM", + RootBridge->PxmDomain, + DeviceNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CRS, <CRS Resource Template>) + Status = AmlCodeGenNameResourceTemplate ("_CRS", DeviceNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertRootBridgeResources (RootBridge, CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + /// Create AML code for below method + /// Method (_OSC, 4, NotSerialized, 4) // _OSC: Operating System Capabilities + /// { + /// \_SB.OSCI (Arg0, Arg1, Arg2, Arg3) + /// } + Status = AmlCodeGenMethodRetNameString ( + "_OSC", + NULL, + 4, + TRUE, + 0, + DeviceNode, + &OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.OSCI method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // call the \\_SB.OSCI method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.OSCI", + 4, + MethodParam, + OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "%a: Failed with Status: %r, Not Critical return SUCCESS\n", __func__, Status)); + Status = EFI_SUCCESS; + } + + return Status; +} + +/** + Insert Pcie base size into the AML table + + @param[in,out] CrsNode - AmlLib table node + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InternalInsertPciExpressBaseSize ( + IN OUT AML_OBJECT_NODE_HANDLE CrsNode + ) +{ + EFI_STATUS Status; + UINT64 RangeLen; + UINT64 RangeMax; + UINT64 RangeMin; + + RangeMin = PcdGet64 (PcdPciExpressBaseAddress); + RangeLen = PcdGet64 (PcdPciExpressBaseSize); + RangeMax = RangeMin + RangeLen - 1; + + Status = AmlCodeGenRdQWordMemory ( + FALSE, + TRUE, + TRUE, + TRUE, + FALSE, // non cacheable + TRUE, + 0x0, + RangeMin, + RangeMax, + 0x0, + RangeLen, + 0, + NULL, + 0, + TRUE, + CrsNode, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} + +/** + Install PCI devices scoped under \_SB into DSDT + + Determine all the PCI Root Bridges and PCI root ports and install resources + including needed _HID, _CID, _UID, _ADR, _CRS and _PRT Nodes. + + @param[in] ImageHandle - Standard UEFI entry point Image Handle + @param[in] SystemTable - Standard UEFI entry point System Table + + @retval EFI_SUCCESS, various EFI FAILUREs. +**/ +EFI_STATUS +EFIAPI +InstallPciAcpi ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + AMD_PCI_ADDR PciAddr; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridge; + AMD_PCI_ROOT_BRIDGE_OBJECT_INSTANCE *RootBridgeHead; + AML_OBJECT_NODE_HANDLE AmdmNode; + AML_OBJECT_NODE_HANDLE CrsNode; + AML_OBJECT_NODE_HANDLE PackageNode; + AML_OBJECT_NODE_HANDLE PciNode; + AML_OBJECT_NODE_HANDLE ScopeNode; + AML_OBJECT_NODE_HANDLE CxldNode; + AML_OBJECT_NODE_HANDLE DsmMethod; + AML_ROOT_NODE_HANDLE RootNode; + CHAR8 AslName[AML_NAME_SEG_SIZE + 1]; + EFI_ACPI_DESCRIPTION_HEADER *Table; + EFI_ACPI_SDT_HEADER *SdtTable; + EFI_STATUS Status; + EFI_STATUS Status1; + UINT32 EisaId; + UINTN GlobalInterruptBase; + UINTN RbIndex; + UINTN RootBridgeCount; + AML_METHOD_PARAM MethodParam[7]; + AML_OBJECT_NODE_HANDLE OscMethod; + + DEBUG ((DEBUG_INFO, "%a: Entry\n", __func__)); + + Status = AmlCodeGenDefinitionBlock ( + "SSDT", + "AMD ", + "AmdTable", + 0x00, + &RootNode + ); + ASSERT_EFI_ERROR (Status); + + ZeroMem ((VOID *)&PciAddr, sizeof (PciAddr)); + mDriverHandle = ImageHandle; + GlobalInterruptBase = 0; + + Status = InternalCollectSortedRootBridges (&RootBridgeHead, &RootBridgeCount); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenScope ("\\_SB_", RootNode, &ScopeNode); // START: Scope (\_SB) + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Create Root Bridge PCXX devices + for (RbIndex = 0, RootBridge = RootBridgeHead; RbIndex < RootBridgeCount; RbIndex++, RootBridge++) { + GlobalInterruptBase = RootBridge->GlobalInterruptStart; + // Make sure there is always PCI0 since this is a defacto standard. And + // therefore PCI0-PCIF and then PC10-PCFF + CopyMem (AslName, "PCIx", AML_NAME_SEG_SIZE + 1); + AslName[AML_NAME_SEG_SIZE - 1] = AsciiFromHex (RootBridge->Uid & 0xF); + if (RootBridge->Uid > 0xF) { + AslName[AML_NAME_SEG_SIZE - 2] = AsciiFromHex ((RootBridge->Uid >> 4) & 0xF); + } + + Status = AmlCodeGenDevice (AslName, ScopeNode, &PciNode); // RootBridge + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + if ((RootBridge->CxlCount > 0) && (RootBridge->CxlPortInfo.IsCxl2 == TRUE)) { + Status = AmlCodeGenNameString ("_HID", "ACPI0016", PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNamePackage ("_CID", PciNode, &PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlAddIntegerToNamedPackage (EisaId, PackageNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } else { + // Name (_HID, EISAID("PNP0A08")) + Status = AmlGetEisaIdFromString ("PNP0A08", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_HID", EisaId, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CID, EISAID("PNP0A03")) + Status = AmlGetEisaIdFromString ("PNP0A03", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_CID", EisaId, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", RootBridge->Uid, PciNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_BBN, <base bus number>) + Status = AmlCodeGenNameInteger ( + "_BBN", + RootBridge->Object->BaseBusNumber, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_SEG, <segment number>) + Status = AmlCodeGenNameInteger ( + "_SEG", + RootBridge->Object->Segment, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PXM, <RootBridge->SocketId>) + PciAddr.Address.Bus = (UINT32)RootBridge->Object->BaseBusNumber; + PciAddr.Address.Segment = (UINT32)RootBridge->Object->Segment; + + Status = AmlCodeGenNameInteger ( + "_PXM", + RootBridge->PxmDomain, + PciNode, + NULL + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_CRS, <CRS Resource Template>) + Status = AmlCodeGenNameResourceTemplate ("_CRS", PciNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertRootBridgeResources (RootBridge, CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_PRT, <Interrupt Packages>) + Status = InternalInsertRootBridgeInterrupts (RootBridge, &GlobalInterruptBase, PciNode); + ASSERT_EFI_ERROR (Status); + + // Create Root Port PXXX devices + // Name (_ADR, <pci address>) + // Name (_PRT, <Interrupt Packages>) + // Needs to be offset by previous IOAPICs interrupt count + InternalInsertRootPorts (RootBridge, RootBridge->GlobalInterruptStart, PciNode); + + /// AML code to generate _OSC method + /// Method (_OSC, 4, NotSerialized, 4) // _OSC: Operating System Capabilities + /// { + /// \_SB.OSCI (Arg0, Arg1, Arg2, Arg3) + /// } + Status = AmlCodeGenMethodRetNameString ( + "_OSC", + NULL, + 4, + TRUE, + 0, + PciNode, + &OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.OSCI method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // call the \\_SB.OSCI method + Status = AmlCodeGenInvokeMethod ( + "\\_SB.OSCI", + 4, + MethodParam, + OscMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + Status = GetExistingAcpiTable ( + CXL_EARLY_DISCOVERY_TABLE_SIGNATURE, + 0, + &SdtTable + ); + if (!EFI_ERROR (Status)) { + // CXL Root Device Specific Methods (_DSM) + Status = AmlCodeGenDevice ("CXLD", ScopeNode, &CxldNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // _DSM Functions that are associated with the CXL Root Device (HID="ACPI0017") + Status = AmlCodeGenNameString ("_HID", "ACPI0017", CxldNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Create a _DSM method + Status = AmlCodeGenMethodRetNameString ( + "_DSM", + NULL, + 4, + TRUE, + 0, + CxldNode, + &DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // fill the AML_METHOD_PARAM structure to call the \\_SB.HDSM method + ZeroMem (MethodParam, sizeof (MethodParam)); + MethodParam[0].Type = AmlMethodParamTypeArg; + MethodParam[0].Data.Arg = 0x0; // Arg0 is the first argument to the method + MethodParam[1].Type = AmlMethodParamTypeArg; + MethodParam[1].Data.Arg = 0x1; // Arg1 is the second argument to the method + MethodParam[2].Type = AmlMethodParamTypeArg; + MethodParam[2].Data.Arg = 0x2; // Arg2 is the third argument to the method + MethodParam[3].Type = AmlMethodParamTypeArg; + MethodParam[3].Data.Arg = 0x3; // Arg3 is the fourth argument to the method + // + // Call the \\_SB.HDSM method + // The CXL DSM will look for UUID: f365f9a6-a7de-4071-a66a-b40c0b4f8e52 + // + Status = AmlCodeGenInvokeMethod ( + "\\_SB.HDSM", + 4, + MethodParam, + DsmMethod + ); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + } + + // + // CXL device are added as Root Bridges but are not part of + // the AMD PCI Resource Protocol + // + InternalInsertCxlRootBridge (RootBridgeHead, RootBridgeCount, ScopeNode); + + // Add Pcie Base Size + Status = AmlCodeGenDevice ("AMDM", ScopeNode, &AmdmNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_HID, EISAID("PNP0C02")) + Status = AmlGetEisaIdFromString ("PNP0C02", &EisaId); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameInteger ("_HID", EisaId, AmdmNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + // Name (_UID, <root bridge number>) + Status = AmlCodeGenNameInteger ("_UID", 0, AmdmNode, NULL); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = AmlCodeGenNameResourceTemplate ("_CRS", AmdmNode, &CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Status = InternalInsertPciExpressBaseSize (CrsNode); + if (EFI_ERROR (Status)) { + ASSERT_EFI_ERROR (Status); + return Status; + } + + Table = NULL; + // Serialize the tree. + Status = AmlSerializeDefinitionBlock ( + RootNode, + &Table + ); + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to Serialize SSDT Table Data." + " Status = %r\n", + Status + )); + return (Status); + } + + // Cleanup + Status1 = AmlDeleteTree (RootNode); + if (EFI_ERROR (Status1)) { + DEBUG (( + DEBUG_ERROR, + "ERROR: SSDT-PCI: Failed to cleanup AML tree." + " Status = %r\n", + Status1 + )); + // If Status was success but we failed to delete the AML Tree + // return Status1 else return the original error code, i.e. Status. + if (!EFI_ERROR (Status)) { + return Status1; + } + } + + FreePool (RootBridgeHead); + + Status = AppendExistingAcpiTable ( + EFI_ACPI_6_5_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE, + AMD_DSDT_OEMID, + Table + ); + + return Status; +} diff --git a/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c new file mode 100644 index 0000000000..3520f29631 --- /dev/null +++ b/Platform/AMD/AmdPlatformPkg/Universal/Acpi/AcpiCommon/Spmi.c @@ -0,0 +1,111 @@ +/** @file + + FV block I/O protocol driver for SPI flash libary. + + Copyright (C) 2023 Advanced Micro Devices, Inc. All rights reserved. + + SPDX-License-Identifier BSD-2-Clause-Patent +**/ +#include <IndustryStandard/ServiceProcessorManagementInterfaceTable.h> +#include <IndustryStandard/Acpi65.h> +#include "AcpiCommon.h" + +EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE gSpmi = { + { + EFI_ACPI_6_5_SERVER_PLATFORM_MANAGEMENT_INTERFACE_TABLE_SIGNATURE, + sizeof (EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE), + 5, + // + // Checksum will be updated at runtime + // + 0x00, + // + // It is expected that these values will be programmed at runtime + // + { 'A', 'M', 'D', 'I', 'N', 'C' }, + SIGNATURE_64 ('S', 'P', 'M', 'I', 'T', 'a', 'b', 'l'), // updated during installation + 0x00, // Spmi revision, + SIGNATURE_32 ('A', 'M', 'D', ' '), + 0x00 // OEM Revision + }, + 0x00, // Interface type + 0x01, // Reserved + 0x0200, // IPMI specification revision + 0x00, // InterruptType + 0x00, // Gpe + 0x00, // Reserved2 + 0x00, // PciDeviceFlag or _UID + 0x00, // GlobalSystemInterrupt + { // BaseAddress + EFI_ACPI_6_5_SYSTEM_IO, + 0x08, // BASE_ADDRESS_BIT_WIDTH, + 0x00, // BASE_ADDRESS_BIT_OFFSET, + 0x00, // RESERVED_BYTE, + 0x0CA2 // BASE_ADDRESS_ADDRESS, + }, + { + { 0x00000000 } + }, + 0x00 +}; + +/** + Installs the ACPI SPMI Table to the System Table. +**/ +VOID +EFIAPI +InstallAcpiSpmiTable ( + VOID + ) +{ + UINT64 AcpiTableOemId; + UINTN TurnKey; + EFI_STATUS Status; + EFI_ACPI_TABLE_PROTOCOL *AcpiTablProtocol; + + if (!PcdGet8 (PcdIpmiInterfaceType)) { + return; + } + + Status = gBS->LocateProtocol ( + &gEfiAcpiTableProtocolGuid, + NULL, + (VOID **)&AcpiTablProtocol + ); + if (EFI_ERROR (Status)) { + // return if ACPI protocol not found + return; + } + + DEBUG ((DEBUG_ERROR, "Installing ACPI SPMI Table.\n")); + // OEM info + CopyMem ( + (VOID *)&gSpmi.Header.OemId, + PcdGetPtr (PcdAcpiDefaultOemId), + sizeof (gSpmi.Header.OemId) + ); + + AcpiTableOemId = PcdGet64 (PcdAcpiDefaultOemTableId); + CopyMem ( + (VOID *)&gSpmi.Header.OemTableId, + (VOID *)&AcpiTableOemId, + sizeof (gSpmi.Header.OemTableId) + ); + + gSpmi.Header.OemRevision = 0; + gSpmi.Header.CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId); + gSpmi.Header.CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision); + + gSpmi.InterfaceType = PcdGet8 (PcdIpmiInterfaceType); + gSpmi.BaseAddress.Address = PcdGet16 (PcdIpmiKcsIoBaseAddress); + // + // Add table + // + Status = AcpiTablProtocol->InstallAcpiTable ( + AcpiTablProtocol, + &gSpmi, + sizeof (EFI_ACPI_SERVICE_PROCESSOR_MANAGEMENT_INTERFACE_TABLE), + &TurnKey + ); + ASSERT_EFI_ERROR (Status); +} -- 2.34.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#118906): https://edk2.groups.io/g/devel/message/118906 Mute This Topic: https://groups.io/mt/106108335/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-