diff options
Diffstat (limited to 'src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c new file mode 100644 index 0000000000..af7bdaf357 --- /dev/null +++ b/src/vendorcode/amd/agesa/f16kb/Proc/Mem/Feat/DMI/mfDMI.c @@ -0,0 +1,721 @@ +/* $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 + } + + 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) { + DmiPhysicalDimmInfoTable->FormFactor = 0x0D; // SO-DIMM + } 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) + 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 == 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; +} |