Skip to content

Commit

Permalink
Use SMBIOS table for topology if PMTT is invalid or missing
Browse files Browse the repository at this point in the history
Some BIOS versions do not produce a PMTT table or do not properly set
the handle field. This change works around needing the PMTT table for
the most part for show -topology. Not all fields are available such as
SocketId for regular DDR. This means if the -socket is used that DDR
dimms will filtered out.

Signed-off-by: Steven Pontsler <[email protected]>
  • Loading branch information
StevenPontsler committed Aug 16, 2021
1 parent ba4ab51 commit b4584d6
Show file tree
Hide file tree
Showing 2 changed files with 161 additions and 11 deletions.
4 changes: 3 additions & 1 deletion DcpmPkg/cli/ShowTopologyCommand.c
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,9 @@ ShowTopology(
}
}
/** display detailed view for PMTT 0.1 **/
else if (IS_ACPI_REV_MAJ_0_MIN_1(Revision)) {
// If we are here with an invalid PMTT, we are able to derive the topology from the SMBIOS table successfully.
// Print in the style of a PMTT 0.1 table
else if (IS_ACPI_REV_MAJ_0_MIN_1(Revision) || IS_PMTT_REVISION_INVALID(Revision)) {
SetDisplayInfo(L"DimmTopology", ListView, NULL);

//Print detailed topology for DDR4 entries if no dimm target specified
Expand Down
168 changes: 158 additions & 10 deletions DcpmPkg/driver/Protocol/Driver/NvmDimmConfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -8860,7 +8860,7 @@ FreePmttItems(
@param[in] pPmttInfo - pointer to generic list head
**/
STATIC VOID
STATIC EFI_STATUS
MapSockets(
LIST_ENTRY * pPmttInfo
)
Expand All @@ -8878,13 +8878,12 @@ MapSockets(
UINT64 PmttLen = 0;
UINT64 Offset = 0;
UINT32 Index1 = 0, Index2 = 0;
#ifndef MDEPKG_NDEBUG
UINT32 InvalidHandleCount = 0;
LIST_ENTRY *pNode = NULL;
#endif

if (NULL == pPmttInfo) {
NVDIMM_ERR("Invalid Parameter");
return;
return EFI_INVALID_PARAMETER;
}

InitializeListHead(pPmttInfo);
Expand All @@ -8894,7 +8893,7 @@ MapSockets(
if (EFI_ERROR(ReturnCode)) {
//error getting PMTT. Nothing to map
//to see ddr4 topology in this case, do not use -socket
return;
goto Finish;
}

if (IS_ACPI_REV_MAJ_0_MIN_1(pPmttRaw->Revision)) {
Expand All @@ -8919,6 +8918,7 @@ MapSockets(
DdrEntry = AllocateZeroPool(sizeof(*DdrEntry));
if (DdrEntry == NULL) {
NVDIMM_ERR("Out of memory");
ReturnCode = EFI_OUT_OF_RESOURCES;
goto Finish;
}
DdrEntry->PmttVersion.Revision.AsUint8 = PMTT_HEADER_REVISION_1;
Expand All @@ -8927,6 +8927,9 @@ MapSockets(
DdrEntry->Signature = PMTT_INFO_SIGNATURE;
InsertTailList(pPmttInfo, &DdrEntry->PmttNode);
}
else {
InvalidHandleCount++;
}
}
Offset += sizeof(PMTT_MODULE) + PMTT_COMMON_HDR_LEN;
}
Expand All @@ -8949,6 +8952,7 @@ MapSockets(
DdrEntry = AllocateZeroPool(sizeof(*DdrEntry));
if (DdrEntry == NULL) {
NVDIMM_ERR("Out of memory");
ReturnCode = EFI_OUT_OF_RESOURCES;
goto Finish;
}

Expand All @@ -8966,6 +8970,10 @@ MapSockets(
}
}
}
else {
ReturnCode = EFI_UNSUPPORTED;
goto Finish;
}

#ifndef MDEPKG_NDEBUG
LIST_FOR_EACH(pNode, pPmttInfo) {
Expand All @@ -8974,9 +8982,25 @@ MapSockets(
}
#endif

// if a module was seen with an invalid handle and no modules with a valid handle were
// seen then indicate a likely problem by returning EFI_NOT_FOUND
if (InvalidHandleCount > 0) {
// get count of items in list. Reuse Index1 to hold count
Index1 = 0;
LIST_COUNT(pNode, pPmttInfo, Index1);

if (Index1 == 0) {
ReturnCode = EFI_NOT_FOUND;
goto Finish;
}
}

ReturnCode = EFI_SUCCESS;

Finish:
FREE_POOL_SAFE(pPmttRaw);
return;

return ReturnCode;
}

/**
Expand Down Expand Up @@ -9015,6 +9039,130 @@ INT32 SortDimmTopologyByMemType(VOID *ppTopologyDimm1, VOID *ppTopologyDimm2)
@retval EFI_OUT_OF_RESOURCES Problem with allocating memory
**/
EFI_STATUS
GetSystemTopologyFromSmbios(
IN EFI_DCPMM_CONFIG2_PROTOCOL* pThis,
OUT TOPOLOGY_DIMM_INFO** ppTopologyDimm,
OUT UINT16* pTopologyDimmsNumber
)
{
EFI_STATUS ReturnCode = EFI_DEVICE_ERROR;

SMBIOS_STRUCTURE_POINTER SmBiosStruct;
SMBIOS_STRUCTURE_POINTER BoundSmBiosStruct;
SMBIOS_VERSION SmbiosVersion;
UINT8 CorrectedMemoryType;
UINT16 Index = 0;
UINT64 Capacity = 0;
DIMM* pDimm = NULL;

NVDIMM_ENTRY();

if (pThis == NULL || ppTopologyDimm == NULL || pTopologyDimmsNumber == NULL) {
goto Finish;
}

*ppTopologyDimm = AllocateZeroPool(sizeof(**ppTopologyDimm) * MAX_DIMMS);
if (*ppTopologyDimm == NULL) {
ReturnCode = EFI_OUT_OF_RESOURCES;
goto Finish;
}

ZeroMem(&SmBiosStruct, sizeof(SmBiosStruct));
ZeroMem(&BoundSmBiosStruct, sizeof(BoundSmBiosStruct));
ZeroMem(&SmbiosVersion, sizeof(SmbiosVersion));

GetFirstAndBoundSmBiosStructPointer(&SmBiosStruct, &BoundSmBiosStruct, &SmbiosVersion);
if (SmBiosStruct.Raw == NULL || BoundSmBiosStruct.Raw == NULL) {
goto Finish;
}

while (SmBiosStruct.Raw < BoundSmBiosStruct.Raw) {
if ((SmBiosStruct.Hdr != NULL) &&
(SmBiosStruct.Hdr->Type == SMBIOS_TYPE_MEM_DEV) &&
((SmBiosStruct.Type17->MemoryType == SMBIOS_MEMORY_TYPE_DDR4) ||
(SmBiosStruct.Type17->MemoryType == SMBIOS_MEMORY_TYPE_LOGICAL_NON_VOLATILE) ||
(SmBiosStruct.Type17->MemoryType == SMBIOS_MEMORY_TYPE_DCPM))) {
(*ppTopologyDimm)[Index].DimmID = SmBiosStruct.Hdr->Handle;

ReturnCode = GetSmbiosCapacity(SmBiosStruct.Type17->Size, SmBiosStruct.Type17->ExtendedSize, SmbiosVersion,
&Capacity);
(*ppTopologyDimm)[Index].VolatileCapacity = Capacity;
ReturnCode = GetSmbiosString((SMBIOS_STRUCTURE_POINTER*)&SmBiosStruct.Type17,
SmBiosStruct.Type17->DeviceLocator, (*ppTopologyDimm)[Index].DeviceLocator,
sizeof((*ppTopologyDimm)[Index].DeviceLocator));
if (EFI_ERROR(ReturnCode)) {
NVDIMM_WARN("Failed to retrieve attribute pDmiPhysicalDev->Type17->DeviceLocator (" FORMAT_EFI_STATUS ")", ReturnCode);
}
ReturnCode = GetSmbiosString((SMBIOS_STRUCTURE_POINTER*)&SmBiosStruct.Type17,
SmBiosStruct.Type17->BankLocator, (*ppTopologyDimm)[Index].BankLabel,
sizeof((*ppTopologyDimm)[Index].BankLabel));
if (EFI_ERROR(ReturnCode)) {
NVDIMM_WARN("Failed to retrieve attribute pDmiPhysicalDev->Type17->BankLocator (" FORMAT_EFI_STATUS ")", ReturnCode);
}
// override types to keep consistency with dimm_info values
CorrectedMemoryType = SmBiosStruct.Type17->MemoryType;
if ((SmBiosStruct.Type17->MemoryType == SMBIOS_MEMORY_TYPE_DDR4) && (SmBiosStruct.Type17->TypeDetail.Nonvolatile)) {
CorrectedMemoryType = SMBIOS_MEMORY_TYPE_LOGICAL_NON_VOLATILE;
}
else {
CorrectedMemoryType = SmBiosStruct.Type17->MemoryType;
}
switch (CorrectedMemoryType) {
case SMBIOS_MEMORY_TYPE_DDR4:
(*ppTopologyDimm)[Index].SocketID = INVALID_SOCKET_ID; // need PMTT to get this value
(*ppTopologyDimm)[Index].MemoryType = MEMORYTYPE_DDR4;
break;
case SMBIOS_MEMORY_TYPE_DCPM: // fall through as both types are considered DCPM
case SMBIOS_MEMORY_TYPE_LOGICAL_NON_VOLATILE:
pDimm = GetDimmByPid(SmBiosStruct.Hdr->Handle, &gNvmDimmData->PMEMDev.Dimms);
if (pDimm == NULL) {
NVDIMM_WARN("Dimm ID: 0x%04x not found!", SmBiosStruct.Hdr->Handle);
goto Finish;
}
(*ppTopologyDimm)[Index].SocketID = pDimm->SocketId;
(*ppTopologyDimm)[Index].DimmHandle = pDimm->DeviceHandle.AsUint32;
(*ppTopologyDimm)[Index].ChannelID = pDimm->ChannelId;
(*ppTopologyDimm)[Index].SlotID = pDimm->ChannelPos;
(*ppTopologyDimm)[Index].MemControllerID = pDimm->ImcId;
(*ppTopologyDimm)[Index].MemoryType = MEMORYTYPE_DCPM;
break;
default:
(*ppTopologyDimm)[Index].SocketID = INVALID_SOCKET_ID; // need PMTT to get this value
(*ppTopologyDimm)[Index].MemoryType = MEMORYTYPE_UNKNOWN;
break;
}
Index++;
(*pTopologyDimmsNumber) = Index;
}

ReturnCode = GetNextSmbiosStruct(&SmBiosStruct);
if (EFI_ERROR(ReturnCode)) {
goto Finish;
}
}

ReturnCode = BubbleSort(*ppTopologyDimm, *pTopologyDimmsNumber, sizeof(**ppTopologyDimm), SortDimmTopologyByMemType);

Finish:

NVDIMM_EXIT_I64(ReturnCode);

return ReturnCode;
}

/**
Get system topology from PMTT table and if that fails try SMBIOS table
@param[in] pThis is a pointer to the EFI_DCPMM_CONFIG2_PROTOCOL instance.
@param[out] ppTopologyDimm Structure containing information about DDR4 entries from SMBIOS.
@param[out] pTopologyDimmsNumber Number of DDR4 entries found in SMBIOS.
@retval EFI_SUCCESS All ok.
@retval EFI_DEVICE_ERROR Unable to find SMBIOS table in system configuration tables.
@retval EFI_OUT_OF_RESOURCES Problem with allocating memory
**/
EFI_STATUS
EFIAPI
GetSystemTopology(
IN EFI_DCPMM_CONFIG2_PROTOCOL *pThis,
Expand Down Expand Up @@ -9045,10 +9193,10 @@ GetSystemTopology(
goto Finish;
}

MapSockets(&PmttInfo);

if (NULL == (&PmttInfo)->ForwardLink) {
NVDIMM_WARN("Error in getting PMTT Info for topology information");
ReturnCode = MapSockets(&PmttInfo);
if (EFI_ERROR(ReturnCode)) {
NVDIMM_WARN("Problem detected with PMTT table. Attempting to retrieve information from SMBIOS.");
ReturnCode = GetSystemTopologyFromSmbios(pThis, ppTopologyDimm, pTopologyDimmsNumber);
goto Finish;
}

Expand Down

0 comments on commit b4584d6

Please sign in to comment.