AGESA F15: AMD family15 AGESA code
[coreboot.git] / src / vendorcode / amd / agesa / f15 / Proc / CPU / Feature / cpuCacheInit.c
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 (file)
index 0000000..ca60b2b
--- /dev/null
@@ -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);
+}
+
+