From b2c49163440805913644d022cdd06bfe28caf216 Mon Sep 17 00:00:00 2001 From: Pierre Gondois Date: Thu, 25 Jan 2024 16:18:48 +0100 Subject: DynamicTablesPkg: Add DynamicTablesScmiInfoLib The SCP holds some power information that could be advertised through the _CPC object. The communication with the SCP is done through SCMI protocols (c.f. ArmScmiDxe). Use the SCMI protocols to query information and feed it to the DynamicTablesPkg. Acked-by: Leif Lindholm Signed-off-by: Pierre Gondois Reviewed-by: Sami Mujawar --- DynamicTablesPkg/DynamicTables.dsc.inc | 3 + DynamicTablesPkg/DynamicTablesPkg.dec | 4 + DynamicTablesPkg/DynamicTablesPkg.dsc | 3 + .../Include/Library/DynamicTablesScmiInfoLib.h | 33 +++ .../DynamicTablesScmiInfoLib.c | 297 +++++++++++++++++++++ .../DynamicTablesScmiInfoLib.inf | 31 +++ 6 files changed, 371 insertions(+) create mode 100644 DynamicTablesPkg/Include/Library/DynamicTablesScmiInfoLib.h create mode 100644 DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.c create mode 100644 DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf (limited to 'DynamicTablesPkg') diff --git a/DynamicTablesPkg/DynamicTables.dsc.inc b/DynamicTablesPkg/DynamicTables.dsc.inc index 8c99574097..19ca62d6a8 100644 --- a/DynamicTablesPkg/DynamicTables.dsc.inc +++ b/DynamicTablesPkg/DynamicTables.dsc.inc @@ -21,6 +21,9 @@ TableHelperLib|DynamicTablesPkg/Library/Common/TableHelperLib/TableHelperLib.inf SmbiosStringTableLib|DynamicTablesPkg/Library/Common/SmbiosStringTableLib/SmbiosStringTableLib.inf +[LibraryClasses.AARCH64] + DynamicTablesScmiInfoLib|DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf + [Components.common] # # Dynamic Tables Manager Dxe diff --git a/DynamicTablesPkg/DynamicTablesPkg.dec b/DynamicTablesPkg/DynamicTablesPkg.dec index cfbcbb9569..25355ace88 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.dec +++ b/DynamicTablesPkg/DynamicTablesPkg.dec @@ -42,6 +42,10 @@ ## @libraryclass Defines a set of SMBIOS string helper methods. SmbiosStringTableLib|Include/Library/SmbiosStringTableLib.h +[LibraryClasses.AARCH64] + ## @libraryclass Defines a set of APIs to populate CmObj using SCMI. + DynamicTablesScmiInfoLib|Include/Library/DynamicTablesScmiInfoLib.h + [Protocols] # Configuration Manager Protocol GUID gEdkiiConfigurationManagerProtocolGuid = { 0xd85a4835, 0x5a82, 0x4894, { 0xac, 0x2, 0x70, 0x6f, 0x43, 0xd5, 0x97, 0x8e } } diff --git a/DynamicTablesPkg/DynamicTablesPkg.dsc b/DynamicTablesPkg/DynamicTablesPkg.dsc index 2f35ac82f2..cf06f0731a 100644 --- a/DynamicTablesPkg/DynamicTablesPkg.dsc +++ b/DynamicTablesPkg/DynamicTablesPkg.dsc @@ -51,6 +51,9 @@ [Components.ARM, Components.AARCH64] DynamicTablesPkg/Library/FdtHwInfoParserLib/FdtHwInfoParserLib.inf +[Components.AARCH64] + DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf + [BuildOptions] *_*_*_CC_FLAGS = -D DISABLE_NEW_DEPRECATED_INTERFACES diff --git a/DynamicTablesPkg/Include/Library/DynamicTablesScmiInfoLib.h b/DynamicTablesPkg/Include/Library/DynamicTablesScmiInfoLib.h new file mode 100644 index 0000000000..ff6b47d51f --- /dev/null +++ b/DynamicTablesPkg/Include/Library/DynamicTablesScmiInfoLib.h @@ -0,0 +1,33 @@ +/** @file + Arm SCMI Info Library. + + Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
+ + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#ifndef ARM_SCMI_INFO_LIB_H_ +#define ARM_SCMI_INFO_LIB_H_ + +#include + +/** Populate a AML_CPC_INFO object based on SCMI information. + + @param[in] DomainId Identifier for the performance domain. + @param[out] CpcInfo If success, this structure was populated from + information queried to the SCP. + + @retval EFI_SUCCESS Success. + @retval EFI_DEVICE_ERROR Device error. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_TIMEOUT Time out. + @retval EFI_UNSUPPORTED Unsupported. +**/ +EFI_STATUS +EFIAPI +DynamicTablesScmiInfoGetFastChannel ( + IN UINT32 DomainId, + OUT AML_CPC_INFO *CpcInfo + ); + +#endif // ARM_SCMI_INFO_LIB_H_ diff --git a/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.c b/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.c new file mode 100644 index 0000000000..da5bc18957 --- /dev/null +++ b/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.c @@ -0,0 +1,297 @@ +/** @file + Arm SCMI Info Library. + + Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.
+ + Arm Functional Fixed Hardware Specification: + - https://developer.arm.com/documentation/den0048/latest/ + + SPDX-License-Identifier: BSD-2-Clause-Patent +**/ + +#include +#include +#include +#include +#include +#include +#include + +/** Arm FFH registers + + Cf. Arm Functional Fixed Hardware Specification + s3.2 Performance management and Collaborative Processor Performance Control +*/ +#define ARM_FFH_DELIVERED_PERF_COUNTER_REGISTER 0x0 +#define ARM_FFH_REFERENCE_PERF_COUNTER_REGISTER 0x1 + +/// Arm SCMI performance protocol. +STATIC SCMI_PERFORMANCE_PROTOCOL *ScmiPerfProtocol; + +/** Arm SCMI Info Library constructor. + + @param ImageHandle Image of the loaded driver. + @param SystemTable Pointer to the System Table. + + @retval EFI_SUCCESS Success. + @retval EFI_DEVICE_ERROR Device error. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_NOT_FOUND Not Found + @retval EFI_TIMEOUT Timeout. + @retval EFI_UNSUPPORTED Unsupported. +**/ +EFI_STATUS +EFIAPI +DynamicTablesScmiInfoLibConstructor ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + UINT32 Version; + + Status = gBS->LocateProtocol ( + &gArmScmiPerformanceProtocolGuid, + NULL, + (VOID **)&ScmiPerfProtocol + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ScmiPerfProtocol->GetVersion (ScmiPerfProtocol, &Version); + if (EFI_ERROR (Status)) { + return Status; + } + + // FastChannels were added in SCMI v2.0 spec. + if (Version < PERFORMANCE_PROTOCOL_VERSION_V2) { + DEBUG (( + DEBUG_ERROR, + "DynamicTablesScmiInfoLib requires SCMI version > 2.0\n" + )); + return EFI_UNSUPPORTED; + } + + return Status; +} + +/** Get the OPPs/performance states of a power domain. + + This function is a wrapper around the SCMI PERFORMANCE_DESCRIBE_LEVELS + command. The list of discrete performance states is returned in a buffer + that must be freed by the caller. + + @param[in] DomainId Identifier for the performance domain. + @param[out] LevelArray If success, pointer to the list of list of + performance state. This memory must be freed by + the caller. + @param[out] LevelArrayCount If success, contains the number of states in + LevelArray. + + @retval EFI_SUCCESS Success. + @retval EFI_DEVICE_ERROR Device error. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_TIMEOUT Time out. + @retval EFI_UNSUPPORTED Unsupported. +**/ +STATIC +EFI_STATUS +EFIAPI +DynamicTablesScmiInfoDescribeLevels ( + IN UINT32 DomainId, + OUT SCMI_PERFORMANCE_LEVEL **LevelArray, + OUT UINT32 *LevelArrayCount + ) +{ + EFI_STATUS Status; + SCMI_PERFORMANCE_LEVEL *Array; + UINT32 Count; + UINT32 Size; + + if ((ScmiPerfProtocol == NULL) || + (LevelArray == NULL) || + (LevelArrayCount == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + // First call to get the number of levels. + Size = 0; + Status = ScmiPerfProtocol->DescribeLevels ( + ScmiPerfProtocol, + DomainId, + &Count, + &Size, + NULL + ); + if (Status != EFI_BUFFER_TOO_SMALL) { + // EFI_SUCCESS is not a valid option. + if (Status == EFI_SUCCESS) { + return EFI_INVALID_PARAMETER; + } else { + return Status; + } + } + + Array = AllocateZeroPool (Size); + if (Array == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // Second call to get the descriptions of the levels. + Status = ScmiPerfProtocol->DescribeLevels ( + ScmiPerfProtocol, + DomainId, + &Count, + &Size, + Array + ); + if (EFI_ERROR (Status)) { + return Status; + } + + *LevelArray = Array; + *LevelArrayCount = Count; + + return Status; +} + +/** Populate a AML_CPC_INFO object based on SCMI information. + + @param[in] DomainId Identifier for the performance domain. + @param[out] CpcInfo If success, this structure was populated from + information queried to the SCP. + + @retval EFI_SUCCESS Success. + @retval EFI_DEVICE_ERROR Device error. + @retval EFI_INVALID_PARAMETER Invalid parameter. + @retval EFI_TIMEOUT Time out. + @retval EFI_UNSUPPORTED Unsupported. +**/ +EFI_STATUS +EFIAPI +DynamicTablesScmiInfoGetFastChannel ( + IN UINT32 DomainId, + OUT AML_CPC_INFO *CpcInfo + ) +{ + EFI_STATUS Status; + SCMI_PERFORMANCE_FASTCHANNEL FcLevelGet; + SCMI_PERFORMANCE_FASTCHANNEL FcLimitsSet; + SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES DomainAttributes; + + SCMI_PERFORMANCE_LEVEL *LevelArray; + UINT32 LevelCount; + + UINT64 FcLevelGetAddr; + UINT64 FcLimitsMaxSetAddr; + UINT64 FcLimitsMinSetAddr; + + if ((ScmiPerfProtocol == NULL) || + (CpcInfo == NULL)) + { + return EFI_INVALID_PARAMETER; + } + + Status = ScmiPerfProtocol->DescribeFastchannel ( + ScmiPerfProtocol, + DomainId, + ScmiMessageIdPerformanceLevelSet, + &FcLevelGet + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ScmiPerfProtocol->DescribeFastchannel ( + ScmiPerfProtocol, + DomainId, + ScmiMessageIdPerformanceLimitsSet, + &FcLimitsSet + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = ScmiPerfProtocol->GetDomainAttributes ( + ScmiPerfProtocol, + DomainId, + &DomainAttributes + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = DynamicTablesScmiInfoDescribeLevels (DomainId, &LevelArray, &LevelCount); + if (EFI_ERROR (Status)) { + return Status; + } + + /* Do some safety checks. + Only support FastChannels (and not doorbells) as this is + the only mechanism supported by SCP. + FcLimits[Get|Set] require 2 UINT32 values (max, then min) and + FcLimits[Get|Set] require 1 UINT32 value (level). + */ + if ((FcLevelGet.ChanSize != sizeof (UINT32)) || + ((FcLevelGet.Attributes & SCMI_PERF_FC_ATTRIB_HAS_DOORBELL) == + SCMI_PERF_FC_ATTRIB_HAS_DOORBELL) || + (FcLimitsSet.ChanSize != 2 * sizeof (UINT32)) || + ((FcLimitsSet.Attributes & SCMI_PERF_FC_ATTRIB_HAS_DOORBELL) == + SCMI_PERF_FC_ATTRIB_HAS_DOORBELL)) + { + Status = EFI_INVALID_PARAMETER; + goto exit_handler; + } + + FcLevelGetAddr = ((UINT64)FcLevelGet.ChanAddrHigh << 32) | + FcLevelGet.ChanAddrLow; + FcLimitsMaxSetAddr = ((UINT64)FcLimitsSet.ChanAddrHigh << 32) | + FcLimitsSet.ChanAddrLow; + FcLimitsMinSetAddr = FcLimitsMaxSetAddr + 0x4; + + CpcInfo->Revision = EFI_ACPI_6_5_AML_CPC_REVISION; + CpcInfo->HighestPerformanceInteger = LevelArray[LevelCount - 1].Level; + CpcInfo->NominalPerformanceInteger = DomainAttributes.SustainedPerfLevel; + CpcInfo->LowestNonlinearPerformanceInteger = LevelArray[0].Level; + CpcInfo->LowestPerformanceInteger = LevelArray[0].Level; + + CpcInfo->DesiredPerformanceRegister.AddressSpaceId = EFI_ACPI_6_5_SYSTEM_MEMORY; + CpcInfo->DesiredPerformanceRegister.RegisterBitWidth = 32; + CpcInfo->DesiredPerformanceRegister.RegisterBitOffset = 0; + CpcInfo->DesiredPerformanceRegister.AccessSize = EFI_ACPI_6_5_DWORD; + CpcInfo->DesiredPerformanceRegister.Address = FcLevelGetAddr; + + CpcInfo->MinimumPerformanceRegister.AddressSpaceId = EFI_ACPI_6_5_SYSTEM_MEMORY; + CpcInfo->MinimumPerformanceRegister.RegisterBitWidth = 32; + CpcInfo->MinimumPerformanceRegister.RegisterBitOffset = 0; + CpcInfo->MinimumPerformanceRegister.AccessSize = EFI_ACPI_6_5_DWORD; + CpcInfo->MinimumPerformanceRegister.Address = FcLimitsMinSetAddr; + + CpcInfo->MaximumPerformanceRegister.AddressSpaceId = EFI_ACPI_6_5_SYSTEM_MEMORY; + CpcInfo->MaximumPerformanceRegister.RegisterBitWidth = 32; + CpcInfo->MaximumPerformanceRegister.RegisterBitOffset = 0; + CpcInfo->MaximumPerformanceRegister.AccessSize = EFI_ACPI_6_5_DWORD; + CpcInfo->MaximumPerformanceRegister.Address = FcLimitsMaxSetAddr; + + CpcInfo->ReferencePerformanceCounterRegister.AddressSpaceId = EFI_ACPI_6_5_FUNCTIONAL_FIXED_HARDWARE; + CpcInfo->ReferencePerformanceCounterRegister.RegisterBitWidth = 0x40; + CpcInfo->ReferencePerformanceCounterRegister.RegisterBitOffset = 0; + CpcInfo->ReferencePerformanceCounterRegister.AccessSize = ARM_FFH_REFERENCE_PERF_COUNTER_REGISTER; + CpcInfo->ReferencePerformanceCounterRegister.Address = 0x4; + + CpcInfo->DeliveredPerformanceCounterRegister.AddressSpaceId = EFI_ACPI_6_5_FUNCTIONAL_FIXED_HARDWARE; + CpcInfo->DeliveredPerformanceCounterRegister.RegisterBitWidth = 0x40; + CpcInfo->DeliveredPerformanceCounterRegister.RegisterBitOffset = 0; + CpcInfo->DeliveredPerformanceCounterRegister.AccessSize = ARM_FFH_DELIVERED_PERF_COUNTER_REGISTER; + CpcInfo->DeliveredPerformanceCounterRegister.Address = 0x4; + + // SCMI should advertise performance values on a unified scale. So frequency + // values are not available. LowestFrequencyInteger and + // NominalFrequencyInteger are populated in the ConfigurationManager. + +exit_handler: + FreePool (LevelArray); + return Status; +} diff --git a/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf b/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf new file mode 100644 index 0000000000..d49277f82b --- /dev/null +++ b/DynamicTablesPkg/Library/DynamicTablesScmiInfoLib/DynamicTablesScmiInfoLib.inf @@ -0,0 +1,31 @@ +## @file +# Arm SCMI Info Library. +# +# Copyright (c) 2022 - 2023, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 0x0001001B + BASE_NAME = DynamicTablesScmiInfoLib + FILE_GUID = 1A7CDB04-9FFC-40DA-A87C-A5ACADAF8136 + VERSION_STRING = 1.0 + MODULE_TYPE = DXE_DRIVER + LIBRARY_CLASS = DynamicTablesScmiInfoLib + CONSTRUCTOR = DynamicTablesScmiInfoLibConstructor + +[Sources] + DynamicTablesScmiInfoLib.c + +[Packages] + ArmPkg/ArmPkg.dec + DynamicTablesPkg/DynamicTablesPkg.dec + EmbeddedPkg/EmbeddedPkg.dec + MdePkg/MdePkg.dec + +[Protocols] + gArmScmiPerformanceProtocolGuid ## CONSUMES + +[Depex] + gArmScmiPerformanceProtocolGuid -- cgit v1.2.3