/* $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; }