mirror of https://github.com/acidanthera/audk.git
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 <quic_llindhol@quicinc.com> Signed-off-by: Pierre Gondois <pierre.gondois@arm.com> Reviewed-by: Sami Mujawar <sami.mujawar@arm.com>
This commit is contained in:
parent
fc04cfd119
commit
b2c4916344
|
@ -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
|
||||
|
|
|
@ -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 } }
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
/** @file
|
||||
Arm SCMI Info Library.
|
||||
|
||||
Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.<BR>
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#ifndef ARM_SCMI_INFO_LIB_H_
|
||||
#define ARM_SCMI_INFO_LIB_H_
|
||||
|
||||
#include <ConfigurationManagerObject.h>
|
||||
|
||||
/** 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_
|
|
@ -0,0 +1,297 @@
|
|||
/** @file
|
||||
Arm SCMI Info Library.
|
||||
|
||||
Copyright (c) 2022 - 2023, Arm Limited. All rights reserved.<BR>
|
||||
|
||||
Arm Functional Fixed Hardware Specification:
|
||||
- https://developer.arm.com/documentation/den0048/latest/
|
||||
|
||||
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
**/
|
||||
|
||||
#include <Library/AcpiLib.h>
|
||||
#include <Library/DynamicTablesScmiInfoLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Protocol/ArmScmi.h>
|
||||
#include <Protocol/ArmScmiPerformanceProtocol.h>
|
||||
|
||||
/** 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;
|
||||
}
|
|
@ -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
|
Loading…
Reference in New Issue