/* $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: 56279 $   @e \$Date: 2011-07-11 13:11:28 -0600 (Mon, 11 Jul 2011) $
 *
 */
/*****************************************************************************
 *
 * Copyright (C) 2012 Advanced Micro Devices, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of Advanced Micro Devices, Inc. nor the names of
 *       its contributors may be used to endorse or promote products derived
 *       from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL ADVANCED MICRO DEVICES, INC. BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 ******************************************************************************
 *----------------------------------------------------------------------------
 */


/*
 *----------------------------------------------------------------------------
 *                                MODULES USED
 *
 *----------------------------------------------------------------------------
 */
#include "AGESA.h"
#include "amdlib.h"
#include "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 (G2_PEI)

#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;
    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++) {
        if ((PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[k].CoreFreq !=
             PStateBufferPtrTmp->PStateCoreStruct[0].PStateStruct[k].CoreFreq) ||
            (PStateBufferPtr[0].PStateCoreStruct[0].PStateStruct[k].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;
      PStateBufferPtr[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);
}
