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