/** * @file * * AMD CPU Execution Cache Allocation functions. * * Contains code for doing Execution Cache Allocation for ROM space * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: CPU * @e \$Revision: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 2010) $ * */ /* ****************************************************************************** * * 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 "amdlib.h" #include "Ids.h" #include "cpuRegisters.h" #include "Topology.h" #include "cpuServices.h" #include "GeneralServices.h" #include "cpuFamilyTranslation.h" #include "cpuCacheInit.h" #include "heapManager.h" #include "Filecode.h" #define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * L2 cache Association to Way translation table *---------------------------------------------------------------------------- */ CONST UINT8 ROMDATA L2AssocToL2WayTranslationTable[] = { 0, 1, 2, 0xFF, 4, 0xFF, 8, 0xFF, 16, 0xFF, 32, 48, 64, 96, 128, 0xFF, }; /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * EXPORTED FUNCTIONS * *---------------------------------------------------------------------------- */ UINT8 STATIC Ceiling ( IN UINT32 Divisor, IN UINT32 Dividend ); UINT32 STATIC CalculateOccupyExeCache ( IN AMD_CONFIG_PARAMS *StdHeader ); /*---------------------------------------------------------------------------------------*/ /** * This function will setup ROM execution cache. * * This function should only be called once. The execution cache regions are passed * in, the max number of execution cache regions are three. If the start address of * all three regions are zero, then no execution cache is allocated. * * -1 available cache size is less than requested, the ROM execution cache * region is reduced or eliminated. * -2 at least one execution cache regions across the 1MB line, the ROM execution * cache size is reduced. * -3 at least one execution cache regions across the 4GB line, the ROM execution * cache size is reduced. * -4 the start address of a region is not at the boundary of cache size * -5 execution cache start address less than D0000 * -6 more than 2 execution cache regions are above 1MB * * @param[in] StdHeader Handle to config for library and services * @param[in] AmdExeAddrMapPtr Pointer to the start of EXECUTION_CACHE_REGION array * * @retval AGESA_SUCCESS No error * @retval AGESA_WARNING AGESA_CACHE_SIZE_REDUCED; AGESA_CACHE_REGIONS_ACROSS_1MB; * AGESA_CACHE_REGIONS_ACROSS_4GB; * @retval AGESA_ERROR AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY; * AGESA_CACHE_START_ADDRESS_LESS_D0000; * AGESA_THREE_CACHE_REGIONS_ABOVE_1MB; * * @todo on Tilapia, this routine returns AGESA_ERROR. */ AGESA_STATUS AllocateExecutionCache ( IN AMD_CONFIG_PARAMS *StdHeader, IN EXECUTION_CACHE_REGION *AmdExeAddrMapPtr ) { AGESA_STATUS AgesaStatus; AMD_GET_EXE_SIZE_PARAMS AmdGetExeSize; UINT64 MsrData; UINT32 RemainingExecutionCacheSize; UINT32 VariableMttrBase; UINT32 AgesaInfo; UINT32 StartAddr; UINT32 ExeCacheSize; UINT32 StartFixMtrr; UINT32 CurrentMtrr; UINT32 EndFixMtrr; UINT32 CurrentAllocatedExeCacheSize; UINT8 i; UINT8 Ignored; UINT64 OccupyExeCacheStartAddr; UINT64 OccupExeCacheSize; CACHE_INFO *CacheInfoPtr; CPU_SPECIFIC_SERVICES *FamilySpecificServices; // // if start address of all three regions are zero, then the default values are used // if (AmdExeAddrMapPtr[0].ExeCacheStartAddr == 0) { if (AmdExeAddrMapPtr[1].ExeCacheStartAddr == 0) { if (AmdExeAddrMapPtr[2].ExeCacheStartAddr == 0) { // No regions defined by the caller return AGESA_SUCCESS; } } } // turn on modification bit LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader); MsrData |= 0x80000; LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader); // get available L2 cache size for ROM execution AmdGetExeSize.StdHeader = *StdHeader; AgesaStatus = AmdGetAvailableExeCacheSize (&AmdGetExeSize); RemainingExecutionCacheSize = AmdGetExeSize.AvailableExeCacheSize; CurrentAllocatedExeCacheSize = CalculateOccupyExeCache (StdHeader); if (CurrentAllocatedExeCacheSize >= RemainingExecutionCacheSize) { RemainingExecutionCacheSize = 0; } else { RemainingExecutionCacheSize = RemainingExecutionCacheSize - CurrentAllocatedExeCacheSize; } GetCpuServicesOfCurrentCore (&FamilySpecificServices, StdHeader); FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **)&CacheInfoPtr, &Ignored, StdHeader); // Setup MTTRs for region 0 to region 2 VariableMttrBase = AMD_MTRR_VARIABLE_BASE6; for (i = 0; i < 3; i++) { // Exit if no more cache available if (RemainingExecutionCacheSize == 0) { break; } // Skip the region if ExeCacheSize = 0 if (AmdExeAddrMapPtr[i].ExeCacheSize == 0) { continue; } // Calculate available execution cache size for region 0 to 2 if (RemainingExecutionCacheSize >= AmdExeAddrMapPtr[i].ExeCacheSize) { RemainingExecutionCacheSize = RemainingExecutionCacheSize - AmdExeAddrMapPtr[i].ExeCacheSize; } else { AgesaStatus = AGESA_WARNING; AgesaInfo = AGESA_CACHE_SIZE_REDUCED; AmdExeAddrMapPtr[i].ExeCacheSize = RemainingExecutionCacheSize; RemainingExecutionCacheSize = 0; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); } // Align starting addresses on 32K boundary AmdExeAddrMapPtr[i].ExeCacheStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr & 0xFFFF8000; // Boundary alignment check mechanism if ((AmdExeAddrMapPtr[i].ExeCacheStartAddr % AmdExeAddrMapPtr[i].ExeCacheSize) != 0) { AgesaStatus = AGESA_ERROR; AgesaInfo = AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); break; } // Check start address if (AmdExeAddrMapPtr[i].ExeCacheStartAddr < 0xD0000) { AgesaStatus = AGESA_ERROR; AgesaInfo = AGESA_CACHE_START_ADDRESS_LESS_D0000; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); break; } StartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr; ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize; ExeCacheSize --; if (StartAddr < 0x100000) { // Region below 1MB // Fixed MTTR region if ((StartAddr + ExeCacheSize) > 0xFFFFF) { ExeCacheSize = 0xFFFFF - StartAddr; AgesaStatus = AGESA_WARNING; AgesaInfo = AGESA_CACHE_REGIONS_ACROSS_1MB; AmdExeAddrMapPtr[i].ExeCacheSize = ExeCacheSize + 1; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, StartAddr, ExeCacheSize, 0, StdHeader); } // Find start and end of MTTR StartFixMtrr = AMD_MTRR_FIX4K_BASE + ((StartAddr >> 15) & 0x7); EndFixMtrr = AMD_MTRR_FIX4K_BASE + (((StartAddr + ExeCacheSize) >> 15) & 0x7); // //Check Mtrr before we use it, if Mtrr has been used, we need to add RemainingExecutionCacheSize back. // for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) { LibAmdMsrRead (CurrentMtrr, &MsrData, StdHeader); if (MsrData != 0) { RemainingExecutionCacheSize = RemainingExecutionCacheSize + 0x8000; } } // Setup MTTRs MsrData = WP_IO; for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) { LibAmdMsrWrite (CurrentMtrr, &MsrData, StdHeader); } } else { // Region above 1MB // Variable MTTR region if (VariableMttrBase > AMD_MTRR_VARIABLE_BASE7) { AgesaStatus = AGESA_ERROR; AgesaInfo = AGESA_THREE_CACHE_REGIONS_ABOVE_1MB; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, StartAddr, ExeCacheSize, 0, StdHeader); continue; } if ((0xFFFFFFFF - StartAddr) < ExeCacheSize) { ExeCacheSize = 0xFFFFFFFF - StartAddr; AgesaStatus = AGESA_WARNING; AgesaInfo = AGESA_CACHE_REGIONS_ACROSS_4GB; AmdExeAddrMapPtr[i].ExeCacheSize = ExeCacheSize + 1; PutEventLog (AgesaStatus, (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo), i, StartAddr, ExeCacheSize, 0, StdHeader); } // //Check Mtrr before we use it. // LibAmdMsrRead (VariableMttrBase, &MsrData, StdHeader); if (MsrData != 0) { // //Check expanded // OccupyExeCacheStartAddr = MsrData & (0xFFFF8000); LibAmdMsrRead ((VariableMttrBase + 1), &MsrData, StdHeader); OccupExeCacheSize = (~((MsrData & (0xFFFF8000)) - 1))&0xFFFF8000; // //Region below || Region above // if ( ((StartAddr + ExeCacheSize + 1) <= OccupyExeCacheStartAddr) || (StartAddr >= (OccupyExeCacheStartAddr + OccupExeCacheSize)) ) { // //Not overlap the original one, but it need to re-process and set an pair of empty Mtrr // VariableMttrBase += 2; RemainingExecutionCacheSize = RemainingExecutionCacheSize + AmdExeAddrMapPtr[i].ExeCacheSize; // //Resume loop count // i--; continue; } else if (OccupyExeCacheStartAddr == StartAddr) { // //Overlap with same start address // if (OccupExeCacheSize > (ExeCacheSize + 1)) { //AgesaInfo = AGESA_DEALLOCATE_CACHE_REGIONS; break; } RemainingExecutionCacheSize = RemainingExecutionCacheSize + (UINT32)OccupExeCacheSize; } else { // //Overlap with different start address // //AgesaInfo = AGESA_DEALLOCATE_CACHE_REGIONS; break; } } MsrData = (UINT64) (StartAddr | (WP_IO & 0xFull)); LibAmdMsrWrite (VariableMttrBase, &MsrData, StdHeader); MsrData = (UINT64) ( 0xFFFFFFFF00000000ull | ((0xFFFFFFFFull - ExeCacheSize) | 0x800ull)); MsrData &= CacheInfoPtr->VariableMtrrMask; LibAmdMsrWrite ((VariableMttrBase + 1), &MsrData, StdHeader); VariableMttrBase += 2; } } // Turn on MTTR enable bit and turn off modification bit LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader); MsrData &= 0xFFFFFFFFFFF7FFFFull; LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader); return AgesaStatus; } /*---------------------------------------------------------------------------------------*/ /** * This function calculates available L2 cache space for ROM execution. * * @param[in] AmdGetExeSizeParams Pointer to the start of AmdGetExeSizeParamsPtr structure * * @retval AGESA_SUCCESS No error * @retval AGESA_ALERT No cache available for execution cache. * */ AGESA_STATUS AmdGetAvailableExeCacheSize ( IN OUT AMD_GET_EXE_SIZE_PARAMS *AmdGetExeSizeParams ) { UINT8 WayUsedForCar; UINT8 L2Assoc; UINT32 L2Size; UINT32 L2WaySize; UINT32 CurrentCoreNum; UINT8 L2Ways; UINT8 Ignored; UINT32 DieNumber; UINT32 TotalCores; CPUID_DATA CpuIdDataStruct; CACHE_INFO *CacheInfoPtr; AP_MAIL_INFO ApMailboxInfo; AGESA_STATUS IgnoredStatus; CPU_SPECIFIC_SERVICES *FamilySpecificServices; GetCpuServicesOfCurrentCore (&FamilySpecificServices, &AmdGetExeSizeParams->StdHeader); // Check for L2 cache size and way size LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuIdDataStruct, &AmdGetExeSizeParams->StdHeader); L2Assoc = (UINT8) ((CpuIdDataStruct.ECX_Reg >> 12) & 0x0F); // get L2Ways from L2 Association to Way translation table L2Ways = L2AssocToL2WayTranslationTable[L2Assoc]; ASSERT (L2Ways != 0xFF); // get L2Size L2Size = 1024 * ((CpuIdDataStruct.ECX_Reg >> 16) & 0xFFFF); // get each L2WaySize L2WaySize = L2Size / L2Ways; FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **)&CacheInfoPtr, &Ignored, &AmdGetExeSizeParams->StdHeader); // Determine the size for execution cache if (IsBsp (&AmdGetExeSizeParams->StdHeader, &IgnoredStatus)) { // BSC (Boot Strap Core) WayUsedForCar = Ceiling (CacheInfoPtr->BspStackSize, L2WaySize) + Ceiling (CacheInfoPtr->MemTrainingBufferSize, L2WaySize) + Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) + Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize); } else { // AP (Application Processor) GetCurrentCore (&CurrentCoreNum, &AmdGetExeSizeParams->StdHeader); GetApMailbox (&ApMailboxInfo.Info, &AmdGetExeSizeParams->StdHeader); DieNumber = (1 << ApMailboxInfo.Fields.ModuleType); GetActiveCoresInCurrentSocket (&TotalCores, &AmdGetExeSizeParams->StdHeader); ASSERT ((TotalCores % DieNumber) == 0); if ((CurrentCoreNum % (TotalCores / DieNumber)) == 0) { WayUsedForCar = Ceiling (CacheInfoPtr->Core0StackSize , L2WaySize) + Ceiling (CacheInfoPtr->MemTrainingBufferSize, L2WaySize) + Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) + Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize); } else { WayUsedForCar = Ceiling (CacheInfoPtr->Core1StackSize , L2WaySize) + Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) + Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize); } } ASSERT (WayUsedForCar < L2Ways); if (WayUsedForCar < L2Ways) { AmdGetExeSizeParams->AvailableExeCacheSize = L2WaySize * (L2Ways - WayUsedForCar); return AGESA_SUCCESS; } else { AmdGetExeSizeParams->AvailableExeCacheSize = 0; return AGESA_ALERT; } } /*---------------------------------------------------------------------------------------*/ /** * This function rounds a quotient up if the remainder is not zero. * * @param[in] Divisor The divisor * @param[in] Dividend The dividend * * @retval Value Rounded quotient * */ UINT8 STATIC Ceiling ( IN UINT32 Divisor, IN UINT32 Dividend ) { if ((Divisor % Dividend) == 0) { return (UINT8) (Divisor / Dividend); } else { return (UINT8) ((Divisor / Dividend) + 1); } } /*---------------------------------------------------------------------------------------*/ /** * This function calculates the amount of cache that has already been allocated on the * executing core. * * @param[in] StdHeader Handle to config for library and services * * @retval Value Allocated size in bytes * */ UINT32 STATIC CalculateOccupyExeCache ( IN AMD_CONFIG_PARAMS *StdHeader ) { UINT64 OccupExeCacheSize; UINT64 MsrData; UINT8 i; MsrData = 0; OccupExeCacheSize = 0; // //Calculate Variable MTRR base 6~7 // for (i = 0; i < 2; i++) { LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i)), &MsrData, StdHeader); if (MsrData != 0) { LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i + 1)), &MsrData, StdHeader); OccupExeCacheSize = OccupExeCacheSize + ((~((MsrData & (0xFFFF8000)) - 1))&0xFFFF8000); } } // //Calculate Fixed MTRR base D0000~F8000 // for (i = 0; i < 6; i++) { LibAmdMsrRead ((AMD_MTRR_FIX4K_BASE + 2 + i), &MsrData, StdHeader); if (MsrData!= 0) { OccupExeCacheSize = OccupExeCacheSize + 0x8000; } } return (UINT32)OccupExeCacheSize; }