blob: 2f919d76e2deef42dcc7ebdd3d19cf222af0535a [file] [log] [blame]
/* $NoKeywords:$ */
/**
* @file
*
* mfDMI.c
*
* Memory DMI table support.
*
* @xrefitem bom "File Content Label" "Release Content"
* @e project: AGESA
* @e sub-project: (Mem/Main)
* @e \$Revision: 84150 $ @e \$Date: 2012-12-12 15:46:25 -0600 (Wed, 12 Dec 2012) $
*
**/
/*****************************************************************************
*
* Copyright (c) 2008 - 2013, Advanced Micro Devices, Inc.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Advanced Micro Devices, Inc. nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
* ***************************************************************************
*
*/
/*
*----------------------------------------------------------------------------
* MODULES USED
*
*----------------------------------------------------------------------------
*/
#include "AGESA.h"
#include "Ids.h"
#include "heapManager.h"
#include "cpuServices.h"
#include "mm.h"
#include "mn.h"
#include "mu.h"
#include "GeneralServices.h"
#include "Filecode.h"
CODE_GROUP (G2_PEI)
RDATA_GROUP (G2_PEI)
#define FILECODE PROC_MEM_FEAT_DMI_MFDMI_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
#define MAX_DCTS_PER_DIE 2
/*----------------------------------------------------------------------------
* TYPEDEFS AND STRUCTURES
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* PROTOTYPES OF LOCAL FUNCTIONS
*
*----------------------------------------------------------------------------
*/
UINT64
MemFGetNodeMemBase (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 NodeLimit
);
UINT64
MemFGetDctMemBase (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 DctLimit
);
UINT64
MemFGetDctInterleavedMemSize (
IN OUT MEM_NB_BLOCK *NBPtr
);
UINT64
MemFGetDctInterleavedLimit (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 Dct,
IN UINT64 DctMemBase,
IN UINT64 DctInterleavedMemSize
);
BOOLEAN
MemFDMISupport3 (
IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
);
/*----------------------------------------------------------------------------
* EXPORTED FUNCTIONS
*
*----------------------------------------------------------------------------
*/
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function gets DDR3 DMI information from SPD buffer and stores the info into heap
*
* @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK
*
*/
BOOLEAN
MemFDMISupport3 (
IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr
)
{
UINT8 i;
UINT8 Dimm;
UINT8 Socket;
UINT8 NodeId;
UINT8 Dct;
UINT8 Channel;
UINT8 temp;
UINT16 LocalHandle;
UINT8 MaxPhysicalDimms;
UINT8 MaxLogicalDimms;
UINT8 NumLogicalDimms;
UINT32 *TotalMemSizePtr;
UINT8 *DmiTable;
UINT8 MaxChannelsPerSocket;
UINT8 MaxDimmsPerChannel;
UINT8 FormFactor;
UINT16 TotalWidth;
UINT16 Capacity;
UINT16 Width;
UINT16 Rank;
UINT16 BusWidth;
UINT64 ManufacturerIdCode;
UINT32 MaxSockets;
UINT32 Address;
UINT8 ChipSelectPairScale;
UINT32 TotalSize;
UINT32 DimmSize;
UINT32 CsBaseAddrReg0;
UINT32 CsBaseAddrReg1;
UINT64 AddrValue;
UINT64 DctMemBase;
UINT64 NodeMemBase;
UINT64 SysMemSize;
INT32 MTB_ps;
INT32 FTB_ps;
INT32 Value32;
BOOLEAN DctInterleaveEnabled;
UINT64 DctInterleavedMemSize;
BOOLEAN NodeInterleaveEnabled;
UINT16 T17HandleMatrix[MAX_SOCKETS_SUPPORTED][MAX_CHANNELS_PER_SOCKET][MAX_DIMMS_PER_CHANNEL];
MEM_NB_BLOCK *NBPtr;
MEM_PARAMETER_STRUCT *RefPtr;
MEM_DATA_STRUCT *MemPtr;
DIE_STRUCT *MCTPtr;
CH_DEF_STRUCT *ChannelPtr;
SPD_DEF_STRUCT *SpdDataStructure;
ALLOCATE_HEAP_PARAMS AllocHeapParams;
MEM_DMI_PHYSICAL_DIMM_INFO *DmiPhysicalDimmInfoTable;
MEM_DMI_LOGICAL_DIMM_INFO *DmiLogicalDimmInfoTable;
DMI_T17_MEMORY_TYPE *DmiType17MemTypePtr;
NBPtr = MemMainPtr->NBPtr;
MemPtr = MemMainPtr->MemPtr;
SpdDataStructure = MemPtr->SpdDataStructure;
MCTPtr = NBPtr->MCTPtr;
RefPtr = MemPtr->ParameterListPtr;
// Initialize local variables
LocalHandle = 1;
MaxPhysicalDimms = 0;
MaxLogicalDimms = 0;
NumLogicalDimms = 0;
TotalSize = 0;
NodeMemBase = 0;
SysMemSize = 0;
AGESA_TESTPOINT (TpProcMemDmi, &MemPtr->StdHeader);
ASSERT (NBPtr != NULL);
MaxSockets = (UINT8) (0x000000FF & GetPlatformNumberOfSockets ());
for (Socket = 0; Socket < MaxSockets; Socket++) {
for (Channel = 0; Channel < GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); Channel++) {
temp = (UINT8) GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
MaxPhysicalDimms = MaxPhysicalDimms + temp;
MaxLogicalDimms += MAX_DIMMS_PER_CHANNEL;
}
}
// Allocate heap for memory DMI table 16, 17, 19, 20
AllocHeapParams.RequestedBufferSize = sizeof (UINT8) + // Storage for MaxPhysicalDimms
sizeof (UINT8) + // Storage for Type Detail
sizeof (UINT32) + // Storage for Total Memory Size
sizeof (DMI_T17_MEMORY_TYPE) +
MaxPhysicalDimms * sizeof (MEM_DMI_PHYSICAL_DIMM_INFO) +
sizeof (UINT8) + // Storage for MaxLogicalDimms
MaxLogicalDimms * sizeof (MEM_DMI_LOGICAL_DIMM_INFO);
AllocHeapParams.BufferHandle = AMD_DMI_MEM_DEV_INFO_HANDLE;
AllocHeapParams.Persist = HEAP_SYSTEM_MEM;
if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) {
PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_DMI_TABLE_DDR3, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader);
SetMemError (AGESA_CRITICAL, MCTPtr);
// Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR3
ASSERT (FALSE);
return FALSE;
}
DmiTable = (UINT8 *) AllocHeapParams.BufferPtr;
// Max number of physical DIMMs
*DmiTable = MaxPhysicalDimms;
DmiTable ++;
// Type Detail;
*DmiTable = 0;
DmiTable ++;
// Pointer to total memory size
TotalMemSizePtr = (UINT32 *) DmiTable;
DmiTable += sizeof (UINT32);
// Memory Type
DmiType17MemTypePtr = (DMI_T17_MEMORY_TYPE *) DmiTable;
*DmiType17MemTypePtr = Ddr3MemType;
DmiType17MemTypePtr ++;
DmiTable = (UINT8 *) DmiType17MemTypePtr;
// Pointer to DMI info of Physical DIMMs
DmiPhysicalDimmInfoTable = (MEM_DMI_PHYSICAL_DIMM_INFO *) DmiTable;
//
// Gather physical DIMM DMI info
//
for (Socket = 0; Socket < MaxSockets; Socket ++) {
MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
DctMemBase = 0;
for (Channel = 0; Channel < MaxChannelsPerSocket; Channel ++) {
//
// Get Node number and Dct number for this channel
//
ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
NodeId = ChannelPtr->MCTPtr->NodeId;
NBPtr = MemMainPtr->NBPtr;
Dct = ChannelPtr->Dct;
NBPtr = &NBPtr[NodeId];
NBPtr->SwitchDCT (NBPtr, Dct);
MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm ++, SpdDataStructure ++, LocalHandle++) {
//
// Initialize default value for DMI fields
//
DmiPhysicalDimmInfoTable->DimmPresent = 0;
DmiPhysicalDimmInfoTable->Socket = Socket;
DmiPhysicalDimmInfoTable->Channel = Channel;
DmiPhysicalDimmInfoTable->Dimm = Dimm;
DmiPhysicalDimmInfoTable->TotalWidth = 0xFFFF;
DmiPhysicalDimmInfoTable->DataWidth = 0xFFFF;
DmiPhysicalDimmInfoTable->MemorySize = 0;
DmiPhysicalDimmInfoTable->Speed = 0;
DmiPhysicalDimmInfoTable->ManufacturerIdCode = 0;
DmiPhysicalDimmInfoTable->Attributes = 0;
DmiPhysicalDimmInfoTable->ConfigSpeed = 0;
DmiPhysicalDimmInfoTable->ExtSize = 0;
DmiPhysicalDimmInfoTable->FormFactor = UnknowFormFactor;
DmiPhysicalDimmInfoTable->Handle = LocalHandle;
T17HandleMatrix[Socket][Channel][Dimm] = LocalHandle;
for (i = 0; i < 4; i++) {
DmiPhysicalDimmInfoTable->SerialNumber[i] = 0xFF;
}
for (i = 0; i < 18; i++) {
DmiPhysicalDimmInfoTable->PartNumber[i] = 0x0;
}
if (SpdDataStructure->DimmPresent) {
// Total Width (offset 08h) & Data Width (offset 0Ah)
TotalWidth = (UINT16) SpdDataStructure->Data[8];
if ((TotalWidth & 0x18) == 0) {
// non ECC
if ((TotalWidth & 0x07) == 0) {
DmiPhysicalDimmInfoTable->TotalWidth = 8; // 8 bits
} else if ((TotalWidth & 0x07) == 1) {
DmiPhysicalDimmInfoTable->TotalWidth = 16; // 16 bits
} else if ((TotalWidth & 0x07) == 2) {
DmiPhysicalDimmInfoTable->TotalWidth = 32; // 32 bits
} else if ((TotalWidth & 0x07) == 3) {
DmiPhysicalDimmInfoTable->TotalWidth = 64; // 64 bits
}
DmiPhysicalDimmInfoTable->DataWidth = DmiPhysicalDimmInfoTable->TotalWidth ;
} else {
// ECC
if ((TotalWidth & 0x07) == 0) {
DmiPhysicalDimmInfoTable->TotalWidth = 8 + 8; // 8 bits
} else if ((TotalWidth & 0x07) == 1) {
DmiPhysicalDimmInfoTable->TotalWidth = 16 + 8; // 16 bits
} else if ((TotalWidth & 0x07) == 2) {
DmiPhysicalDimmInfoTable->TotalWidth = 32 + 8; // 32 bits
} else if ((TotalWidth & 0x07) == 3) {
DmiPhysicalDimmInfoTable->TotalWidth = 64 + 8; // 64 bits
}
DmiPhysicalDimmInfoTable->DataWidth = DmiPhysicalDimmInfoTable->TotalWidth - 8;
}
// Memory Size (offset 0Ch)
Capacity = 0;
BusWidth = 0;
Width = 0;
Rank = 0;
temp = (UINT8) SpdDataStructure->Data[4];
if ((temp & 0x0F) == 0) {
Capacity = 0x0100; // 256M
} else if ((temp & 0x0F) == 1) {
Capacity = 0x0200; // 512M
} else if ((temp & 0x0F) == 2) {
Capacity = 0x0400; // 1G
} else if ((temp & 0x0F) == 3) {
Capacity = 0x0800; // 2G
} else if ((temp & 0x0F) == 4) {
Capacity = 0x1000; // 4G
} else if ((temp & 0x0F) == 5) {
Capacity = 0x2000; // 8G
} else if ((temp & 0x0F) == 6) {
Capacity = 0x4000; // 16G
}
temp = (UINT8) SpdDataStructure->Data[8];
if ((temp & 0x07) == 0) {
BusWidth = 8; // 8 bits
} else if ((temp & 0x07) == 1) {
BusWidth = 16; // 16 bits
} else if ((temp & 0x07) == 2) {
BusWidth = 32; // 32 bits
} else if ((temp & 0x07) == 3) {
BusWidth = 64; // 64 bits
}
temp = (UINT8) SpdDataStructure->Data[7];
if ((temp & 0x07) == 0) {
Width = 4; // 4 bits
} else if ((temp & 0x07) == 1) {
Width = 8; // 8 bits
} else if ((temp & 0x07) == 2) {
Width = 16; // 16 bits
} else if ((temp & 0x07) == 3) {
Width = 32; // 32 bits
}
temp = (UINT8) SpdDataStructure->Data[7];
if (((temp >> 3) & 0x07) == 0) {
Rank = 1; // 4 bits
DmiPhysicalDimmInfoTable->Attributes = 1; // Single Rank Dimm
} else if (((temp >> 3) & 0x07) == 1) {
Rank = 2; // 8 bits
DmiPhysicalDimmInfoTable->Attributes = 2; // Dual Rank Dimm
} else if (((temp >> 3) & 0x07) == 2) {
Rank = 3; // 16 bits
} else if (((temp >> 3) & 0x07) == 3) {
Rank = 4; // 32 bits
DmiPhysicalDimmInfoTable->Attributes = 4; // Quad Rank Dimm
}
if ((!BusWidth) || (!Width) || (!Rank))
DimmSize = 0xFFFF; // size is unknown
else
DimmSize = (UINT32) (Capacity / 8 * BusWidth / Width * Rank);
if (DimmSize < 0x7FFF) {
DmiPhysicalDimmInfoTable->MemorySize = (UINT16) DimmSize;
} else {
DmiPhysicalDimmInfoTable->MemorySize = 0x7FFF;
DmiPhysicalDimmInfoTable->ExtSize = DimmSize;
}
// Form Factor (offset 0Eh)
FormFactor = (UINT8) SpdDataStructure->Data[3];
if (((FormFactor & 0x0F) == 0x01) || ((FormFactor & 0x0F) == 0x02) || ((FormFactor & 0x0F) == 0x0B)) {
DmiPhysicalDimmInfoTable->FormFactor = 0x09; // RDIMM or UDIMM or LRDIMM
} else if (((FormFactor & 0x0F) == 0x03) || ((FormFactor & 0x0F) == 0x08) || ((FormFactor & 0x0F) == 0x09) || ((FormFactor & 0x0F) == 0x0A)) {
DmiPhysicalDimmInfoTable->FormFactor = 0x0D; // SO-DIMM, SO-UDIMM, SO-RDIMM and SO-CDIMM
} else {
DmiPhysicalDimmInfoTable->FormFactor = 0x02; // UNKNOWN
}
// DIMM Present
DmiPhysicalDimmInfoTable->DimmPresent = 1;
// Type Detail (offset 13h)
if (((FormFactor & 0x0F) == 0x01) || ((FormFactor & 0x0F) == 0x0B)) {
*((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 1; // Registered (Buffered)
} else {
*((UINT8 *) (AllocHeapParams.BufferPtr) + 1) = 2; // Unbuffered (Unregistered)
}
// Speed (offset 15h)
// If SPD is wrong, division by 0 in DIMM speed calculation could reboot CPU
// So avoid it by this check
if ((SpdDataStructure->Data[11]==0) ||
((SpdDataStructure->Data[9] & 0xF) == 0)) {
DmiPhysicalDimmInfoTable->Speed = 0; // Unknown
} else {
MTB_ps = ((INT32) SpdDataStructure->Data[10] * 1000) /
SpdDataStructure->Data[11];
FTB_ps = (SpdDataStructure->Data[9] >> 4) /
(SpdDataStructure->Data[9] & 0xF);
Value32 = (MTB_ps * SpdDataStructure->Data[12]) +
(FTB_ps * (INT8) SpdDataStructure->Data[34]);
if (Value32 <= 938) {
DmiPhysicalDimmInfoTable->Speed = 1067; // DDR3-2133
} else if (Value32 <= 1071) {
DmiPhysicalDimmInfoTable->Speed = 933; // DDR3-1866
} else if (Value32 <= 1250) {
DmiPhysicalDimmInfoTable->Speed = 800; // DDR3-1600
} else if (Value32 <= 1500) {
DmiPhysicalDimmInfoTable->Speed = 667; // DDR3-1333
} else if (Value32 <= 1875) {
DmiPhysicalDimmInfoTable->Speed = 533; // DDR3-1066
} else if (Value32 <= 2500) {
DmiPhysicalDimmInfoTable->Speed = 400; // DDR3-800
}
}
// Manufacturer (offset 17h)
ManufacturerIdCode = (UINT64) SpdDataStructure->Data[118];
DmiPhysicalDimmInfoTable->ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure->Data[117]);
// Serial Number (offset 18h)
for (i = 0; i < 4; i++) {
DmiPhysicalDimmInfoTable->SerialNumber[i] = (UINT8) SpdDataStructure->Data[i + 122];
}
// Part Number (offset 1Ah)
for (i = 0; i < 18; i++) {
DmiPhysicalDimmInfoTable->PartNumber[i] = (UINT8) SpdDataStructure->Data[i + 128];
}
// Configured Memory Clock Speed (offset 20h)
DmiPhysicalDimmInfoTable->ConfigSpeed = NBPtr->DCTPtr->Timings.Speed;
} // Dimm present
TotalSize += (UINT32) DmiPhysicalDimmInfoTable->MemorySize;
DmiPhysicalDimmInfoTable ++;
} // Dimm loop
} // Channel loop
} // Socket loop
// Max number of logical DIMMs
DmiTable = (UINT8 *) DmiPhysicalDimmInfoTable;
*DmiTable = MaxLogicalDimms;
DmiTable ++;
// Pointer to DMI info of Logical DIMMs
DmiLogicalDimmInfoTable = (MEM_DMI_LOGICAL_DIMM_INFO *) DmiTable;
// Calculate the total memory size in the system
SysMemSize = MemFGetNodeMemBase (MemMainPtr->NBPtr, MemPtr->DieCount);
//
// Gather logical DIMM DMI info
//
for (Socket = 0; Socket < MaxSockets; Socket ++) {
MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader);
DctMemBase = 0;
for (Channel = 0; Channel < MaxChannelsPerSocket; Channel ++) {
MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel);
//
// Get Node number and Dct number for this channel
//
ChannelPtr = MemPtr->SocketList[Socket].ChannelPtr[Channel];
NodeId = ChannelPtr->MCTPtr->NodeId;
NBPtr = MemMainPtr->NBPtr;
Dct = ChannelPtr->Dct;
NodeMemBase = MemFGetNodeMemBase (NBPtr, NodeId);
NBPtr = &NBPtr[NodeId];
DctMemBase = MemFGetDctMemBase (NBPtr, Dct);
DctInterleavedMemSize = MemFGetDctInterleavedMemSize (NBPtr);
NBPtr->SwitchDCT (NBPtr, Dct);
NodeInterleaveEnabled = (NBPtr->GetBitField (NBPtr, BFDramIntlvEn) == 0) ? FALSE : TRUE;
DctInterleaveEnabled = (NBPtr->GetBitField (NBPtr, BFDctSelIntLvEn) == 0) ? FALSE : TRUE;
for (Dimm = 0; Dimm < MAX_DIMMS_PER_CHANNEL; Dimm ++, DmiLogicalDimmInfoTable ++) {
//
// Initialize default value for DMI fields
//
DmiLogicalDimmInfoTable->DimmPresent = 0;
DmiLogicalDimmInfoTable->Socket = Socket;
DmiLogicalDimmInfoTable->Channel = Channel;
DmiLogicalDimmInfoTable->Dimm = Dimm;
DmiLogicalDimmInfoTable->StartingAddr = 0;
DmiLogicalDimmInfoTable->EndingAddr = 0;
DmiLogicalDimmInfoTable->ExtStartingAddr = 0;
DmiLogicalDimmInfoTable->ExtEndingAddr = 0;
//
// Starting/Ending Address for each DIMM
//
// If Ending Address >= 0xFFFFFFFF, update Starting Address & Ending Address to 0xFFFFFFFF,
// and use the Extended Starting Address & Extended Ending Address instead.
//
CsBaseAddrReg0 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + 2 * Dimm);
CsBaseAddrReg1 = NBPtr->GetBitField (NBPtr, BFCSBaseAddr0Reg + 2 * Dimm + 1);
if ((CsBaseAddrReg0 & 1) != 0 || (CsBaseAddrReg1 & 1) != 0) {
ASSERT (NumLogicalDimms < MaxLogicalDimms);
NumLogicalDimms ++;
DmiLogicalDimmInfoTable->DimmPresent = 1;
if (Dimm < MaxDimmsPerChannel) {
// The logical DIMM is mapped from a SR/QR physical DIMM
DmiLogicalDimmInfoTable->MemoryDeviceHandle = T17HandleMatrix[Socket][Channel][Dimm];
} else {
// The logical DIMM is mapped from a QR physical DIMM
DmiLogicalDimmInfoTable->MemoryDeviceHandle = T17HandleMatrix[Socket][Channel][Dimm - 2];
}
//
// For DR and QR DIMMs, DIMM size should be scaled based on the CS pair presence
//
ChipSelectPairScale = ((CsBaseAddrReg0 & 1) != 0 && (CsBaseAddrReg1 & 1) != 0) ? 1 : 0;
Address = ((CsBaseAddrReg0 & 1) != 0 ? CsBaseAddrReg0 : CsBaseAddrReg1) & NBPtr->CsRegMsk;
Address = (Address & 0xFFFF0000) >> 2;
if (DctInterleaveEnabled) {
//
// When channel interleaving is enabled, all the DIMMs on the node share the same starting address
//
Address = (UINT32)NodeMemBase;
} else {
if (NBPtr->DCTPtr->BkIntDis == FALSE && NBPtr->RefPtr->EnableBankIntlv == TRUE) {
//
// When bank interleaving is enabled, all the chip selects share the same starting address
//
Address = (UINT32) (NodeMemBase + DctMemBase);
} else {
Address += (UINT32) (NodeMemBase + DctMemBase);
}
}
if (NodeInterleaveEnabled) {
//
// When node interleaving is enabled, all the DIMMs in the system share the same starting address
//
Address = 0;
}
DmiLogicalDimmInfoTable->StartingAddr = Address;
AddrValue = (UINT64) Address +
((UINT64) ((NBPtr->GetBitField (NBPtr, BFCSMask0Reg + Dimm) & 0xFFFF0000) + 0x00080000) >>
(2 - ChipSelectPairScale) ) - 1;
if (NBPtr->DCTPtr->BkIntDis == FALSE && NBPtr->RefPtr->EnableBankIntlv == TRUE) {
//
// When bank interleaving is enabled, all the chip selects share the same ending address
//
AddrValue = NodeMemBase + DctMemBase + (NBPtr->DCTPtr->Timings.DctMemSize << 6) - 1;
}
if (DctInterleaveEnabled) {
//
// When channel interleaving is enabled, the interleaved range is accounted for in the ending address of each DCT
//
AddrValue = NodeMemBase + MemFGetDctInterleavedLimit (NBPtr, Dct, DctMemBase, DctInterleavedMemSize);
}
if (NodeInterleaveEnabled) {
//
// When node interleaving is enabled, all the DIMMs in the system share the same ending address
//
AddrValue = SysMemSize - 1;
}
if (AddrValue >= ((UINT64) 0xFFFFFFFF)) {
DmiLogicalDimmInfoTable->StartingAddr = 0xFFFFFFFFUL;
DmiLogicalDimmInfoTable->EndingAddr = 0xFFFFFFFFUL;
DmiLogicalDimmInfoTable->ExtStartingAddr = (UINT64) Address;
DmiLogicalDimmInfoTable->ExtEndingAddr = AddrValue;
} else {
DmiLogicalDimmInfoTable->EndingAddr = (UINT32) AddrValue;
}
}
} // Dimm loop
} // Channel loop
} // Socket loop
// Max Capacity
*TotalMemSizePtr = TotalSize;
return TRUE;
}
/*---------------------------------------------------------------------------------------
* L O C A L F U N C T I O N S
*---------------------------------------------------------------------------------------
*/
/**
*
*
* This function obtains the memory size RJ6 contributed by the previous nodes
*
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] NodeLimit - Node number
*
*/
UINT64
MemFGetNodeMemBase (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 NodeLimit
)
{
UINT8 Node;
UINT64 NodeMemBase;
NodeMemBase = 0;
// Calculate the total memory size in the system
for (Node = 0; Node < NodeLimit; Node++) {
NodeMemBase += (NBPtr[Node].MCTPtr->NodeMemSize << 6);
}
return NodeMemBase;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function obtains the memory size RJ6 contributed by the previous dcts on
* the current node
*
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] DctLimit - Dct number
*
*/
UINT64
MemFGetDctMemBase (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 DctLimit
)
{
UINT8 Dct;
UINT64 DctMemBase;
DctMemBase = 0;
// Calculate the total memory size in the system
for (Dct = 0; Dct < DctLimit; Dct++) {
MemNSwitchDCTNb (NBPtr, Dct);
DctMemBase += (NBPtr->DCTPtr->Timings.DctMemSize << 6);
}
return DctMemBase;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function obtains the interleaved memory size RJ6 contributed on the
* current dct
*
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
*
*/
UINT64
MemFGetDctInterleavedMemSize (
IN OUT MEM_NB_BLOCK *NBPtr
)
{
UINT8 Dct;
UINT64 DctInterleavedMemSize;
DctInterleavedMemSize = NBPtr->MCTPtr->NodeMemSize << 6;
// Find minimum memory size among the interleaved DCTs
for (Dct = 0; Dct < NBPtr->DctCount; Dct++) {
MemNSwitchDCTNb (NBPtr, Dct);
if (DctInterleavedMemSize > (NBPtr->DCTPtr->Timings.DctMemSize << 6)) {
DctInterleavedMemSize = (NBPtr->DCTPtr->Timings.DctMemSize << 6);
}
}
return DctInterleavedMemSize;
}
/* -----------------------------------------------------------------------------*/
/**
*
*
* This function obtains the memory ending address RJ6 contributed by a dct
* under channel interleaving
*
*
* @param[in,out] *NBPtr - Pointer to the MEM_NB_BLOCK
* @param[in] Dct - Dct number
* @param[in] DctMemBase - Dct memory base
* @param[in] DctInterleavedMemSize - Dct interleaved memory size
*
*/
UINT64
MemFGetDctInterleavedLimit (
IN OUT MEM_NB_BLOCK *NBPtr,
IN UINT8 Dct,
IN UINT64 DctMemBase,
IN UINT64 DctInterleavedMemSize
)
{
UINT64 DctMemLimit;
UINT8 i;
DctMemLimit = 0;
if (DctInterleavedMemSize == (UINT64)(NBPtr->DCTPtr->Timings.DctMemSize) << 6) {
// The whole memory range is interleaved for the DCTs with the minimum memory size
for (i = 0; i < NBPtr->DctCount; i++) {
DctMemLimit += DctInterleavedMemSize;
}
DctMemLimit -= 1;
} else {
// Part of the memory range is interleaved for the DCTs with memory size larger than
// the minimum. The remaining is treated as non-interleaved.
for (i = 0; i < NBPtr->DctCount - 1 - Dct; i++) {
DctMemLimit += DctInterleavedMemSize;
}
DctMemLimit += DctMemBase + (NBPtr->DCTPtr->Timings.DctMemSize << 6) - 1;
}
return DctMemLimit;
}