/** @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
#include
#include
#include
#include
#include
///
/// Global Variables
///
GLOBAL_REMOVE_IF_UNREFERENCED SYSTEM_AGENT_NVS_AREA_PROTOCOL mSaNvsAreaProtocol;
GLOBAL_REMOVE_IF_UNREFERENCED SA_POLICY_PROTOCOL *mSaPolicy;
extern SA_CONFIG_HOB *mSaConfigHob;
/**
A protocol callback which updates 64bits MMIO Base and Length in SA GNVS area
**/
VOID
UpdateSaGnvsForMmioResourceBaseLength (
VOID
)
{
EFI_PHYSICAL_ADDRESS PciBaseAddress;
UINT32 Tolud;
UINT64 Length;
UINT64 McD0BaseAddress;
UINTN ResMemLimit1;
UINT8 EnableAbove4GBMmioBiosAssignemnt;
HOST_BRIDGE_DATA_HOB *HostBridgeDataHob;
PciBaseAddress = 0;
Tolud = 0;
Length = 0;
ResMemLimit1 = 0;
EnableAbove4GBMmioBiosAssignemnt = 0;
HostBridgeDataHob = NULL;
//
// Read memory map registers
//
McD0BaseAddress = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS, 0, 0, 0);
Tolud = PciSegmentRead32 (McD0BaseAddress + R_SA_TOLUD) & B_SA_TOLUD_TOLUD_MASK;
PciBaseAddress = Tolud;
ResMemLimit1 = (UINTN) PcdGet64 (PcdSiPciExpressBaseAddress);
Length = ResMemLimit1 - PciBaseAddress;
//
// Get HostBridgeData HOB and see if above 4GB MMIO BIOS assignment enabled
//
HostBridgeDataHob = (HOST_BRIDGE_DATA_HOB *) GetFirstGuidHob (&gHostBridgeDataHobGuid);
if ((HostBridgeDataHob != NULL) && (HostBridgeDataHob->EnableAbove4GBMmio == 1)) {
EnableAbove4GBMmioBiosAssignemnt = 1;
}
//
// Enable Above 4GB MMIO when Aperture Size is 2GB or higher
//
if ((mSaConfigHob != NULL) && (mSaConfigHob->ApertureSize >= 15)) {
EnableAbove4GBMmioBiosAssignemnt = 1;
}
//
// Check Enable Above 4GB MMIO or not
//
DEBUG ((DEBUG_INFO, "Update SA GNVS Area.\n"));
mSaNvsAreaProtocol.Area->Mmio32Base = (UINT32) PciBaseAddress;
mSaNvsAreaProtocol.Area->Mmio32Length = (UINT32) Length;
if (EnableAbove4GBMmioBiosAssignemnt == 1) {
mSaNvsAreaProtocol.Area->Mmio64Base = BASE_256GB;
mSaNvsAreaProtocol.Area->Mmio64Length = SIZE_256GB;
}
DEBUG ((DEBUG_INFO, "SaNvsAreaProtocol.Area->Mmio64Base = %lx\n", mSaNvsAreaProtocol.Area->Mmio64Base));
DEBUG ((DEBUG_INFO, "SaNvsAreaProtocol.Area->Mmio64Length = %lx\n", mSaNvsAreaProtocol.Area->Mmio64Length));
DEBUG ((DEBUG_INFO, "SaNvsAreaProtocol.Area->Mmio32Base = %lx\n", mSaNvsAreaProtocol.Area->Mmio32Base));
DEBUG ((DEBUG_INFO, "SaNvsAreaProtocol.Area->Mmio32Length = %lx\n", mSaNvsAreaProtocol.Area->Mmio32Length));
}
/**
Install SSDT Table
@retval EFI_SUCCESS - SSDT Table load successful.
**/
EFI_STATUS
InstallSsdtAcpiTable (
IN GUID SsdtTableGuid,
IN UINT64 Signature
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
BOOLEAN LoadTable;
UINTN NumberOfHandles;
UINTN Index;
INTN Instance;
UINTN Size;
UINT32 FvStatus;
UINTN TableHandle;
EFI_FV_FILETYPE FileType;
EFI_FV_FILE_ATTRIBUTES Attributes;
EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVol;
EFI_ACPI_TABLE_PROTOCOL *AcpiTable;
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
EFI_ACPI_COMMON_HEADER *Table;
FwVol = NULL;
Table = NULL;
DEBUG ((DEBUG_INFO, "Loading SSDT Table GUID: %g\n", SsdtTableGuid));
///
/// Locate FV protocol.
///
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiFirmwareVolume2ProtocolGuid,
NULL,
&NumberOfHandles,
&HandleBuffer
);
ASSERT_EFI_ERROR (Status);
///
/// Look for FV with ACPI storage file
///
for (Index = 0; Index < NumberOfHandles; Index++) {
///
/// Get the protocol on this handle
/// This should not fail because of LocateHandleBuffer
///
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiFirmwareVolume2ProtocolGuid,
(VOID **) &FwVol
);
ASSERT_EFI_ERROR (Status);
if (FwVol == NULL) {
return EFI_NOT_FOUND;
}
///
/// See if it has the ACPI storage file
///
Size = 0;
FvStatus = 0;
Status = FwVol->ReadFile (
FwVol,
&SsdtTableGuid,
NULL,
&Size,
&FileType,
&Attributes,
&FvStatus
);
///
/// If we found it, then we are done
///
if (!EFI_ERROR (Status)) {
break;
}
}
///
/// Our exit status is determined by the success of the previous operations
/// If the protocol was found, Instance already points to it.
///
///
/// Free any allocated buffers
///
FreePool (HandleBuffer);
///
/// Sanity check that we found our data file
///
ASSERT (FwVol);
///
/// Locate ACPI tables
///
Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);
///
/// Read tables from the storage file.
///
if (FwVol == NULL) {
ASSERT_EFI_ERROR (EFI_NOT_FOUND);
return EFI_NOT_FOUND;
}
Instance = 0;
while (Status == EFI_SUCCESS) {
///
/// Read the ACPI tables
///
Status = FwVol->ReadSection (
FwVol,
&SsdtTableGuid,
EFI_SECTION_RAW,
Instance,
(VOID **) &Table,
&Size,
&FvStatus
);
if (!EFI_ERROR (Status)) {
///
/// check and load HybridGraphics SSDT table
///
LoadTable = FALSE;
TableHeader = (EFI_ACPI_DESCRIPTION_HEADER *) Table;
if (((EFI_ACPI_DESCRIPTION_HEADER *) TableHeader)->OemTableId == Signature) {
///
/// This is the SSDT table that match the Signature
///
DEBUG ((DEBUG_INFO, "Found out SSDT Table GUID: %g\n", SsdtTableGuid));
LoadTable = TRUE;
}
///
/// Add the table
///
if (LoadTable) {
TableHandle = 0;
Status = AcpiTable->InstallAcpiTable (
AcpiTable,
TableHeader,
TableHeader->Length,
&TableHandle
);
}
///
/// Increment the instance
///
Instance++;
Table = NULL;
}
}
return EFI_SUCCESS;
}
/**
This function gets registered as a callback to perform Dmar Igd
@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
SaAcpiEndOfDxeCallback (
IN EFI_EVENT Event,
IN VOID *Context
)
{
EFI_STATUS Status;
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, PCI_VENDOR_ID_OFFSET)) != 0xFFFF) {
Status = PostPmInitEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe GraphicsInit Error, Status = %r \n", Status));
ASSERT_EFI_ERROR (Status);
}
}
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, IGD_BUS_NUM, IGD_DEV_NUM, IGD_FUN_NUM, PCI_VENDOR_ID_OFFSET)) != 0xFFFF) {
Status = GetVBiosVbtEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe Op Region Error, Status = %r \n", Status));
}
Status = UpdateIgdOpRegionEndOfDxe ();
if (EFI_SUCCESS != Status) {
DEBUG ((DEBUG_WARN, "[SA] EndOfDxe Update Op Region Error, Status = %r \n", Status));
}
}
return;
}
/**
SystemAgent Acpi Initialization.
@param[in] ImageHandle Handle for the image of this driver
@retval EFI_SUCCESS The function completed successfully
@retval EFI_OUT_OF_RESOURCES No enough buffer to allocate
**/
EFI_STATUS
EFIAPI
SaAcpiInit (
IN EFI_HANDLE ImageHandle
)
{
EFI_STATUS Status;
EFI_CPUID_REGISTER CpuidRegs;
EFI_EVENT EndOfDxeEvent;
CPU_PCIE_HOB *CpuPcieHob;
AsmCpuid (1, &CpuidRegs.RegEax, 0, 0, 0);
///
/// Get the platform setup policy.
///
Status = gBS->LocateProtocol (&gSaPolicyProtocolGuid, NULL, (VOID **) &mSaPolicy);
ASSERT_EFI_ERROR (Status);
///
/// Install System Agent Global NVS protocol
///
DEBUG ((DEBUG_INFO, "Install SA GNVS protocol\n"));
Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof (SYSTEM_AGENT_NVS_AREA), (VOID **) &mSaNvsAreaProtocol.Area);
ASSERT_EFI_ERROR (Status);
ZeroMem ((VOID *) mSaNvsAreaProtocol.Area, sizeof (SYSTEM_AGENT_NVS_AREA));
mSaNvsAreaProtocol.Area->XPcieCfgBaseAddress = (UINT32) (PcdGet64 (PcdSiPciExpressBaseAddress));
mSaNvsAreaProtocol.Area->CpuIdInfo = CpuidRegs.RegEax;
///
/// Get CpuPcieHob HOB
///
CpuPcieHob = NULL;
CpuPcieHob = (CPU_PCIE_HOB *) GetFirstGuidHob (&gCpuPcieHobGuid);
if (CpuPcieHob == NULL) {
DEBUG((DEBUG_ERROR, "CpuPcieHob not found\n"));
// @todo: Will add it back once it will get add into NVS library since currently it is failing for JSL
//ASSERT(CpuPcieHob != NULL);
//return EFI_NOT_FOUND;
} else {
mSaNvsAreaProtocol.Area->SlotSelection = CpuPcieHob->SlotSelection;
DEBUG((DEBUG_INFO, "RpEnabledMask == %x\n", CpuPcieHob->RpEnabledMask));
if (CpuPcieHob->RpEnabledMask == 0) {
DEBUG ((DEBUG_ERROR, "All CPU PCIe root ports are disabled!!\n"));
} else {
if (CpuPcieHob->RpEnabledMask & BIT0) {
mSaNvsAreaProtocol.Area->CpuPcieRp0Enable = 1;
}
if (CpuPcieHob->RpEnabledMask & BIT1) {
mSaNvsAreaProtocol.Area->CpuPcieRp1Enable = 1;
}
if (CpuPcieHob->RpEnabledMask & BIT2) {
mSaNvsAreaProtocol.Area->CpuPcieRp2Enable = 1;
}
if (CpuPcieHob->RpEnabledMask & BIT3) {
mSaNvsAreaProtocol.Area->CpuPcieRp3Enable = 1;
}
}
mSaNvsAreaProtocol.Area->MaxPegPortNumber = GetMaxCpuPciePortNum ();
}
mSaNvsAreaProtocol.Area->SimicsEnvironment = 0;
Status = gBS->InstallMultipleProtocolInterfaces (
&ImageHandle,
&gSaNvsAreaProtocolGuid,
&mSaNvsAreaProtocol,
NULL
);
ASSERT_EFI_ERROR (Status);
///
/// GtPostInit Initialization
///
DEBUG ((DEBUG_INFO, "Initializing GT ACPI tables\n"));
GraphicsInit (ImageHandle, mSaPolicy);
///
/// Audio (dHDA) Initialization
///
///
/// Vtd Initialization
///
DEBUG ((DEBUG_INFO, "Initializing VT-d ACPI tables\n"));
VtdInit (mSaPolicy);
///
/// IgdOpRegion Install Initialization
///
DEBUG ((DEBUG_INFO, "Initializing IGD OpRegion\n"));
IgdOpRegionInit ();
///
/// Register an end of DXE event for SA ACPI to do tasks before invoking any UEFI drivers,
/// applications, or connecting consoles,...
///
Status = gBS->CreateEventEx (
EVT_NOTIFY_SIGNAL,
TPL_CALLBACK,
SaAcpiEndOfDxeCallback,
NULL,
&gEfiEndOfDxeEventGroupGuid,
&EndOfDxeEvent
);
///
/// Install System Agent Global NVS ACPI table
///
Status = InstallSsdtAcpiTable (gSaSsdtAcpiTableStorageGuid, SIGNATURE_64 ('S', 'a', 'S', 's', 'd', 't', ' ', 0));
ASSERT_EFI_ERROR (Status);
///
/// Update CPU PCIE RP NVS AREA
///
UpdateCpuPcieNVS();
///
/// Install Intel Graphics SSDT
///
Status = InstallSsdtAcpiTable (gGraphicsAcpiTableStorageGuid, SIGNATURE_64 ('I','g','f','x','S','s','d','t'));
ASSERT_EFI_ERROR (Status);
///
/// Install IPU SSDT if IPU is present.
///
if (PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, IPU_BUS_NUM, IPU_DEV_NUM, IPU_FUN_NUM, 0)) != V_SA_DEVICE_ID_INVALID) {
Status = InstallSsdtAcpiTable (gIpuAcpiTableStorageGuid, SIGNATURE_64 ('I','p','u','S','s','d','t',0));
ASSERT_EFI_ERROR (Status);
}
return EFI_SUCCESS;
}