331 lines
9.7 KiB
C
331 lines
9.7 KiB
C
/** @file
|
|
This is the driver that initializes the Intel System Agent.
|
|
|
|
@copyright
|
|
INTEL CONFIDENTIAL
|
|
Copyright 2015 - 2021 Intel Corporation.
|
|
|
|
The source code contained or described herein and all documents related to the
|
|
source code ("Material") are owned by Intel Corporation or its suppliers or
|
|
licensors. Title to the Material remains with Intel Corporation or its suppliers
|
|
and licensors. The Material may contain trade secrets and proprietary and
|
|
confidential information of Intel Corporation and its suppliers and licensors,
|
|
and is protected by worldwide copyright and trade secret laws and treaty
|
|
provisions. No part of the Material may be used, copied, reproduced, modified,
|
|
published, uploaded, posted, transmitted, distributed, or disclosed in any way
|
|
without Intel's prior express written permission.
|
|
|
|
No license under any patent, copyright, trade secret or other intellectual
|
|
property right is granted to or conferred upon you by disclosure or delivery
|
|
of the Materials, either expressly, by implication, inducement, estoppel or
|
|
otherwise. Any license under such intellectual property rights must be
|
|
express and approved by Intel in writing.
|
|
|
|
Unless otherwise agreed by Intel in writing, you may not remove or alter
|
|
this notice or any other notice embedded in Materials by Intel or
|
|
Intel's suppliers or licensors in any way.
|
|
|
|
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
|
|
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
|
|
the terms of your license agreement with Intel or your vendor. This file may
|
|
be modified by the user, subject to additional terms of the license agreement.
|
|
|
|
@par Specification Reference:
|
|
**/
|
|
#include "SaInitDxe.h"
|
|
#include "SaInit.h"
|
|
#include <SaConfigHob.h>
|
|
#include <PcieRegs.h>
|
|
#include <CpuSbInfo.h>
|
|
#include <MemInfoHob.h>
|
|
#include <Protocol/SaIotrapSmi.h>
|
|
#include <Protocol/PciEnumerationComplete.h>
|
|
#include <Library/TelemetryPrivateLib.h>
|
|
#include <Library/CpuPlatformLib.h>
|
|
#include <Library/CpuPcieRpLib.h>
|
|
#include <Library/CpuPcieInfoFruLib.h>
|
|
#include <Library/VmdInfoLib.h>
|
|
#include <Library/DxeIpuInit.h>
|
|
#include <Library/PcieHelperLib.h>
|
|
#include <Library/CpuRegbarAccessLib.h>
|
|
#include <Library/PreSiliconEnvDetectLib.h>
|
|
#include <Register/CpuPcieRegs.h>
|
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress;
|
|
|
|
///
|
|
/// Global Variables
|
|
///
|
|
extern SA_CONFIG_HOB *mSaConfigHob;
|
|
|
|
VOID
|
|
EFIAPI
|
|
SaOnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
);
|
|
|
|
|
|
/**
|
|
SystemAgent Dxe Initialization.
|
|
|
|
@param[in] ImageHandle Handle for the image of this driver
|
|
@param[in] SystemTable Pointer to the EFI System Table
|
|
|
|
@retval EFI_SUCCESS The function completed successfully
|
|
@retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
SaInitEntryPointDxe (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *Registration;
|
|
#if FixedPcdGetBool(PcdFspWrapperEnable) == 0
|
|
EFI_EVENT Event;
|
|
#endif
|
|
|
|
EFI_EVENT ReadyToBoot;
|
|
|
|
|
|
DEBUG ((DEBUG_INFO, "SaInitDxe Start\n"));
|
|
|
|
#if (FixedPcdGetBool (PcdVmdEnable) == 1)
|
|
ClearVmdTempBars();
|
|
#endif
|
|
|
|
SaInitEntryPoint ();
|
|
|
|
Status = SaAcpiInit (ImageHandle);
|
|
///
|
|
/// Create PCI Enumeration Completed callback for CPU PCIe
|
|
///
|
|
EfiCreateProtocolNotifyEvent (
|
|
&gEfiPciEnumerationCompleteProtocolGuid,
|
|
TPL_CALLBACK,
|
|
CpuPciEnumCompleteCallback,
|
|
NULL,
|
|
&Registration
|
|
);
|
|
#if FixedPcdGetBool(PcdFspWrapperEnable) == 0
|
|
DEBUG ((DEBUG_INFO, "RegisterForExitBootService() to set PAM lock before OS handoff\n"));
|
|
Status = EfiCreateEventLegacyBootEx (
|
|
TPL_CALLBACK,
|
|
SaPamLockDxe,
|
|
NULL,
|
|
&Event
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
Status = gBS->CreateEvent (
|
|
EVT_SIGNAL_EXIT_BOOT_SERVICES,
|
|
TPL_CALLBACK,
|
|
SaPamLockDxe,
|
|
NULL,
|
|
&Event
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
#endif
|
|
|
|
//
|
|
// Register a Ready to boot event to config PCIE power management setting after OPROM executed
|
|
//
|
|
Status = EfiCreateEventReadyToBootEx (
|
|
TPL_CALLBACK,
|
|
SaOnReadyToBoot,
|
|
NULL,
|
|
&ReadyToBoot
|
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
|
|
|
DEBUG ((DEBUG_INFO, "SaInitDxe End\n"));
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Do PCIE power management while resume from S3
|
|
**/
|
|
VOID
|
|
ReconfigureCpuPciePowerManagementForS3 (
|
|
VOID
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 Data32;
|
|
SA_IOTRAP_SMI_PROTOCOL *CpuPcieIoTrapProtocol;
|
|
|
|
Status = gBS->LocateProtocol (&gCpuPcieIoTrapProtocolGuid, NULL, (VOID **) &CpuPcieIoTrapProtocol);
|
|
if (EFI_ERROR (Status)) {
|
|
return;
|
|
}
|
|
mPcieIoTrapAddress = CpuPcieIoTrapProtocol->SaIotrapSmiAddress;
|
|
DEBUG ((DEBUG_INFO, "PcieIoTrapAddress: %0x\n", mPcieIoTrapAddress));
|
|
|
|
if (mPcieIoTrapAddress != 0) {
|
|
//
|
|
// Save PCH PCIE IoTrap address to re-config PCIE power management setting after resume from S3
|
|
//
|
|
Data32 = CpuPciePmTrap;
|
|
S3BootScriptSaveIoWrite (
|
|
S3BootScriptWidthUint32,
|
|
(UINTN) (mPcieIoTrapAddress),
|
|
1,
|
|
&Data32
|
|
);
|
|
} else {
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|
|
|
|
/**
|
|
This function updates dekel register based on L0s is enabled or not
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
CpuPcieDekelRegUpdate (
|
|
VOID
|
|
)
|
|
{
|
|
UINT32 RpIndex;
|
|
UINT64 RpBase;
|
|
UINT8 CapId;
|
|
UINT16 Data16;
|
|
CPU_SB_DEVICE_PID CpuSbDevicePid;
|
|
|
|
DEBUG ((DEBUG_INFO, "CpuPcieDekelRegUpdate () Start\n"));
|
|
|
|
for (RpIndex = 0; RpIndex < GetMaxCpuPciePortNum(); RpIndex++) {
|
|
if (GetCpuPcieSipInfo(RpIndex) == PCIE_SIP16) {
|
|
RpBase = CpuPcieBase (RpIndex);
|
|
CapId = PcieBaseFindCapId (RpBase, EFI_PCI_CAPABILITY_ID_PCIEXP);
|
|
Data16 = ((PciSegmentRead16 (RpBase + CapId + R_PCIE_LCTL_OFFSET)) & B_PCIE_LCTL_ASPM);
|
|
CpuSbDevicePid = CPU_SB_PID_PCIE_PHYx4_0;
|
|
if (RpIndex == 2) {
|
|
CpuSbDevicePid = CPU_SB_PID_PCIE_PHYx4_2;
|
|
}
|
|
if (Data16 == V_PCIE_LCTL_ASPM_L0S || Data16 == V_PCIE_LCTL_ASPM_L0S_L1) {
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_CMN_DIG_DWORD54, 0x3A2024A0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE0_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE1_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE2_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE3_PMD_LANE_SUSWEL_SQUELCH, 0x3A2024A0);
|
|
} else {
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_CMN_DIG_DWORD54, 0x3A202FA0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE0_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE1_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE2_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0);
|
|
CpuRegbarWrite32 (CpuSbDevicePid, R_DEKEL_PCS_LANE3_PMD_LANE_SUSWEL_SQUELCH, 0x3A202FA0);
|
|
}
|
|
}
|
|
}
|
|
DEBUG ((DEBUG_INFO, "CpuPcieDekelRegUpdate () End\n"));
|
|
}
|
|
|
|
/**
|
|
SA initialization before boot to OS
|
|
|
|
@param[in] Event A pointer to the Event that triggered the callback.
|
|
@param[in] Context A pointer to private data registered with the callback function.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SaOnReadyToBoot (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "Uefi SaOnReadyToBoot() Start\n"));
|
|
|
|
if (Event != NULL) {
|
|
gBS->CloseEvent (Event);
|
|
}
|
|
|
|
//
|
|
// Trigger an Iotrap SMI to config PCIE power management setting after PCI enumrate is done
|
|
//
|
|
#if FixedPcdGetBool(PcdCpuPcieEnable) == 1
|
|
if (mPcieIoTrapAddress != 0) {
|
|
IoWrite32 ((UINTN) mPcieIoTrapAddress, CpuPciePmTrap);
|
|
} else {
|
|
ASSERT(FALSE);
|
|
}
|
|
#endif
|
|
//
|
|
// Update Dekel register
|
|
//
|
|
if (!IsSimicsEnvironment ()) {
|
|
CpuPcieDekelRegUpdate ();
|
|
}
|
|
DEBUG ((DEBUG_INFO, "Uefi SaOnReadyToBoot() End\n"));
|
|
}
|
|
|
|
|
|
/**
|
|
This function gets registered as a callback to perform CPU PCIe initialization before EndOfDxe
|
|
|
|
@param[in] Event - A pointer to the Event that triggered the callback.
|
|
@param[in] Context - A pointer to private data registered with the callback function.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
CpuPciEnumCompleteCallback (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
VOID *ProtocolPointer;
|
|
|
|
DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback Start\n"));
|
|
///
|
|
/// Check if this is first time called by EfiCreateProtocolNotifyEvent() or not,
|
|
/// if it is, we will skip it until real event is triggered
|
|
///
|
|
Status = gBS->LocateProtocol (&gEfiPciEnumerationCompleteProtocolGuid, NULL, (VOID **) &ProtocolPointer);
|
|
if (EFI_SUCCESS != Status) {
|
|
return;
|
|
}
|
|
|
|
gBS->CloseEvent (Event);
|
|
|
|
ReconfigureCpuPciePowerManagementForS3 ();
|
|
SaveGfxBarForS3 ();
|
|
SaveIpuBarForS3 ();
|
|
//
|
|
// Routine for update DMAR
|
|
//
|
|
UpdateDmarEndOfPcieEnum ();
|
|
UpdateSaGnvsForMmioResourceBaseLength ();
|
|
#if FixedPcdGetBool(PcdFspWrapperEnable) == 0
|
|
TelemetryMseEn ();
|
|
#endif
|
|
DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback End\n"));
|
|
return;
|
|
}
|
|
|
|
/**
|
|
This function locks the PAM register as part of the SA Security requirements.
|
|
|
|
@param[in] Event - A pointer to the Event that triggered the callback.
|
|
@param[in] Context - A pointer to private data registered with the callback function.
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
SaPamLockDxe (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
DEBUG ((DEBUG_INFO, "SaPamLockDxe Start\n"));
|
|
|
|
SaPamLock ();
|
|
|
|
DEBUG ((DEBUG_INFO, "SaPamLockDxe End\n"));
|
|
}
|
|
|