mirror of https://github.com/acidanthera/audk.git
458 lines
12 KiB
C
458 lines
12 KiB
C
/** @file
|
|
|
|
Copyright (c) 2017-2018, Arm Limited. All rights reserved.
|
|
|
|
This program and the accompanying materials
|
|
are licensed and made available under the terms and conditions of the BSD License
|
|
which accompanies this distribution. The full text of the license may be found at
|
|
http://opensource.org/licenses/bsd-license.php
|
|
|
|
THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
|
|
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
|
|
|
System Control and Management Interface V1.0
|
|
http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/
|
|
DEN0056A_System_Control_and_Management_Interface.pdf
|
|
**/
|
|
|
|
#include <Library/BaseMemoryLib.h>
|
|
#include <Library/UefiBootServicesTableLib.h>
|
|
#include <Protocol/ArmScmiPerformanceProtocol.h>
|
|
|
|
#include "ArmScmiPerformanceProtocolPrivate.h"
|
|
#include "ScmiPrivate.h"
|
|
|
|
/** Return version of the performance management protocol supported by SCP.
|
|
firmware.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
|
|
@param[out] Version Version of the supported SCMI performance management
|
|
protocol.
|
|
|
|
@retval EFI_SUCCESS The version is returned.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
PerformanceGetVersion (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
OUT UINT32 *Version
|
|
)
|
|
{
|
|
return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_PERFORMANCE, Version);
|
|
}
|
|
|
|
/** Return protocol attributes of the performance management protocol.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
|
|
@param[out] Attributes Protocol attributes.
|
|
|
|
@retval EFI_SUCCESS Protocol attributes are returned.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
PerformanceGetAttributes (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
OUT SCMI_PERFORMANCE_PROTOCOL_ATTRIBUTES *Attributes
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32* ReturnValues;
|
|
|
|
Status = ScmiGetProtocolAttributes (
|
|
SCMI_PROTOCOL_ID_PERFORMANCE,
|
|
&ReturnValues
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
CopyMem (
|
|
Attributes,
|
|
ReturnValues,
|
|
sizeof (SCMI_PERFORMANCE_PROTOCOL_ATTRIBUTES)
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Return performance domain attributes.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
|
|
@param[out] Attributes Performance domain attributes.
|
|
|
|
@retval EFI_SUCCESS Domain attributes are returned.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
PerformanceDomainAttributes (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
IN UINT32 DomainId,
|
|
OUT SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES *DomainAttributes
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 *MessageParams;
|
|
UINT32 *ReturnValues;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*MessageParams = DomainId;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_DOMAIN_ATTRIBUTES;
|
|
|
|
PayloadLength = sizeof (DomainId);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
&ReturnValues
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
CopyMem (
|
|
DomainAttributes,
|
|
ReturnValues,
|
|
sizeof (SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES)
|
|
);
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Return list of performance domain levels of a given domain.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
|
|
@param[out] NumLevels Total number of levels a domain can support.
|
|
|
|
@param[in,out] LevelArraySize Size of the performance level array.
|
|
|
|
@param[out] LevelArray Array of the performance levels.
|
|
|
|
@retval EFI_SUCCESS Domain levels are returned.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval EFI_BUFFER_TOO_SMALL LevelArraySize is too small for the result.
|
|
It has been updated to the size needed.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
PerformanceDescribeLevels (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
IN UINT32 DomainId,
|
|
OUT UINT32 *NumLevels,
|
|
IN OUT UINT32 *LevelArraySize,
|
|
OUT SCMI_PERFORMANCE_LEVEL *LevelArray
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
UINT32* MessageParams;
|
|
UINT32 LevelIndex;
|
|
UINT32 RequiredSize;
|
|
UINT32 LevelNo;
|
|
UINT32 ReturnNumLevels;
|
|
UINT32 ReturnRemainNumLevels;
|
|
|
|
PERF_DESCRIBE_LEVELS *Levels;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
LevelIndex = 0;
|
|
RequiredSize = 0;
|
|
|
|
*MessageParams++ = DomainId;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_DESCRIBE_LEVELS;
|
|
|
|
do {
|
|
|
|
*MessageParams = LevelIndex;
|
|
|
|
// Note, PayloadLength is an IN/OUT parameter.
|
|
PayloadLength = sizeof (DomainId) + sizeof (LevelIndex);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
(UINT32**)&Levels
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
ReturnNumLevels = NUM_PERF_LEVELS (Levels->NumLevels);
|
|
ReturnRemainNumLevels = NUM_REMAIN_PERF_LEVELS (Levels->NumLevels);
|
|
|
|
if (RequiredSize == 0) {
|
|
*NumLevels = ReturnNumLevels + ReturnRemainNumLevels;
|
|
|
|
RequiredSize = (*NumLevels) * sizeof (SCMI_PERFORMANCE_LEVEL);
|
|
if (RequiredSize > (*LevelArraySize)) {
|
|
// Update LevelArraySize with required size.
|
|
*LevelArraySize = RequiredSize;
|
|
return EFI_BUFFER_TOO_SMALL;
|
|
}
|
|
}
|
|
|
|
for (LevelNo = 0; LevelNo < ReturnNumLevels; LevelNo++) {
|
|
CopyMem (
|
|
&LevelArray[LevelIndex++],
|
|
&Levels->PerfLevel[LevelNo],
|
|
sizeof (SCMI_PERFORMANCE_LEVEL)
|
|
);
|
|
}
|
|
|
|
} while (ReturnRemainNumLevels != 0);
|
|
|
|
*LevelArraySize = RequiredSize;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Set performance limits of a domain.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
@param[in] Limit Performance limit to set.
|
|
|
|
@retval EFI_SUCCESS Performance limits set successfully.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
EFI_STATUS
|
|
PerformanceLimitsSet (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
IN UINT32 DomainId,
|
|
IN SCMI_PERFORMANCE_LIMITS *Limits
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
UINT32 *MessageParams;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*MessageParams++ = DomainId;
|
|
*MessageParams++ = Limits->RangeMax;
|
|
*MessageParams = Limits->RangeMin;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_LIMITS_SET;
|
|
|
|
PayloadLength = sizeof (DomainId) + sizeof (SCMI_PERFORMANCE_LIMITS);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
NULL
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Get performance limits of a domain.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
|
|
@param[out] Limit Performance Limits of the domain.
|
|
|
|
@retval EFI_SUCCESS Performance limits are returned.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
EFI_STATUS
|
|
PerformanceLimitsGet (
|
|
SCMI_PERFORMANCE_PROTOCOL *This,
|
|
UINT32 DomainId,
|
|
SCMI_PERFORMANCE_LIMITS *Limits
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
UINT32 *MessageParams;
|
|
|
|
SCMI_PERFORMANCE_LIMITS *ReturnValues;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*MessageParams = DomainId;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_LIMITS_GET;
|
|
|
|
PayloadLength = sizeof (DomainId);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
(UINT32**)&ReturnValues
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
Limits->RangeMax = ReturnValues->RangeMax;
|
|
Limits->RangeMin = ReturnValues->RangeMin;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/** Set performance level of a domain.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
@param[in] Level Performance level of the domain.
|
|
|
|
@retval EFI_SUCCESS Performance level set successfully.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
EFI_STATUS
|
|
PerformanceLevelSet (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
IN UINT32 DomainId,
|
|
IN UINT32 Level
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
UINT32 *MessageParams;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*MessageParams++ = DomainId;
|
|
*MessageParams = Level;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_LEVEL_SET;
|
|
|
|
PayloadLength = sizeof (DomainId) + sizeof (Level);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
NULL
|
|
);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/** Get performance level of a domain.
|
|
|
|
@param[in] This A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
|
|
@param[in] DomainId Identifier for the performance domain.
|
|
|
|
@param[out] Level Performance level of the domain.
|
|
|
|
@retval EFI_SUCCESS Performance level got successfully.
|
|
@retval EFI_DEVICE_ERROR SCP returns an SCMI error.
|
|
@retval !(EFI_SUCCESS) Other errors.
|
|
**/
|
|
EFI_STATUS
|
|
PerformanceLevelGet (
|
|
IN SCMI_PERFORMANCE_PROTOCOL *This,
|
|
IN UINT32 DomainId,
|
|
OUT UINT32 *Level
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 PayloadLength;
|
|
SCMI_COMMAND Cmd;
|
|
UINT32 *ReturnValues;
|
|
UINT32 *MessageParams;
|
|
|
|
Status = ScmiCommandGetPayload (&MessageParams);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*MessageParams = DomainId;
|
|
|
|
Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
|
|
Cmd.MessageId = SCMI_MESSAGE_ID_PERFORMANCE_LEVEL_GET;
|
|
|
|
PayloadLength = sizeof (DomainId);
|
|
|
|
Status = ScmiCommandExecute (
|
|
&Cmd,
|
|
&PayloadLength,
|
|
&ReturnValues
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
|
|
*Level = *ReturnValues;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
// Instance of the SCMI performance management protocol.
|
|
STATIC CONST SCMI_PERFORMANCE_PROTOCOL PerformanceProtocol = {
|
|
PerformanceGetVersion,
|
|
PerformanceGetAttributes,
|
|
PerformanceDomainAttributes,
|
|
PerformanceDescribeLevels,
|
|
PerformanceLimitsSet,
|
|
PerformanceLimitsGet,
|
|
PerformanceLevelSet,
|
|
PerformanceLevelGet
|
|
};
|
|
|
|
/** Initialize performance management protocol and install on a given Handle.
|
|
|
|
@param[in] Handle Handle to install performance management
|
|
protocol.
|
|
|
|
@retval EFI_SUCCESS Performance protocol installed successfully.
|
|
**/
|
|
EFI_STATUS
|
|
ScmiPerformanceProtocolInit (
|
|
IN EFI_HANDLE* Handle
|
|
)
|
|
{
|
|
return gBS->InstallMultipleProtocolInterfaces (
|
|
Handle,
|
|
&gArmScmiPerformanceProtocolGuid,
|
|
&PerformanceProtocol,
|
|
NULL
|
|
);
|
|
}
|