/** @file Copyright (c) 2016, Hisilicon Limited. All rights reserved. SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #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; }