/* $NoKeywords:$ */
/**
 * @file
 *
 * AMD Integrated Debug library Routines
 *
 * Contains AMD AGESA debug macros and library functions
 *
 * @xrefitem bom "File Content Label" "Release Content"
 * @e project:      AGESA
 * @e sub-project:  IDS
 * @e \$Revision: 63425 $   @e \$Date: 2011-12-22 11:24:10 -0600 (Thu, 22 Dec 2011) $
 */
/*****************************************************************************
 * Copyright (c) 2008 - 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.
 ******************************************************************************
 */
/*----------------------------------------------------------------------------------------
 *                             M O D U L E S    U S E D
 *----------------------------------------------------------------------------------------
 */

#include "AGESA.h"
#include "Ids.h"
#include "amdlib.h"
#include "GeneralServices.h"
#include "cpuServices.h"
#include "cpuFamilyTranslation.h"
#include "cpuPstateTables.h"
#include "IdsLib.h"
#include "heapManager.h"

#include "mm.h"
#include "mn.h"
#include "cpuLateInit.h"
#include "Filecode.h"
CODE_GROUP (G1_PEICC)
RDATA_GROUP (G1_PEICC)

#define FILECODE PROC_IDS_LIBRARY_IDSLIB_FILECODE

/*----------------------------------------------------------------------------
 *                          DEFINITIONS AND MACROS
 *
 *----------------------------------------------------------------------------
 */
extern CPU_FAMILY_SUPPORT_TABLE            PstateFamilyServiceTable;

/*----------------------------------------------------------------------------
 *                            EXPORTED FUNCTIONS
 *
 *----------------------------------------------------------------------------
 */

/**
 *
 *  Get IDS NV table pointer in the AGESA Heap.
 *
 *  @param[in,out] IdsNvTable   The Pointer of IDS NV Table.
 *  @param[in,out] StdHeader    The Pointer of Standard Header.
 *
 *  @retval AGESA_SUCCESS       Success to get the pointer of NV Table.
 *  @retval AGESA_ERROR         Fail to get the pointer of NV Table.
 **/
AGESA_STATUS
AmdGetIdsNvTable (
  IN OUT   VOID  **IdsNvTable,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  AGESA_STATUS status;
  LOCATE_HEAP_PTR LocateHeapStructPtr;
  IDS_CONTROL_STRUCT *IdsCtrlPtr;

  LocateHeapStructPtr.BufferHandle = IDS_CONTROL_HANDLE;
  LocateHeapStructPtr.BufferPtr = NULL;
  status = HeapLocateBuffer (&LocateHeapStructPtr, StdHeader);
  if (status == AGESA_SUCCESS) {
    IdsCtrlPtr = (IDS_CONTROL_STRUCT *) LocateHeapStructPtr.BufferPtr;
    *IdsNvTable = LocateHeapStructPtr.BufferPtr + IdsCtrlPtr->IdsNvTableOffset;
  }
  return status;
}

/**
 *
 *  Get IDS Override Image Base Address
 *
 *  @param[in,out] IdsImageBase The Base Address of IDS Override Image.
 *  @param[in,out] StdHeader    The Pointer of Standard Header.
 *
 *  @retval AGESA_SUCCESS       Success to get the pointer of NV Table.
 *  @retval AGESA_ERROR         Fail to get the pointer of NV Table.
 *
 **/
#if 0
AGESA_STATUS
AmdGetIdsImagebase (
  IN OUT   UINT64 *IdsImageBase,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  AGESA_STATUS status;
  LOCATE_HEAP_PTR LocateHeapStructPtr;
  IDS_CONTROL_STRUCT *IdsCtrlPtr;

  LocateHeapStructPtr.BufferHandle = IDS_CONTROL_HANDLE;
  LocateHeapStructPtr.BufferPtr = NULL;
  status = HeapLocateBuffer (&LocateHeapStructPtr, StdHeader);
  if (status == AGESA_SUCCESS) {
    IdsCtrlPtr = (IDS_CONTROL_STRUCT *) LocateHeapStructPtr.BufferPtr;
    *IdsImageBase = IdsCtrlPtr->IdsImageBase;
  }
  return status;
}
#endif
/**
 *
 * Read IDS NV value in NV table.
 *
 * It searches the table until the Nv Id is found and return the NV value
 * in the table. Otherwise, return IDS_UNSUPPORTED.
 *
 * @param[in] IdsNvId       IDS NV ID
 * @param[in] NvTablePtr    NV Table pointer.
 * @param[in,out] StdHeader    The Pointer of Standard Header.
 *
 * @retval IDS_UNSUPPORTED  NV ID is not found in the table
 *         Other Value      The NV value
 *
 **/
IDS_STATUS
AmdIdsNvReader (
  IN       UINT16 IdsNvId,
  IN       IDS_NV_ITEM *NvTablePtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  IDS_STATUS Status;
  IDS_NV_ITEM *NvPtr;
  BOOLEAN IgnoreIdsDefault;
  AGESA_STATUS status;
  LOCATE_HEAP_PTR LocateHeapStructPtr;
  IDS_CONTROL_STRUCT *IdsCtrlPtr;

  IgnoreIdsDefault = FALSE;
  Status = IDS_UNSUPPORTED;
  NvPtr = NvTablePtr;

  if (NvPtr != NULL) {
    while (NvPtr->IdsNvId != AGESA_IDS_NV_END) {
      if (NvPtr->IdsNvId == IdsNvId) {
        break;
      } else {
        NvPtr ++;
      }
    }
    if ((NvPtr->IdsNvId != AGESA_IDS_NV_END)) {
      //Get IgnoreIdsDefault from heap
      LocateHeapStructPtr.BufferHandle = IDS_CONTROL_HANDLE;
      LocateHeapStructPtr.BufferPtr = NULL;
      status = HeapLocateBuffer (&LocateHeapStructPtr, StdHeader);
      if (status == AGESA_SUCCESS) {
        IdsCtrlPtr = (IDS_CONTROL_STRUCT *) LocateHeapStructPtr.BufferPtr;
        IgnoreIdsDefault = IdsCtrlPtr->IgnoreIdsDefault;
      }

      if (IgnoreIdsDefault || (NvPtr->IdsNvValue != AGESA_IDS_DFT_VAL)) {
        Status = NvPtr->IdsNvValue;
      }
    }
  }
  return Status;
}

/**
 * IDS function for only return IDS_SUCCESS
 *
 *
 *  @param[in,out]   DataPtr      meaningless data pointer
 *  @param[in,out]   StdHeader    The Pointer of AMD_CONFIG_PARAMS.
 *  @param[in]     IdsNvPtr     The Pointer of NV Table.
 *
 *  @retval IDS_SUCCESS          Always succeeds.
 *
 **/
IDS_STATUS
IdsCommonReturn (
  IN OUT   VOID *DataPtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader,
  IN       IDS_NV_ITEM *IdsNvPtr
  )
{
  return IDS_SUCCESS;
}


/**
 * IDS function for ap run specific task after amdinitpost
 *
 *
 *  @param[in]   ApicIdOfCore      apic id of specific AP
 *  @param[in]   ApLateTaskPtr    The Pointer of IDSAPLATETASK.
 *  @param[in,out]   StdHeader    The Pointer of AMD_CONFIG_PARAMS.
 *
 *  @retval AGESA_SUCCESS       Success
 *  @retval AGESA_ERROR         meet some error
 *
 **/
AGESA_STATUS
IdsAgesaRunFcnOnApLate  (
  IN       UINTN               ApicIdOfCore,
  IN       IDSAPLATETASK  *ApLateTaskPtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  AGESA_STATUS  Status;
  AP_EXE_PARAMS LaunchApParams;

//init AgesaRunFcnOnAp parameters
  LaunchApParams.FunctionNumber = IDS_LATE_RUN_AP_TASK_ID;
  LaunchApParams.RelatedBlockLength = SIZE_IN_DWORDS (IDSAPLATETASK);
  LaunchApParams.RelatedDataBlock = ApLateTaskPtr;
  LaunchApParams.StdHeader = *StdHeader;

  AGESA_TESTPOINT (TpIfBeforeRunApFromIds, StdHeader);
  Status = AgesaRunFcnOnAp ((UINTN) ApicIdOfCore, &LaunchApParams);
  AGESA_TESTPOINT (TpIfAfterRunApFromIds, StdHeader);

  return Status;
}

/**
 * IDS function force all cores run specific task after amdinitpost
 *
 *
 *  @param[in]   ApLateTaskPtr    The Pointer of IDSAPLATETASK.
 *  @param[in,out]   StdHeader    The Pointer of AMD_CONFIG_PARAMS.
 *
 *  @retval AGESA_SUCCESS       Success
 *  @retval AGESA_ERROR         meet some error
 *
 **/
AGESA_STATUS
IdsAgesaRunFcnOnAllCoresLate  (
  IN       IDSAPLATETASK  *ApLateTaskPtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  AP_EXE_PARAMS LaunchApParams;
  AGESA_STATUS Status;

//init AgesaRunFcnOnAp parameters
  Status = AGESA_SUCCESS;
  LaunchApParams.FunctionNumber = IDS_LATE_RUN_AP_TASK_ID;
  LaunchApParams.RelatedBlockLength = SIZE_IN_DWORDS (IDSAPLATETASK);
  LaunchApParams.RelatedDataBlock = ApLateTaskPtr;
  LaunchApParams.StdHeader = *StdHeader;

  Status = RunLateApTaskOnAllAPs (&LaunchApParams, StdHeader);

//do it on Bsp
  Status = ApLateTaskPtr->ApTask (ApLateTaskPtr->ApTaskPara, StdHeader);
  return Status;
}

/**
 * IDS call-back function for ApDispatchTable
 *
 *  @param[in] AmdApExeParams  AP_EXE_PARAMS.
 *
 *  @retval AGESA_SUCCESS       Success
 *  @retval AGESA_ERROR         meet some error
 *
 **/
AGESA_STATUS
AmdIdsRunApTaskLate (
  IN       AP_EXE_PARAMS  *AmdApExeParams
  )
{
  IDSAPLATETASK *ApLateTaskPtr;
  AGESA_STATUS Status;

  ApLateTaskPtr = (IDSAPLATETASK *)AmdApExeParams->RelatedDataBlock;
  Status = ApLateTaskPtr->ApTask (ApLateTaskPtr->ApTaskPara, &AmdApExeParams->StdHeader);
  return Status;
}

/**
 *  Get the number of P-State to support
 *
 *  @param[in,out] StdHeader The Pointer of AMD_CONFIG_PARAMS.
 *
 *  @retval num    The number of P-State to support.
 *
 **/
UINT8
IdsGetNumPstatesFamCommon (
  IN OUT   AMD_CONFIG_PARAMS  *StdHeader
  )
{
  UINT8 pstatesnum;
  UINT8 i;
  UINT8 IgnoredByte;
  UINT32 Ignored;
  BOOLEAN PStateEnabled;
  UINT32 TempVar_c;
  PSTATE_CPU_FAMILY_SERVICES  *FamilyServices;

  pstatesnum = 0;
  GetFeatureServicesOfCurrentCore (&PstateFamilyServiceTable, (CONST VOID **)&FamilyServices, StdHeader);
  ASSERT (FamilyServices != NULL);

  FamilyServices->GetPstateMaxState (FamilyServices, &TempVar_c, &IgnoredByte, StdHeader);
  for (i = 0; i <= TempVar_c; i++) {
    // Check if PState is enabled
    FamilyServices->GetPstateRegisterInfo (        FamilyServices,
                                                   (UINT32) i,
                                                   &PStateEnabled,
                                                   &Ignored,
                                                   &Ignored,
                                                   &Ignored,
                                                   StdHeader);
    if (PStateEnabled) {
      pstatesnum++;
    }
  }
  return pstatesnum;
}

/*---------------------------------------------------------------------------------------*/
/**
 * Runs the given task on all cores (including self) on the socket of the executing
 * core 0.
 *
 * This function is used to invoke all APs on the socket of the executing core 0 to
 * run a specified AGESA procedure.
 *
 * @param[in]  TaskPtr      Function descriptor
 * @param[in]  StdHeader    Config handle for library and services
 *
 */
VOID
IdsApRunCodeOnAllLocalCores (
  IN       AP_TASK *TaskPtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 Core;
  UINT32 BscCoreNum;
  UINT32 Socket;
  UINT32 BscSocket;
  UINT32 IgnoredModule;
  UINT32 NumberOfCores;
  UINT32 NumberOfSockets;
  AGESA_STATUS IgnoredSts;

  IdentifyCore (StdHeader, &BscSocket, &IgnoredModule, &BscCoreNum, &IgnoredSts);
  NumberOfSockets = GetPlatformNumberOfSockets ();


  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);
        }
      }
    }
  }
 // BSP codes
  ApUtilTaskOnExecutingCore (TaskPtr, StdHeader, NULL);
}

/**
 *  IdsMakePciRegEntry
 *
 *
 *  @param[in,out]      TableEntry      The Pointer of TableEntry
*  @param[in]      Family      Family
*  @param[in]      Revision      Revision
*  @param[in]      PciAddr      PCI address
*  @param[in]      Data      Or Mask
*  @param[in]      Mask      And Mask
 *
 *
 */
VOID
IdsMakePciRegEntry (
  IN OUT   TABLE_ENTRY_FIELDS **TableEntry,
  IN       UINT64 Family,
  IN       UINT64 Revision,
  IN       UINT32 PciAddr,
  IN       UINT32 Data,
  IN       UINT32 Mask
  )
{
  (*TableEntry)->EntryType = PciRegister;
  (*TableEntry)->CpuRevision.Family = Family;
  (*TableEntry)->CpuRevision.Revision = Revision;
  (*TableEntry)->Features.PlatformValue = AMD_PF_ALL;
  (*TableEntry)->Entry.PciEntry.Address.AddressValue = PciAddr;
  (*TableEntry)->Entry.PciEntry.Data = Data;
  (*TableEntry)->Entry.PciEntry.Mask = Mask;
  (*TableEntry)++;
}

/**
 *  IdsMakeHtLinkPciRegEntry
 *
 *
 *  @param[in,out]      TableEntry      The Pointer of TableEntry
*  @param[in]      Family      Family
*  @param[in]      Revision      Revision
*  @param[in]      HtHostFeat      HtHostFeat
*  @param[in]      PciAddr      PCI address
*  @param[in]      Data      Or Mask
*  @param[in]      Mask      And Mask
 *
 *
 */
VOID
IdsMakeHtLinkPciRegEntry (
  IN OUT   TABLE_ENTRY_FIELDS **TableEntry,
  IN       UINT64 Family,
  IN       UINT64 Revision,
  IN       UINT32 HtHostFeat,
  IN       UINT32 PciAddr,
  IN       UINT32 Data,
  IN       UINT32 Mask
  )
{
  (*TableEntry)->EntryType = HtLinkPciRegister;
  (*TableEntry)->CpuRevision.Family = Family;
  (*TableEntry)->CpuRevision.Revision = Revision;
  (*TableEntry)->Features.PlatformValue = AMD_PF_ALL;
  (*TableEntry)->Entry.HtLinkPciEntry.LinkFeats.HtHostValue = HtHostFeat;
  (*TableEntry)->Entry.HtLinkPciEntry.PciEntry.Address.AddressValue = PciAddr;
  (*TableEntry)->Entry.HtLinkPciEntry.PciEntry.Data = Data;
  (*TableEntry)->Entry.HtLinkPciEntry.PciEntry.Mask = Mask;
  (*TableEntry)++;
}
/**
 *  IdsMakeHtFeatPciRegEntry
 *
 *
 *  @param[in,out]      TableEntry      The Pointer of TableEntry
*  @param[in]      Family      Family
*  @param[in]      Revision      Revision
*  @param[in]      HtHostFeat      HtHostFeat
*  @param[in]      PackageType      PackageType
*  @param[in]      PciAddr      PCI address
*  @param[in]      Data      Or Mask
*  @param[in]      Mask      And Mask
 *
 *
 */
VOID
IdsMakeHtFeatPciRegEntry (
  IN OUT   TABLE_ENTRY_FIELDS **TableEntry,
  IN       UINT64 Family,
  IN       UINT64 Revision,
  IN       UINT32 HtHostFeat,
  IN       UINT32 PackageType,
  IN       UINT32 PciAddr,
  IN       UINT32 Data,
  IN       UINT32 Mask
  )
{
  (*TableEntry)->EntryType = HtFeatPciRegister;
  (*TableEntry)->CpuRevision.Family = Family;
  (*TableEntry)->CpuRevision.Revision = Revision;
  (*TableEntry)->Features.PlatformValue = AMD_PF_ALL;
  (*TableEntry)->Entry.HtFeatPciEntry.LinkFeats.HtHostValue = HtHostFeat;
  (*TableEntry)->Entry.HtFeatPciEntry.PackageType.PackageTypeValue = PackageType;
  (*TableEntry)->Entry.HtFeatPciEntry.PciEntry.Address.AddressValue = PciAddr;
  (*TableEntry)->Entry.HtFeatPciEntry.PciEntry.Data = Data;
  (*TableEntry)->Entry.HtFeatPciEntry.PciEntry.Mask = Mask;
  (*TableEntry)++;
}
/**
 *  IdsMakeHostPciRegEntry
 *
 *
 *  @param[in,out]      TableEntry      The Pointer of TableEntry
*  @param[in]      Family      Family
*  @param[in]      Revision      Revision
*  @param[in]      HtHostFeat      HtHostFeat
*  @param[in]      PciAddr      PCI address
*  @param[in]      Data      Or Mask
*  @param[in]      Mask      And Mask
 *
 *
 */
VOID
IdsMakeHtHostPciRegEntry (
  IN OUT   TABLE_ENTRY_FIELDS **TableEntry,
  IN       UINT64 Family,
  IN       UINT64 Revision,
  IN       UINT32 HtHostFeat,
  IN       UINT32 PciAddr,
  IN       UINT32 Data,
  IN       UINT32 Mask
  )
{
  (*TableEntry)->EntryType = HtHostPciRegister;
  (*TableEntry)->CpuRevision.Family = Family;
  (*TableEntry)->CpuRevision.Revision = Revision;
  (*TableEntry)->Features.PlatformValue = AMD_PF_ALL;
  (*TableEntry)->Entry.HtHostEntry.TypeFeats.HtHostValue = HtHostFeat;
  (*TableEntry)->Entry.HtHostEntry.Address.AddressValue = PciAddr;
  (*TableEntry)->Entry.HtHostEntry.Data = Data;
  (*TableEntry)->Entry.HtHostEntry.Mask = Mask;
  (*TableEntry)++;
}
/**
 *  IdsMakeHtPhyRegEntry
 *
 *
 *  @param[in,out]      TableEntry      The Pointer of TableEntry
*  @param[in]      Family      Family
*  @param[in]      Revision      Revision
*  @param[in]      HtPhyLinkFeat      HtPhyLinkFeat
*  @param[in]      Address      PCI address
*  @param[in]      Data      Or Mask
*  @param[in]      Mask      And Mask
 *
 *
 */
VOID
IdsMakeHtPhyRegEntry (
  IN OUT   TABLE_ENTRY_FIELDS **TableEntry,
  IN       UINT64 Family,
  IN       UINT64 Revision,
  IN       UINT32 HtPhyLinkFeat,
  IN       UINT32 Address,
  IN       UINT32 Data,
  IN       UINT32 Mask
  )
{
  (*TableEntry)->EntryType = HtPhyRegister;
  (*TableEntry)->CpuRevision.Family = Family;
  (*TableEntry)->CpuRevision.Revision = Revision;
  (*TableEntry)->Features.PlatformValue = AMD_PF_ALL;
  (*TableEntry)->Entry.HtPhyEntry.TypeFeats.HtPhyLinkValue = HtPhyLinkFeat;
  (*TableEntry)->Entry.HtPhyEntry.Address = Address;
  (*TableEntry)->Entry.HtPhyEntry.Data = Data;
  (*TableEntry)->Entry.HtPhyEntry.Mask = Mask;
  (*TableEntry)++;
}

/**
 *  IdsOptionCallout
 *
 * Description
 *    Call the host environment interface to provide a user hook opportunity.
 *
 *  @param[in]      CallOutId         This parameter indicates the IDS Call-Out-function desired.
 *  @param[in,out]  DataPtr           The pointer for callout function use
 *  @param[in,out]  StdHeader    Config handle for library and services
 *
 *  @retval AGESA_SUCCESS       Success
 *  @retval AGESA_ERROR         meet some error
 *
 */
AGESA_STATUS
IdsOptionCallout (
  IN       UINTN                CallOutId,
  IN OUT   VOID *DataPtr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  IDS_CALLOUT_STRUCT IdsCalloutData;
  IDS_NV_ITEM NullEntry;

  NullEntry.IdsNvId = 0xFFFF;
  NullEntry.IdsNvValue = 0xFFFF;
  IdsCalloutData.StdHeader = *StdHeader;
  IdsCalloutData.IdsNvPtr = &NullEntry;
  IdsCalloutData.Reserved = (UINTN) DataPtr;

  return AgesaGetIdsData (CallOutId, &IdsCalloutData);

}

/**
 * Ids Write PCI register to All node
 *
 *
 * @param[in] PciAddress    Pci address
 * @param[in]   Highbit       High bit position of the field in DWORD
 * @param[in]   Lowbit        Low bit position of the field in DWORD
 * @param[in] Value         Pointer to input value
 * @param[in] StdHeader     Standard configuration header
 *
 */
VOID
IdsLibPciWriteBitsToAllNode (
  IN       PCI_ADDR PciAddress,
  IN       UINT8 Highbit,
  IN       UINT8 Lowbit,
  IN       UINT32 *Value,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 Socket;
  UINT32 Module;
  AGESA_STATUS IgnoreStatus;
  PCI_ADDR PciAddr;


  for (Socket = 0; Socket < GetPlatformNumberOfSockets (); Socket++) {
    for (Module = 0; Module < GetPlatformNumberOfModules (); Module++) {
      if (GetPciAddress (StdHeader, Socket, Module, &PciAddr, &IgnoreStatus)) {
        PciAddr.Address.Function = PciAddress.Address.Function;
        PciAddr.Address.Register = PciAddress.Address.Register;
        LibAmdPciWriteBits (PciAddr, Highbit, Lowbit, Value, StdHeader);
      }
    }
  }
}

/**
 *
 *
 *     Core 0 task to run local ap task at early
 *
 *     @param[in]   PEarlyApTask   - point to  IDS_EARLY_AP_TASK structure
 *     @param[in,out]   StdHeader    - The Pointer of AGESA Header
 *
 */

STATIC VOID
IdsCmnTaskCore0Early (
  IN       IDS_EARLY_AP_TASK *PEarlyApTask,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 Socket;
  UINT32 IgnoredModule;
  UINT32 IgnoredCore;
  AGESA_STATUS IgnoredSts;

  ASSERT (PEarlyApTask->Ap_Task0.Core != 0);

  PEarlyApTask->Ap_Task0.ApTask.DataTransfer.DataPtr = &PEarlyApTask->Parameters[0];
  IdentifyCore (StdHeader, &Socket, &IgnoredModule, &IgnoredCore, &IgnoredSts);
  ApUtilRunCodeOnSocketCore ((UINT8)Socket, PEarlyApTask->Ap_Task0.Core, &PEarlyApTask->Ap_Task0.ApTask, StdHeader);
}

/**
 *
 *
 *     BSC task to run Core0 task at early, must only run on BSC
 *
 *     @param[in]   Socket   - Socket which run the task
 *     @param[in]   Core   - Core which run the task
 *     @param[in]   ApTask   - Task for AP
 *     @param[in,out]   StdHeader    - The Pointer of AGESA Header
 *
 */
VOID
IdsRunCodeOnCoreEarly (
  IN       UINT8 Socket,
  IN       UINT8 Core,
  IN       AP_TASK* ApTask,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  UINT32 BscSocket;
  UINT32 BscCoreNum;
  UINT32 IgnoredModule;
  AGESA_STATUS IgnoredSts;
  AP_TASK Core0Task;
  IDS_EARLY_AP_TASK IdsEarlyTask;

  IdentifyCore (StdHeader, &BscSocket, &IgnoredModule, &BscCoreNum, &IgnoredSts);
  ASSERT (!((Socket == BscSocket) && (Core == BscCoreNum)));
  if ((Socket == BscSocket) || (Core == 0)) {
    ApUtilRunCodeOnSocketCore (Socket, Core, ApTask, StdHeader);
  } else {
    //Init IDS_EARLY_AP_TASK for Core 0
    IdsEarlyTask.Ap_Task0.ApTask = *ApTask;
    IdsEarlyTask.Ap_Task0.Core = Core;
    //Init Parameter buffer, Target core can't get the parameter from pointer, which point to Host Core memory space
    ASSERT ((ApTask->DataTransfer.DataSizeInDwords * sizeof (UINT32)) <= IDS_EARLY_AP_TASK_PARA_NUM);
    LibAmdMemCopy (&IdsEarlyTask.Parameters[0], ApTask->DataTransfer.DataPtr, sizeof (UINT32) * ApTask->DataTransfer.DataSizeInDwords, StdHeader);
    if ((ApTask->DataTransfer.DataSizeInDwords * sizeof (UINT32)) <= IDS_EARLY_AP_TASK_PARA_NUM) {
      //Lauch Core0 1st
      Core0Task.FuncAddress.PfApTaskI = (PF_AP_TASK_I)IdsCmnTaskCore0Early;
      Core0Task.ExeFlags = WAIT_FOR_CORE;
      Core0Task.DataTransfer.DataSizeInDwords = SIZE_IN_DWORDS (IDS_EARLY_AP_TASK0) + ApTask->DataTransfer.DataSizeInDwords;
      Core0Task.DataTransfer.DataPtr = &IdsEarlyTask;
      Core0Task.DataTransfer.DataTransferFlags = 0;
      ApUtilRunCodeOnSocketCore (Socket, 0, &Core0Task, StdHeader);
    }
  }
}

/**
 *
 *
 *     This function get start end Module according to input ModuleId
 *
 *     @param[in]   ModuleId   - 0xFF means all nodes, other value Specifies real NodeId
 *     @param[in,out]   StartModule    - Point to start Node
 *     @param[in,out]   EndModule   - Point to end Node
 *
 */
VOID
IdsGetStartEndModule (
  IN       UINT8  ModuleId,
  IN OUT   UINT8 *StartModule,
  IN OUT   UINT8 *EndModule
  )
{
  if (ModuleId == 0xFF) {
    *StartModule = 0;
    *EndModule = (UINT8) (GetPlatformNumberOfSockets () * GetPlatformNumberOfModules () - 1);
    if (*EndModule > 7) {
      *EndModule = 7;
    }
  } else {
    *StartModule = ModuleId;
    *EndModule = ModuleId;
  }
}

/**
 *
 *
 *     This function get start end socket according to input SocketId
 *
 *     @param[in]   SocketId   - 0xFF means all sockets, other value Specifies real SokcetId
 *     @param[in,out]   StartSocket    - Point to start Socket
 *     @param[in,out]   EndSocket   - Point to end Socket
 *
 */
VOID
IdsGetStartEndSocket (
  IN       UINT8  SocketId,
  IN OUT   UINT8 *StartSocket,
  IN OUT   UINT8 *EndSocket
  )
{
  if (SocketId == 0xFF) {
    *StartSocket = 0;
    *EndSocket = (UINT8) (GetPlatformNumberOfSockets () - 1);
  } else {
    *StartSocket = SocketId;
    *EndSocket = SocketId;
  }
}

/**
 *
 *
 *     This function transfer input High low bit to Mask
 *
 *     @param[in]   RegVal   - Regval want to set
 *     @param[in]   Highbit   - (0~63)
 *     @param[in]   Lowbit    - (0~63)
 *     @param[in,out]   AndMask   - point value contain output AndMask
 *     @param[in,out]   OrMask   - point value contain output OrMask
 *
 */
VOID
IdsGetMask64bits (
  IN       UINT64 RegVal,
  IN       UINT8  Highbit,
  IN       UINT8  Lowbit,
  IN OUT   UINT64 *AndMask,
  IN OUT   UINT64 *OrMask
  )
{
  UINT64 Mask;

  if ((Highbit - Lowbit) != 63) {
    Mask = (((UINT64) 1 << (Highbit - Lowbit + 1)) - 1);
  } else {
    Mask = (UINT64) 0xFFFFFFFFFFFFFFFF;
  }
  *AndMask = ~(Mask << Lowbit);
  *OrMask = (RegVal & Mask) << Lowbit;
}
/**
 *
 *
 *     This function transfer input High low bit to Mask
 *
 *     @param[in]   RegVal   - Regval want to set
 *     @param[in]   Highbit   - (0~31)
 *     @param[in]   Lowbit    - (0~31)
 *     @param[in,out]   AndMask   - point value contain output AndMask
 *     @param[in,out]   OrMask   - point value contain output OrMask
 *
 */

VOID
IdsGetMask32bits (
  IN       UINT32 RegVal,
  IN       UINT8  Highbit,
  IN       UINT8  Lowbit,
  IN OUT   UINT32 *AndMask,
  IN OUT   UINT32 *OrMask
  )
{
  UINT32 Mask;

  if ((Highbit - Lowbit) != 31) {
    Mask = (((UINT32) 1 << (Highbit - Lowbit + 1)) - 1);
  } else {
    Mask = (UINT32) 0xFFFFFFFF;
  }
  *AndMask = ~(Mask << Lowbit);
  *OrMask = (RegVal & Mask) << Lowbit;

}
/**
 *
 *
 *     This function transfer input High low bit to Mask
 *
 *     @param[in]   RegVal   - Regval want to set
 *     @param[in]   Highbit   - (0~15)
 *     @param[in]   Lowbit    - (0~15)
 *     @param[in,out]   AndMask   - point value contain output AndMask
 *     @param[in,out]   OrMask   - point value contain output OrMask
 *
 */

VOID
IdsGetMask16bits (
  IN       UINT16 RegVal,
  IN       UINT8  Highbit,
  IN       UINT8  Lowbit,
  IN OUT   UINT32 *AndMask,
  IN OUT   UINT32 *OrMask
  )
{
  UINT16 Mask;

  if ((Highbit - Lowbit) != 15) {
    Mask = (((UINT16) 1 << (Highbit - Lowbit + 1)) - 1);
  } else {
    Mask = (UINT16) 0xFFFF;
  }
  *AndMask = ~(Mask << Lowbit);
  *OrMask = (RegVal & Mask) << Lowbit;
}

/**
 *
 *
 *     IdsCheckPciExisit
 *     Use to check is the PCI device exisit of given address
 *
 *     @param[in]   PciAddr   - Given PCI address
 *     @param[in,out]   StdHeader    - The Pointer of AGESA Header
 *
 *     @retval TRUE         The PCI device exisit
 *     @retval FALSE        The PCI device doesn't exisit
 *
 *
 */
BOOLEAN
IdsCheckPciExisit (
  IN       PCI_ADDR PciAddr,
  IN OUT   AMD_CONFIG_PARAMS *StdHeader
  )
{
  PCI_ADDR _pciaddr;
  UINT32 _pcidata;
  BOOLEAN status;

  status = FALSE;
  _pciaddr = PciAddr;
  _pciaddr.Address.Register = 0;
  LibAmdPciRead (AccessWidth32, _pciaddr, &_pcidata, StdHeader);
  if (_pcidata != 0xFFFFFFFF || _pcidata != 0) {
    status = TRUE;
  }
  return status;
}

/**
 *
 *
 *     This function transfer input High low bit to Mask
 *
 *     @param[in,out]   Value   - Regval want to And Or with Mask
 *     @param[in]   AndMask   - AndMask
 *     @param[in]   OrMask   - OrMask
 *
 */

VOID
IdsLibDataMaskSet32 (
  IN OUT   UINT32 *Value,
  IN       UINT32  AndMask,
  IN       UINT32  OrMask
  )
{
  *Value &= AndMask;
  *Value |= OrMask;
}



VOID
IdsOutPort (
  IN       UINT32 Addr,
  IN       UINT32 Value,
  IN       UINT32 Flag
  )
{
  __outdword ((UINT16) Addr, Value);
}
