blob: 10f4f5c4f1c402760373fb643996ba196ee23d13 [file] [log] [blame]
/**
* @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: 44323 $ @e \$Date: 2010-12-22 01:24:58 -0700 (Wed, 22 Dec 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"
#define FILECODE PROC_CPU_FEATURE_CPUCACHEINIT_FILECODE
/*----------------------------------------------------------------------------
* DEFINITIONS AND MACROS
*
*----------------------------------------------------------------------------
*/
/*----------------------------------------------------------------------------
* 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
CalculateOccupyExeCache (
IN AMD_CONFIG_PARAMS *StdHeader
);
/*---------------------------------------------------------------------------------------*/
/**
* This function will setup ROM execution cache.
*
* This function should only be called once. The execution cache regions are passed
* in, the max number of execution cache regions are three. If the start address of
* all three regions are zero, then no execution cache is allocated.
*
* -1 available cache size is less than requested, the ROM execution cache
* region is reduced or eliminated.
* -2 at least one execution cache regions across the 1MB line, the ROM execution
* cache size is reduced.
* -3 at least one execution cache regions across the 4GB line, the ROM execution
* cache size is reduced.
* -4 the start address of a region is not at the boundary of cache size
* -5 execution cache start address less than D0000
* -6 more than 2 execution cache regions are above 1MB
*
* @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;
*
* @todo on Tilapia, this routine returns AGESA_ERROR.
*/
AGESA_STATUS
AllocateExecutionCache (
IN AMD_CONFIG_PARAMS *StdHeader,
IN EXECUTION_CACHE_REGION *AmdExeAddrMapPtr
)
{
AGESA_STATUS AgesaStatus;
AMD_GET_EXE_SIZE_PARAMS AmdGetExeSize;
UINT64 MsrData;
UINT32 RemainingExecutionCacheSize;
UINT32 VariableMttrBase;
UINT32 AgesaInfo;
UINT32 StartAddr;
UINT32 ExeCacheSize;
UINT32 StartFixMtrr;
UINT32 CurrentMtrr;
UINT32 EndFixMtrr;
UINT32 CurrentAllocatedExeCacheSize;
UINT8 i;
UINT8 Ignored;
UINT64 OccupyExeCacheStartAddr;
UINT64 OccupExeCacheSize;
CACHE_INFO *CacheInfoPtr;
CPU_SPECIFIC_SERVICES *FamilySpecificServices;
//
// if start address of all three regions are zero, then the default values are used
//
if (AmdExeAddrMapPtr[0].ExeCacheStartAddr == 0) {
if (AmdExeAddrMapPtr[1].ExeCacheStartAddr == 0) {
if (AmdExeAddrMapPtr[2].ExeCacheStartAddr == 0) {
// No regions defined by the caller
return AGESA_SUCCESS;
}
}
}
// turn on modification bit
LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader);
MsrData |= 0x80000;
LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
// get available L2 cache size for ROM execution
AmdGetExeSize.StdHeader = *StdHeader;
AgesaStatus = AmdGetAvailableExeCacheSize (&AmdGetExeSize);
RemainingExecutionCacheSize = AmdGetExeSize.AvailableExeCacheSize;
CurrentAllocatedExeCacheSize = CalculateOccupyExeCache (StdHeader);
if (CurrentAllocatedExeCacheSize >= RemainingExecutionCacheSize) {
RemainingExecutionCacheSize = 0;
} else {
RemainingExecutionCacheSize = RemainingExecutionCacheSize - CurrentAllocatedExeCacheSize;
}
GetCpuServicesOfCurrentCore (&FamilySpecificServices, StdHeader);
FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **)&CacheInfoPtr, &Ignored, StdHeader);
// Setup MTTRs for region 0 to region 2
VariableMttrBase = AMD_MTRR_VARIABLE_BASE6;
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;
}
// Calculate available execution cache size for region 0 to 2
if (RemainingExecutionCacheSize >= AmdExeAddrMapPtr[i].ExeCacheSize) {
RemainingExecutionCacheSize = RemainingExecutionCacheSize - AmdExeAddrMapPtr[i].ExeCacheSize;
} else {
AgesaStatus = AGESA_WARNING;
AgesaInfo = AGESA_CACHE_SIZE_REDUCED;
AmdExeAddrMapPtr[i].ExeCacheSize = RemainingExecutionCacheSize;
RemainingExecutionCacheSize = 0;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
}
// Align starting addresses on 32K boundary
AmdExeAddrMapPtr[i].ExeCacheStartAddr =
AmdExeAddrMapPtr[i].ExeCacheStartAddr & 0xFFFF8000;
// Boundary alignment check mechanism
if ((AmdExeAddrMapPtr[i].ExeCacheStartAddr % AmdExeAddrMapPtr[i].ExeCacheSize) != 0) {
AgesaStatus = AGESA_ERROR;
AgesaInfo = AGESA_REGION_NOT_ALIGNED_ON_BOUNDARY;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
break;
}
// Check start address
if (AmdExeAddrMapPtr[i].ExeCacheStartAddr < 0xD0000) {
AgesaStatus = AGESA_ERROR;
AgesaInfo = AGESA_CACHE_START_ADDRESS_LESS_D0000;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, AmdExeAddrMapPtr[i].ExeCacheStartAddr, AmdExeAddrMapPtr[i].ExeCacheSize, 0, StdHeader);
break;
}
StartAddr = AmdExeAddrMapPtr[i].ExeCacheStartAddr;
ExeCacheSize = AmdExeAddrMapPtr[i].ExeCacheSize;
ExeCacheSize --;
if (StartAddr < 0x100000) {
// Region below 1MB
// Fixed MTTR region
if ((StartAddr + ExeCacheSize) > 0xFFFFF) {
ExeCacheSize = 0xFFFFF - StartAddr;
AgesaStatus = AGESA_WARNING;
AgesaInfo = AGESA_CACHE_REGIONS_ACROSS_1MB;
AmdExeAddrMapPtr[i].ExeCacheSize = ExeCacheSize + 1;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, StartAddr, ExeCacheSize, 0, StdHeader);
}
// Find start and end of MTTR
StartFixMtrr = AMD_MTRR_FIX4K_BASE + ((StartAddr >> 15) & 0x7);
EndFixMtrr = AMD_MTRR_FIX4K_BASE + (((StartAddr + ExeCacheSize) >> 15) & 0x7);
//
//Check Mtrr before we use it, if Mtrr has been used, we need to add RemainingExecutionCacheSize back.
//
for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) {
LibAmdMsrRead (CurrentMtrr, &MsrData, StdHeader);
if (MsrData != 0) {
RemainingExecutionCacheSize = RemainingExecutionCacheSize + 0x8000;
}
}
// Setup MTTRs
MsrData = WP_IO;
for (CurrentMtrr = StartFixMtrr; CurrentMtrr <= EndFixMtrr; CurrentMtrr++) {
LibAmdMsrWrite (CurrentMtrr, &MsrData, StdHeader);
}
} else {
// Region above 1MB
// Variable MTTR region
if (VariableMttrBase > AMD_MTRR_VARIABLE_BASE7) {
AgesaStatus = AGESA_ERROR;
AgesaInfo = AGESA_THREE_CACHE_REGIONS_ABOVE_1MB;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, StartAddr, ExeCacheSize, 0, StdHeader);
continue;
}
if ((0xFFFFFFFF - StartAddr) < ExeCacheSize) {
ExeCacheSize = 0xFFFFFFFF - StartAddr;
AgesaStatus = AGESA_WARNING;
AgesaInfo = AGESA_CACHE_REGIONS_ACROSS_4GB;
AmdExeAddrMapPtr[i].ExeCacheSize = ExeCacheSize + 1;
PutEventLog (AgesaStatus,
(CPU_EVENT_EXECUTION_CACHE_ALLOCATION_ERROR | (UINT8) AgesaInfo),
i, StartAddr, ExeCacheSize, 0, StdHeader);
}
//
//Check Mtrr before we use it.
//
LibAmdMsrRead (VariableMttrBase, &MsrData, StdHeader);
if (MsrData != 0) {
//
//Check expanded
//
OccupyExeCacheStartAddr = MsrData & (0xFFFF8000);
LibAmdMsrRead ((VariableMttrBase + 1), &MsrData, StdHeader);
OccupExeCacheSize = (~((MsrData & (0xFFFF8000)) - 1))&0xFFFF8000;
//
//Region below || Region above
//
if ( ((StartAddr + ExeCacheSize + 1) <= OccupyExeCacheStartAddr) ||
(StartAddr >= (OccupyExeCacheStartAddr + OccupExeCacheSize)) ) {
//
//Not overlap the original one, but it need to re-process and set an pair of empty Mtrr
//
VariableMttrBase += 2;
RemainingExecutionCacheSize = RemainingExecutionCacheSize + AmdExeAddrMapPtr[i].ExeCacheSize;
//
//Resume loop count
//
i--;
continue;
} else if (OccupyExeCacheStartAddr == StartAddr) {
//
//Overlap with same start address
//
if (OccupExeCacheSize > (ExeCacheSize + 1)) {
//AgesaInfo = AGESA_DEALLOCATE_CACHE_REGIONS;
break;
}
RemainingExecutionCacheSize = RemainingExecutionCacheSize + (UINT32)OccupExeCacheSize;
} else {
//
//Overlap with different start address
//
//AgesaInfo = AGESA_DEALLOCATE_CACHE_REGIONS;
break;
}
}
MsrData = (UINT64) (StartAddr | (WP_IO & 0xFull));
LibAmdMsrWrite (VariableMttrBase, &MsrData, StdHeader);
MsrData = (UINT64) ( 0xFFFFFFFF00000000ull | ((0xFFFFFFFFull - ExeCacheSize) | 0x800ull));
MsrData &= CacheInfoPtr->VariableMtrrMask;
LibAmdMsrWrite ((VariableMttrBase + 1), &MsrData, StdHeader);
VariableMttrBase += 2;
}
}
// Turn on MTTR enable bit and turn off modification bit
LibAmdMsrRead (MSR_SYS_CFG, &MsrData, StdHeader);
MsrData &= 0xFFFFFFFFFFF7FFFFull;
LibAmdMsrWrite (MSR_SYS_CFG, &MsrData, StdHeader);
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);
// 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;
FamilySpecificServices->GetCacheInfo (FamilySpecificServices, (CONST VOID **)&CacheInfoPtr, &Ignored, &AmdGetExeSizeParams->StdHeader);
// 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
*
* @retval Value Allocated size in bytes
*
*/
UINT32
STATIC
CalculateOccupyExeCache (
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;
}