/** @file
|
Copyright (c) 2016, Hisilicon Limited. All rights reserved.
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
#include <PlatformArch.h>
|
#include <IndustryStandard/Acpi.h>
|
#include <Library/AcpiNextLib.h>
|
#include <Library/BaseLib.h>
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/HobLib.h>
|
#include <Library/HwMemInitLib.h>
|
#include <Library/OemConfigData.h>
|
#include <Library/OemMiscLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
#include <Library/UefiLib.h>
|
|
#define CORECOUNT(X) ((X) * CORE_NUM_PER_SOCKET)
|
|
#define FIELD_IORT_NODE_OFFSET 40
|
|
typedef enum {
|
NodeTypeIts = 0,
|
NodeTypeNameComponent,
|
NodeTypePciRC,
|
NodeTypeSmmuV1,
|
NodeTypeSmmuV3,
|
NodeTypePMCG
|
} IORT_NODE_TYPE;
|
|
#pragma pack(1)
|
typedef struct {
|
UINT8 Type;
|
UINT16 Length;
|
UINT8 Revision;
|
UINT32 Reserved;
|
UINT32 IdMapNumber;
|
UINT32 IdArrayOffset;
|
} IORT_NODE_HEAD;
|
#pragma pack()
|
|
BOOLEAN
|
IsIortWithSmmu (
|
IN EFI_ACPI_DESCRIPTION_HEADER *TableHeader
|
)
|
{
|
UINT32 *NodeOffset;
|
UINT32 NextOffset;
|
IORT_NODE_HEAD *Node;
|
|
NodeOffset = (UINT32 *)((UINT8 *)TableHeader + FIELD_IORT_NODE_OFFSET);
|
NextOffset = *NodeOffset;
|
|
while (NextOffset < TableHeader->Length) {
|
Node = (IORT_NODE_HEAD *)((UINT8 *)TableHeader + NextOffset);
|
NextOffset += Node->Length;
|
|
if ((Node->Type == NodeTypeSmmuV1) || (Node->Type == NodeTypeSmmuV3)) {
|
return TRUE;
|
}
|
}
|
|
return FALSE;
|
}
|
|
EFI_STATUS
|
SelectIort (
|
IN EFI_ACPI_DESCRIPTION_HEADER *TableHeader
|
)
|
{
|
EFI_STATUS Status;
|
UINTN Size;
|
OEM_CONFIG_DATA Configuration;
|
|
Configuration.EnableSmmu = 0;
|
Size = sizeof (OEM_CONFIG_DATA);
|
Status = gRT->GetVariable (
|
OEM_CONFIG_NAME,
|
&gOemConfigGuid,
|
NULL,
|
&Size,
|
&Configuration
|
);
|
if (EFI_ERROR (Status)) {
|
DEBUG ((DEBUG_ERROR, "Get OemConfig variable (%r).\n", Status));
|
}
|
|
Status = EFI_SUCCESS;
|
if (IsIortWithSmmu (TableHeader)) {
|
if (!Configuration.EnableSmmu) {
|
Status = EFI_ABORTED;
|
}
|
} else {
|
if (Configuration.EnableSmmu) {
|
Status = EFI_ABORTED;
|
}
|
}
|
DEBUG ((DEBUG_INFO, "SmmuEnable=%x, return %r for Iort table.\n",
|
Configuration.EnableSmmu, Status));
|
|
return Status;
|
}
|
|
STATIC
|
VOID
|
RemoveUnusedMemoryNode (
|
IN OUT EFI_ACPI_STATIC_RESOURCE_AFFINITY_TABLE *Table,
|
IN UINTN MemoryNodeNum
|
)
|
{
|
UINTN CurrPtr, NewPtr;
|
|
if (MemoryNodeNum >= EFI_ACPI_MEMORY_AFFINITY_STRUCTURE_COUNT) {
|
return;
|
}
|
|
CurrPtr = (UINTN) &(Table->Memory[EFI_ACPI_MEMORY_AFFINITY_STRUCTURE_COUNT]);
|
NewPtr = (UINTN) &(Table->Memory[MemoryNodeNum]);
|
|
CopyMem ((VOID *)NewPtr, (VOID *)CurrPtr, (UINTN)Table + Table->Header.Header.Length - CurrPtr);
|
|
Table->Header.Header.Length -= CurrPtr - NewPtr;
|
|
return;
|
}
|
|
STATIC
|
EFI_STATUS
|
UpdateSrat (
|
IN OUT EFI_ACPI_STATIC_RESOURCE_AFFINITY_TABLE *Table
|
)
|
{
|
UINT8 Skt = 0;
|
UINTN Index = 0;
|
VOID *HobList;
|
GBL_INTERFACE *Gbl_Data;
|
UINTN Base;
|
UINTN Size;
|
UINT8 NodeId;
|
UINT32 ScclInterleaveEn;
|
UINTN MemoryNode = 0;
|
|
DEBUG((DEBUG_INFO, "SRAT: Updating SRAT memory information.\n"));
|
|
HobList = GetHobList();
|
if (HobList == NULL) {
|
return EFI_UNSUPPORTED;
|
}
|
Gbl_Data = (GBL_INTERFACE*)GetNextGuidHob(&gHisiEfiMemoryMapGuid, HobList);
|
if (Gbl_Data == NULL) {
|
DEBUG((DEBUG_ERROR, "Get next Guid HOb fail.\n"));
|
return EFI_NOT_FOUND;
|
}
|
Gbl_Data = GET_GUID_HOB_DATA(Gbl_Data);
|
for(Skt = 0; Skt < MAX_SOCKET; Skt++) {
|
for(Index = 0; Index < MAX_NUM_PER_TYPE; Index++) {
|
NodeId = Gbl_Data->NumaInfo[Skt][Index].NodeId;
|
Base = Gbl_Data->NumaInfo[Skt][Index].Base;
|
Size = Gbl_Data->NumaInfo[Skt][Index].Length;
|
DEBUG((DEBUG_INFO, "Skt %d Index %d: NodeId = %d, Base = 0x%lx, Size = 0x%lx\n", Skt, Index, NodeId, Base, Size));
|
if (Size > 0) {
|
Table->Memory[MemoryNode].ProximityDomain = NodeId;
|
Table->Memory[MemoryNode].AddressBaseLow = Base;
|
Table->Memory[MemoryNode].AddressBaseHigh = Base >> 32;
|
Table->Memory[MemoryNode].LengthLow = Size;
|
Table->Memory[MemoryNode].LengthHigh = Size >> 32;
|
MemoryNode = MemoryNode + 1;
|
}
|
}
|
ScclInterleaveEn = Gbl_Data->NumaInfo[Skt][0].ScclInterleaveEn;
|
DEBUG((DEBUG_INFO, "ScclInterleaveEn = %d\n", ScclInterleaveEn));
|
//update gicc structure
|
if (ScclInterleaveEn != 0) {
|
DEBUG((DEBUG_INFO, "SRAT: Updating SRAT Gicc information.\n"));
|
for (Index = CORECOUNT (Skt); Index < CORECOUNT (Skt + 1); Index++) {
|
Table->Gicc[Index].ProximityDomain = Skt * NODE_IN_SOCKET;
|
}
|
}
|
}
|
|
//remove invalid memory node
|
RemoveUnusedMemoryNode (Table, MemoryNode);
|
|
return EFI_SUCCESS;
|
}
|
|
STATIC
|
EFI_STATUS
|
UpdateSlit (
|
IN OUT EFI_ACPI_DESCRIPTION_HEADER *Table
|
)
|
{
|
return EFI_SUCCESS;
|
}
|
|
EFI_STATUS
|
UpdateAcpiTable (
|
IN OUT EFI_ACPI_DESCRIPTION_HEADER *TableHeader
|
)
|
{
|
EFI_STATUS Status = EFI_SUCCESS;
|
|
switch (TableHeader->Signature) {
|
|
case EFI_ACPI_6_0_SYSTEM_RESOURCE_AFFINITY_TABLE_SIGNATURE:
|
Status = UpdateSrat ((EFI_ACPI_STATIC_RESOURCE_AFFINITY_TABLE *) TableHeader);
|
break;
|
|
case EFI_ACPI_6_0_SYSTEM_LOCALITY_INFORMATION_TABLE_SIGNATURE:
|
Status = UpdateSlit (TableHeader);
|
break;
|
case EFI_ACPI_6_2_IO_REMAPPING_TABLE_SIGNATURE:
|
Status = SelectIort (TableHeader);
|
break;
|
}
|
return Status;
|
}
|