/** @file This file will perform SA PCIE Root Complex initialization. Copyright (c) 2019 Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PciExpressInit.h" #include #include "PcieComplex.h" #include #include "SaInit.h" /// /// Global variables /// UINT16 mSaIotrapSmiAddress; extern SA_CONFIG_HOB *mSaConfigHob; /// /// Functions /// /** This function gets registered as a callback to perform all SA late initialization @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 SaLateInitSmiCallback ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; SA_IOTRAP_SMI_PROTOCOL *SaIotrapSmiProtocol; if (mSaIotrapSmiAddress == 0) { // // Use global variable instead of protocol data since it maybe tampered in unsecure environment // Get IOTrap address when first time this routine calling (gEfiPciEnumerationCompleteProtocolGuid callback) // SaIotrapSmiProtocol = NULL; Status = gBS->LocateProtocol (&gSaIotrapSmiProtocolGuid, NULL, (VOID **) &SaIotrapSmiProtocol); ASSERT_EFI_ERROR (Status); if (SaIotrapSmiProtocol != NULL) { mSaIotrapSmiAddress = SaIotrapSmiProtocol->SaIotrapSmiAddress; } } ASSERT (mSaIotrapSmiAddress != 0); if (mSaIotrapSmiAddress != 0) { // // Generate IOTRAP SMI immediately // DEBUG ((DEBUG_INFO, "[SA] Issue IOTRAP SMI %X\n", mSaIotrapSmiAddress)); IoWrite8 (mSaIotrapSmiAddress, 0); } if (Event != NULL) { gBS->CloseEvent (Event); } return; } /** This function performs Peg initialization before EndOfDxe. @note This function will be executed as gEfiPciEnumerationCompleteProtocolGuid protocol callback and assumed SA DXE/SMM drivers have been dispatched. @retval EFI_SUCCESS - Always. **/ EFI_STATUS PegInitBeforeEndOfDxe ( VOID ) { EFI_EVENT ReadyToBoot; EFI_STATUS Status; BOOLEAN AspmHasBeenHandled; DEBUG ((DEBUG_INFO, "[SA] Pcie before EndOfDxe callback.\n")); AspmHasBeenHandled = FALSE; /// /// SMM mode ASPM handling /// Check if supported and enabled /// if ((mSaConfigHob != NULL) && (mSaConfigHob->InitPcieAspmAfterOprom == TRUE)) { /// /// Do the Phase 1 SMI callback /// This will enumerate PCIe downstream devices /// SaLateInitSmiCallback (NULL, NULL); if (mSaIotrapSmiAddress != 0) { /// /// Create an ReadyToBoot call back event to do the Phase 3 SMI callback /// This will handle PEG ASPM programming after OROM execution /// Note: Phase 2 SMI callback will be triggered in EndOfDxe callback /// to initialize rest of PCIe settings prior to OPROM /// Status = EfiCreateEventReadyToBootEx ( TPL_NOTIFY, (EFI_EVENT_NOTIFY) SaLateInitSmiCallback, NULL, &ReadyToBoot ); ASSERT_EFI_ERROR (Status); AspmHasBeenHandled = TRUE; } } /// /// DXE mode ASPM handling /// Check if SMM mode already taken care all things /// TRUE to skip DXE mode task. Otherwise do DXE mode ASPM initialization /// if (AspmHasBeenHandled == FALSE) { } return EFI_SUCCESS; } /** This function performs SA registers Saving/Restoring in EndOfDxe callback @retval EFI_SUCCESS - Save/restore has done @retval EFI_UNSUPPORTED - Save/restore not done successfully **/ EFI_STATUS SaSaveRestore ( VOID ) { BOOLEAN SaveRestoreHasBeenHandled; UINT8 SmiData; SaveRestoreHasBeenHandled = FALSE; if ((mSaConfigHob != NULL) && (mSaConfigHob->InitPcieAspmAfterOprom == TRUE)) { /// /// Generate the Phase 2 of SA SMI to do SA chipset save/restore and security lock /// SaLateInitSmiCallback (NULL, NULL); if (mSaIotrapSmiAddress != 0) { /// /// Store IOTRAP SMI address into Boot Script save table /// This is required to trigger this IOTRAP during S3 resume to restore all settings /// SmiData = 0; S3BootScriptSaveIoWrite ( S3BootScriptWidthUint8, (UINTN) mSaIotrapSmiAddress, 1, &SmiData ); SaveRestoreHasBeenHandled = TRUE; } } /// /// Check if SMM mode already taken care this task /// if (SaveRestoreHasBeenHandled == TRUE) { return EFI_SUCCESS; } else { return EFI_UNSUPPORTED; } }