/* $NoKeywords:$ */ /** * @file * * mfCrat.c * * Feature CRAT table support * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: (Mem/Main) * @e \$Revision: 64574 $ @e \$Date: 2012-01-25 01:01:51 -0600 (Wed, 25 Jan 2012) $ * **/ /***************************************************************************** * * Copyright 2008 - 2012 ADVANCED MICRO DEVICES, INC. All Rights Reserved. * * AMD is granting you permission to use this software (the Materials) * pursuant to the terms and conditions of your Software License Agreement * with AMD. This header does *NOT* give you permission to use the Materials * or any rights under AMD's intellectual property. Your use of any portion * of these Materials shall constitute your acceptance of those terms and * conditions. If you do not agree to the terms and conditions of the Software * License Agreement, please do not use any portion of these Materials. * * CONFIDENTIALITY: The Materials and all other information, identified as * confidential and provided to you by AMD shall be kept confidential in * accordance with the terms and conditions of the Software License Agreement. * * LIMITATION OF LIABILITY: THE MATERIALS AND ANY OTHER RELATED INFORMATION * PROVIDED TO YOU BY AMD ARE PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED * WARRANTY OF ANY KIND, INCLUDING BUT NOT LIMITED TO WARRANTIES OF * MERCHANTABILITY, NONINFRINGEMENT, TITLE, FITNESS FOR ANY PARTICULAR PURPOSE, * OR WARRANTIES ARISING FROM CONDUCT, COURSE OF DEALING, OR USAGE OF TRADE. * IN NO EVENT SHALL AMD OR ITS LICENSORS BE LIABLE FOR ANY DAMAGES WHATSOEVER * (INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF PROFITS, BUSINESS * INTERRUPTION, OR LOSS OF INFORMATION) ARISING OUT OF AMD'S NEGLIGENCE, * GROSS NEGLIGENCE, THE USE OF OR INABILITY TO USE THE MATERIALS OR ANY OTHER * RELATED INFORMATION PROVIDED TO YOU BY AMD, EVEN IF AMD HAS BEEN ADVISED OF * THE POSSIBILITY OF SUCH DAMAGES. BECAUSE SOME JURISDICTIONS PROHIBIT THE * EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES, * THE ABOVE LIMITATION MAY NOT APPLY TO YOU. * * AMD does not assume any responsibility for any errors which may appear in * the Materials or any other related information provided to you by AMD, or * result from use of the Materials or any related information. * * You agree that you will not reverse engineer or decompile the Materials. * * NO SUPPORT OBLIGATION: AMD is not obligated to furnish, support, or make any * further information, software, technical information, know-how, or show-how * available to you. Additionally, AMD retains the right to modify the * Materials at any time, without notice, and is not obligated to provide such * modified Materials to you. * * U.S. GOVERNMENT RESTRICTED RIGHTS: The Materials are provided with * "RESTRICTED RIGHTS." Use, duplication, or disclosure by the Government is * subject to the restrictions as set forth in FAR 52.227-14 and * DFAR252.227-7013, et seq., or its successor. Use of the Materials by the * Government constitutes acknowledgement of AMD's proprietary rights in them. * * EXPORT ASSURANCE: You agree and certify that neither the Materials, nor any * direct product thereof will be exported directly or indirectly, into any * country prohibited by the United States Export Administration Act and the * regulations thereunder, without the required authorization from the U.S. * government nor will be used for any purpose prohibited by the same. * *************************************************************************** * */ /* *---------------------------------------------------------------------------- * MODULES USED * *---------------------------------------------------------------------------- */ #include "AGESA.h" #include "amdlib.h" #include "Ids.h" #include "heapManager.h" #include "cpuServices.h" #include "mm.h" #include "mn.h" #include "mu.h" #include "mfCrat.h" #include "GeneralServices.h" #include "Filecode.h" CODE_GROUP (G2_PEI) RDATA_GROUP (G2_PEI) #define FILECODE (0xF095) /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ #define FOURGB 0x010000ul /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ CRAT_MEMORY_AFFINITY_INFO_ENTRY STATIC *MakeMemAffinityInfoEntry ( IN UINT8 Domain, IN UINT32 Base, IN UINT32 Size, IN CRAT_MEMORY_AFFINITY_INFO_ENTRY *BufferLocPtr ); /*---------------------------------------------------------------------------- * EXPORTED FUNCTIONS * *---------------------------------------------------------------------------- */ BOOLEAN MemFCratSupport ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ); /* -----------------------------------------------------------------------------*/ /** * * * This function gets CRAT memory affinity info and stores the info into heap * * @param[in,out] *MemMainPtr - Pointer to the MEM_MAIN_DATA_BLOCK * */ BOOLEAN MemFCratSupport ( IN OUT MEM_MAIN_DATA_BLOCK *MemMainPtr ) { UINT8 Node; UINT32 DramLeng; UINT32 DramBase; UINT32 DramLimit; UINT8 DramRngRE; UINT8 DramRngWE; UINT8 Domain; UINT8 DomainForBase640K; UINT32 ValueLimit; UINT32 ValueTOM; UINT64 MsrValue; BOOLEAN isModified; UINT8 MaxNumOfMemAffinityInfoEntries; UINT8 NumOfMemAffinityInfoEntries; UINT32 TopOfMemoryAbove4Gb; CRAT_MEMORY_AFFINITY_INFO_HEADER *MemAffinityInfoHeaderPtr; CRAT_MEMORY_AFFINITY_INFO_ENTRY *MemAffinityInfoEntryPtr; ALLOCATE_HEAP_PARAMS AllocHeapParams; MEM_NB_BLOCK *NBPtr; MEM_DATA_STRUCT *MemPtr; DIE_STRUCT *MCTPtr; MEM_SHARED_DATA *SharedPtr; NBPtr = MemMainPtr->NBPtr; MemPtr = MemMainPtr->MemPtr; MCTPtr = NBPtr->MCTPtr; SharedPtr = NBPtr->SharedPtr; // The maximum number of entries take the following two factors into consideration // 1. The entry for conventional memory less than 640k // 2. The memory hole below 4G may divide the memory range across the hole into two MaxNumOfMemAffinityInfoEntries = NBPtr->NodeCount + 2; // Allocate heap for CRAT memory affinity info entry AllocHeapParams.RequestedBufferSize = MaxNumOfMemAffinityInfoEntries * sizeof (CRAT_MEMORY_AFFINITY_INFO_ENTRY) + sizeof (CRAT_MEMORY_AFFINITY_INFO_HEADER); AllocHeapParams.BufferHandle = AMD_MEM_CRAT_INFO_BUFFER_HANDLE; AllocHeapParams.Persist = HEAP_SYSTEM_MEM; if (AGESA_SUCCESS != HeapAllocateBuffer (&AllocHeapParams, &MemPtr->StdHeader)) { // Could not allocate heap for CRAT memory affinity info PutEventLog (AGESA_CRITICAL, MEM_ERROR_HEAP_ALLOCATE_FOR_CRAT_MEM_AFFINITY, NBPtr->Node, 0, 0, 0, &MemPtr->StdHeader); SetMemError (AGESA_CRITICAL, MCTPtr); ASSERT (FALSE); return FALSE; } MemAffinityInfoHeaderPtr = (CRAT_MEMORY_AFFINITY_INFO_HEADER *) ((UINT8 *) (AllocHeapParams.BufferPtr)); MemAffinityInfoHeaderPtr ++; MemAffinityInfoEntryPtr = (CRAT_MEMORY_AFFINITY_INFO_ENTRY *) MemAffinityInfoHeaderPtr; MemAffinityInfoHeaderPtr --; NumOfMemAffinityInfoEntries = 0; DomainForBase640K = 0xFF; for (Node = 0; Node < NBPtr->NodeCount; Node++) { // FALSE means normal update procedure isModified = FALSE; // Get DRAM Base Address DramBase = MemNGetBitFieldNb (NBPtr, BFDramBaseReg0 + Node); DramRngRE = (UINT8) MemNGetBitFieldNb (NBPtr, BFDramRngRE0 + Node); DramRngWE = (UINT8) MemNGetBitFieldNb (NBPtr, BFDramRngWE0 + Node); if ((DramRngRE == 0) || (DramRngWE == 0)) { // 0:1 set if memory range enabled // Not set, so we don't have an enabled range // Proceed to next Base register continue; } // Get DRAM Limit DramLimit = MemNGetBitFieldNb (NBPtr, BFDramLimitReg0 + Node); if (DramLimit == 0xFFFFFFFF) { // Node not installed(all FF's)? // Proceed to next Base register continue; } // Node ID is assigned to Domain Domain = (UINT8) MemNGetBitFieldNb (NBPtr, BFDramRngDstNode0 + Node); // Get DRAM Limit addr [47:24] DramLimit = ((((MemNGetBitFieldNb (NBPtr, BFDramLimitHiReg0 + Node) & 0xFF) << 16) | DramLimit >> 16)); // Add 1 for potential length DramLimit++; DramLimit <<= 8; // Get DRAM Base Address // Get DRAM Base Base value [47:24] DramBase = (((MemNGetBitFieldNb (NBPtr, BFDramBaseHiReg0 + Node) & 0xFF) << 24) | (DramBase >> 8) & 0xFFFFFF00); // Subtract base from limit to get length DramLeng = DramLimit - DramBase; // Leave hole for conventional memory (Less than 640K). It must be on CPU 0. if (DramBase == 0) { if (DomainForBase640K == 0xFF) { // It is the first time that the range start at 0. // If Yes, then Place 1MB memory gap and save Domain to PDomainForBase640K MemAffinityInfoEntryPtr = MakeMemAffinityInfoEntry ( Domain, 0, // Base = 0 0xA0000 >> 16, // Put it into format used in DRAM regs.. MemAffinityInfoEntryPtr ); NumOfMemAffinityInfoEntries ++; // Add 1MB, so range = 1MB to Top of Region DramBase += 0x10; // Also subtract 1MB from the length DramLeng -= 0x10; // Save Domain number for memory Less than 640K DomainForBase640K = Domain; } else { // If No, there are more than one memory range less than 640K, it should that // node interleaving is enabled. All nodes have the same memory ranges // and all cores in these nodes belong to the same domain. Domain = DomainForBase640K; break; } } LibAmdMsrRead (TOP_MEM, &MsrValue, &MemPtr->StdHeader); // Save it in 39:24 format ValueTOM = (UINT32) MsrValue >> 16; // We need to know how large region is ValueLimit = DramBase + DramLeng; LibAmdMsrRead (SYS_CFG, &MsrValue, &MemPtr->StdHeader); if ((MsrValue & BIT21) != 0) { LibAmdMsrRead (TOP_MEM2, &MsrValue, &MemPtr->StdHeader); // Save it in 47:16 format TopOfMemoryAbove4Gb = (UINT32) (MsrValue >> 16); } else { TopOfMemoryAbove4Gb = 0xFFFFFFFF; } // SPECIAL CASES: // // Several conditions require that we process the values of the memory range differently. // Here are descriptions of the corner cases. // // 1. TRUNCATE LOW - Memory range starts below TOM, ends in TOM (memory hole). For this case, // the range must be truncated to end at TOM. // ******************************* ******************************* // * * * -> * * // ******************************* ******************************* // 2 TOM 4 2 TOM // // 2. TRUNCATE HIGH - Memory range starts below 4GB, ends above 4GB. This is handled by changing the // start base to 4GB. // **************** ********** // * * * -> * * // **************** ********** // TOM 3.8 4 6 TOM 3.8 4 6 // // 3. Memory range starts below TOM, ends above 4GB. For this case, the range must be truncated // to end at TOM. Note that this scenario creates two ranges, as the second comparison below // will find that it ends above 4GB since base and limit have been restored after first truncation, // and a second range will be written based at 4GB ending at original end address. // ******************************* **************** ********** // * * * * -> * * * * // ******************************* **************** ********** // 2 TOM 4 6 2 TOM 4 6 // // 4. Memory range starts above TOM, ends below or equal to 4GB. This invalid range should simply // be ignored. // ******* // * * -> < NULL > // ******* // TOM 3.8 4 // // 5. Memory range starts below TOM2, and ends beyond TOM2. This range must be truncated to TOM2. // ************************ ******************************* // * * * -> * * // ************************ ******************************* // 768 TOM2 1024 768 TOM2 // // 6. Memory range starts above TOM2. This invalid range should simply be ignored. // ******************** // * * -> < NULL > // ******************** // TOM2 1024 1280 if (((DramBase < ValueTOM) && (ValueLimit <= FOURGB) && (ValueLimit > ValueTOM)) || ((DramBase < ValueTOM) && (ValueLimit > FOURGB))) { // TRUNCATE LOW!!! Shrink entry below TOM... // Base = DramBase, Size = TOM - DramBase MemAffinityInfoEntryPtr = MakeMemAffinityInfoEntry (Domain, DramBase, (ValueTOM - DramBase), MemAffinityInfoEntryPtr); NumOfMemAffinityInfoEntries ++; isModified = TRUE; } if ((ValueLimit > FOURGB) && (DramBase < FOURGB)) { // TRUNCATE HIGH!!! Shrink entry above 4GB... // Size = Base + Size - 4GB, Base = 4GB MemAffinityInfoEntryPtr = MakeMemAffinityInfoEntry (Domain, FOURGB, (DramLeng + DramBase - FOURGB), MemAffinityInfoEntryPtr); NumOfMemAffinityInfoEntries ++; isModified = TRUE; } if ((DramBase >= ValueTOM) && (ValueLimit <= FOURGB)) { // IGNORE!!! Entry located entirely within memory hole isModified = TRUE; } if ((DramBase < TopOfMemoryAbove4Gb) && (ValueLimit > TopOfMemoryAbove4Gb)) { // Truncate to TOM2 // Base = DramBase, Size = TOM2 - DramBase MemAffinityInfoEntryPtr = MakeMemAffinityInfoEntry (Domain, DramBase, (TopOfMemoryAbove4Gb - DramBase), MemAffinityInfoEntryPtr); NumOfMemAffinityInfoEntries ++; isModified = TRUE; } if (DramBase >= TopOfMemoryAbove4Gb) { // IGNORE!!! Entry located entirely above TOM2 isModified = TRUE; } // If special range(isModified), we are done. // If not, finally write the memory entry. if (isModified == FALSE) { // Finally write the memory entry. MemAffinityInfoEntryPtr = MakeMemAffinityInfoEntry (Domain, DramBase, DramLeng, MemAffinityInfoEntryPtr); NumOfMemAffinityInfoEntries ++; } } MemAffinityInfoHeaderPtr->NumOfMemAffinityInfoEntries = NumOfMemAffinityInfoEntries; MemAffinityInfoHeaderPtr->MemoryWidth = NBPtr->MemNGetMemoryWidth (NBPtr); return TRUE; } /*--------------------------------------------------------------------------------------- * L O C A L F U N C T I O N S *--------------------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------------------*/ /** * * This function will add Memory entry. * * Parameters: * @param[in] Domain Proximity Domain * @param[in] Base Memory Base * @param[in] Size Memory Size * @param[in] BufferLocPtr Point to the address of buffer * * @retval CRAT_MEMORY_AFFINITY_INFO_ENTRY * (new buffer location ptr) */ CRAT_MEMORY_AFFINITY_INFO_ENTRY STATIC *MakeMemAffinityInfoEntry ( IN UINT8 Domain, IN UINT32 Base, IN UINT32 Size, IN CRAT_MEMORY_AFFINITY_INFO_ENTRY *BufferLocPtr ) { BufferLocPtr->Domain = Domain; BufferLocPtr->BaseAddressLow = Base << 16; BufferLocPtr->BaseAddressHigh = Base >> 16; BufferLocPtr->LengthLow = Size << 16; BufferLocPtr->LengthHigh = Size >> 16; BufferLocPtr ++; return BufferLocPtr; }