summaryrefslogtreecommitdiff
path: root/src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c')
-rw-r--r--src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c744
1 files changed, 744 insertions, 0 deletions
diff --git a/src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c b/src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c
new file mode 100644
index 0000000000..a38434a1cb
--- /dev/null
+++ b/src/vendorcode/amd/agesa/f14/Proc/CPU/Feature/cpuCacheInit.c
@@ -0,0 +1,744 @@
+/* $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: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 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"
+CODE_GROUP (G1_PEICC)
+RDATA_GROUP (G1_PEICC)
+
+#define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE
+/*----------------------------------------------------------------------------
+ * DEFINITIONS AND MACROS
+ *
+ *----------------------------------------------------------------------------
+ */
+// 8Meg, ~max ROM space
+#define SIZE_INFINITE_EXE_CACHE ((1024 * 1024) * 8)
+
+/*----------------------------------------------------------------------------
+ * 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 (&FamilySpecificServices, StdHeader);
+ FamilySpecificServices->GetCacheInfo (FamilySpecificServices, &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;
+ }
+ // 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 {
+ IDS_HDT_CONSOLE (CPU_TRACE, " Exe cache allocated: Base 0x%x, Size 0x%x\n", AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize);
+ RemainingExecutionCacheSize = RemainingExecutionCacheSize - 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 (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;
+ RemainingExecutionCacheSize += Result.OverlapAmount;
+ }
+ } else {
+ // Request overlaps with MTRR6, Merge request with MTRR6
+ MtrrV6.ExeCacheStartAddr = Result.MergedStartAddr;
+ MtrrV6.ExeCacheSize = Result.MergedSize;
+ 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;
+ RemainingExecutionCacheSize += Result.OverlapAmount;
+ }
+ }
+
+ // Set the VarMTRRs. Size first, then base; 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 + 1), &MsrData, StdHeader);
+ LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE6, &SecondMsrData, 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 + 1), &MsrData, StdHeader);
+ LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE7, &SecondMsrData, 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 (&FamilySpecificServices, &AmdGetExeSizeParams->StdHeader);
+ FamilySpecificServices->GetCacheInfo (FamilySpecificServices, &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);
+}
+
+