5 * AMD CPU Execution Cache Allocation functions.
7 * Contains code for doing Execution Cache Allocation for ROM space
9 * @xrefitem bom "File Content Label" "Release Content"
12 * @e \$Revision: 35136 $ @e \$Date: 2010-07-16 11:29:48 +0800 (Fri, 16 Jul 2010) $
16 *****************************************************************************
18 * Copyright (c) 2011, Advanced Micro Devices, Inc.
19 * All rights reserved.
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.
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.
43 * ***************************************************************************
49 *----------------------------------------------------------------------------
52 *----------------------------------------------------------------------------
57 #include "cpuRegisters.h"
59 #include "cpuServices.h"
60 #include "GeneralServices.h"
61 #include "cpuFamilyTranslation.h"
62 #include "cpuCacheInit.h"
63 #include "heapManager.h"
66 RDATA_GROUP (G1_PEICC)
68 #define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE
69 /*----------------------------------------------------------------------------
70 * DEFINITIONS AND MACROS
72 *----------------------------------------------------------------------------
74 // 8Meg, ~max ROM space
75 #define SIZE_INFINITE_EXE_CACHE ((1024 * 1024) * 8)
77 /*----------------------------------------------------------------------------
78 * TYPEDEFS AND STRUCTURES
80 *----------------------------------------------------------------------------
83 /*----------------------------------------------------------------------------
84 * L2 cache Association to Way translation table
85 *----------------------------------------------------------------------------
87 CONST UINT8 ROMDATA L2AssocToL2WayTranslationTable[] =
108 /*----------------------------------------------------------------------------
109 * PROTOTYPES OF LOCAL FUNCTIONS
111 *----------------------------------------------------------------------------
114 /*----------------------------------------------------------------------------
117 *----------------------------------------------------------------------------
128 CalculateOccupiedExeCache (
129 IN AMD_CONFIG_PARAMS *StdHeader
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
147 /*---------------------------------------------------------------------------------------*/
149 * This function will setup ROM execution cache.
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.
167 * @param[in] StdHeader Handle to config for library and services
168 * @param[in] AmdExeAddrMapPtr Pointer to the start of EXECUTION_CACHE_REGION array
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;
179 AllocateExecutionCache (
180 IN AMD_CONFIG_PARAMS *StdHeader,
181 IN EXECUTION_CACHE_REGION *AmdExeAddrMapPtr
184 AGESA_STATUS AgesaStatus;
185 AMD_GET_EXE_SIZE_PARAMS AmdGetExeSize;
186 UINT32 CurrentAllocatedExeCacheSize;
187 UINT32 RemainingExecutionCacheSize;
189 UINT64 SecondMsrData;
190 UINT32 RequestStartAddr;
197 CACHE_INFO *CacheInfoPtr;
198 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
199 EXECUTION_CACHE_REGION MtrrV6;
200 EXECUTION_CACHE_REGION MtrrV7;
201 MERGED_CACHE_REGION Result;
204 // If start addresses of all three regions are zero, then return early
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;
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;
223 GetCpuServicesOfCurrentCore ((const CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader);
224 FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (const VOID **)&CacheInfoPtr, &Ignored, StdHeader);
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) {
233 // Skip the region if ExeCacheSize = 0
234 if (AmdExeAddrMapPtr[i].ExeCacheSize == 0) {
238 // Align starting addresses on 32K boundary
239 AmdExeAddrMapPtr[i].ExeCacheStartAddr =
240 AmdExeAddrMapPtr[i].ExeCacheStartAddr & 0xFFFF8000;
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);
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);
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);
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);
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;
279 RequestStartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr;
280 RequestSize = AmdExeAddrMapPtr[i].ExeCacheSize;
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);
287 LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
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);
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);
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);
312 // MTRR previously allocated, recover size
313 RemainingExecutionCacheSize = RemainingExecutionCacheSize + 0x8000;
315 // Allocate this MTRR
317 LibAmdMsrWrite (CurrentMtrr, &MsrData, StdHeader);
320 // Turn off modification bit: MtrrFixDramModEn
321 LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader);
322 MsrData &= 0xFFFFFFFFFFF7FFFFULL;
323 LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
327 // Region above 1MB - Variable MTTR region
328 // Need to check both VarMTRRs for each requested region for match or overlap
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);
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;
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;
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);
373 // Merge request with MTRR7
374 MtrrV7.ExeCacheStartAddr = Result.MergedStartAddr;
375 MtrrV7.ExeCacheSize = Result.MergedSize;
376 RemainingExecutionCacheSize += Result.OverlapAmount;
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;
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));
405 LibAmdMsrWrite ((AMD_MTRR_VARIABLE_BASE6 + 1), &MsrData, StdHeader);
406 LibAmdMsrWrite (AMD_MTRR_VARIABLE_BASE6, &SecondMsrData, StdHeader);
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));
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
424 /*---------------------------------------------------------------------------------------*/
426 * This function calculates available L2 cache space for ROM execution.
428 * @param[in] AmdGetExeSizeParams Pointer to the start of AmdGetExeSizeParamsPtr structure
430 * @retval AGESA_SUCCESS No error
431 * @retval AGESA_ALERT No cache available for execution cache.
435 AmdGetAvailableExeCacheSize (
436 IN OUT AMD_GET_EXE_SIZE_PARAMS *AmdGetExeSizeParams
443 UINT32 CurrentCoreNum;
448 CPUID_DATA CpuIdDataStruct;
449 CACHE_INFO *CacheInfoPtr;
450 AP_MAIL_INFO ApMailboxInfo;
451 AGESA_STATUS IgnoredStatus;
452 CPU_SPECIFIC_SERVICES *FamilySpecificServices;
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;
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);
468 // get L2Ways from L2 Association to Way translation table
469 L2Ways = L2AssocToL2WayTranslationTable[L2Assoc];
470 ASSERT (L2Ways != 0xFF);
473 L2Size = 1024 * ((CpuIdDataStruct.ECX_Reg >> 16) & 0xFFFF);
475 // get each L2WaySize
476 L2WaySize = L2Size / L2Ways;
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);
486 // AP (Application Processor)
487 GetCurrentCore (&CurrentCoreNum, &AmdGetExeSizeParams->StdHeader);
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);
499 WayUsedForCar = Ceiling (CacheInfoPtr->Core1StackSize , L2WaySize) +
500 Ceiling (AMD_HEAP_SIZE_PER_CORE , L2WaySize) +
501 Ceiling (CacheInfoPtr->SharedMemSize, L2WaySize);
505 ASSERT (WayUsedForCar < L2Ways);
507 if (WayUsedForCar < L2Ways) {
508 AmdGetExeSizeParams->AvailableExeCacheSize = L2WaySize * (L2Ways - WayUsedForCar);
509 return AGESA_SUCCESS;
511 AmdGetExeSizeParams->AvailableExeCacheSize = 0;
517 /*---------------------------------------------------------------------------------------*/
519 * This function rounds a quotient up if the remainder is not zero.
521 * @param[in] Divisor The divisor
522 * @param[in] Dividend The dividend
524 * @retval Value Rounded quotient
534 if ((Divisor % Dividend) == 0) {
535 return (UINT8) (Divisor / Dividend);
537 return (UINT8) ((Divisor / Dividend) + 1);
542 /*---------------------------------------------------------------------------------------*/
544 * This function calculates the amount of cache that has already been allocated on the
547 * @param[in] StdHeader Handle to config for library and services
549 * @returns Allocated size in bytes
554 CalculateOccupiedExeCache (
555 IN AMD_CONFIG_PARAMS *StdHeader
558 UINT64 OccupExeCacheSize;
563 OccupExeCacheSize = 0;
566 //Calculate Variable MTRR base 6~7
568 for (i = 0; i < 2; i++) {
569 LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i)), &MsrData, StdHeader);
571 LibAmdMsrRead ((AMD_MTRR_VARIABLE_BASE6 + (2*i + 1)), &MsrData, StdHeader);
572 OccupExeCacheSize = OccupExeCacheSize + ((~((MsrData & (0xFFFF8000)) - 1))&0xFFFF8000);
577 //Calculate Fixed MTRR base D0000~F8000
579 for (i = 0; i < 6; i++) {
580 LibAmdMsrRead ((AMD_MTRR_FIX4K_BASE + 2 + i), &MsrData, StdHeader);
582 OccupExeCacheSize = OccupExeCacheSize + 0x8000;
586 return (UINT32)OccupExeCacheSize;
590 /*---------------------------------------------------------------------------------------*/
592 * This function compares two memory regions for overlap and returns the combined
593 * Base,Size to describe the new combined region.
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
603 * 8- [**]** common start, extending
604 * 0- one of the regions is empty (has base=0)
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
612 * @returns void, nothing
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
624 // Use Int64 to handle regions ending at or above the 4G boundary.
629 if ((BRegion.ExeCacheStartAddr == 0) ||
630 (ARegion.ExeCacheStartAddr == 0)) {
631 CRegion->MergedStartAddr =
632 CRegion->MergedSize =
633 CRegion->OverlapAmount = 0;
634 CRegion->OverlapType = EmptySet;
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;
642 BRegion.ExeCacheStartAddr = CRegion->MergedStartAddr;
643 BRegion.ExeCacheSize = CRegion->MergedSize;
645 CRegion->MergedStartAddr =
646 CRegion->MergedSize =
647 CRegion->OverlapType =
648 CRegion->OverlapAmount = 0;
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;
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;
672 // A_Base is less than B_Base. check for cases 1-5
673 EndOfA = ((UINT64) ARegion.ExeCacheStartAddr) + ((UINT64) ARegion.ExeCacheSize);
675 if (EndOfA < ((UINT64) BRegion.ExeCacheStartAddr)) {
677 CRegion->MergedStartAddr =
678 CRegion->MergedSize =
679 CRegion->OverlapAmount = 0;
680 CRegion->OverlapType = Disjoint;
682 } else if (EndOfA == ((UINT64) BRegion.ExeCacheStartAddr)) {
684 CRegion->OverlapType = Adjacent;
685 CRegion->MergedStartAddr = ARegion.ExeCacheStartAddr;
686 CRegion->MergedSize = ARegion.ExeCacheSize + BRegion.ExeCacheSize;
687 CRegion->OverlapAmount = 0;
689 // EndOfA is > B_Base. check for cases 3,4,5
690 EndOfB = ((UINT64) BRegion.ExeCacheStartAddr) + ((UINT64) BRegion.ExeCacheSize);
692 if ( EndOfA < EndOfB) {
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));
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;
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;
718 /*---------------------------------------------------------------------------------------*/
720 * This local function tests the parameter for being an even power of two
722 * @param[in] TestNumber Number to check
724 * @retval TRUE - TestNumber is a power of two,
725 * @retval FALSE - TestNumber is not a power of two
736 ASSERT (TestNumber >= 0x8000UL);
737 PowerTwo = 0x8000UL; // Start at 32K
738 while ( TestNumber > PowerTwo ) {
739 PowerTwo = PowerTwo * 2;
741 return (((TestNumber % PowerTwo) == 0) ? TRUE: FALSE);