diff options
author | Kerry Sheh <shekairui@gmail.com> | 2012-01-20 13:57:48 +0800 |
---|---|---|
committer | Patrick Georgi <patrick@georgi-clan.de> | 2012-01-26 10:09:22 +0100 |
commit | e8689ed974992b35aede9cd831b428ac37d9be76 (patch) | |
tree | 32ef9887fe057294f7a7fb2be069dd8d39d0c5d6 /src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c | |
parent | d2b31bda6738e370414622bd750cebf2e28e73de (diff) |
AGESA F15: AMD family15 AGESA code
AMD AGESA code to support Orochi platform family15 model 00-0fh processores,
AMD C32, G34, and AM3r2 Sockets are supported.
Change-Id: If79392c104ace25f7e01db794fa205f47746bcad
Signed-off-by: Kerry Sheh <kerry.she@amd.com>
Signed-off-by: Kerry Sheh <shekairui@gmail.com>
Reviewed-on: http://review.coreboot.org/554
Tested-by: build bot (Jenkins)
Reviewed-by: Ronald G. Minnich <rminnich@gmail.com>
Reviewed-by: Stefan Reinauer <stefan.reinauer@coreboot.org>
Diffstat (limited to 'src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c')
-rw-r--r-- | src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c | 752 |
1 files changed, 752 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c b/src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c new file mode 100644 index 0000000000..ca60b2bb0f --- /dev/null +++ b/src/vendorcode/amd/agesa/f15/Proc/CPU/Feature/cpuCacheInit.c @@ -0,0 +1,752 @@ +/* $NoKeywords:$ */ +/** + * @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: 56322 $ @e \$Date: 2011-07-11 16:51:42 -0600 (Mon, 11 Jul 2011) $ + * + */ +/* + ****************************************************************************** + * + * Copyright (C) 2012 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" +CODE_GROUP (G1_PEICC) +RDATA_GROUP (G2_PEI) + +#define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE +/*---------------------------------------------------------------------------- + * DEFINITIONS AND MACROS + * + *---------------------------------------------------------------------------- + */ +// 4G - 1, ~max ROM space +#define SIZE_INFINITE_EXE_CACHE 0xFFFFFFFF + +/*---------------------------------------------------------------------------- + * 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 +CalculateOccupiedExeCache ( + IN AMD_CONFIG_PARAMS *StdHeader + ); + +VOID +STATIC +CompareRegions ( + IN EXECUTION_CACHE_REGION ARegion, + IN EXECUTION_CACHE_REGION BRegion, + IN OUT MERGED_CACHE_REGION *CRegion, + IN AMD_CONFIG_PARAMS *StdHeader + ); + +BOOLEAN +STATIC +IsPowerOfTwo ( + IN UINT32 TestNumber + ); + +/*---------------------------------------------------------------------------------------*/ +/** + * This function will setup ROM execution cache. + * + * The execution cache regions are passed in, the max number of execution cache regions + * is three. Several rules are checked for compliance. If a rule test fails then one of + * these error suffixes will be added to the general CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + * in the SubReason field + * -1 available cache size is less than requested, the ROM execution cache + * region has been reduced or eliminated. + * -2 at least one execution cache region crosses the 1MB line, the ROM execution + * cache size has been reduced. + * -3 at least one execution cache region crosses the 4GB line, the ROM execution + * cache size has been reduced. + * -4 the start address of a region is not at the boundary of cache size, + * the starting address has been adjusted downward + * -5 execution cache start address less than D0000, request is ignored + * -6 more than 2 execution cache regions are above 1MB, request is ignored + * If the start address of all three regions are zero, then no execution cache is allocated. + * + * @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; + * + */ +AGESA_STATUS +AllocateExecutionCache ( + IN AMD_CONFIG_PARAMS *StdHeader, + IN EXECUTION_CACHE_REGION *AmdExeAddrMapPtr + ) +{ + AGESA_STATUS AgesaStatus; + AMD_GET_EXE_SIZE_PARAMS AmdGetExeSize; + UINT32 CurrentAllocatedExeCacheSize; + UINT32 RemainingExecutionCacheSize; + UINT64 MsrData; + UINT64 SecondMsrData; + UINT32 RequestStartAddr; + UINT32 RequestSize; + UINT32 StartFixMtrr; + UINT32 CurrentMtrr; + UINT32 EndFixMtrr; + UINT8 i; + UINT8 Ignored; + CACHE_INFO *CacheInfoPtr; + CPU_SPECIFIC_SERVICES *FamilySpecificServices; + EXECUTION_CACHE_REGION MtrrV6; + EXECUTION_CACHE_REGION MtrrV7; + MERGED_CACHE_REGION Result; + + // + // If start addresses of all three regions are zero, then return early + // + if (AmdExeAddrMapPtr[0].ExeCacheStartAddr == 0) { + if (AmdExeAddrMapPtr[1].ExeCacheStartAddr == 0) { + if (AmdExeAddrMapPtr[2].ExeCacheStartAddr == 0) { + // No regions defined by the caller + return AGESA_SUCCESS; + } + } + } + + // Get available cache size for ROM execution + AmdGetExeSize.StdHeader = *StdHeader; + AgesaStatus = AmdGetAvailableExeCacheSize (&AmdGetExeSize); + CurrentAllocatedExeCacheSize = CalculateOccupiedExeCache (StdHeader); + ASSERT (CurrentAllocatedExeCacheSize <= AmdGetExeSize.AvailableExeCacheSize); + IDS_HDT_CONSOLE (CPU_TRACE, " Cache size available for execution cache: 0x%x\n", AmdGetExeSize.AvailableExeCacheSize); + RemainingExecutionCacheSize = AmdGetExeSize.AvailableExeCacheSize - CurrentAllocatedExeCacheSize; + + GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); + FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &Ignored, StdHeader); + + // Process each request entry 0 to 2 + 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; + } + + // Align starting addresses on 32K boundary + AmdExeAddrMapPtr[i].ExeCacheStartAddr = + AmdExeAddrMapPtr[i].ExeCacheStartAddr & 0xFFFF8000; + + // Adjust size to multiple of 32K (rounding up) + if ((AmdExeAddrMapPtr[i].ExeCacheSize % 0x8000) != 0) { + AmdExeAddrMapPtr[i].ExeCacheSize = ((AmdExeAddrMapPtr[i].ExeCacheSize + 0x8000) & 0xFFFF8000); + } + + // Boundary alignment check and confirm size is an even power of two + if ( !IsPowerOfTwo (AmdExeAddrMapPtr[i].ExeCacheSize) || + ((AmdExeAddrMapPtr[i].ExeCacheStartAddr % AmdExeAddrMapPtr[i].ExeCacheSize) != 0) ) { + AgesaStatus = AGESA_ERROR; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY), + i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); + break; + } + + // Check start address boundary + if (AmdExeAddrMapPtr[i].ExeCacheStartAddr < 0xD0000) { + AgesaStatus = AGESA_ERROR; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_START_ADDRESS_LESS_D0000), + i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); + break; + } + + if (CacheInfoPtr->CarExeType == LimitedByL2Size) { + // Verify available execution cache size for region 0 to 2 request + if (RemainingExecutionCacheSize < AmdExeAddrMapPtr[i].ExeCacheSize) { + // Request is larger than available, reduce the allocation & report the change + AmdExeAddrMapPtr[i].ExeCacheSize = RemainingExecutionCacheSize; + RemainingExecutionCacheSize = 0; + AgesaStatus = AGESA_WARNING; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_SIZE_REDUCED), + i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); + } else { + RemainingExecutionCacheSize = RemainingExecutionCacheSize - AmdExeAddrMapPtr[i].ExeCacheSize; + } + } + IDS_HDT_CONSOLE (CPU_TRACE, " Exe cache allocated: Base 0x%x, Size 0x%x\n", AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize); + + RequestStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr; + RequestSize = AmdExeAddrMapPtr[i].ExeCacheSize; + + if (RequestStartAddr < 0x100000) { + // Region starts below 1MB - Fixed MTTR region, + // turn on modification bit: MtrrFixDramModEn + LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader); + MsrData |= 0x80000; + LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader); + + + // Check for 1M boundary crossing + if ((RequestStartAddr + RequestSize) > 0x100000) { + // Request spans the 1M boundary, reduce the size & report the change + RequestSize = 0x100000 - RequestStartAddr; + AmdExeAddrMapPtr[i].ExeCacheSize = RequestSize; + AgesaStatus = AGESA_WARNING; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_REGIONS_ACROSS_1MB), + i, RequestStartAddr, RequestSize, 0, StdHeader); + } + + // Find start MTTR and end MTTR for the requested region + StartFixMtrr = AMD_MTRR_FIX4K_BASE + ((RequestStartAddr >> 15) & 0x7); + EndFixMtrr = AMD_MTRR_FIX4K_BASE + ((((RequestStartAddr + RequestSize) - 1) >> 15) & 0x7); + + // + //Check Mtrr before we use it, + // if Mtrr has been used, we need to recover the previously allocated size. + // (only work in blocks of 32K size - no splitting of ways) + for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) { + LibAmdMsrRead (CurrentMtrr, &MsrData, StdHeader); + if ((CacheInfoPtr->CarExeType == LimitedByL2Size) && (MsrData != 0)) { + // MTRR previously allocated, recover size + RemainingExecutionCacheSize = RemainingExecutionCacheSize + 0x8000; + } else { + // Allocate this MTRR + MsrData = WP_IO; + LibAmdMsrWrite (CurrentMtrr, &MsrData, StdHeader); + } + } + // Turn off modification bit: MtrrFixDramModEn + LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader); + MsrData &= 0xFFFFFFFFFFF7FFFFULL; + LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader); + + + } else { + // Region above 1MB - Variable MTTR region + // Need to check both VarMTRRs for each requested region for match or overlap + // + + // Check for 4G boundary crossing (using size-1 to keep in 32bit math range) + if ((0xFFFFFFFFUL - RequestStartAddr) < (RequestSize - 1)) { + RequestSize = (0xFFFFFFFFUL - RequestStartAddr) + 1; + AgesaStatus = AGESA_WARNING; + AmdExeAddrMapPtr[i].ExeCacheSize = RequestSize; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_REGIONS_ACROSS_4GB), + i, RequestStartAddr, RequestSize, 0, StdHeader); + } + LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE6, &MsrData, StdHeader); + MtrrV6.ExeCacheStartAddr = ((UINT32) MsrData) & 0xFFFFF000UL; + LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE6 + 1, &MsrData, StdHeader); + MtrrV6.ExeCacheSize = (0xFFFFFFFFUL - (((UINT32) MsrData) & 0xFFFFF000UL)) + 1; + + LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE7, &MsrData, StdHeader); + MtrrV7.ExeCacheStartAddr = ((UINT32) MsrData) & 0xFFFFF000UL; + LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE7 + 1, &MsrData, StdHeader); + MtrrV7.ExeCacheSize = (0xFFFFFFFFUL - (((UINT32) MsrData) & 0xFFFFF000UL)) + 1; + + CompareRegions (AmdExeAddrMapPtr[i], MtrrV6, &Result, StdHeader); + if (Result.OverlapType == EmptySet) { + // MTRR6 is empty. Allocate request into MTRR6. + // Note: since all merges are moved down to MTRR6, if MTRR6 is empty so should MTRR7 also be empty + MtrrV6.ExeCacheStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr; + MtrrV6.ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize; + } else if ((Result.OverlapType == Disjoint) || + (Result.OverlapType == NotCombinable)) { + // MTRR6 is in use, and request does not overlap with MTRR6, check MTRR7 + CompareRegions (AmdExeAddrMapPtr[i], MtrrV7, &Result, StdHeader); + if (Result.OverlapType == EmptySet) { + // MTRR7 is empty. Allocate request into MTRR7. + MtrrV7.ExeCacheStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr; + MtrrV7.ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize; + } else if ((Result.OverlapType == Disjoint) || + (Result.OverlapType == NotCombinable)) { + // MTRR7 is also in use and request does not overlap - error: 3rd region above 1M + AgesaStatus = AGESA_ERROR; + PutEventLog (AgesaStatus, + (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_THREE_CACHE_REGIONS_ABOVE_1MB), + i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader); + break; + } else { + // Merge request with MTRR7 + MtrrV7.ExeCacheStartAddr = Result.MergedStartAddr; + MtrrV7.ExeCacheSize = Result.MergedSize; + if (CacheInfoPtr->CarExeType == LimitedByL2Size) { + RemainingExecutionCacheSize += Result.OverlapAmount; + } + } + } else { + // Request overlaps with MTRR6, Merge request with MTRR6 + MtrrV6.ExeCacheStartAddr = Result.MergedStartAddr; + MtrrV6.ExeCacheSize = Result.MergedSize; + if (CacheInfoPtr->CarExeType == LimitedByL2Size) { + RemainingExecutionCacheSize += Result.OverlapAmount; + } + CompareRegions (MtrrV6, MtrrV7, &Result, StdHeader); + if ((Result.OverlapType != Disjoint) && + (Result.OverlapType != EmptySet) && + (Result.OverlapType != NotCombinable)) { + // MTRR6 and MTRR7 now overlap, merge them into MTRR6 + MtrrV6.ExeCacheStartAddr = Result.MergedStartAddr; + MtrrV6.ExeCacheSize = Result.MergedSize; + MtrrV7.ExeCacheStartAddr = 0; + MtrrV7.ExeCacheSize = 0; + if (CacheInfoPtr->CarExeType == LimitedByL2Size) { + RemainingExecutionCacheSize += Result.OverlapAmount; + } + } + } + + // Set the VarMTRRs. Base first, then size/mask; this allows for expanding the region safely. + if (MtrrV6.ExeCacheSize != 0) { + MsrData = (UINT64) ( 0xFFFFFFFF00000000ULL | ((0xFFFFFFFFUL - (MtrrV6.ExeCacheSize - 1)) | 0x0800UL)); + MsrData &= CacheInfoPtr->VariableMtrrMask; + SecondMsrData = (UINT64) ( MtrrV6.ExeCacheStartAddr | (WP_IO & 0xFULL)); + } else { + MsrData = 0; + SecondMsrData = 0; + } + LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE6, &SecondMsrData, StdHeader); + LibAmdMsrWrite ((AMD_MTRR_VARIABLE_BASE6 + 1), &MsrData, StdHeader); + + if (MtrrV7.ExeCacheSize != 0) { + MsrData = (UINT64) ( 0xFFFFFFFF00000000ULL | ((0xFFFFFFFFUL - (MtrrV7.ExeCacheSize - 1)) | 0x0800UL)); + MsrData &= CacheInfoPtr->VariableMtrrMask; + SecondMsrData = (UINT64) ( MtrrV7.ExeCacheStartAddr | (WP_IO & 0xFULL)); + } else { + MsrData = 0; + SecondMsrData = 0; + } + LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE7, &SecondMsrData, StdHeader); + LibAmdMsrWrite ((AMD_MTRR_VARIABLE_BASE7 + 1), &MsrData, StdHeader); + } // endif of MTRR region check + } // end of requests For loop + + 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 ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &AmdGetExeSizeParams->StdHeader); + FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **) &CacheInfoPtr, &Ignored, &AmdGetExeSizeParams->StdHeader); + // CAR_EXE mode is either "Limited by L2 size" or "Infinite Execution space" + ASSERT (CacheInfoPtr->CarExeType < MaxCarExeMode); + if (CacheInfoPtr->CarExeType == InfiniteExe) { + AmdGetExeSizeParams->AvailableExeCacheSize = SIZE_INFINITE_EXE_CACHE; + return AGESA_SUCCESS; + } + + // EXE cache size is limited by size of the L2, minus previous allocations for stack, heap, etc. + // 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; + + // 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 + * + * @returns Allocated size in bytes + * + */ +UINT32 +STATIC +CalculateOccupiedExeCache ( + 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; +} + + +/*---------------------------------------------------------------------------------------*/ +/** + * This function compares two memory regions for overlap and returns the combined + * Base,Size to describe the new combined region. + * + * There are 13 cases for how two regions may overlap: key: [] region A, ** region B + * 1- [ ] *** 9- *** [ ] disjoint regions + * 2- [ ]*** 10- ***[ ] adjacent regions + * 3- [ ***] 11- **[**] common ending + * 4- [ *]** 12- *[** ] extending + * 5- [ ** ] 13- *[*]* contained + * 6- [*** ] common start, contained + * 7- [***] identity + * 8- [**]** common start, extending + * 0- one of the regions is empty (has base=0) + * + * @param[in] ARegion pointer to the base,size pair that describes region A + * @param[in] BRegion pointer to the base,size pair that describes region B + * @param[in,out] CRegion pointer to the base,size pair that describes region C This struct also has the + * overlap type and the amount of overlap between the regions. + * @param[in] StdHeader Handle to config for library and services + * + * @returns void, nothing + */ + +VOID +STATIC +CompareRegions ( + IN EXECUTION_CACHE_REGION ARegion, + IN EXECUTION_CACHE_REGION BRegion, + IN OUT MERGED_CACHE_REGION *CRegion, + IN AMD_CONFIG_PARAMS *StdHeader + ) +{ + // Use Int64 to handle regions ending at or above the 4G boundary. + UINT64 EndOfA; + UINT64 EndOfB; + + + if ((BRegion.ExeCacheStartAddr == 0) || + (ARegion.ExeCacheStartAddr == 0)) { + CRegion->MergedStartAddr = + CRegion->MergedSize = + CRegion->OverlapAmount = 0; + CRegion->OverlapType = EmptySet; + return; + } + if (BRegion.ExeCacheStartAddr < ARegion.ExeCacheStartAddr) { + //swap regions A & B. this collapses types 9-13 onto 1-5 and reduces the number of tests + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = ARegion.ExeCacheSize; + ARegion = BRegion; + BRegion.ExeCacheStartAddr = CRegion->MergedStartAddr; + BRegion.ExeCacheSize = CRegion->MergedSize; + } + CRegion->MergedStartAddr = + CRegion->MergedSize = + CRegion->OverlapType = + CRegion->OverlapAmount = 0; + + if (ARegion.ExeCacheStartAddr == BRegion.ExeCacheStartAddr) { + // Common start, cases 6,7, or 8 + if (ARegion.ExeCacheSize == BRegion.ExeCacheSize) { + // case 7, identity. Need to recover the overlap size + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = ARegion.ExeCacheSize; + CRegion->OverlapAmount = ARegion.ExeCacheSize; + CRegion->OverlapType = Identity; + } else if (ARegion.ExeCacheSize < BRegion.ExeCacheSize) { + // case 8, common start extending + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = BRegion.ExeCacheSize; + CRegion->OverlapType = CommonStartExtending; + CRegion->OverlapAmount = ARegion.ExeCacheSize; + } else { + // case 6, common start contained + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = ARegion.ExeCacheSize; + CRegion->OverlapType = CommonStartContained; + CRegion->OverlapAmount = BRegion.ExeCacheSize; + } + } else { + // A_Base is less than B_Base. check for cases 1-5 + EndOfA = ((UINT64) ARegion.ExeCacheStartAddr) + ((UINT64) ARegion.ExeCacheSize); + + if (EndOfA < ((UINT64) BRegion.ExeCacheStartAddr)) { + // case 1, disjoint + CRegion->MergedStartAddr = + CRegion->MergedSize = + CRegion->OverlapAmount = 0; + CRegion->OverlapType = Disjoint; + + } else if (EndOfA == ((UINT64) BRegion.ExeCacheStartAddr)) { + // case 2, adjacent + CRegion->OverlapType = Adjacent; + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = ARegion.ExeCacheSize + BRegion.ExeCacheSize; + CRegion->OverlapAmount = 0; + } else { + // EndOfA is > B_Base. check for cases 3,4,5 + EndOfB = ((UINT64) BRegion.ExeCacheStartAddr) + ((UINT64) BRegion.ExeCacheSize); + + if ( EndOfA < EndOfB) { + // case 4, extending + CRegion->OverlapType = Extending; + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = (UINT32) (EndOfB - ((UINT64) ARegion.ExeCacheStartAddr)); + CRegion->OverlapAmount = (UINT32) (EndOfA - ((UINT64) BRegion.ExeCacheStartAddr)); + } else { + // case 3, same end; or case 5, contained + CRegion->OverlapType = Contained; + CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr; + CRegion->MergedSize = ARegion.ExeCacheSize; + CRegion->OverlapAmount = BRegion.ExeCacheSize; + } + } + } // endif + // Once we have combined the regions, they must still obey the MTRR size and boundary rules + if ( CRegion->OverlapType != Disjoint ) { + if ((!(IsPowerOfTwo (CRegion->MergedSize))) || + ((CRegion->MergedStartAddr % CRegion->MergedSize) != 0) ) { + CRegion->OverlapType = NotCombinable; + } + } + +} + + +/*---------------------------------------------------------------------------------------*/ +/** + * This local function tests the parameter for being an even power of two + * + * @param[in] TestNumber Number to check + * + * @retval TRUE - TestNumber is a power of two, + * @retval FALSE - TestNumber is not a power of two + * + */ +BOOLEAN +STATIC +IsPowerOfTwo ( + IN UINT32 TestNumber + ) +{ + UINT32 PowerTwo; + + ASSERT (TestNumber >= 0x8000UL); + PowerTwo = 0x8000UL; // Start at 32K + while ( TestNumber > PowerTwo ) { + PowerTwo = PowerTwo * 2; + } + return (((TestNumber % PowerTwo) == 0) ? TRUE: FALSE); +} + + |