/* $NoKeywords:$ */ /** * @file * * AMD CPU Pstate Leveling Function. * * Contains code to level the Pstates in a multi-socket system * * @xrefitem bom "File Content Label" "Release Content" * @e project: AGESA * @e sub-project: CPU * @e \$Revision: 84150 $ @e \$Date: 2012-12-12 15:46:25 -0600 (Wed, 12 Dec 2012) $ * */ /***************************************************************************** * * Copyright (c) 2008 - 2013, 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 "OptionPstate.h" #include "cpuLateInit.h" #include "cpuRegisters.h" #include "cpuPostInit.h" #include "Ids.h" #include "cpuFamilyTranslation.h" #include "cpuPstateTables.h" #include "cpuApicUtilities.h" #include "cpuServices.h" #include "GeneralServices.h" #include "Filecode.h" CODE_GROUP (G1_PEICC) RDATA_GROUP (G1_PEICC) #define FILECODE PROC_CPU_FEATURE_CPUPSTATELEVELING_FILECODE /*---------------------------------------------------------------------------- * DEFINITIONS AND MACROS * *---------------------------------------------------------------------------- */ extern OPTION_PSTATE_POST_CONFIGURATION OptionPstatePostConfiguration; // global user config record extern CPU_FAMILY_SUPPORT_TABLE PstateFamilyServiceTable; /*---------------------------------------------------------------------------- * TYPEDEFS AND STRUCTURES * *---------------------------------------------------------------------------- */ /*---------------------------------------------------------------------------- * PROTOTYPES OF LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ AGESA_STATUS PutAllCoreInPState0 ( IN OUT PSTATE_LEVELING *PStateBufferPtr, IN AMD_CONFIG_PARAMS *StdHeader ); AGESA_STATUS StartPstateMsrModify ( IN S_CPU_AMD_PSTATE *CpuAmdPState, IN AMD_CONFIG_PARAMS *StdHeader ); VOID STATIC PutCoreInPState0 ( IN VOID *PStateBuffer, IN AMD_CONFIG_PARAMS *StdHeader ); AGESA_STATUS PStateLevelingStub ( IN OUT S_CPU_AMD_PSTATE *PStateStrucPtr, IN AMD_CONFIG_PARAMS *StdHeader ); AGESA_STATUS PStateLevelingMain ( IN OUT S_CPU_AMD_PSTATE *PStateStrucPtr, IN AMD_CONFIG_PARAMS *StdHeader ); VOID CorePstateRegModify ( IN VOID *CpuAmdPState, IN AMD_CONFIG_PARAMS *StdHeader ); /** *--------------------------------------------------------------------------------------- * * PStateLeveling * * Description: * This function will populate the PStateBuffer, after doing the PState Leveling * Note: This function should be called for every core in the system. * * Parameters: * @param[in,out] *PStateStrucPtr * @param[in] *StdHeader * * @retval AGESA_STATUS * *--------------------------------------------------------------------------------------- **/ AGESA_STATUS PStateLeveling ( IN OUT S_CPU_AMD_PSTATE *PStateStrucPtr, IN AMD_CONFIG_PARAMS *StdHeader ) { AGESA_TESTPOINT (TpProcCpuEntryPstateLeveling, StdHeader); return ((*(OptionPstatePostConfiguration.PstateLeveling)) (PStateStrucPtr, StdHeader)); // Note: Split config struct into PEI/DXE halves. This one is PEI. } /**-------------------------------------------------------------------------------------- * * PStateLevelingStub * * Description: * This is the default routine for use when the PState option is NOT requested. * The option install process will create and fill the transfer vector with * the address of the proper routine (Main or Stub). The link optimizer will * strip out of the .DLL the routine that is not used. * * Parameters: * @param[in,out] *PStateStrucPtr * @param[in] *StdHeader * * @retval AGESA_STATUS * *--------------------------------------------------------------------------------------- **/ AGESA_STATUS PStateLevelingStub ( IN OUT S_CPU_AMD_PSTATE *PStateStrucPtr, IN AMD_CONFIG_PARAMS *StdHeader ) { return AGESA_UNSUPPORTED; } /**-------------------------------------------------------------------------------------- * * PStateLevelingMain * * Description: * This is the common routine for creating the ACPI information tables. * * Parameters: * @param[in,out] *PStateStrucPtr * @param[in] *StdHeader * * @retval AGESA_STATUS * *--------------------------------------------------------------------------------------- **/ AGESA_STATUS PStateLevelingMain ( IN OUT S_CPU_AMD_PSTATE *PStateStrucPtr, IN AMD_CONFIG_PARAMS *StdHeader ) { UINT32 i; UINT32 k; UINT32 m; UINT32 TotalIterations; UINT32 LogicalSocketCount; UINT32 TempVar_a; UINT32 TempVar_b; UINT32 TempVar_c; UINT32 TempVar_d; UINT32 TempVar_e; UINT32 TempVar_f; PCI_ADDR PciAddress; UINT32 TempFreqArray[20]; UINT32 TempPowerArray[20]; UINT32 TempIddValueArray[20]; UINT32 TempIddDivArray[20]; UINT32 TempSocketPiArray[20]; UINT32 TempSwP0Array[MAX_SOCKETS_SUPPORTED]; BOOLEAN TempFlag1; BOOLEAN TempFlag2; BOOLEAN TempFlag3; BOOLEAN TempFlag4; BOOLEAN AllCoresHaveHtcCapEquToZeroFlag; BOOLEAN AllCoreHaveMaxOnePStateFlag; BOOLEAN PstateMaxValEquToPstateHtcLimitFlag; BOOLEAN AtLeastOneCoreHasPstateHtcLimitEquToOneFlag; BOOLEAN PstateMaxValMinusHtcPstateLimitLessThan2Flag; PSTATE_LEVELING *PStateBufferPtr; PSTATE_LEVELING *PStateBufferPtrTmp; UINT32 MaxPstateInNode; AGESA_STATUS Status; TempFlag1 = FALSE; TempFlag2 = FALSE; TempFlag3 = FALSE; TempFlag4 = FALSE; AllCoresHaveHtcCapEquToZeroFlag = FALSE; AllCoreHaveMaxOnePStateFlag = FALSE; PstateMaxValEquToPstateHtcLimitFlag = FALSE; AtLeastOneCoreHasPstateHtcLimitEquToOneFlag = FALSE; PstateMaxValMinusHtcPstateLimitLessThan2Flag = FALSE; PStateBufferPtr = PStateStrucPtr->PStateLevelingStruc; Status = AGESA_SUCCESS; if (PStateBufferPtr[0].SetPState0 == PSTATE_FLAG_1) { PStateBufferPtr[0].AllCpusHaveIdenticalPStates = TRUE; PStateBufferPtr[0].InitStruct = 1; return AGESA_UNSUPPORTED; } LogicalSocketCount = PStateStrucPtr->TotalSocketInSystem; ASSERT (LogicalSocketCount <= MAX_SOCKETS_SUPPORTED); // This section of code will execute only for "core 0" i.e. BSP // Read P-States of all the cores. if (PStateBufferPtr[0].InitStruct == 0) { // Determine 'software' P0 indices for each socket for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempSwP0Array[i] = (UINT32) (PStateBufferPtrTmp->PStateCoreStruct[0].NumberOfBoostedStates); } // Check if core frequency and power are same across all sockets. TempFlag1 = FALSE; m = TempSwP0Array[0]; for (i = 1; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if ((PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue != PStateBufferPtr[0].PStateCoreStruct[0].PStateMaxValue)) { TempFlag1 = TRUE; break; } MaxPstateInNode = PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue; for (k = TempSwP0Array[i]; k <= MaxPstateInNode; k++, m++) { if ((PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[m].CoreFreq != PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].CoreFreq) || (PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[m].Power != PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].Power)) { TempFlag1 = TRUE; break; // Come out of the inner FOR loop } } if (TempFlag1) { break; // Come out of the outer FOR loop } } if (!TempFlag1) { // No need to do pStateLeveling, or writing to pState MSR registers // if all CPUs have Identical PStates PStateBufferPtr[0].AllCpusHaveIdenticalPStates = TRUE; PStateBufferPtr[0].InitStruct = 1; PutAllCoreInPState0 (PStateBufferPtr, StdHeader); return AGESA_UNSUPPORTED; } else { PStateBufferPtr[0].AllCpusHaveIdenticalPStates = FALSE; } // 1_b) & 1_c) TempFlag1 = FALSE; TempFlag2 = FALSE; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue == TempSwP0Array[i]) { TempFlag1 = TRUE; } else { TempFlag2 = TRUE; } if (PStateBufferPtrTmp->PStateCoreStruct[0].HtcCapable == 0) { TempFlag3 = TRUE; } else { TempFlag4 = TRUE; } if ((PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue - PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit) < 2) { PstateMaxValMinusHtcPstateLimitLessThan2Flag = TRUE; } if (PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue == PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit) { PstateMaxValEquToPstateHtcLimitFlag = TRUE; } if (PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit == 1) { AtLeastOneCoreHasPstateHtcLimitEquToOneFlag = TRUE; } } // Do general setup of flags, that we may use later // Implementation of (1_b) if (TempFlag1 && TempFlag2) { // //Processors with only one enabled P-state (F3xDC[PstateMaxVal]=000b) cannot be mixed in a system with //processors with more than one enabled P-state (F3xDC[PstateMaxVal]!=000b). // PStateBufferPtr[0].InitStruct = 1; PStateBufferPtr[0].CreateAcpiTables = 0; PutAllCoreInPState0 (PStateBufferPtr, StdHeader); return AGESA_UNSUPPORTED; } else if (TempFlag1 && !TempFlag2) { // //all processors have only 1 enabled P-state // AllCoreHaveMaxOnePStateFlag = TRUE; PStateBufferPtr[0].OnlyOneEnabledPState = TRUE; } // Processors with F3xE8[HTC_CAPABLE] = 1 can not be // mixed in system with processors with F3xE8[HTC_CAPABLE] = 0. if (TempFlag3 && TempFlag4) { PStateBufferPtr[0].InitStruct = 1; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); PStateBufferPtrTmp[0].CreateAcpiTables = 0; } PutAllCoreInPState0 (PStateBufferPtr, StdHeader); return AGESA_UNSUPPORTED; } if (TempFlag3) { // //If code run to here means that all processors do not have HTC_CAPABLE. // AllCoresHaveHtcCapEquToZeroFlag = TRUE; } //-------------------------------------------------------------------------------- // S T E P - 2 //-------------------------------------------------------------------------------- // Now run the PState Leveling Algorithm which will create mixed CPU P-State // Tables. // Follow the algorithm in the latest BKDG // ------------------------------------------------------------------------------- // Match P0 CPU COF for all CPU cores to the lowest P0 CPU COF value in the // coherent fabric, and match P0 power for all CPU cores to the highest P0 power // value in the coherent fabric. // 2_a) If all processors have only 1 enabled P-State BIOS must write the // appropriate CpuFid value resulting from the matched CPU COF to all // copies of MSRC001_0070[CpuFid], and exit the sequence (No further // steps are executed) //-------------------------------------------------------------------------------- // Identify the lowest P0 Frequency and maximum P0 Power TempVar_d = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSwP0Array[0]].CoreFreq; TempVar_e = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSwP0Array[0]].Power; TempVar_a = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSwP0Array[0]].IddValue; TempVar_b = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSwP0Array[0]].IddDiv; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (TempVar_d > PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].CoreFreq) { TempVar_d = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].CoreFreq; } if (TempVar_e < PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].Power) { TempVar_e = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].Power; TempVar_a = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].IddValue; TempVar_b = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].IddDiv; } } // Set P0 Frequency and Power for all CPUs for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].CoreFreq = TempVar_d; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].Power = TempVar_e; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].IddValue = TempVar_a; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSwP0Array[i]].IddDiv = TempVar_b; } // 2_a) if (!AllCoreHaveMaxOnePStateFlag) { //-------------------------------------------------------------------------- // STEP - 3 //-------------------------------------------------------------------------- // Match the CPU COF and power for P-states used by HTC. Skip to step 4 // is any processor reports F3xE8[HTC_Capable] = 0; // 3_a) Set F3x64[HtcPstateLimit] = 001b and F3x68[StcPstateLimit] = 001b for // processors with F3x64[HtcPstateLimit] = 000b. // 3_b) Identify the lowest CPU COF for all processors in the P-state // pointed to by [The Hardware Thermal Control (HTC) Register] // F3x64[HtcPstateLimit] // 3_c) Modify the CPU COF pointed to by [The Hardware Thermal Control // (HTC) Register] F3x64[HtcPstateLimit] for all processors to the // previously identified lowest CPU COF value. // 3_d) Identify the highest power for all processors in the P-state // pointed to by [The Hardware Thermal Control (HTC) Register] // F3x64[HtcPstateLimit]. // 3_e) Modify the power pointed to by [The Hardware Thermal Control (HTC) // Register] F3x64[HtcPstateLimit] to the previously identified // highest power value. if (!AllCoresHaveHtcCapEquToZeroFlag) { // 3_a) for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit == 0) { // To Be Done (Set Htc and Stc PstateLimit values) // for this CPU (using PCI address space) for (k = 0; k < (UINT8)GetPlatformNumberOfModules (); k++) { if (GetPciAddress (StdHeader, PStateBufferPtrTmp->SocketNumber, k, &PciAddress, &Status)) { // Set F3x64[HtcPstateLimit] = 001b PciAddress.Address.Function = FUNC_3; PciAddress.Address.Register = HARDWARE_THERMAL_CTRL_REG; LibAmdPciRead (AccessWidth32, PciAddress, &TempVar_d, StdHeader); // Bits 30:28 TempVar_d = (TempVar_d & 0x8FFFFFFF) | 0x10000000; LibAmdPciWrite (AccessWidth32, PciAddress, &TempVar_d, StdHeader); // Set F3x68[StcPstateLimit] = 001b PciAddress.Address.Register = SOFTWARE_THERMAL_CTRL_REG; LibAmdPciRead (AccessWidth32, PciAddress, &TempVar_d, StdHeader); // Bits 28:30 TempVar_d = (TempVar_d & 0x8FFFFFFF) | 0x10000000; LibAmdPciWrite (AccessWidth32, PciAddress, &TempVar_d, StdHeader); } } // Set LocalBuffer PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit = 1; if ((PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue - 1) < 2) { PstateMaxValMinusHtcPstateLimitLessThan2Flag = TRUE; } if (PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue == 1) { PstateMaxValEquToPstateHtcLimitFlag = TRUE; } } if (PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit == 1) { AtLeastOneCoreHasPstateHtcLimitEquToOneFlag = TRUE; } } // 3_b) and 3_d) TempVar_a = PStateBufferPtr[0].PStateCoreStruct[0].HtcPstateLimit; TempVar_d = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].CoreFreq; TempVar_e = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].Power; TempVar_f = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].IddValue; TempVar_c = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].IddDiv; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); for (k = 0; k < 1; k++) { TempVar_b = PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit; if (TempVar_d > PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].CoreFreq) { TempVar_d = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].CoreFreq; } if (TempVar_e < PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].Power) { TempVar_e = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].Power; TempVar_f = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].IddValue; TempVar_c = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].IddDiv; } } } // 3_c) and 3_e) for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempVar_a = PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].CoreFreq = TempVar_d; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].Power = TempVar_e; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].IddValue = TempVar_f; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].IddDiv = TempVar_c; } } // if(AllCoresHaveHtcCapEquToZeroFlag) //-------------------------------------------------------------------------- // STEP - 4 //-------------------------------------------------------------------------- // Match the CPU COF and power for the lowest performance P-state: // 4_a) If F3xDC[PstateMaxVal] = F3x64[HtcPstateLimit] for any processor, // set PstateEn = 0 for all the P-states greater than // F3x64[HtcPstateLimit] for all processors. // 4_b) Identify the lowest CPU COF for all processors in the P-state // pointed to by F3xDC[PstateMaxVal]. // 4_c) Modify the CPU COF for all processors in the P-state pointed to by // F3xDC[PstateMaxVal] to the previously identified lowest CPU COF // value. // 4_d) Identify the highest power for all processors in the P-state // pointed to by F3xDC[PstateMaxVal]. // 4_e) Modify the power for all processors in the P-state pointed to by // F3xDC[PstateMaxVal] to the previously identified highest power // value. // 4_a) if (PstateMaxValEquToPstateHtcLimitFlag) { for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempVar_b = PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit + 1; for (k = TempVar_b; k <= PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue; k++) { PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].PStateEnable = 0; } //-------------------------------------------------------------------------- // STEP - 5 //-------------------------------------------------------------------------- // 5_a) Modify F3xDC[PstateMaxVal] to indicate the lowest performance // P-state with PstateEn set for each processor (Step 4 can disable // P-states pointed to by F3xDC[PstateMaxVal]) // Use this value of HtcPstateLimit to program the // F3xDC[pStateMaxValue] TempVar_e = PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit; TempVar_e <<= 8; // Bits 10:8 for (m = 0; m < (UINT8)GetPlatformNumberOfModules (); m++) { if (GetPciAddress (StdHeader, PStateBufferPtrTmp->SocketNumber, m, &PciAddress, &Status)) { PciAddress.Address.Function = FUNC_3; PciAddress.Address.Register = CLOCK_POWER_TIMING_CTRL2_REG; LibAmdPciRead (AccessWidth32, PciAddress, &TempVar_d, StdHeader); TempVar_d = (TempVar_d & 0xFFFFF8FF) | TempVar_e; LibAmdPciWrite (AccessWidth32, PciAddress, &TempVar_d, StdHeader); } }//End of step 5 } }// End of 4_a) // 4_b) and 4_d) TempVar_a = PStateBufferPtr[0].PStateCoreStruct[0].PStateMaxValue; TempVar_d = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].CoreFreq; TempVar_e = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].Power; TempVar_f = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].IddValue; TempVar_c = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempVar_a].IddDiv; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempVar_b = PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue; if (TempVar_d > PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].CoreFreq) { TempVar_d = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].CoreFreq; } if (TempVar_e < PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].Power) { TempVar_e = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].Power; TempVar_f = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].IddValue; TempVar_c = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_b].IddDiv; } } // 4_c) and 4_e) for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempVar_a = PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].CoreFreq = TempVar_d; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].Power = TempVar_e; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].IddValue = TempVar_f; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempVar_a].IddDiv = TempVar_c; } //-------------------------------------------------------------------------- // STEP - 6 //-------------------------------------------------------------------------- // Match the CPU COF and power for upper intermediate performance // P-state(s): // Upper intermediate PStates = PStates between (Not including) P0 and // F3x64[HtcPstateLimit] // 6_a) If F3x64[HtcPstateLimit] = 001b for any processor, set PstateEn = 0 // for enabled upper intermediate P-states for all processors with // F3x64[HtcPstateLimit] > 001b and skip the remaining actions for // this numbered step. // 6_b) Define each of the available upper intermediate P-states; for each // processor concurrently evaluate the following loop; when any // processor falls out of the loop (runs out of available upper // intermediate Pstates) all other processors have their remaining // upper intermediate P-states invalidated (PstateEn = 0); // for (i = F3x64[HtcPstateLimit] - 1; i > 0; i--) // - Identify the lowest CPU COF for P(i). // - Identify the highest power for P(i). // - Modify P(i) CPU COF for all processors to the previously // identified lowest CPU COF value. // - Modify P(i) power for all processors to the previously // identified highest power value. // 6_a) if (AtLeastOneCoreHasPstateHtcLimitEquToOneFlag) { for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); for (k = TempSwP0Array[i] + 1; k < (PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit); k++) { if (PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit > 1) { // Make a function call to clear the // structure values PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].PStateEnable = 0; } } } } // 6_b) else { // Identify Lowest Frequency and Highest Power TotalIterations = 0; TempFlag1 = TRUE; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempSocketPiArray[i] = PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit - 1; } do { //For first socket, try to find a candidate if (TempSocketPiArray[0] != TempSwP0Array[0]) { while (PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].PStateEnable == 0) { TempSocketPiArray[0] = TempSocketPiArray[0] - 1; if (TempSocketPiArray[0] == TempSwP0Array[0]) { TempFlag1 = FALSE; break; } } } else { TempFlag1 = FALSE; } if (TempFlag1) { TempFreqArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].CoreFreq; TempPowerArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].Power; TempIddValueArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].IddValue; TempIddDivArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].IddDiv; //Try to find next candidate for (i = 1; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (TempSocketPiArray[i] != TempSwP0Array[i]) { while (PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].PStateEnable == 0) { TempSocketPiArray[i]--; if (TempSocketPiArray[i] == TempSwP0Array[i]) { TempFlag1 = FALSE; break; } }//end while } else { TempFlag1 = FALSE; } } //end for LogicalSocketCount } if (TempFlag1) { for (i = 0; i < LogicalSocketCount; i++) { // //Compare // CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (TempFreqArray[TotalIterations] > PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq) { TempFreqArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq; } if (TempPowerArray[TotalIterations] < PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power) { TempPowerArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power; TempIddValueArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddValue; TempIddDivArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddDiv; } } // Modify (Pi) CPU COF and Power for all the CPUs for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq = TempFreqArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power = TempPowerArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddValue = TempIddValueArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddDiv = TempIddDivArray[TotalIterations]; TempSocketPiArray[i] = TempSocketPiArray[i] - 1; } } else { for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); for (m = TempSocketPiArray[i]; m > TempSwP0Array[i]; m--) { PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[m].PStateEnable = 0; } } } TotalIterations++; } while (TempFlag1); } // else //-------------------------------------------------------------------------- // STEP - 7 //-------------------------------------------------------------------------- // Match the CPU COF and power for lower intermediate performance P - state(s) // Lower Intermediate Pstates = Pstates between (not including) // F3x64[HtcPstateLimit] and F3xDC[PstateMaxVal] // 7_a) If F3xDC[PstateMaxVal] - F3x64[HtcPstateLimit] < 2 for any // processor, set PstateEn = 0 for enabled lower intermediate P - states // for all processors with (F3xDC[PstateMaxVal] - // F3x64[HtcPstateLimit] > 1) and skip the remaining actions for this // numbered step. // 7_b) Define each of the available lower intermediate P-states; for each // processor concurrently evaluate the following loop; when any // processor falls out of the loop (runs out of available lower // intermediate Pstates) all other processors have their remaining // lower intermediate P-states invalidated (PstateEn = 0); // for (i = F3xDC[PstateMaxVal]-1; i > F3x64[HtcPstateLimit]; i--) // - Identify the lowest CPU COF for P-states between // (not including) F3x64[HtcPstateLimit] and P(i). // - Identify the highest power for P-states between // (not including) F3x64[HtcPstateLimit] and P(i). // - Modify P(i) CPU COF for all processors to the previously // identified lowest CPU COF value. // - Modify P(i) power for all processors to the previously // identified highest power value. // 7_a) if (PstateMaxValMinusHtcPstateLimitLessThan2Flag) { for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); for (k = PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue - 1; k > PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit; k--) { if ((PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue - PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit) > 1) { PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].PStateEnable = 0; } } } } // 7_b) else { // Identify Lowest Frequency and Highest Power TotalIterations = 0; TempFlag1 = TRUE; for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); TempSocketPiArray[i] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateMaxValue - 1; } do { //For first socket, try to find a candidate if (TempSocketPiArray[0] != PStateBufferPtr[0].PStateCoreStruct[0].HtcPstateLimit) { while (PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].PStateEnable == 0) { TempSocketPiArray[0] = TempSocketPiArray[0] - 1; if (TempSocketPiArray[0] == PStateBufferPtr[0].PStateCoreStruct[0].HtcPstateLimit) { TempFlag1 = FALSE; break; } } } else { TempFlag1 = FALSE; } if (TempFlag1) { TempFreqArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].CoreFreq; TempPowerArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].Power; TempIddValueArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].IddValue; TempIddDivArray[TotalIterations] = PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[TempSocketPiArray[0]].IddDiv; //Try to find next candidate for (i = 1; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (TempSocketPiArray[i] != PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit) { while (PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].PStateEnable == 0) { TempSocketPiArray[i]--; if (TempSocketPiArray[i] == PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit) { TempFlag1 = FALSE; break; } }//end while } else { TempFlag1 = FALSE; } } //end for LogicalSocketCount } if (TempFlag1) { for (i = 0; i < LogicalSocketCount; i++) { // //Compare // CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); if (TempFreqArray[TotalIterations] > PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq) { TempFreqArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq; } if (TempPowerArray[TotalIterations] < PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power) { TempPowerArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power; TempIddValueArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddValue; TempIddDivArray[TotalIterations] = PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddDiv; } } // Modify (Pi) CPU COF and Power for all the CPUs for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].CoreFreq = TempFreqArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].Power = TempPowerArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddValue = TempIddValueArray[TotalIterations]; PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[TempSocketPiArray[i]].IddDiv = TempIddDivArray[TotalIterations]; TempSocketPiArray[i] = TempSocketPiArray[i] - 1; } } else { for (i = 0; i < LogicalSocketCount; i++) { CpuGetPStateLevelStructure (&PStateBufferPtrTmp, PStateStrucPtr, i, StdHeader); for (m = TempSocketPiArray[i]; m > PStateBufferPtrTmp->PStateCoreStruct[0].HtcPstateLimit; m--) { PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[m].PStateEnable = 0; } } } TotalIterations++; } while (TempFlag1); } // else } // if(!AllCoreHaveMaxOnePStateFlag) PStateBufferPtr[0].InitStruct = 1; } // CurrentCore // Update the pState MSRs // This can be done only by individual core StartPstateMsrModify (PStateStrucPtr, StdHeader); //---------------------------------------------------------------------------------- // STEP - 8 //---------------------------------------------------------------------------------- // Place all cores into a valid COF and VID configuration corresponding to an // enabled P-state: // 8_a) Select an enabled P-state != to the P-state pointed to by // MSRC001_0063[CurPstate] for each core. // 8_b) Transition all cores to the selected P-states by writing the Control value // from the_PSS object corresponding to the selected P-state to // MSRC001_0062[PstateCmd]. // 8_c) Wait for all cores to report the Status value from the _PSS object // corresponding to the selected P-state in MSRC001_0063[CurPstate]. // PutAllCoreInPState0 (PStateBufferPtr, StdHeader); return AGESA_SUCCESS; } /*---------------------------------------------------------------------------- * LOCAL FUNCTIONS * *---------------------------------------------------------------------------- */ /** *--------------------------------------------------------------------------------------- * * PutAllCoreInPState0 * * Description: * This function will put core pstate to p0. * * Parameters: * @param[in,out] *PStateBufferPtr * @param[in] *StdHeader * * @retval AGESA_STATUS * *--------------------------------------------------------------------------------------- **/ AGESA_STATUS PutAllCoreInPState0 ( IN OUT PSTATE_LEVELING *PStateBufferPtr, IN AMD_CONFIG_PARAMS *StdHeader ) { AP_TASK TaskPtr; UINT32 BscSocket; UINT32 Ignored; UINT32 BscCoreNum; UINT32 Core; UINT32 Socket; UINT32 NumberOfSockets; UINT32 NumberOfCores; AGESA_STATUS IgnoredSts; TaskPtr.FuncAddress.PfApTaskI = PutCoreInPState0; TaskPtr.DataTransfer.DataSizeInDwords = SIZE_IN_DWORDS (PSTATE_LEVELING); TaskPtr.ExeFlags = WAIT_FOR_CORE; TaskPtr.DataTransfer.DataPtr = PStateBufferPtr; TaskPtr.DataTransfer.DataTransferFlags = DATA_IN_MEMORY; IdentifyCore (StdHeader, &BscSocket, &Ignored, &BscCoreNum, &IgnoredSts); NumberOfSockets = GetPlatformNumberOfSockets (); PutCoreInPState0 (PStateBufferPtr, StdHeader); for (Socket = 0; Socket < NumberOfSockets; Socket++) { if (GetActiveCoresInGivenSocket (Socket, &NumberOfCores, StdHeader)) { for (Core = 0; Core < NumberOfCores; Core++) { if ((Socket != (UINT32) BscSocket) || (Core != (UINT32) BscCoreNum)) { ApUtilRunCodeOnSocketCore ((UINT8) Socket, (UINT8) Core, &TaskPtr, StdHeader); } } } } return AGESA_SUCCESS; } /** *--------------------------------------------------------------------------------------- * * CorePstateRegModify * * Description: * This function will setting the Pstate MSR to each APs base on Pstate Buffer. * Note: This function should be called for every core in the system. * * Parameters: * @param[in,out] *CpuAmdPState * @param[in] *StdHeader * * @retval VOID * *--------------------------------------------------------------------------------------- **/ VOID CorePstateRegModify ( IN VOID *CpuAmdPState, IN AMD_CONFIG_PARAMS *StdHeader ) { PSTATE_CPU_FAMILY_SERVICES *FamilySpecificServices; FamilySpecificServices = NULL; GetFeatureServicesOfCurrentCore (&PstateFamilyServiceTable, (CONST VOID **)&FamilySpecificServices, StdHeader); ASSERT (FamilySpecificServices != NULL) FamilySpecificServices->SetPStateLevelReg (FamilySpecificServices, (S_CPU_AMD_PSTATE *) CpuAmdPState, StdHeader); } /*---------------------------------------------------------------------------------------*/ /** * This function will set msr on all cores of all nodes. * * @param[in] CpuAmdPState Pointer to S_CPU_AMD_PSTATE. * @param[in] StdHeader Header for library and services. * * @retval AGESA_SUCCESS Always succeeds * */ AGESA_STATUS StartPstateMsrModify ( IN S_CPU_AMD_PSTATE *CpuAmdPState, IN AMD_CONFIG_PARAMS *StdHeader ) { AP_TASK TaskPtr; UINT32 BscSocket; UINT32 Ignored; UINT32 BscCoreNum; UINT32 Core; UINT32 Socket; UINT32 NumberOfSockets; UINT32 NumberOfCores; AGESA_STATUS IgnoredSts; TaskPtr.FuncAddress.PfApTaskI = CorePstateRegModify; TaskPtr.DataTransfer.DataSizeInDwords = (UINT16) (CpuAmdPState->SizeOfBytes / 4 + 1); TaskPtr.ExeFlags = WAIT_FOR_CORE; TaskPtr.DataTransfer.DataPtr = CpuAmdPState; TaskPtr.DataTransfer.DataTransferFlags = DATA_IN_MEMORY; IdentifyCore (StdHeader, &BscSocket, &Ignored, &BscCoreNum, &IgnoredSts); NumberOfSockets = GetPlatformNumberOfSockets (); CorePstateRegModify (CpuAmdPState, StdHeader); for (Socket = 0; Socket < NumberOfSockets; Socket++) { if (GetActiveCoresInGivenSocket (Socket, &NumberOfCores, StdHeader)) { for (Core = 0; Core < NumberOfCores; Core++) { if ((Socket != (UINT32) BscSocket) || (Core != (UINT32) BscCoreNum)) { ApUtilRunCodeOnSocketCore ((UINT8) Socket, (UINT8) Core, &TaskPtr, StdHeader); } } } } return AGESA_SUCCESS; } /** *--------------------------------------------------------------------------------------- * * CpuGetPStateLevelStructure * * Description: * Based on the LogicalSocketNumber, this function will return a pointer * point to the accurate offset of the PSTATE_LEVELING structure. * * Parameters: * @param[in,out] *PStateBufferPtr * @param[in] *CpuAmdPState * @param[in] LogicalSocketNumber * @param[in] *StdHeader * * @retval VOID * *--------------------------------------------------------------------------------------- **/ AGESA_STATUS CpuGetPStateLevelStructure ( OUT PSTATE_LEVELING **PStateBufferPtr, IN S_CPU_AMD_PSTATE *CpuAmdPState, IN UINT32 LogicalSocketNumber, IN AMD_CONFIG_PARAMS *StdHeader ) { PSTATE_LEVELING *PStateBufferPtrTmp; UINT32 i; if (LogicalSocketNumber > CpuAmdPState->TotalSocketInSystem) { return AGESA_UNSUPPORTED; } PStateBufferPtrTmp = CpuAmdPState->PStateLevelingStruc; for (i = 1; i <= LogicalSocketNumber; i++) { PStateBufferPtrTmp = (PSTATE_LEVELING *) ((UINT8 *) PStateBufferPtrTmp + ((UINTN) PStateBufferPtrTmp->PStateLevelingSizeOfBytes)); } *PStateBufferPtr = PStateBufferPtrTmp; return AGESA_SUCCESS; } /** *--------------------------------------------------------------------------------------- * * PutCoreInPState0 * * Description: * This function will take the CPU core into P0 * * Parameters: * @param[in] *PStateBuffer * @param[in] *StdHeader * * @retval VOID * *--------------------------------------------------------------------------------------- **/ VOID STATIC PutCoreInPState0 ( IN VOID *PStateBuffer, IN AMD_CONFIG_PARAMS *StdHeader ) { CPU_SPECIFIC_SERVICES *FamilySpecificServices; PSTATE_LEVELING *PStateBufferPtr; PStateBufferPtr = (PSTATE_LEVELING *) PStateBuffer; if ((PStateBufferPtr[0].SetPState0 == PSTATE_FLAG_1 ) || (PStateBufferPtr[0].SetPState0 == PSTATE_FLAG_2)) { return; } GetCpuServicesOfCurrentCore ((CONST CPU_SPECIFIC_SERVICES **)&FamilySpecificServices, StdHeader); FamilySpecificServices->TransitionPstate (FamilySpecificServices, (UINT8) 0, (BOOLEAN) FALSE, StdHeader); }