/** @file
Copyright (c) 2021 - 2023, Ampere Computing LLC. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
UINT32 Ac01CoreOrderMonolithic[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
36, 37, 40, 41, 52, 53, 56, 57, 32, 33,
44, 45, 48, 49, 60, 61, 20, 21, 24, 25,
68, 69, 72, 73, 16, 17, 28, 29, 64, 65,
76, 77, 4, 5, 8, 9, 0, 1, 12, 13,
38, 39, 42, 43, 54, 55, 58, 59, 34, 35,
46, 47, 50, 51, 62, 63, 22, 23, 26, 27,
70, 71, 74, 75, 18, 19, 30, 31, 66, 67,
78, 79, 6, 7, 10, 11, 2, 3, 14, 15,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127,
};
UINT32 Ac01CoreOrderHemisphere[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
32, 33, 48, 49, 16, 17, 64, 65, 36, 37,
52, 53, 0, 1, 20, 21, 68, 69, 4, 5,
34, 35, 50, 51, 18, 19, 66, 67, 38, 39,
54, 55, 2, 3, 22, 23, 70, 71, 6, 7,
44, 45, 60, 61, 28, 29, 76, 77, 40, 41,
56, 57, 12, 13, 24, 25, 72, 73, 8, 9,
46, 47, 62, 63, 30, 31, 78, 79, 42, 43,
58, 59, 14, 15, 26, 27, 74, 75, 10, 11,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127,
};
UINT32 Ac01CoreOrderQuadrant[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
16, 17, 32, 33, 0, 1, 20, 21, 4, 5,
18, 19, 34, 35, 2, 3, 22, 23, 6, 7,
48, 49, 64, 65, 52, 53, 68, 69, 36, 37,
50, 51, 66, 67, 54, 55, 70, 71, 38, 39,
28, 29, 44, 45, 12, 13, 24, 25, 8, 9,
30, 31, 46, 47, 14, 15, 26, 27, 10, 11,
60, 61, 76, 77, 56, 57, 72, 73, 40, 41,
62, 63, 78, 79, 58, 59, 74, 75, 42, 43,
80, 81, 82, 83, 84, 85, 86, 87,
88, 89, 90, 91, 92, 93, 94, 95,
96, 97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
120, 121, 122, 123, 124, 125, 126, 127,
};
UINT32 Ac02CoreOrderMonolithic[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
36, 37, 40, 41, 52, 53, 56, 57, 32, 33,
44, 45, 48, 49, 60, 61, 20, 21, 24, 25,
68, 69, 72, 73, 16, 17, 28, 29, 64, 65,
76, 77, 4, 5, 8, 9, 84, 85, 88, 89,
0, 1, 12, 13, 80, 81, 92, 93, 100, 101,
104, 105, 96, 97, 108, 109, 116, 117, 120, 121,
112, 113, 124, 125, 38, 39, 42, 43, 54, 55,
58, 59, 34, 35, 46, 47, 50, 51, 62, 63,
22, 23, 26, 27, 70, 71, 74, 75, 18, 19,
30, 31, 66, 67, 78, 79, 6, 7, 10, 11,
86, 87, 90, 91, 2, 3, 14, 15, 82, 83,
94, 95, 102, 103, 106, 107, 98, 99, 110, 111,
118, 119, 122, 123, 114, 115, 126, 127,
};
UINT32 Ac02CoreOrderHemisphere[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
32, 33, 48, 49, 16, 17, 64, 65, 36, 37,
52, 53, 0, 1, 20, 21, 68, 69, 80, 81,
4, 5, 84, 85, 96, 97, 100, 101, 112, 113,
116, 117, 34, 35, 50, 51, 18, 19, 66, 67,
38, 39, 54, 55, 2, 3, 22, 23, 70, 71,
82, 83, 6, 7, 86, 87, 98, 99, 102, 103,
114, 115, 118, 119, 44, 45, 60, 61, 28, 29,
76, 77, 40, 41, 56, 57, 12, 13, 24, 25,
72, 73, 92, 93, 8, 9, 88, 89, 108, 109,
104, 105, 124, 125, 120, 121, 46, 47, 62, 63,
30, 31, 78, 79, 42, 43, 58, 59, 14, 15,
26, 27, 74, 75, 94, 95, 10, 11, 90, 91,
110, 111, 106, 107, 126, 127, 122, 123,
};
UINT32 Ac02CoreOrderQuadrant[PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM] = {
16, 17, 32, 33, 0, 1, 20, 21,
36, 37, 4, 5, 84, 85, 96, 97,
18, 19, 34, 35, 2, 3, 22, 23,
38, 39, 6, 7, 86, 87, 98, 99,
48, 49, 64, 65, 52, 53, 68, 69,
80, 81, 100, 101, 112, 113, 116, 117,
50, 51, 66, 67, 54, 55, 70, 71,
82, 83, 102, 103, 114, 115, 118, 119,
28, 29, 44, 45, 12, 13, 24, 25,
40, 41, 8, 9, 88, 89, 108, 109,
30, 31, 46, 47, 14, 15, 26, 27,
42, 43, 10, 11, 90, 91, 110, 111,
60, 61, 76, 77, 56, 57, 72, 73,
92, 93, 104, 105, 124, 125, 120, 121,
62, 63, 78, 79, 58, 59, 74, 75,
94, 95, 106, 107, 126, 127, 122, 123,
};
PLATFORM_INFO_HOB *
GetPlatformHob (
VOID
);
/**
Get current CPU frequency.
@param Socket Socket index.
@return UINTN Current CPU frequency.
**/
UINTN
EFIAPI
CpuGetCurrentFreq (
UINT8 Socket
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
ASSERT (PlatformHob != NULL);
return PlatformHob->CpuClk;
}
/**
Get maximum CPU frequency.
@param Socket Socket index.
@return UINTN Maximum CPU frequency.
**/
UINTN
EFIAPI
CpuGetMaxFreq (
UINT8 Socket
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
ASSERT (PlatformHob != NULL);
if (PlatformHob->TurboCapability[Socket]) {
return PlatformHob->TurboFrequency[Socket];
}
return PlatformHob->CpuClk;
}
/**
Get CPU voltage.
@param Socket Socket index.
@return UINT8 CPU voltage.
**/
UINT8
EFIAPI
CpuGetVoltage (
UINT8 Socket
)
{
PLATFORM_INFO_HOB *PlatformHob;
UINT8 Voltage;
PlatformHob = GetPlatformHob ();
ASSERT (PlatformHob != NULL);
Voltage = 0x80 | (PlatformHob->CoreVoltage[Socket] / 100);
return Voltage;
}
/**
Get CPU Core order number.
@return UINT32* The order number.
**/
UINT32 *
CpuGetCoreOrder (
VOID
)
{
UINT32 *CoreOrder;
UINT8 SubNumaMode;
BOOLEAN IsAc01;
SubNumaMode = CpuGetSubNumaMode ();
IsAc01 = IsAc01Processor ();
switch (SubNumaMode) {
case SUBNUMA_MODE_MONOLITHIC:
default:
CoreOrder = IsAc01 ? Ac01CoreOrderMonolithic : Ac02CoreOrderMonolithic;
break;
case SUBNUMA_MODE_HEMISPHERE:
CoreOrder = IsAc01 ? Ac01CoreOrderHemisphere : Ac02CoreOrderHemisphere;
break;
case SUBNUMA_MODE_QUADRANT:
CoreOrder = IsAc01 ? Ac01CoreOrderQuadrant : Ac02CoreOrderQuadrant;
break;
}
return CoreOrder;
}
/**
Get the SubNUMA mode.
@return UINT8 The SubNUMA mode.
**/
UINT8
EFIAPI
CpuGetSubNumaMode (
VOID
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
return SUBNUMA_MODE_MONOLITHIC;
}
return PlatformHob->SubNumaMode[0];
}
/**
Get the number of SubNUMA region.
@return UINT8 The number of SubNUMA region.
**/
UINT8
EFIAPI
CpuGetNumberOfSubNumaRegion (
VOID
)
{
UINT8 SubNumaMode;
UINT8 NumberOfSubNumaRegion;
SubNumaMode = CpuGetSubNumaMode ();
ASSERT (SubNumaMode <= SUBNUMA_MODE_QUADRANT);
switch (SubNumaMode) {
case SUBNUMA_MODE_MONOLITHIC:
NumberOfSubNumaRegion = MONOLITIC_NUM_OF_REGION;
break;
case SUBNUMA_MODE_HEMISPHERE:
NumberOfSubNumaRegion = HEMISPHERE_NUM_OF_REGION;
break;
case SUBNUMA_MODE_QUADRANT:
NumberOfSubNumaRegion = QUADRANT_NUM_OF_REGION;
break;
default:
// Should never reach there.
NumberOfSubNumaRegion = 0;
ASSERT (FALSE);
break;
}
return NumberOfSubNumaRegion;
}
STATIC
UINT8
CpuGetLogicCoreId (
UINT32 PhyCoreId
)
{
UINT32 *CoreOrder;
UINT8 LogicCoreId;
UINT8 SktMaxCoreNum ;
CoreOrder = CpuGetCoreOrder();
SktMaxCoreNum = PLATFORM_CPU_MAX_CPM * PLATFORM_CPU_NUM_CORES_PER_CPM;
for (LogicCoreId = 0; LogicCoreId < SktMaxCoreNum; LogicCoreId++) {
if (CoreOrder[LogicCoreId] == PhyCoreId) {
return LogicCoreId;
}
}
return 0;
}
UINT8
EFIAPI
CpuGetSubNumNode (
UINT8 SocketId,
UINT16 Cpm
)
{
UINT8 LogicCoreId;
UINT8 MaxFamliyCore;
UINT8 MaxNumCorePerNode;
UINT8 SubNumaNode;
LogicCoreId = CpuGetLogicCoreId (Cpm * PLATFORM_CPU_NUM_CORES_PER_CPM);
MaxFamliyCore = IsAc01Processor () ? MAX_AMPERE_ALTRA_CORES : MAX_AMPERE_ALTRA_MAX_CORES;
switch (CpuGetSubNumaMode ()) {
case SUBNUMA_MODE_MONOLITHIC:
SubNumaNode = (SocketId == 0) ? 0 : 1;
break;
case SUBNUMA_MODE_HEMISPHERE:
MaxNumCorePerNode = MaxFamliyCore / HEMISPHERE_NUM_OF_REGION;
SubNumaNode = LogicCoreId / MaxNumCorePerNode;
if (SocketId == 1) {
SubNumaNode += HEMISPHERE_NUM_OF_REGION;
}
break;
case SUBNUMA_MODE_QUADRANT:
MaxNumCorePerNode = MaxFamliyCore / QUADRANT_NUM_OF_REGION;
SubNumaNode = LogicCoreId / MaxNumCorePerNode;
if (SocketId == 1) {
SubNumaNode += QUADRANT_NUM_OF_REGION;
}
break;
default:
// Should never reach there.
SubNumaNode = (SocketId == 0) ? 0 : 1;
ASSERT (FALSE);
break;
}
return SubNumaNode;
}
/**
Get the number of supported socket.
@return UINT8 Number of supported socket.
**/
UINT8
EFIAPI
GetNumberOfSupportedSockets (
VOID
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
//
// By default, the number of supported sockets is 1.
//
return 1;
}
return (sizeof (PlatformHob->ClusterEn) / sizeof (PLATFORM_CLUSTER_EN));
}
/**
Get the number of active socket.
@return UINT8 Number of active socket.
**/
UINT8
EFIAPI
GetNumberOfActiveSockets (
VOID
)
{
UINT8 NumberOfActiveSockets, Count, Index, Index1;
PLATFORM_CLUSTER_EN *Socket;
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
//
// By default, the number of active sockets is 1.
//
return 1;
}
NumberOfActiveSockets = 0;
for (Index = 0; Index < GetNumberOfSupportedSockets (); Index++) {
Socket = &PlatformHob->ClusterEn[Index];
Count = ARRAY_SIZE (Socket->EnableMask);
for (Index1 = 0; Index1 < Count; Index1++) {
if (Socket->EnableMask[Index1] != 0) {
NumberOfActiveSockets++;
break;
}
}
}
return NumberOfActiveSockets;
}
/**
Get the number of active CPM per socket.
@param SocketId Socket index.
@return UINT16 Number of CPM.
**/
UINT16
EFIAPI
GetNumberOfActiveCPMsPerSocket (
UINT8 SocketId
)
{
UINT16 NumberOfCPMs, Count, Index;
UINT32 Val32;
PLATFORM_CLUSTER_EN *Socket;
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
return 0;
}
if (SocketId >= GetNumberOfActiveSockets ()) {
return 0;
}
NumberOfCPMs = 0;
Socket = &PlatformHob->ClusterEn[SocketId];
Count = ARRAY_SIZE (Socket->EnableMask);
for (Index = 0; Index < Count; Index++) {
Val32 = Socket->EnableMask[Index];
while (Val32 > 0) {
if ((Val32 & 0x1) != 0) {
NumberOfCPMs++;
}
Val32 >>= 1;
}
}
return NumberOfCPMs;
}
/**
Get the number of configured CPM per socket. This number
should be the same for all sockets.
@param SocketId Socket index.
@return UINT8 Number of configured CPM.
**/
UINT16
EFIAPI
GetNumberOfConfiguredCPMs (
UINT8 SocketId
)
{
EFI_STATUS Status;
UINT32 Value;
UINT32 Param, ParamStart, ParamEnd;
UINT16 Count;
Count = 0;
ParamStart = NV_SI_S0_PCP_ACTIVECPM_0_31 + SocketId * NV_PARAM_ENTRYSIZE * (PLATFORM_CPU_MAX_CPM / 32);
ParamEnd = ParamStart + NV_PARAM_ENTRYSIZE * (PLATFORM_CPU_MAX_CPM / 32);
for (Param = ParamStart; Param < ParamEnd; Param += NV_PARAM_ENTRYSIZE) {
Status = NVParamGet (
Param,
NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
&Value
);
if (EFI_ERROR (Status)) {
break;
}
while (Value != 0) {
if ((Value & 0x01) != 0) {
Count++;
}
Value >>= 1;
}
}
return Count;
}
/**
Set the number of configured CPM per socket.
@param SocketId Socket index.
@param NumberOfCPMs Number of CPM to be configured.
@return EFI_SUCCESS Operation succeeded.
@return Others An error has occurred.
**/
EFI_STATUS
EFIAPI
SetNumberOfConfiguredCPMs (
UINT8 SocketId,
UINT16 NumberOfCPMs
)
{
EFI_STATUS Status;
UINT32 Value;
UINT32 Param, ParamStart, ParamEnd;
BOOLEAN IsClear;
IsClear = FALSE;
if (NumberOfCPMs == 0) {
IsClear = TRUE;
}
Status = EFI_SUCCESS;
ParamStart = NV_SI_S0_PCP_ACTIVECPM_0_31 + SocketId * NV_PARAM_ENTRYSIZE * (PLATFORM_CPU_MAX_CPM / 32);
ParamEnd = ParamStart + NV_PARAM_ENTRYSIZE * (PLATFORM_CPU_MAX_CPM / 32);
for (Param = ParamStart; Param < ParamEnd; Param += NV_PARAM_ENTRYSIZE) {
if (NumberOfCPMs >= 32) {
Value = 0xffffffff;
NumberOfCPMs -= 32;
} else {
Value = 0;
while (NumberOfCPMs > 0) {
Value |= (1 << (--NumberOfCPMs));
}
}
if (IsClear) {
/* Clear this param */
Status = NVParamClr (
Param,
NV_PERM_BIOS | NV_PERM_MANU
);
} else {
Status = NVParamSet (
Param,
NV_PERM_ATF | NV_PERM_BIOS | NV_PERM_MANU | NV_PERM_BMC,
NV_PERM_BIOS | NV_PERM_MANU,
Value
);
}
}
return Status;
}
/**
Get the maximum number of core per socket.
@return UINT16 Maximum number of core.
**/
UINT16
EFIAPI
GetMaximumNumberOfCores (
VOID
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
return 0;
}
return PlatformHob->MaxNumOfCore[0];
}
/**
Get the number of active cores of a sockets.
@param SocketId Socket Index.
@return UINT16 Number of active core.
**/
UINT16
EFIAPI
GetNumberOfActiveCoresPerSocket (
UINT8 SocketId
)
{
return GetNumberOfActiveCPMsPerSocket (SocketId) * PLATFORM_CPU_NUM_CORES_PER_CPM;
}
/**
Get the number of active cores of all sockets.
@return UINT16 Number of active core.
**/
UINT16
EFIAPI
GetNumberOfActiveCores (
VOID
)
{
UINT16 NumberOfActiveCores;
UINT8 Index;
NumberOfActiveCores = 0;
for (Index = 0; Index < GetNumberOfActiveSockets (); Index++) {
NumberOfActiveCores += GetNumberOfActiveCoresPerSocket (Index);
}
return NumberOfActiveCores;
}
/**
Check if the logical CPU is enabled or not.
@param CpuId The logical Cpu ID. Started from 0.
@return BOOLEAN TRUE if the Cpu enabled
FALSE if the Cpu disabled.
**/
BOOLEAN
EFIAPI
IsCpuEnabled (
UINT16 CpuId
)
{
PLATFORM_CLUSTER_EN *Socket;
PLATFORM_INFO_HOB *PlatformHob;
UINT8 SocketId;
UINT16 ClusterId;
SocketId = SOCKET_ID (CpuId);
ClusterId = CLUSTER_ID (CpuId);
PlatformHob = GetPlatformHob ();
if (PlatformHob == NULL) {
return FALSE;
}
if (SocketId >= GetNumberOfActiveSockets ()) {
return FALSE;
}
Socket = &PlatformHob->ClusterEn[SocketId];
if ((Socket->EnableMask[ClusterId / 32] & (1 << (ClusterId % 32))) != 0) {
return TRUE;
}
return FALSE;
}
/**
Check if the slave socket is present
@return BOOLEAN TRUE if the Slave Cpu is present
FALSE if the Slave Cpu is not present
**/
BOOLEAN
EFIAPI
IsSlaveSocketAvailable (
VOID
)
{
UINT32 Value;
Value = MmioRead32 (SMPRO_EFUSE_SHADOW0 + CFG2P_OFFSET);
return ((Value & SLAVE_PRESENT_N) != 0) ? FALSE : TRUE;
}
/**
Check if the slave socket is active
@return BOOLEAN TRUE if the Slave CPU Socket is active.
FALSE if the Slave CPU Socket is not active.
**/
BOOLEAN
EFIAPI
IsSlaveSocketActive (
VOID
)
{
return (GetNumberOfActiveSockets () > 1) ? TRUE : FALSE;
}
/**
Check if the CPU product ID is Ac01
@return BOOLEAN TRUE if the Product ID is Ac01
FALSE otherwise.
**/
BOOLEAN
EFIAPI
IsAc01Processor (
VOID
)
{
PLATFORM_INFO_HOB *PlatformHob;
PlatformHob = GetPlatformHob ();
ASSERT (PlatformHob != NULL);
if (PlatformHob != NULL) {
if ((PlatformHob->ScuProductId[0] & 0xFF) == 0x01) {
return TRUE;
}
}
return FALSE;
}