/* $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: 46495 $ @e \$Date: 2011-02-03 14:10:56 -0700 (Thu, 03 Feb 2011) $ * **/ /* ***************************************************************************** * * Copyright (c) 2011, 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 * *---------------------------------------------------------------------------- */ BOOLEAN MemFDMISupport3 ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ); BOOLEAN MemFDMISupport2 ( 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; UINT8 MaxDimms; UINT8 DimmIndex; UINT8 MaxChannelsPerSocket; UINT8 MaxDimmsPerChannel; UINT8 FormFactor; UINT16 TotalWidth; UINT16 Speed; UINT16 Capacity; UINT16 Width; UINT16 Rank; UINT16 BusWidth; UINT64 ManufacturerIdCode; UINT32 MaxSockets; UINT32 Address; MEM_NB_BLOCK *NBPtr; MEM_DATA_STRUCT *MemPtr; ALLOCATE_HEAP_PARAMS AllocHeapParams; MEM_DMI_INFO *DmiTable; MEM_PARAMETER_STRUCT *RefPtr; DIE_STRUCT *MCTPtr; CH_DEF_STRUCT *ChannelPtr; SPD_DEF_STRUCT *SpdDataStructure; NBPtr = MemMainPtr->NBPtr; MemPtr = MemMainPtr->MemPtr; SpdDataStructure = MemPtr->SpdDataStructure; MCTPtr = NBPtr->MCTPtr; RefPtr = MemPtr->ParameterListPtr; // Initialize local variables MaxDimms = 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 = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel); MaxDimms = MaxDimms + temp; } } // Allocate heap for memory DMI table 16, 17, 19, 20 AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 2 + sizeof (DMI_T17_MEMORY_TYPE); 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); ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR3 return FALSE; } DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2 + sizeof (DMI_T17_MEMORY_TYPE)); *((UINT16 *) (AllocHeapParams.BufferPtr)) = MaxDimms; // Number of memory devices *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = Ddr3MemType; // Memory type // // DMI TYPE 17 // DimmIndex = 0; for (Socket = 0; Socket < MaxSockets; Socket++) { MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); 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; Dct = ChannelPtr->Dct; NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct); MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel); for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) { DmiTable[DimmIndex].TotalWidth = 0xFFFF; DmiTable[DimmIndex].DataWidth = 0xFFFF; DmiTable[DimmIndex].MemorySize = 0xFFFF; DmiTable[DimmIndex].Speed = 0; DmiTable[DimmIndex].ManufacturerIdCode = 0; DmiTable[DimmIndex].Attributes = 0; DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF; DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF; DmiTable[DimmIndex].DimmPresent = 0; DmiTable[DimmIndex].Socket = Socket; DmiTable[DimmIndex].Channel = Channel; DmiTable[DimmIndex].Dimm = Dimm; DmiTable[DimmIndex].ConfigSpeed = 0; for (i = 0; i < 4; i++) { DmiTable[DimmIndex].SerialNumber[i] = 0xFF; } for (i = 0; i < 18; i++) { DmiTable[DimmIndex].PartNumber[i] = 0xFF; } if (SpdDataStructure[DimmIndex].DimmPresent) { // Total Width (offset 08h) & Data Width (offset 0Ah) TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[8]; if ((TotalWidth & 0x18) == 0) { // non ECC if ((TotalWidth & 0x07) == 0) { DmiTable[DimmIndex].TotalWidth = 8; // 8 bits } else if ((TotalWidth & 0x07) == 1) { DmiTable[DimmIndex].TotalWidth = 16; // 16 bits } else if ((TotalWidth & 0x07) == 2) { DmiTable[DimmIndex].TotalWidth = 32; // 32 bits } else if ((TotalWidth & 0x07) == 3) { DmiTable[DimmIndex].TotalWidth = 64; // 64 bits } DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth ; } else { // ECC if ((TotalWidth & 0x07) == 0) { DmiTable[DimmIndex].TotalWidth = 8 + 8; // 8 bits } else if ((TotalWidth & 0x07) == 1) { DmiTable[DimmIndex].TotalWidth = 16 + 8; // 16 bits } else if ((TotalWidth & 0x07) == 2) { DmiTable[DimmIndex].TotalWidth = 32 + 8; // 32 bits } else if ((TotalWidth & 0x07) == 3) { DmiTable[DimmIndex].TotalWidth = 64 + 8; // 64 bits } DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth - 8; } // Memory Size (offset 0Ch) Capacity = 0; BusWidth = 0; Width = 0; Rank = 0; temp = (UINT8) SpdDataStructure[DimmIndex].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[DimmIndex].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[DimmIndex].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[DimmIndex].Data[7]; if (((temp >> 3) & 0x07) == 0) { Rank = 1; // 4 bits DmiTable[DimmIndex].Attributes = 1; // Single Rank Dimm } else if (((temp >> 3) & 0x07) == 1) { Rank = 2; // 8 bits DmiTable[DimmIndex].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 DmiTable[DimmIndex].Attributes = 4; // Quad Rank Dimm } DmiTable[DimmIndex].MemorySize = (UINT16) (Capacity / 8 * BusWidth / Width * Rank); // Form Factor (offset 0Eh) FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[3]; if ((FormFactor & 0x01) == 0 || (FormFactor & 0x02) == 0) { DmiTable[DimmIndex].FormFactor = 0x09; // RDIMM or UDIMM } else if ((FormFactor & 0x03) == 0) { DmiTable[DimmIndex].FormFactor = 0x0D; // SO-DIMM } // DIMM Present DmiTable[DimmIndex].DimmPresent = 1; // Speed (offset 15h) Speed = (UINT16) SpdDataStructure[DimmIndex].Data[12]; if (Speed == 20) { DmiTable[DimmIndex].Speed = 800; // DDR3-800 } else if (Speed == 15) { DmiTable[DimmIndex].Speed = 1066; // DDR3-1066 } else if (Speed == 12) { DmiTable[DimmIndex].Speed = 1333; // DDR3-1333 } else if (Speed == 10) { DmiTable[DimmIndex].Speed = 1600; // DDR3-1600 } // Manufacturer (offset 17h) ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[118]; DmiTable[DimmIndex].ManufacturerIdCode = (ManufacturerIdCode << 8) | ((UINT64) SpdDataStructure[DimmIndex].Data[117]); // Serial Number (offset 18h) for (i = 0; i < 4; i++) { DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 122]; } // Part Number (offset 1Ah) for (i = 0; i < 18; i++) { DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 128]; } // Extended Size (offset 1Ch) - @todo: pending for SPD SPEC update DmiTable[DimmIndex].ExtSize = 0; // Configured Memory Clock Speed (offset 20h) DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed; // AGESA does NOT support this feature when bank interleaving is enabled. if (!RefPtr->EnableBankIntlv) { if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) { Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & 0x1FF83FE0; Address = Address >> 2; DmiTable[DimmIndex].StartingAddr = Address; DmiTable[DimmIndex].EndingAddr = Address + (UINT32) (DmiTable[DimmIndex].MemorySize * 0x0400); } } } // Dimm present } // Dimm loop } // Channel loop } // Socket loop return TRUE; } /* -----------------------------------------------------------------------------*/ /** * * * This function gets DDR2 DMI information from SPD buffer and stores the info into heap * * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK * */ BOOLEAN MemFDMISupport2 ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ) { UINT8 i; UINT8 Dimm; UINT8 Socket; UINT8 NodeId; UINT8 Dct; UINT8 Channel; UINT8 temp; UINT8 MaxDimms; UINT8 DimmIndex; UINT8 MaxChannelsPerSocket; UINT8 MaxDimmsPerChannel; UINT8 FormFactor; UINT8 Temp; UINT8 Rank; UINT16 TotalWidth; UINT32 Speed; UINT32 MaxSockets; UINT32 Address; MEM_NB_BLOCK *NBPtr; MEM_DATA_STRUCT *MemPtr; ALLOCATE_HEAP_PARAMS AllocHeapParams; MEM_DMI_INFO *DmiTable; DIE_STRUCT *MCTPtr; CH_DEF_STRUCT *ChannelPtr; SPD_DEF_STRUCT *SpdDataStructure; MEM_PARAMETER_STRUCT *RefPtr; NBPtr = MemMainPtr->NBPtr; MemPtr = MemMainPtr->MemPtr; SpdDataStructure = MemPtr->SpdDataStructure; MCTPtr = NBPtr->MCTPtr; RefPtr = MemPtr->ParameterListPtr; // Initialize local variables MaxDimms = 0; 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 = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel); MaxDimms = MaxDimms + temp; } } // Allocate heap for memory DMI table 16, 17, 19, 20 AllocHeapParams.RequestedBufferSize = MaxDimms * sizeof (MEM_DMI_INFO) + 3; 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_DDR2, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader); SetMemError (AGESA_CRITICAL, MCTPtr); ASSERT(FALSE); // Could not allocate heap for memory DMI table 16,17,19 and 20 for DDR2 return FALSE; } DmiTable = (MEM_DMI_INFO *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2 + sizeof (DMI_T17_MEMORY_TYPE)); *((UINT16 *) (AllocHeapParams.BufferPtr)) = MaxDimms; // Number of memory devices *((DMI_T17_MEMORY_TYPE *) ((UINT8 *) (AllocHeapParams.BufferPtr) + 2)) = Ddr2MemType; // Memory type // // DMI TYPE 17 // DimmIndex = 0; for (Socket = 0; Socket < MaxSockets; Socket++) { MaxChannelsPerSocket = GetMaxChannelsPerSocket (RefPtr->PlatformMemoryConfiguration, Socket, &MemPtr->StdHeader); 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; Dct = ChannelPtr->Dct; NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct); NBPtr[NodeId].SwitchDCT (&NBPtr[NodeId], Dct); MaxDimmsPerChannel = GetMaxDimmsPerChannel (RefPtr->PlatformMemoryConfiguration, Socket, Channel); for (Dimm = 0; Dimm < MaxDimmsPerChannel; Dimm++, DimmIndex++) { DmiTable[DimmIndex].TotalWidth = 0xFFFF; DmiTable[DimmIndex].DataWidth = 0xFFFF; DmiTable[DimmIndex].MemorySize = 0xFFFF; DmiTable[DimmIndex].Speed = 0; DmiTable[DimmIndex].ManufacturerIdCode = 0; DmiTable[DimmIndex].Attributes = 0; DmiTable[DimmIndex].StartingAddr = 0xFFFFFFFF; DmiTable[DimmIndex].EndingAddr = 0xFFFFFFFF; DmiTable[DimmIndex].DimmPresent = 0; DmiTable[DimmIndex].ConfigSpeed = 0; for (i = 0; i < 4; i++) { DmiTable[DimmIndex].SerialNumber[i] = 0xFF; } for (i = 0; i < 18; i++) { DmiTable[DimmIndex].PartNumber[i] = 0xFF; } if (SpdDataStructure[DimmIndex].DimmPresent) { // Total Width (offset 08h) & Data Width (offset 0Ah) TotalWidth = (UINT16) SpdDataStructure[DimmIndex].Data[13]; if ((TotalWidth & 0x04) != 0) { DmiTable[DimmIndex].TotalWidth = 4; // 4 bits } else if ((TotalWidth & 0x08) != 0) { DmiTable[DimmIndex].TotalWidth = 8; // 8 bits } else if ((TotalWidth & 0x10) != 0) { DmiTable[DimmIndex].TotalWidth = 16; // 16 bits } else if ((TotalWidth & 0x20) != 0) { DmiTable[DimmIndex].TotalWidth = 32; // 32 bits } DmiTable[DimmIndex].DataWidth = DmiTable[DimmIndex].TotalWidth; // Memory Size (offset 0Ch), Attributes (offset 1Bh) Rank = (UINT8) SpdDataStructure[DimmIndex].Data[5] & 0x07; if (Rank == 0) { DmiTable[DimmIndex].Attributes = 1; // Single Rank Dimm } else if (Rank == 1) { DmiTable[DimmIndex].Attributes = 2; // Dual Rank Dimm } else if (Rank == 3) { DmiTable[DimmIndex].Attributes = 4; // Quad Rank Dimm } Temp = (UINT8) SpdDataStructure[DimmIndex].Data[31]; for (i = 0; i < 8; i++) { if ((Temp & 0x01) == 1) { DmiTable[DimmIndex].MemorySize = 0x80 * (i + 1) * (Rank + 1); } Temp = Temp >> 1; } // Form Factor (offset 0Eh) FormFactor = (UINT8) SpdDataStructure[DimmIndex].Data[20]; if ((FormFactor & 0x04) == 4) { DmiTable[DimmIndex].FormFactor = 0x0D; // SO-DIMM } else { DmiTable[DimmIndex].FormFactor = 0x09; // RDIMM or UDIMM } // DIMM Present DmiTable[DimmIndex].DimmPresent = 1; // DIMM Index DmiTable[DimmIndex].Socket = Socket; DmiTable[DimmIndex].Channel = Channel; DmiTable[DimmIndex].Dimm = Dimm; // Speed (offset 15h) Speed = NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFDramConfigHiReg); Speed = Speed & 0x00000007; if (Speed == 0) { DmiTable[DimmIndex].Speed = 400; // 400MHz } else if (Speed == 1) { DmiTable[DimmIndex].Speed = 533; // 533MHz } else if (Speed == 2) { DmiTable[DimmIndex].Speed = 667; // 667MHz } else if (Speed == 3) { DmiTable[DimmIndex].Speed = 800; // 800MHz } // Manufacturer (offset 17h) DmiTable[DimmIndex].ManufacturerIdCode = (UINT64) SpdDataStructure[DimmIndex].Data[64]; // Serial Number (offset 18h) for (i = 0; i < 4; i++) { DmiTable[DimmIndex].SerialNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 95]; } // Part Number (offset 1Ah) for (i = 0; i < 18; i++) { DmiTable[DimmIndex].PartNumber[i] = (UINT8) SpdDataStructure[DimmIndex].Data[i + 73]; } // Configured Memory Clock Speed (offset 20h) DmiTable[DimmIndex].ConfigSpeed = NBPtr[NodeId].DCTPtr->Timings.Speed; // AGESA does NOT support this feature when bank interleaving is enabled. if (!RefPtr->EnableBankIntlv) { if ((NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm) & 1) != 0) { Address = (NBPtr[NodeId].GetBitField (&NBPtr[NodeId], BFCSBaseAddr0Reg + 2 * Dimm)) & 0x1FF83FE0; Address = Address >> 2; DmiTable[DimmIndex].StartingAddr = Address; DmiTable[DimmIndex].EndingAddr = Address + (UINT32) (DmiTable[DimmIndex].MemorySize * 0x0400); } } } // DIMM Present } // DIMM loop } } return TRUE; } /*--------------------------------------------------------------------------------------- * L O C A L F U N C T I O N S *--------------------------------------------------------------------------------------- */