Update AMD F14 Agesa to support Rev C0 cpus
[coreboot.git] / src / vendorcode / amd / agesa / f14 / Proc / CPU / Feature / cpuCacheInit.c
1 /* $NoKeywords:$ */
2 /**
3  * @file
4  *
5  * AMD CPU Execution Cache Allocation functions.
6  *
7  * Contains code for doing Execution Cache Allocation for ROM space
8  *
9  * @xrefitem bom "File Content Label" "Release Content"
10  * @e project:      AGESA
11  * @e sub-project:  CPU
12  * @e \$Revision: 35136 $   @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 2010) $
13  *
14  */
15 /*
16  *****************************************************************************
17  *
18  * Copyright (c) 2011, Advanced Micro Devices, Inc.
19  * All rights reserved.
20  * 
21  * Redistribution and use in source and binary forms, with or without
22  * modification, are permitted provided that the following conditions are met:
23  *     * Redistributions of source code must retain the above copyright
24  *       notice, this list of conditions and the following disclaimer.
25  *     * Redistributions in binary form must reproduce the above copyright
26  *       notice, this list of conditions and the following disclaimer in the
27  *       documentation and/or other materials provided with the distribution.
28  *     * Neither the name of Advanced Micro Devices, Inc. nor the names of 
29  *       its contributors may be used to endorse or promote products derived 
30  *       from this software without specific prior written permission.
31  * 
32  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
33  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
34  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
35  * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
36  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
37  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
38  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
39  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
40  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
41  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42  * 
43  * ***************************************************************************
44  *
45  */
46
47
48 /*
49  *----------------------------------------------------------------------------
50  *                                MODULES USED
51  *
52  *----------------------------------------------------------------------------
53  */
54 #include "AGESA.h"
55 #include "amdlib.h"
56 #include "Ids.h"
57 #include "cpuRegisters.h"
58 #include "Topology.h"
59 #include "cpuServices.h"
60 #include "GeneralServices.h"
61 #include "cpuFamilyTranslation.h"
62 #include "cpuCacheInit.h"
63 #include "heapManager.h"
64 #include "Filecode.h"
65 CODE_GROUP (G1_PEICC)
66 RDATA_GROUP (G1_PEICC)
67
68 #define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE
69 /*----------------------------------------------------------------------------
70  *                          DEFINITIONS AND MACROS
71  *
72  *----------------------------------------------------------------------------
73  */
74 // 8Meg, ~max ROM space
75 #define SIZE_INFINITE_EXE_CACHE   ((1024 * 1024) * 8)
76
77 /*----------------------------------------------------------------------------
78  *                           TYPEDEFS AND STRUCTURES
79  *
80  *----------------------------------------------------------------------------
81  */
82
83 /*----------------------------------------------------------------------------
84  *             L2 cache Association to Way translation table
85  *----------------------------------------------------------------------------
86  */
87 CONST UINT8 ROMDATA L2AssocToL2WayTranslationTable[] =
88 {
89   0,
90   1,
91   2,
92   0xFF,
93   4,
94   0xFF,
95   8,
96   0xFF,
97   16,
98   0xFF,
99   32,
100   48,
101   64,
102   96,
103   128,
104   0xFF,
105 };
106
107
108 /*----------------------------------------------------------------------------
109  *                        PROTOTYPES OF LOCAL FUNCTIONS
110  *
111  *----------------------------------------------------------------------------
112  */
113
114 /*----------------------------------------------------------------------------
115  *                            EXPORTED FUNCTIONS
116  *
117  *----------------------------------------------------------------------------
118  */
119 UINT8
120 STATIC
121 Ceiling (
122   IN UINT32 Divisor,
123   IN UINT32 Dividend
124   );
125
126 UINT32
127 STATIC
128 CalculateOccupiedExeCache (
129   IN AMD_CONFIG_PARAMS *StdHeader
130   );
131
132 VOID
133 STATIC
134 CompareRegions (
135   IN      EXECUTION_CACHE_REGION  ARegion,
136   IN      EXECUTION_CACHE_REGION  BRegion,
137   IN OUT  MERGED_CACHE_REGION     *CRegion,
138   IN      AMD_CONFIG_PARAMS       *StdHeader
139   );
140
141 BOOLEAN
142 STATIC
143 IsPowerOfTwo (
144   IN      UINT32                  TestNumber
145   );
146
147 /*---------------------------------------------------------------------------------------*/
148 /**
149  * This function will setup ROM execution cache.
150  *
151  * The execution cache regions are passed in, the max number of execution cache regions
152  * is three.  Several rules are checked for compliance. If a rule test fails then one of
153  * these error suffixes will be added to the general CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR
154  * in the SubReason field
155  *   -1  available cache size is less than requested, the ROM execution cache
156  *       region has been reduced or eliminated.
157  *   -2  at least one execution cache region crosses the 1MB line, the ROM execution
158  *       cache size has been reduced.
159  *   -3  at least one execution cache region crosses the 4GB line, the ROM execution
160  *       cache size has been reduced.
161  *   -4  the start address of a region is not at the boundary of cache size,
162  *        the starting address has been adjusted downward
163  *   -5  execution cache start address less than D0000, request is ignored
164  *   -6  more than 2 execution cache regions are above 1MB, request is ignored
165  * If the start address of all three regions are zero, then no execution cache is allocated.
166  *
167  * @param[in]   StdHeader          Handle to config for library and services
168  * @param[in]   AmdExeAddrMapPtr   Pointer to the start of EXECUTION_CACHE_REGION array
169  *
170  * @retval      AGESA_SUCCESS      No error
171  * @retval      AGESA_WARNING      AGESA_CACHE_SIZE_REDUCED; AGESA_CACHE_REGIONS_ACROSS_1MB;
172  *                                 AGESA_CACHE_REGIONS_ACROSS_4GB;
173  * @retval      AGESA_ERROR        AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY;
174  *                                 AGESA_CACHE_START_ADDRESS_LESS_D0000;
175  *                                 AGESA_THREE_CACHE_REGIONS_ABOVE_1MB;
176  *
177  */
178 AGESA_STATUS
179 AllocateExecutionCache (
180   IN AMD_CONFIG_PARAMS *StdHeader,
181   IN EXECUTION_CACHE_REGION *AmdExeAddrMapPtr
182   )
183 {
184   AGESA_STATUS               AgesaStatus;
185   AMD_GET_EXE_SIZE_PARAMS    AmdGetExeSize;
186   UINT32                     CurrentAllocatedExeCacheSize;
187   UINT32                     RemainingExecutionCacheSize;
188   UINT64                     MsrData;
189   UINT64                     SecondMsrData;
190   UINT32                     RequestStartAddr;
191   UINT32                     RequestSize;
192   UINT32                     StartFixMtrr;
193   UINT32                     CurrentMtrr;
194   UINT32                     EndFixMtrr;
195   UINT8                      i;
196   UINT8                      Ignored;
197   CACHE_INFO                 *CacheInfoPtr;
198   CPU_SPECIFIC_SERVICES      *FamilySpecificServices;
199   EXECUTION_CACHE_REGION      MtrrV6;
200   EXECUTION_CACHE_REGION      MtrrV7;
201   MERGED_CACHE_REGION         Result;
202
203   //
204   // If start addresses of all three regions are zero, then return early
205   //
206   if (AmdExeAddrMapPtr[0].ExeCacheStartAddr == 0) {
207     if (AmdExeAddrMapPtr[1].ExeCacheStartAddr == 0) {
208       if (AmdExeAddrMapPtr[2].ExeCacheStartAddr == 0) {
209         // No regions defined by the caller
210         return AGESA_SUCCESS;
211       }
212     }
213   }
214
215   // Get available cache size for ROM execution
216   AmdGetExeSize.StdHeader = *StdHeader;
217   AgesaStatus = AmdGetAvailableExeCacheSize (&AmdGetExeSize);
218   CurrentAllocatedExeCacheSize = CalculateOccupiedExeCache (StdHeader);
219   ASSERT (CurrentAllocatedExeCacheSize <= AmdGetExeSize.AvailableExeCacheSize);
220   IDS_HDT_CONSOLE (CPU_TRACE, "  Cache size available for execution cache: 0x%x\n", AmdGetExeSize.AvailableExeCacheSize);
221   RemainingExecutionCacheSize = AmdGetExeSize.AvailableExeCacheSize - CurrentAllocatedExeCacheSize;
222
223   GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
224   FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (const VOID **)&CacheInfoPtr, &Ignored, StdHeader);
225
226   // Process each request entry 0 to 2
227   for (i = 0; i < 3; i++) {
228     // Exit if no more cache available
229     if (RemainingExecutionCacheSize == 0) {
230       break;
231     }
232
233     // Skip the region if ExeCacheSize = 0
234     if (AmdExeAddrMapPtr[i].ExeCacheSize == 0) {
235       continue;
236     }
237
238     // Align starting addresses on 32K boundary
239     AmdExeAddrMapPtr[i].ExeCacheStartAddr =
240       AmdExeAddrMapPtr[i].ExeCacheStartAddr & 0xFFFF8000;
241
242     // Adjust size to multiple of 32K (rounding up)
243     if ((AmdExeAddrMapPtr[i].ExeCacheSize % 0x8000) != 0) {
244       AmdExeAddrMapPtr[i].ExeCacheSize = ((AmdExeAddrMapPtr[i].ExeCacheSize + 0x8000) & 0xFFFF8000);
245     }
246
247     // Boundary alignment check and confirm size is an even power of two
248     if ( !IsPowerOfTwo (AmdExeAddrMapPtr[i].ExeCacheSize) ||
249     ((AmdExeAddrMapPtr[i].ExeCacheStartAddr % AmdExeAddrMapPtr[i].ExeCacheSize) != 0) ) {
250       AgesaStatus = AGESA_ERROR;
251       PutEventLog (AgesaStatus,
252                    (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY),
253                    i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
254       break;
255     }
256
257     // Check start address boundary
258     if (AmdExeAddrMapPtr[i].ExeCacheStartAddr < 0xD0000) {
259       AgesaStatus = AGESA_ERROR;
260       PutEventLog (AgesaStatus,
261                    (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_START_ADDRESS_LESS_D0000),
262                    i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
263       break;
264     }
265     // Verify available execution cache size for region 0 to 2 request
266     if (RemainingExecutionCacheSize < AmdExeAddrMapPtr[i].ExeCacheSize) {
267       // Request is larger than available, reduce the allocation & report the change
268       AmdExeAddrMapPtr[i].ExeCacheSize = RemainingExecutionCacheSize;
269       RemainingExecutionCacheSize = 0;
270       AgesaStatus = AGESA_WARNING;
271       PutEventLog (AgesaStatus,
272                    (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_SIZE_REDUCED),
273                    i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
274     } else {
275       IDS_HDT_CONSOLE (CPU_TRACE, "  Exe cache allocated: Base 0x%x, Size 0x%x\n", AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize);
276       RemainingExecutionCacheSize = RemainingExecutionCacheSize - AmdExeAddrMapPtr[i].ExeCacheSize;
277     }
278
279     RequestStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr;
280     RequestSize = AmdExeAddrMapPtr[i].ExeCacheSize;
281
282     if (RequestStartAddr < 0x100000) {
283       // Region starts below 1MB - Fixed MTTR region,
284       // turn on modification bit: MtrrFixDramModEn
285       LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader);
286       MsrData |= 0x80000;
287       LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
288
289
290       // Check for 1M boundary crossing
291       if ((RequestStartAddr + RequestSize) > 0x100000) {
292         // Request spans the 1M boundary, reduce the size & report the change
293         RequestSize = 0x100000 - RequestStartAddr;
294         AmdExeAddrMapPtr[i].ExeCacheSize = RequestSize;
295         AgesaStatus = AGESA_WARNING;
296         PutEventLog (AgesaStatus,
297                      (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_REGIONS_ACROSS_1MB),
298                      i, RequestStartAddr, RequestSize, 0, StdHeader);
299       }
300
301       // Find start MTTR and end MTTR for the requested region
302       StartFixMtrr = AMD_MTRR_FIX4K_BASE + ((RequestStartAddr >> 15) & 0x7);
303       EndFixMtrr = AMD_MTRR_FIX4K_BASE + ((((RequestStartAddr + RequestSize) - 1) >> 15) & 0x7);
304
305       //
306       //Check Mtrr before we use it,
307       //  if Mtrr has been used, we need to recover the previously allocated size.
308       //    (only work in blocks of 32K size - no splitting of ways)
309       for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) {
310         LibAmdMsrRead (CurrentMtrr, &MsrData, StdHeader);
311         if (MsrData != 0) {
312           // MTRR previously allocated, recover size
313           RemainingExecutionCacheSize = RemainingExecutionCacheSize + 0x8000;
314         } else {
315           // Allocate this MTRR
316           MsrData = WP_IO;
317           LibAmdMsrWrite (CurrentMtrr, &MsrData, StdHeader);
318         }
319       }
320       // Turn off modification bit: MtrrFixDramModEn
321       LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader);
322       MsrData &= 0xFFFFFFFFFFF7FFFFULL;
323       LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
324
325
326     } else {
327       // Region above 1MB -  Variable MTTR region
328       //    Need to check both VarMTRRs for each requested region for match or overlap
329       //
330
331       // Check for 4G boundary crossing   (using size-1 to keep in 32bit math range)
332       if ((0xFFFFFFFFUL - RequestStartAddr) < (RequestSize - 1)) {
333         RequestSize = (0xFFFFFFFFUL - RequestStartAddr) + 1;
334         AgesaStatus = AGESA_WARNING;
335         AmdExeAddrMapPtr[i].ExeCacheSize = RequestSize;
336         PutEventLog (AgesaStatus,
337                      (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_CACHE_REGIONS_ACROSS_4GB),
338                      i, RequestStartAddr, RequestSize, 0, StdHeader);
339       }
340       LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE6, &MsrData, StdHeader);
341       MtrrV6.ExeCacheStartAddr = ((UINT32) MsrData) & 0xFFFFF000UL;
342       LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE6 + 1, &MsrData, StdHeader);
343       MtrrV6.ExeCacheSize = (0xFFFFFFFFUL - (((UINT32) MsrData) & 0xFFFFF000UL)) + 1;
344
345       LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE7, &MsrData, StdHeader);
346       MtrrV7.ExeCacheStartAddr = ((UINT32) MsrData) & 0xFFFFF000UL;
347       LibAmdMsrRead (AMD_MTRR_VARIABLE_BASE7 + 1, &MsrData, StdHeader);
348       MtrrV7.ExeCacheSize = (0xFFFFFFFFUL - (((UINT32) MsrData) & 0xFFFFF000UL)) + 1;
349
350       CompareRegions (AmdExeAddrMapPtr[i], MtrrV6, &Result, StdHeader);
351       if (Result.OverlapType == EmptySet) {
352         // MTRR6 is empty. Allocate request into MTRR6.
353         // Note: since all merges are moved down to MTRR6, if MTRR6 is empty so should MTRR7 also be empty
354         MtrrV6.ExeCacheStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr;
355         MtrrV6.ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize;
356       } else if ((Result.OverlapType == Disjoint) ||
357                  (Result.OverlapType == NotCombinable)) {
358         // MTRR6 is in use, and request does not overlap with MTRR6, check MTRR7
359         CompareRegions (AmdExeAddrMapPtr[i], MtrrV7, &Result, StdHeader);
360         if (Result.OverlapType == EmptySet) {
361           // MTRR7 is empty. Allocate request into MTRR7.
362           MtrrV7.ExeCacheStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr;
363           MtrrV7.ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize;
364         } else if ((Result.OverlapType == Disjoint) ||
365                    (Result.OverlapType == NotCombinable)) {
366           // MTRR7 is also in use and request does not overlap - error: 3rd region above 1M
367           AgesaStatus = AGESA_ERROR;
368           PutEventLog (AgesaStatus,
369                          (CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR + AGESA_THREE_CACHE_REGIONS_ABOVE_1MB),
370                          i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
371           break;
372         } else {
373           // Merge request with MTRR7
374           MtrrV7.ExeCacheStartAddr = Result.MergedStartAddr;
375           MtrrV7.ExeCacheSize = Result.MergedSize;
376           RemainingExecutionCacheSize += Result.OverlapAmount;
377         }
378       } else {
379         // Request overlaps with MTRR6, Merge request with MTRR6
380         MtrrV6.ExeCacheStartAddr = Result.MergedStartAddr;
381         MtrrV6.ExeCacheSize = Result.MergedSize;
382         RemainingExecutionCacheSize += Result.OverlapAmount;
383         CompareRegions (MtrrV6, MtrrV7, &Result, StdHeader);
384         if ((Result.OverlapType != Disjoint) &&
385             (Result.OverlapType != EmptySet) &&
386             (Result.OverlapType != NotCombinable)) {
387           // MTRR6 and MTRR7 now overlap, merge them into MTRR6
388           MtrrV6.ExeCacheStartAddr = Result.MergedStartAddr;
389           MtrrV6.ExeCacheSize = Result.MergedSize;
390           MtrrV7.ExeCacheStartAddr = 0;
391           MtrrV7.ExeCacheSize = 0;
392           RemainingExecutionCacheSize += Result.OverlapAmount;
393         }
394       }
395
396       // Set the VarMTRRs.  Size first, then base; this allows for expanding the region safely.
397       if (MtrrV6.ExeCacheSize != 0) {
398         MsrData = (UINT64) ( 0xFFFFFFFF00000000ULL | ((0xFFFFFFFFUL - (MtrrV6.ExeCacheSize - 1)) | 0x0800UL));
399         MsrData &= CacheInfoPtr->VariableMtrrMask;
400         SecondMsrData = (UINT64) ( MtrrV6.ExeCacheStartAddr | (WP_IO & 0xFULL));
401       } else {
402         MsrData = 0;
403         SecondMsrData = 0;
404       }
405       LibAmdMsrWrite ((AMD_MTRR_VARIABLE_BASE6 + 1), &MsrData, StdHeader);
406       LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE6, &SecondMsrData, StdHeader);
407
408       if (MtrrV7.ExeCacheSize != 0) {
409         MsrData = (UINT64) ( 0xFFFFFFFF00000000ULL | ((0xFFFFFFFFUL - (MtrrV7.ExeCacheSize - 1)) | 0x0800UL));
410         MsrData &= CacheInfoPtr->VariableMtrrMask;
411         SecondMsrData = (UINT64) ( MtrrV7.ExeCacheStartAddr | (WP_IO & 0xFULL));
412       } else {
413         MsrData = 0;
414         SecondMsrData = 0;
415       }
416       LibAmdMsrWrite ((AMD_MTRR_VARIABLE_BASE7 + 1), &MsrData, StdHeader);
417       LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE7, &SecondMsrData, StdHeader);
418     } // endif of MTRR region check
419   } // end of requests For loop
420
421   return AgesaStatus;
422 }
423
424 /*---------------------------------------------------------------------------------------*/
425 /**
426  * This function calculates available L2 cache space for ROM execution.
427  *
428  * @param[in]   AmdGetExeSizeParams  Pointer to the start of AmdGetExeSizeParamsPtr structure
429  *
430  * @retval      AGESA_SUCCESS      No error
431  * @retval      AGESA_ALERT        No cache available for execution cache.
432  *
433  */
434 AGESA_STATUS
435 AmdGetAvailableExeCacheSize (
436   IN OUT   AMD_GET_EXE_SIZE_PARAMS *AmdGetExeSizeParams
437   )
438 {
439   UINT8     WayUsedForCar;
440   UINT8     L2Assoc;
441   UINT32    L2Size;
442   UINT32    L2WaySize;
443   UINT32    CurrentCoreNum;
444   UINT8     L2Ways;
445   UINT8     Ignored;
446   UINT32    DieNumber;
447   UINT32    TotalCores;
448   CPUID_DATA  CpuIdDataStruct;
449   CACHE_INFO  *CacheInfoPtr;
450   AP_MAIL_INFO ApMailboxInfo;
451   AGESA_STATUS IgnoredStatus;
452   CPU_SPECIFIC_SERVICES *FamilySpecificServices;
453
454   GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, &AmdGetExeSizeParams->StdHeader);
455   FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (const VOID **)&CacheInfoPtr, &Ignored, &AmdGetExeSizeParams->StdHeader);
456   // CAR_EXE mode is either "Limited by L2 size" or "Infinite Execution space"
457   ASSERT (CacheInfoPtr->CarExeType < MaxCarExeMode);
458   if (CacheInfoPtr->CarExeType == InfiniteExe) {
459     AmdGetExeSizeParams->AvailableExeCacheSize = SIZE_INFINITE_EXE_CACHE;
460     return AGESA_SUCCESS;
461   }
462
463   // EXE cache size is limited by size of the L2, minus previous allocations for stack, heap, etc.
464   // Check for L2 cache size and way size
465   LibAmdCpuidRead (AMD_CPUID_L2L3Cache_L2TLB, &CpuIdDataStruct, &AmdGetExeSizeParams->StdHeader);
466   L2Assoc = (UINT8) ((CpuIdDataStruct.ECX_Reg >> 12) & 0x0F);
467
468   // get L2Ways from L2 Association to Way translation table
469   L2Ways = L2AssocToL2WayTranslationTable[L2Assoc];
470   ASSERT (L2Ways != 0xFF);
471
472   // get L2Size
473   L2Size = 1024 * ((CpuIdDataStruct.ECX_Reg >> 16) & 0xFFFF);
474
475   // get each L2WaySize
476   L2WaySize = L2Size / L2Ways;
477
478   // Determine the size for execution cache
479   if (IsBsp (&AmdGetExeSizeParams->StdHeader, &IgnoredStatus)) {
480     // BSC (Boot Strap Core)
481     WayUsedForCar = Ceiling (CacheInfoPtr->BspStackSize, L2WaySize) +
482                     Ceiling (CacheInfoPtr->MemTrainingBufferSize, L2WaySize) +
483                     Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) +
484                     Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize);
485   } else {
486     // AP (Application Processor)
487     GetCurrentCore (&CurrentCoreNum, &AmdGetExeSizeParams->StdHeader);
488
489     GetApMailbox (&ApMailboxInfo.Info, &AmdGetExeSizeParams->StdHeader);
490     DieNumber = (1 << ApMailboxInfo.Fields.ModuleType);
491     GetActiveCoresInCurrentSocket (&TotalCores, &AmdGetExeSizeParams->StdHeader);
492     ASSERT ((TotalCores % DieNumber) == 0);
493     if ((CurrentCoreNum % (TotalCores / DieNumber)) == 0) {
494       WayUsedForCar = Ceiling (CacheInfoPtr->Core0StackSize , L2WaySize) +
495                       Ceiling (CacheInfoPtr->MemTrainingBufferSize, L2WaySize) +
496                       Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) +
497                       Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize);
498     } else {
499       WayUsedForCar = Ceiling (CacheInfoPtr->Core1StackSize , L2WaySize) +
500                       Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) +
501                       Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize);
502     }
503   }
504
505   ASSERT (WayUsedForCar < L2Ways);
506
507   if (WayUsedForCar < L2Ways) {
508     AmdGetExeSizeParams->AvailableExeCacheSize = L2WaySize * (L2Ways - WayUsedForCar);
509     return AGESA_SUCCESS;
510   } else {
511     AmdGetExeSizeParams->AvailableExeCacheSize = 0;
512     return AGESA_ALERT;
513   }
514 }
515
516
517 /*---------------------------------------------------------------------------------------*/
518 /**
519  * This function rounds a quotient up if the remainder is not zero.
520  *
521  * @param[in]   Divisor            The divisor
522  * @param[in]   Dividend           The dividend
523  *
524  * @retval      Value              Rounded quotient
525  *
526  */
527 UINT8
528 STATIC
529 Ceiling (
530   IN UINT32 Divisor,
531   IN UINT32 Dividend
532   )
533 {
534   if ((Divisor % Dividend) == 0) {
535     return (UINT8) (Divisor / Dividend);
536   } else {
537     return (UINT8) ((Divisor / Dividend) + 1);
538   }
539 }
540
541
542 /*---------------------------------------------------------------------------------------*/
543 /**
544  * This function calculates the amount of cache that has already been allocated on the
545  * executing core.
546  *
547  * @param[in]   StdHeader       Handle to config for library and services
548  *
549  * @returns     Allocated size in bytes
550  *
551  */
552 UINT32
553 STATIC
554 CalculateOccupiedExeCache (
555   IN AMD_CONFIG_PARAMS *StdHeader
556   )
557 {
558   UINT64                     OccupExeCacheSize;
559   UINT64                     MsrData;
560   UINT8                      i;
561
562   MsrData = 0;
563   OccupExeCacheSize = 0;
564
565   //
566   //Calculate Variable MTRR base 6~7
567   //
568   for (i = 0; i < 2; i++) {
569     LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i)), &MsrData, StdHeader);
570     if (MsrData != 0) {
571       LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i + 1)), &MsrData, StdHeader);
572       OccupExeCacheSize = OccupExeCacheSize + ((~((MsrData & (0xFFFF8000)) - 1))&0xFFFF8000);
573     }
574   }
575
576   //
577   //Calculate Fixed MTRR base D0000~F8000
578   //
579   for (i = 0; i < 6; i++) {
580     LibAmdMsrRead ((AMD_MTRR_FIX4K_BASE + 2 + i), &MsrData, StdHeader);
581     if (MsrData!= 0) {
582       OccupExeCacheSize = OccupExeCacheSize + 0x8000;
583     }
584   }
585
586   return (UINT32)OccupExeCacheSize;
587 }
588
589
590 /*---------------------------------------------------------------------------------------*/
591 /**
592  * This function compares two memory regions for overlap and returns the combined
593  *  Base,Size  to describe the new combined region.
594  *
595  * There are 13 cases for how two regions may overlap:  key: [] region A, ** region B
596  * 1- [  ] ***      9-  ***  [  ]   disjoint regions
597  * 2- [  ]***       10- ***[  ]     adjacent regions
598  * 3- [ ***]        11- **[**]      common ending
599  * 4- [  *]**       12- *[**  ]     extending
600  * 5- [ ** ]        13- *[*]*       contained
601  * 6- [***  ]                       common start, contained
602  * 7- [***]                         identity
603  * 8- [**]**                        common start, extending
604  * 0- one of the regions is empty (has base=0)
605  *
606  * @param[in]     ARegion       pointer to the base,size pair that describes region A
607  * @param[in]     BRegion       pointer to the base,size pair that describes region B
608  * @param[in,out] CRegion       pointer to the base,size pair that describes region C This struct also has the
609  *                              overlap type and the amount of overlap between the regions.
610  * @param[in]     StdHeader     Handle to config for library and services
611  *
612  * @returns       void, nothing
613  */
614
615 VOID
616 STATIC
617 CompareRegions (
618   IN       EXECUTION_CACHE_REGION  ARegion,
619   IN       EXECUTION_CACHE_REGION  BRegion,
620   IN OUT   MERGED_CACHE_REGION     *CRegion,
621   IN       AMD_CONFIG_PARAMS       *StdHeader
622   )
623 {
624   // Use Int64 to handle regions ending at or above the 4G boundary.
625   UINT64        EndOfA;
626   UINT64        EndOfB;
627
628
629   if ((BRegion.ExeCacheStartAddr == 0) ||
630       (ARegion.ExeCacheStartAddr == 0)) {
631     CRegion->MergedStartAddr  =
632     CRegion->MergedSize       =
633     CRegion->OverlapAmount    = 0;
634     CRegion->OverlapType = EmptySet;
635     return;
636   }
637   if (BRegion.ExeCacheStartAddr < ARegion.ExeCacheStartAddr) {
638     //swap regions A & B. this collapses types 9-13 onto 1-5 and reduces the number of tests
639     CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
640     CRegion->MergedSize       = ARegion.ExeCacheSize;
641     ARegion                   = BRegion;
642     BRegion.ExeCacheStartAddr = CRegion->MergedStartAddr;
643     BRegion.ExeCacheSize      = CRegion->MergedSize;
644   }
645   CRegion->MergedStartAddr  =
646   CRegion->MergedSize       =
647   CRegion->OverlapType      =
648   CRegion->OverlapAmount    = 0;
649
650   if (ARegion.ExeCacheStartAddr == BRegion.ExeCacheStartAddr) {
651     // Common start, cases 6,7, or 8
652     if (ARegion.ExeCacheSize == BRegion.ExeCacheSize) {
653       // case 7, identity. Need to recover the overlap size
654       CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
655       CRegion->MergedSize       = ARegion.ExeCacheSize;
656       CRegion->OverlapAmount    = ARegion.ExeCacheSize;
657       CRegion->OverlapType      = Identity;
658     } else if (ARegion.ExeCacheSize < BRegion.ExeCacheSize) {
659       // case 8, common start extending
660       CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
661       CRegion->MergedSize       = BRegion.ExeCacheSize;
662       CRegion->OverlapType      = CommonStartExtending;
663       CRegion->OverlapAmount    = ARegion.ExeCacheSize;
664     } else {
665       // case 6, common start contained
666       CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
667       CRegion->MergedSize       = ARegion.ExeCacheSize;
668       CRegion->OverlapType      = CommonStartContained;
669       CRegion->OverlapAmount    = BRegion.ExeCacheSize;
670     }
671   } else {
672     // A_Base is less than B_Base. check for cases 1-5
673     EndOfA = ((UINT64) ARegion.ExeCacheStartAddr) + ((UINT64) ARegion.ExeCacheSize);
674
675     if (EndOfA < ((UINT64) BRegion.ExeCacheStartAddr)) {
676       // case 1, disjoint
677       CRegion->MergedStartAddr  =
678       CRegion->MergedSize       =
679       CRegion->OverlapAmount    = 0;
680       CRegion->OverlapType = Disjoint;
681
682     } else if (EndOfA == ((UINT64) BRegion.ExeCacheStartAddr)) {
683       // case 2, adjacent
684       CRegion->OverlapType = Adjacent;
685       CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
686       CRegion->MergedSize       = ARegion.ExeCacheSize + BRegion.ExeCacheSize;
687       CRegion->OverlapAmount    = 0;
688     } else {
689       // EndOfA is > B_Base. check for cases 3,4,5
690       EndOfB = ((UINT64) BRegion.ExeCacheStartAddr) + ((UINT64) BRegion.ExeCacheSize);
691
692       if ( EndOfA < EndOfB) {
693         // case 4, extending
694         CRegion->OverlapType = Extending;
695         CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
696         CRegion->MergedSize       = (UINT32) (EndOfB - ((UINT64) ARegion.ExeCacheStartAddr));
697         CRegion->OverlapAmount    = (UINT32) (EndOfA - ((UINT64) BRegion.ExeCacheStartAddr));
698       } else {
699         // case 3, same end; or case 5, contained
700         CRegion->OverlapType = Contained;
701         CRegion->MergedStartAddr  = ARegion.ExeCacheStartAddr;
702         CRegion->MergedSize       = ARegion.ExeCacheSize;
703         CRegion->OverlapAmount    = BRegion.ExeCacheSize;
704       }
705     }
706   } // endif
707   // Once we have combined the regions, they must still obey the MTRR size and boundary rules
708   if ( CRegion->OverlapType != Disjoint ) {
709     if ((!(IsPowerOfTwo (CRegion->MergedSize))) ||
710        ((CRegion->MergedStartAddr % CRegion->MergedSize) != 0) ) {
711       CRegion->OverlapType = NotCombinable;
712     }
713   }
714
715 }
716
717
718 /*---------------------------------------------------------------------------------------*/
719 /**
720  * This local function tests the parameter for being an even power of two
721  *
722  * @param[in]   TestNumber    Number to check
723  *
724  * @retval      TRUE - TestNumber is a power of two,
725  * @retval      FALSE - TestNumber is not a power of two
726  *
727  */
728 BOOLEAN
729 STATIC
730 IsPowerOfTwo (
731   IN      UINT32                  TestNumber
732   )
733 {
734   UINT32      PowerTwo;
735
736   ASSERT (TestNumber >= 0x8000UL);
737   PowerTwo = 0x8000UL;                    // Start at 32K
738   while ( TestNumber > PowerTwo ) {
739     PowerTwo = PowerTwo * 2;
740   }
741   return (((TestNumber % PowerTwo) == 0) ? TRUE: FALSE);
742 }
743
744