/** @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; }