/** @file
This is the driver that initializes the Intel System Agent.
Copyright (c) 2021, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "SaInitDxe.h"
#include "SaInit.h"
#include
#include
#include
#include
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mPcieIoTrapAddress;
///
/// Global Variables
///
extern SA_CONFIG_HOB *mSaConfigHob;
/**
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;
EFI_EVENT ReadyToBoot;
DEBUG ((DEBUG_INFO, "SaInitDxe Start\n"));
SaInitEntryPoint ();
Status = SaAcpiInit (ImageHandle);
///
/// Create PCI Enumeration Completed callback for CPU PCIe
///
EfiCreateProtocolNotifyEvent (
&gEfiPciEnumerationCompleteProtocolGuid,
TPL_CALLBACK,
CpuPciEnumCompleteCallback,
NULL,
&Registration
);
//
// 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);
}
}
/**
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
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();
//
// Routine for update DMAR
//
UpdateDmarEndOfPcieEnum ();
UpdateSaGnvsForMmioResourceBaseLength ();
DEBUG ((DEBUG_INFO, "CpuPciEnumCompleteCallback End\n"));
return;
}