From: "Nate DeSimone" <nathaniel.l.desimone@intel.com>
To: "Luo, Heng" <heng.luo@intel.com>,
"devel@edk2.groups.io" <devel@edk2.groups.io>
Cc: "Chaganty, Rangasai V" <rangasai.v.chaganty@intel.com>
Subject: Re: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules
Date: Thu, 4 Feb 2021 03:56:42 +0000 [thread overview]
Message-ID: <BN6PR1101MB2147EEDA2BA37FD01047EB45CDB39@BN6PR1101MB2147.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20210201013657.1833-36-heng.luo@intel.com>
Hi Heng,
Please see comments inline.
Thanks,
Nate
> -----Original Message-----
> From: Luo, Heng <heng.luo@intel.com>
> Sent: Sunday, January 31, 2021 5:37 PM
> To: devel@edk2.groups.io
> Cc: Chaganty, Rangasai V <rangasai.v.chaganty@intel.com>; Desimone,
> Nathaniel L <nathaniel.l.desimone@intel.com>
> Subject: [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules
>
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3171
>
> Adds the following files:
> * Pch/PchInit/Dxe
> * Pch/PchInit/Smm
> * Pch/PchSmiDispatcher/Smm
> * Pch/SmmControl/RuntimeDxe
>
> Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> Signed-off-by: Heng Luo <heng.luo@intel.com>
> ---
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c | 494
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c |
> 41 ++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c |
> 201
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c | 314
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h | 122
> ++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c |
> 354
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf |
> 96 ++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c | 89
> ++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c | 33
> +++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c |
> 134 ++++++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c |
> 266
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
> | 137 +++++++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
> | 33 +++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c |
> 285
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h |
> 254
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf |
> 110 +++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c |
> 451
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c |
> 67 +++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
> | 1284
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
> | 226
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatc
> h.c | 2442
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispatc
> her.inf | 116 ++++++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper.
> h | 40 +++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelper
> Client.c | 57 ++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
> | 1043
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCore.
> c | 926
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.c
> | 1588
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi.h
> | 341
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.c
> | 263
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpe
> rs.c | 332
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHelpe
> rs.h | 155
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPerio
> dicTimer.c | 667
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPowe
> rButton.c | 81 +++++++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.c
> | 381
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
> | 224
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb.c
> | 230
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelp
> ers.c | 778
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHelp
> ers.h | 107 ++++++++++++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl
> .inf | 54 +++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl
> Driver.c | 394
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++++++++++++
>
> Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmControl
> Driver.h | 130
> +++++++++++++++++++++++++++++++++++++++++++++++++
> 41 files changed, 15340 insertions(+)
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
> new file mode 100644
> index 0000000000..e88afa5ded
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchAcpi.c
> @@ -0,0 +1,494 @@
> +/** @file
>
> + This is the driver that initializes the Intel PCH.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/HobLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +
>
> +#include "PchInit.h"
>
> +#include <Protocol/PchPolicy.h>
>
> +#include <GpioDevConfig.h>
>
> +#include <ScsConfig.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/GpioLib.h>
>
> +#include <Library/GpioNativeLib.h>
>
> +#include <Library/PchCycleDecodingLib.h>
>
> +#include <Library/PmcLib.h>
>
> +#include <Library/SerialIoAccessLib.h>
>
> +#include <Library/GbeLib.h>
>
> +#include <PchRstHob.h>
>
> +#include <Library/PchPcieRpLib.h>
>
> +#include <TraceHubConfig.h>
>
> +#include <PchReservedResources.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Library/BaseLib.h>
>
> +#include <Register/UsbRegs.h>
>
> +#include <Library/PcdLib.h>
>
> +#include <IndustryStandard/Pci22.h>
>
> +#include <PcieRegs.h>
>
> +#include <Library/PchPcrLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <PchHybridStorageHob.h>
>
> +#include <Library/SataLib.h>
>
> +
>
> +//
>
> +// Module variables
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA_PROTOCOL
> mPchNvsAreaProtocol;
>
> +
>
> +/**
>
> + Retrieve interrupt information about a PCH device from policy
>
> +
>
> + @param[in] UartNumber Uart number
>
> +
>
> + @retval PCH_DEVICE_INTERRUPT_CONFIG structure with device's
> interrupt information
>
> +**/
>
> +PCH_DEVICE_INTERRUPT_CONFIG
>
> +GetUartInterrupt (
>
> + IN UINT8 UartNumber
>
> + )
>
> +{
>
> + PCH_DEVICE_INTERRUPT_CONFIG EmptyRecord;
>
> + UINT8 DevNum;
>
> + UINT8 FuncNum;
>
> + UINT8 Index;
>
> +
>
> + ZeroMem (&EmptyRecord, sizeof (PCH_DEVICE_INTERRUPT_CONFIG));
>
> + DevNum = SerialIoUartDevNumber (UartNumber);
>
> + FuncNum = SerialIoUartFuncNumber (UartNumber);
>
> +
>
> + for (Index = 0; Index < mPchConfigHob->Interrupt.NumOfDevIntConfig;
> Index++) {
>
> + if ((mPchConfigHob->Interrupt.DevIntConfig[Index].Device == DevNum)
> &&
>
> + (mPchConfigHob->Interrupt.DevIntConfig[Index].Function ==
> FuncNum)) {
>
> + return mPchConfigHob->Interrupt.DevIntConfig[Index];
>
> + }
>
> + }
>
> + return EmptyRecord;
>
> +}
>
> +
>
> +/**
>
> + Update ASL definitions for SerialIo devices.
>
> +
>
> +**/
>
> +VOID
>
> +UpdateSerialIoAcpiData (
>
> + VOID
>
> + )
>
> +{
>
> + UINT8 Index;
>
> +
>
> + for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
>
> + mPchNvsAreaProtocol.Area->SM0[Index] = mPchConfigHob-
> >SerialIo.SpiDeviceConfig[Index].Mode;
>
> + mPchNvsAreaProtocol.Area->SC0[Index] = GetSerialIoSpiPciCfg (Index);
>
> + }
>
> + for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
>
> + mPchNvsAreaProtocol.Area->IM0[Index] = mPchConfigHob-
> >SerialIo.I2cDeviceConfig[Index].Mode;
>
> + mPchNvsAreaProtocol.Area->IC0[Index] = GetSerialIoI2cPciCfg (Index);
>
> + }
>
> + for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++)
> {
>
> + mPchNvsAreaProtocol.Area->UM0[Index] = mPchConfigHob-
> >SerialIo.UartDeviceConfig[Index].Mode;
>
> + mPchNvsAreaProtocol.Area->UC0[Index] = GetSerialIoUartPciCfg
> (Index);
>
> + mPchNvsAreaProtocol.Area->UD0[Index] = mPchConfigHob-
> >SerialIo.UartDeviceConfig[Index].DmaEnable;
>
> + mPchNvsAreaProtocol.Area->UP0[Index] = mPchConfigHob-
> >SerialIo.UartDeviceConfig[Index].PowerGating;
>
> + mPchNvsAreaProtocol.Area->UI0[Index] = (GetUartInterrupt
> (Index)).Irq;
>
> + }
>
> +}
>
> +
>
> +#if FixedPcdGet8(PcdEmbeddedEnable) == 0x1
>
> +/**
>
> + Update NVS Area for Timed GPIO devices.
>
> +**/
>
> +VOID
>
> +UpdateTimedGpioSetup (
>
> + VOID
>
> + )
>
> +{
>
> + mPchNvsAreaProtocol.Area->EnableTimedGpio0 =
> (UINT8)mPchConfigHob->Pm.EnableTimedGpio0;
>
> + mPchNvsAreaProtocol.Area->EnableTimedGpio1 =
> (UINT8)mPchConfigHob->Pm.EnableTimedGpio1;
>
> +}
>
> +#endif
>
> +
>
> +/**
>
> + Update NVS Area after RST PCIe Storage Remapping and before Boot
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> + @retval EFI_NOT_FOUND Couldn't fetch RstHob
>
> +**/
>
> +EFI_STATUS
>
> +PchUpdateNvsAreaAfterRemapping (
>
> + VOID
>
> + )
>
> +{
>
> + UINTN Index;
>
> + VOID *Hob;
>
> + PCH_RST_HOB *RstHob;
>
> +
>
> + Hob = GetFirstGuidHob (&gPchRstHobGuid);
>
> + if (Hob == NULL) {
>
> + return EFI_NOT_FOUND;
>
> + }
>
> +
>
> + RstHob = (PCH_RST_HOB *) GET_GUID_HOB_DATA (Hob);
>
> +
>
> + for (Index = 0; Index < PCH_MAX_RST_PCIE_STORAGE_CR; Index++) {
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageInterfaceType[Index] =
> RstHob->RstCrConfiguration[Index].DeviceInterface;
>
> + mPchNvsAreaProtocol.Area->RstPcieStoragePmCapPtr[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].PmCapPtr;
>
> + mPchNvsAreaProtocol.Area->RstPcieStoragePcieCapPtr[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].PcieCapPtr;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageL1ssCapPtr[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].L1ssCapPtr;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl2[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl2;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpL1ssControl1[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointL1ssControl1;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageLtrCapPtr[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].LtrCapPtr;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpLtrData[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLtrData;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpLctlData16[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointLctlData16;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctlData16[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctlData16;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageEpDctl2Data16[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].EndpointDctl2Data16;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageRpDctl2Data16[Index] =
> RstHob->SavedRemapedDeviceConfigSpace[Index].RootPortDctl2Data16;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageUniqueTableBar[Index] =
> RstHob->RstCrConfiguration[Index].EndPointUniqueMsixTableBar;
>
> + mPchNvsAreaProtocol.Area-
> >RstPcieStorageUniqueTableBarValue[Index] = RstHob-
> >RstCrConfiguration[Index].EndPointUniqueMsixTableBarValue;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBar[Index] =
> RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBar;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageUniquePbaBarValue[Index]
> = RstHob->RstCrConfiguration[Index].EndPointUniqueMsixPbaBarValue;
>
> + mPchNvsAreaProtocol.Area->RstPcieStorageRootPortNum[Index] =
> RstHob->RstCrConfiguration[Index].RootPortNum;
>
> + }
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Update the Hybrid storage location NVS Area if Hybrid Storage device is
> present
>
> +**/
>
> +EFI_STATUS
>
> +UpdateHybridStorageLocation (
>
> + VOID
>
> + )
>
> +{
>
> + VOID *Hob;
>
> + PCH_HYBRIDSTORAGE_HOB *HybridStorageHob;
>
> +
>
> + Hob = GetFirstGuidHob (&gHybridStorageHobGuid);
>
> + if (Hob == NULL) {
>
> + return EFI_NOT_FOUND;
>
> + }
>
> +
>
> + HybridStorageHob = (PCH_HYBRIDSTORAGE_HOB *)
> GET_GUID_HOB_DATA (Hob);
>
> + mPchNvsAreaProtocol.Area->HybridStorageLocation = HybridStorageHob-
> >HybridStorageLocation;
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + PCH ACPI initialization before Boot Sript Table is closed
>
> + It update ACPI table and ACPI NVS area.
>
> +
>
> + @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
>
> +PchAcpiOnEndOfDxe (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() Start\n"));
>
> +
>
> + ///
>
> + /// Closed the event to avoid call twice when launch shell
>
> + ///
>
> + gBS->CloseEvent (Event);
>
> +
>
> + //
>
> + // Init HDA Audio ACPI tables
>
> + //
>
> + PchHdAudioAcpiInit ();
>
> + //
>
> + // Update ASL definitions for SerialIo devices.
>
> + //
>
> + UpdateSerialIoAcpiData ();
>
> + UpdateCnviAcpiData ();
>
> +#if FixedPcdGet8(PcdEmbeddedEnable) == 0x1
>
> + UpdateTimedGpioSetup();
>
> +#endif
>
> +
>
> + //
>
> + // Update Pch Nvs Area
>
> + //
>
> + PchUpdateNvsArea ();
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchAcpiOnEndOfDxe() End\n"));
>
> +
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + Initialize Pch acpi
>
> + @param[in] ImageHandle Handle for the image of this driver
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to
> initialize the driver
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiInit (
>
> + IN EFI_HANDLE ImageHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_EVENT EndOfDxeEvent;
>
> +
>
> + DEBUG ((DEBUG_INFO, "Install PCH NVS protocol\n"));
>
> +
>
> + Status = (gBS->AllocatePool) (EfiACPIMemoryNVS, sizeof
> (PCH_NVS_AREA), (VOID **) &mPchNvsAreaProtocol.Area);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ZeroMem ((VOID *) mPchNvsAreaProtocol.Area, sizeof
> (PCH_NVS_AREA));
>
> + Status = gBS->InstallMultipleProtocolInterfaces (
>
> + &ImageHandle,
>
> + &gPchNvsAreaProtocolGuid,
>
> + &mPchNvsAreaProtocol,
>
> + NULL
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Update the NVS Area after RST PCIe Storage Remapping
>
> + ///
>
> + PchUpdateNvsAreaAfterRemapping ();
>
> +
>
> + UpdateHybridStorageLocation ();
>
> + //
>
> + // Register an end of DXE event for PCH ACPI to do tasks before invoking
> any UEFI drivers,
>
> + // applications, or connecting consoles,...
>
> + //
>
> + Status = gBS->CreateEventEx (
>
> + EVT_NOTIFY_SIGNAL,
>
> + TPL_CALLBACK,
>
> + PchAcpiOnEndOfDxe,
>
> + NULL,
>
> + &gEfiEndOfDxeEventGroupGuid,
>
> + &EndOfDxeEvent
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +
>
> +/**
>
> + Update NVS area for PCIe root ports.
>
> +**/
>
> +STATIC
>
> +VOID
>
> +PcieRpUpdateNvsArea (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 Index;
>
> +
>
> + for (Index = 0; Index < PCH_MAX_PCIE_CLOCKS; Index++) {
>
> + mPchNvsAreaProtocol.Area->ClockToRootPortMap[Index] =
> mPchConfigHob->PcieRp.PcieClock[Index].Usage;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Update ASL object before Boot
>
> +
>
> + @retval EFI_STATUS
>
> + @retval EFI_NOT_READY The Acpi protocols are not ready.
>
> +**/
>
> +EFI_STATUS
>
> +PchUpdateNvsArea (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINTN Index;
>
> + UINT32 HpetBaseAdress;
>
> + GPIO_GROUP GroupToGpeDwX[3];
>
> + UINT32 GroupDw[3];
>
> + UINTN RpDev;
>
> + UINTN RpFun;
>
> + UINT32 Data32;
>
> + PCH_POLICY_PROTOCOL *PchPolicy;
>
> + GPIO_DXE_CONFIG *GpioDxeConfig;
>
> + UINT64 XdciPciBase;
>
> + UINT64 XdciBar;
>
> + UINT16 PciMemConfig;
>
> + UINT16 TcoBase;
>
> + UINT8 ClearXdciBar = FALSE;
>
> +
>
> + ///
>
> + /// Get PCH Policy Protocol
>
> + ///
>
> + Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID
> **)&PchPolicy);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Get GPIO DXE Config Block
>
> + ///
>
> + Status = GetConfigBlock ((VOID *)PchPolicy, &gGpioDxeConfigGuid, (VOID
> *)&GpioDxeConfig);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Update ASL PCIE port address according to root port device and function
>
> + //
>
> + for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
>
> + RpDev = PchPcieRpDevNumber (Index);
>
> + RpFun = PchPcieRpFuncNumber (Index);
>
> + Data32 = ((UINT8) RpDev << 16) | (UINT8) RpFun;
>
> + mPchNvsAreaProtocol.Area->RpAddress[Index] = Data32;
>
> +
>
> + //
>
> + // Update Maximum Snoop Latency and Maximum No-Snoop Latency
> values for PCIE
>
> + //
>
> + mPchNvsAreaProtocol.Area->PcieLtrMaxSnoopLatency[Index] =
> mPchConfigHob-
> >PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxSno
> opLatency;
>
> + mPchNvsAreaProtocol.Area->PcieLtrMaxNoSnoopLatency[Index] =
> mPchConfigHob-
> >PcieRp.RootPort[Index].PcieRpCommonConfig.PcieRpLtrConfig.LtrMaxNoS
> noopLatency;
>
> + }
>
> +
>
> + //
>
> + // Update PCHS.
>
> + //
>
> + mPchNvsAreaProtocol.Area->PchSeries = PchSeries ();
>
> + //
>
> + // Update PCHG.
>
> + //
>
> + mPchNvsAreaProtocol.Area->PchGeneration = (UINT16) PchGeneration ();
>
> + //
>
> + // Update PSTP.
>
> + //
>
> + mPchNvsAreaProtocol.Area->PchStepping = (UINT16) PchStepping ();
>
> + //
>
> + // Update HPET base address.
>
> + //
>
> + PchHpetBaseGet (&HpetBaseAdress);
>
> + mPchNvsAreaProtocol.Area->HPTE = TRUE; // @todo remove the
> NVS, since it's always enabled.
>
> + mPchNvsAreaProtocol.Area->HPTB = HpetBaseAdress;
>
> + //
>
> + // Update SBREG_BAR.
>
> + //
>
> + mPchNvsAreaProtocol.Area->SBRG = PCH_PCR_BASE_ADDRESS;
>
> +
>
> + //
>
> + // Update base address
>
> + //
>
> + mPchNvsAreaProtocol.Area->PMBS = PmcGetAcpiBase ();
>
> + mPchNvsAreaProtocol.Area->PWRM = PmcGetPwrmBase ();
>
> + PchTcoBaseGet (&TcoBase);
>
> + mPchNvsAreaProtocol.Area->TcoBase = TcoBase;
>
> +
>
> + //
>
> + // Update PCH PID info
>
> + //
>
> + mPchNvsAreaProtocol.Area->IclkPid = PchPcrGetPid (PchIpIclk);
>
> +
>
> + //
>
> + // Update GPIO device ACPI variables
>
> + //
>
> + mPchNvsAreaProtocol.Area->SGIR = mPchConfigHob-
> >Interrupt.GpioIrqRoute;
>
> + mPchNvsAreaProtocol.Area->GPHD = (UINT8)GpioDxeConfig-
> >HideGpioAcpiDevice;
>
> +
>
> + //
>
> + // Update GPP_X to GPE_DWX mapping.
>
> + //
>
> + GpioGetGroupDwToGpeDwX (
>
> + &GroupToGpeDwX[0], &GroupDw[0],
>
> + &GroupToGpeDwX[1], &GroupDw[1],
>
> + &GroupToGpeDwX[2], &GroupDw[2]
>
> + );
>
> +
>
> + //
>
> + // GEI0/1/2 and GED0/1/2 are objects for informing how GPIO groups are
> mapped to GPE0.
>
> + // If Group is mapped to 1-Tier GPE information is also stored on what
> Group DW
>
> + // is mapped to GPE_DWx. Because GPE_DWx register is 32 bits large if
> groups have more than
>
> + // 32 pads only part of it can be mapped.
>
> + //
>
> + // GEIx - GroupIndex mapped to GPE0_DWx
>
> + // GEDx - DoubleWorld part of Group: 0 - pins 31-0, 1 - pins 63-32, ...
>
> + //
>
> + mPchNvsAreaProtocol.Area->GEI0 = (UINT8)
> GpioGetGroupIndexFromGroup (GroupToGpeDwX[0]);
>
> + mPchNvsAreaProtocol.Area->GEI1 = (UINT8)
> GpioGetGroupIndexFromGroup (GroupToGpeDwX[1]);
>
> + mPchNvsAreaProtocol.Area->GEI2 = (UINT8)
> GpioGetGroupIndexFromGroup (GroupToGpeDwX[2]);
>
> + mPchNvsAreaProtocol.Area->GED0 = (UINT8) GroupDw[0];
>
> + mPchNvsAreaProtocol.Area->GED1 = (UINT8) GroupDw[1];
>
> + mPchNvsAreaProtocol.Area->GED2 = (UINT8) GroupDw[2];
>
> +
>
> + //
>
> + // SCS Configuration
>
> + //
>
> +
>
> + PcieRpUpdateNvsArea ();
>
> +
>
> + //
>
> + // SATA configuration.
>
> + //
>
> + mPchNvsAreaProtocol.Area->SataPortPresence =
> GetSataPortPresentStatus (0);
>
> + DEBUG ((DEBUG_INFO, "SataPortPresence: 0x%x\n",
> mPchNvsAreaProtocol.Area->SataPortPresence));
>
> +
>
> + //
>
> + // CPU SKU
>
> + //
>
> + mPchNvsAreaProtocol.Area->CpuSku = 0;
>
> + mPchNvsAreaProtocol.Area->PsOnEnable = (UINT8)mPchConfigHob-
> >Pm.PsOnEnable;
>
> +
>
> + for (Index = 0; Index < GetPchMaxPciePortNum (); Index++) {
>
> + mPchNvsAreaProtocol.Area->LtrEnable[Index] =
> (UINT8)mPchConfigHob-
> >PcieRp.RootPort[Index].PcieRpCommonConfig.LtrEnable;
>
> + }
>
> +
>
> + mPchNvsAreaProtocol.Area->GBES = IsGbePresent ();
>
> +
>
> + //
>
> + // Update PCH Trace Hub Mode
>
> + //
>
> + mPchNvsAreaProtocol.Area->PchTraceHubMode = (UINT8)
> mPchConfigHob->PchTraceHub.PchTraceHubMode;
>
> +
>
> + //
>
> + // Saving GCTL value into PCH NVS area
>
> + //
>
> +
>
> + XdciPciBase = PchXdciPciCfgBase ();
>
> +
>
> + //
>
> + // Determine Base address for Base address register (Offset 0x10)
>
> + //
>
> + if (PciSegmentRead32 (XdciPciBase) != 0xFFFFFFFF) {
>
> +
>
> + XdciBar = PciSegmentRead32 (XdciPciBase +
> PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0;
>
> +
>
> + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET) &
> B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
>
> + XdciBar += (UINT64)PciSegmentRead32 (XdciPciBase +
> (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32;
>
> + }
>
> +
>
> + if (XdciBar == 0x0) {
>
> + ClearXdciBar = TRUE;
>
> + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET),
> PcdGet32 (PcdSiliconInitTempMemBaseAddr));
>
> + XdciBar = PciSegmentRead32 (XdciPciBase +
> PCI_BASE_ADDRESSREG_OFFSET) & 0xFFFFFFF0;
>
> +
>
> + if ((PciSegmentRead32 (XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET)
> & B_PCI_BAR_MEMORY_TYPE_MASK) == B_PCI_BAR_MEMORY_TYPE_64) {
>
> + XdciBar += (UINT64)PciSegmentRead32 (XdciPciBase +
> (PCI_BASE_ADDRESSREG_OFFSET + 4)) << 32;
>
> + }
>
> + }
>
> +
>
> + //
>
> + // Enable Pci Memconfig to read the correct value for GCTL register
>
> + //
>
> + PciMemConfig = PciSegmentRead16 (XdciPciBase +
> PCI_COMMAND_OFFSET);
>
> + PciSegmentWrite16 (XdciPciBase + PCI_COMMAND_OFFSET,
> PciMemConfig | (EFI_PCI_COMMAND_BUS_MASTER |
> EFI_PCI_COMMAND_MEMORY_SPACE));
>
> +
>
> + mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale = MmioRead32(XdciBar
> + R_XDCI_MEM_GCTL);
>
> + DEBUG ((DEBUG_INFO, "PchxDCIPwrDnScale 0x%x\n",
> (UINT64)mPchNvsAreaProtocol.Area->PchxDCIPwrDnScale));
>
> + //
>
> + // Disable Pci Memconfig & clear Base address
>
> + //
>
> + PciSegmentWrite16(XdciPciBase + PCI_COMMAND_OFFSET,
> PciMemConfig);
>
> +
>
> + if (ClearXdciBar == TRUE) {
>
> + PciSegmentWrite32 ((XdciPciBase + PCI_BASE_ADDRESSREG_OFFSET),
> 0x0);
>
> + PciSegmentWrite32 ((XdciPciBase + (PCI_BASE_ADDRESSREG_OFFSET +
> 4)), 0x0);
>
> + }
>
> + }
>
> +
>
> + return Status;
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c
> new file mode 100644
> index 0000000000..5c8e1ce5b4
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchCnviAcpi.c
> @@ -0,0 +1,41 @@
> +/** @file
>
> + Initializes PCH CNVi device ACPI data.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/HobLib.h>
>
> +#include <CnviConfigHob.h>
>
> +#include "PchInit.h"
>
> +#include <Register/PchPcrRegs.h>
>
> +
>
> +/**
>
> + Update ASL definitions for CNVi device.
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +UpdateCnviAcpiData (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_PEI_HOB_POINTERS HobPtr;
>
> + CNVI_CONFIG_HOB *CnviConfigHob;
>
> +
>
> + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() Start\n"));
>
> +
>
> + // Get CNVi Config HOB.
>
> + HobPtr.Guid = GetFirstGuidHob (&gCnviConfigHobGuid);
>
> + if (HobPtr.Guid != NULL) {
>
> + CnviConfigHob = (CNVI_CONFIG_HOB *) GET_GUID_HOB_DATA
> (HobPtr.Guid);
>
> + mPchNvsAreaProtocol.Area->CnviMode = (UINT8)CnviConfigHob-
> >Mode;
>
> + mPchNvsAreaProtocol.Area->CnviBtCore = (UINT8)CnviConfigHob-
> >BtCore;
>
> + mPchNvsAreaProtocol.Area->CnviBtAudioOffload =
> (UINT8)CnviConfigHob->BtAudioOffload;
>
> + }
>
> + mPchNvsAreaProtocol.Area->CnviPortId = PID_CNVI;
>
> + DEBUG ((DEBUG_INFO, "UpdateCnviAcpiData() End\n"));
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
> new file mode 100644
> index 0000000000..dbdb028483
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchHdaAcpi.c
> @@ -0,0 +1,201 @@
> +
>
> +/** @file
>
> + Initializes the PCH HD Audio ACPI Tables.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiLib.h>
>
> +#include <Protocol/AcpiTable.h>
>
> +#include <DxeHdaNhlt.h>
>
> +#include <Library/DxeHdaNhltLib.h>
>
> +#include "PchInit.h"
>
> +#include <HdAudioConfig.h>
>
> +#include <PchConfigHob.h>
>
> +#include <Library/PcdLib.h>
>
> +#include <Protocol/PchPolicy.h>
>
> +#include <HdAudioConfig.h>
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +
>
> +#define XTAL_FREQ_38P4MHZ 1
>
> +
>
> +/**
>
> + Retrieves address of NHLT table from XSDT/RSDT.
>
> +
>
> + @retval NHLT_ACPI_TABLE* Pointer to NHLT table if found
>
> + @retval NULL NHLT could not be found
>
> +**/
>
> +NHLT_ACPI_TABLE *
>
> +LocateNhltAcpiTable (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
>
> + EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
>
> + NHLT_ACPI_TABLE *Nhlt;
>
> + UINTN Index;
>
> + UINT64 Data64;
>
> + EFI_STATUS Status;
>
> + Rsdp = NULL;
>
> + Xsdt = NULL;
>
> + Nhlt = NULL;
>
> +
>
> + ///
>
> + /// Find the AcpiSupport protocol returns RSDP (or RSD PTR) address.
>
> + ///
>
> + DEBUG ((DEBUG_INFO, "LocateNhltAcpiTable() Start\n"));
>
> +
>
> + Status = EfiGetSystemConfigurationTable (&gEfiAcpiTableGuid, (VOID *)
> &Rsdp);
>
> + if (EFI_ERROR (Status) || (Rsdp == NULL)) {
>
> + DEBUG ((DEBUG_ERROR, "EFI_ERROR or Rsdp == NULL\n"));
>
> + return NULL;
>
> + }
>
> +
>
> + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->XsdtAddress;
>
> + if (Xsdt == NULL || Xsdt->Signature !=
> EFI_ACPI_5_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
>
> + // If XSDT has not been found, check RSDT
>
> + Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) (UINTN) Rsdp->RsdtAddress;
>
> + if (Xsdt == NULL || Xsdt->Signature !=
> EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) {
>
> + DEBUG ((DEBUG_ERROR, "XSDT/RSDT == NULL or wrong signature\n"));
>
> + return NULL;
>
> + }
>
> + }
>
> +
>
> + for (Index = sizeof (EFI_ACPI_DESCRIPTION_HEADER); Index < Xsdt-
> >Length; Index = Index + sizeof (UINT64)) {
>
> + Data64 = *(UINT64 *) ((UINT8 *) Xsdt + Index);
>
> + Nhlt = (NHLT_ACPI_TABLE *) (UINTN) Data64;
>
> + if (Nhlt != NULL && Nhlt->Header.Signature ==
> NHLT_ACPI_TABLE_SIGNATURE) {
>
> + break;
>
> + }
>
> + Nhlt = NULL;
>
> + }
>
> +
>
> + if (Nhlt == NULL || Nhlt->Header.Signature !=
> NHLT_ACPI_TABLE_SIGNATURE) {
>
> + DEBUG ((DEBUG_ERROR, "Nhlt == NULL or wrong signature\n"));
>
> + return NULL;
>
> + }
>
> +
>
> + DEBUG ((DEBUG_INFO, "Found NhltTable, Address = 0x%016x\n", Nhlt));
>
> +
>
> + return Nhlt;
>
> +}
>
> +
>
> +/**
>
> + Sets NVS ACPI variables for HDAS._DSM and SNDW._DSD accordingly to
> policy.
>
> +
>
> + @param[in] NhltAcpiTableAddress
>
> + @param[in] NhltAcpiTableLength
>
> + @param[in] *HdAudioConfigHob
>
> + @param[in] *HdAudioDxeConfig
>
> +**/
>
> +VOID
>
> +UpdateHdaAcpiData (
>
> + IN UINT64 NhltAcpiTableAddress,
>
> + IN UINT32 NhltAcpiTableLength,
>
> + IN CONST HDAUDIO_HOB *HdAudioConfigHob,
>
> + IN CONST HDAUDIO_DXE_CONFIG *HdAudioDxeConfig
>
> + )
>
> +{
>
> + DEBUG ((DEBUG_INFO, "UpdateHdaAcpiData():\n NHLT Address =
> 0x%016x, Length = 0x%08x\n", NhltAcpiTableAddress,
> NhltAcpiTableLength));
>
> + DEBUG ((DEBUG_INFO, " FeatureMask = 0x%08x\n", HdAudioDxeConfig-
> >DspFeatureMask));
>
> +
>
> + mPchNvsAreaProtocol.Area->XTAL = XTAL_FREQ_38P4MHZ;
>
> + mPchNvsAreaProtocol.Area->NHLA = NhltAcpiTableAddress;
>
> + mPchNvsAreaProtocol.Area->NHLL = NhltAcpiTableLength;
>
> + mPchNvsAreaProtocol.Area->ADFM = HdAudioDxeConfig-
> >DspFeatureMask;
>
> +
>
> + if (HdAudioConfigHob->DspEnable || HdAudioConfigHob-
> >DspUaaCompliance == FALSE) {
>
> + mPchNvsAreaProtocol.Area->SWQ0 = HdAudioConfigHob-
> >AudioLinkSndw1 ? 0 : BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ1 = HdAudioConfigHob-
> >AudioLinkSndw2 ? 0 : BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ2 = HdAudioConfigHob-
> >AudioLinkSndw3 ? 0 : BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ3 = HdAudioConfigHob-
> >AudioLinkSndw4 ? 0 : BIT1;
>
> + } else {
>
> + mPchNvsAreaProtocol.Area->SWQ0 = BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ1 = BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ2 = BIT1;
>
> + mPchNvsAreaProtocol.Area->SWQ3 = BIT1;
>
> + }
>
> +
>
> + mPchNvsAreaProtocol.Area->SWMC = GetPchHdaMaxSndwLinkNum ();
>
> +
>
> + mPchNvsAreaProtocol.Area->ACS0 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[0].AutonomousClockStop;
>
> + mPchNvsAreaProtocol.Area->ACS1 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[1].AutonomousClockStop;
>
> + mPchNvsAreaProtocol.Area->ACS2 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[2].AutonomousClockStop;
>
> + mPchNvsAreaProtocol.Area->ACS3 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[3].AutonomousClockStop;
>
> +
>
> + mPchNvsAreaProtocol.Area->DAI0 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[0].DataOnActiveIntervalSelect;
>
> + mPchNvsAreaProtocol.Area->DAI1 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[1].DataOnActiveIntervalSelect;
>
> + mPchNvsAreaProtocol.Area->DAI2 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[2].DataOnActiveIntervalSelect;
>
> + mPchNvsAreaProtocol.Area->DAI3 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[3].DataOnActiveIntervalSelect;
>
> +
>
> + mPchNvsAreaProtocol.Area->DOD0 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[0].DataOnDelaySelect;
>
> + mPchNvsAreaProtocol.Area->DOD1 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[1].DataOnDelaySelect;
>
> + mPchNvsAreaProtocol.Area->DOD2 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[2].DataOnDelaySelect;
>
> + mPchNvsAreaProtocol.Area->DOD3 = (UINT8)HdAudioDxeConfig-
> >SndwConfig[3].DataOnDelaySelect;
>
> +}
>
> +
>
> +/**
>
> + Initialize Intel High Definition Audio ACPI Tables
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> + @retval EFI_LOAD_ERROR ACPI table cannot be installed
>
> + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disabled
>
> +**/
>
> +EFI_STATUS
>
> +PchHdAudioAcpiInit (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT64 HdaPciBase;
>
> + CONST HDAUDIO_HOB *HdAudioConfigHob;
>
> + PCH_POLICY_PROTOCOL *PchPolicy;
>
> + HDAUDIO_DXE_CONFIG *HdAudioDxeConfig;
>
> + NHLT_ACPI_TABLE *NhltTable;
>
> +
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() Start\n"));
>
> +
>
> + HdAudioConfigHob = &mPchConfigHob->HdAudio;
>
> +
>
> + ///
>
> + /// Get PCH Policy Protocol
>
> + ///
>
> + Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID
> **)&PchPolicy);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Get HD Audio DXE Config Block
>
> + ///
>
> + Status = GetConfigBlock ((VOID *)PchPolicy, &gHdAudioDxeConfigGuid,
> (VOID *)&HdAudioDxeConfig);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + HdaPciBase = HdaPciCfgBase ();
>
> +
>
> + if ((PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) ==
> 0xFFFF) || (HdAudioConfigHob->DspEnable == FALSE)) {
>
> + // Do not set ACPI tables if HDAudio is Function disabled or DSP is disabled
>
> + DEBUG ((DEBUG_INFO, "AudioDSP: Non-HDAudio ACPI Table (NHLT) not
> set!\n"));
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +
>
> + NhltTable = LocateNhltAcpiTable ();
>
> + if (NhltTable == NULL) {
>
> + return EFI_LOAD_ERROR;
>
> + }
>
> +
>
> + UpdateHdaAcpiData ((UINT64) (UINTN) NhltTable, (UINT32) (NhltTable-
> >Header.Length), HdAudioConfigHob, HdAudioDxeConfig);
>
> + DEBUG_CODE ( NhltAcpiTableDump (NhltTable); );
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchHdAudioAcpiInit() End - Status = %r\n",
> Status));
>
> + return Status;
>
> +}
>
> +
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
> new file mode 100644
> index 0000000000..734d4e295a
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.c
> @@ -0,0 +1,314 @@
> +/** @file
>
> + This is the Common driver that initializes the Intel PCH.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/TimerLib.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <Library/HobLib.h>
>
> +
>
> +#include "PchInit.h"
>
> +#include <PchPolicyCommon.h>
>
> +#include <Library/SpiCommonLib.h>
>
> +#include <Library/PmcPrivateLib.h>
>
> +#include <Library/PchDmiLib.h>
>
> +#include <Library/SiScheduleResetLib.h>
>
> +#include <Library/PchCycleDecodingLib.h>
>
> +#include <Library/PchPcrLib.h>
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Library/SpiAccessPrivateLib.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PchPcrRegs.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/SpiRegs.h>
>
> +#include <Register/PchRegsPsth.h>
>
> +#include <Register/PmcRegs.h>
>
> +#include <Register/HdaRegs.h>
>
> +#include <Library/GpioCheckConflictLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +
>
> +//
>
> +// Module variables
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB
> *mPchConfigHob;
>
> +
>
> +//
>
> +// EFI_EVENT
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_EVENT mHeciEvent;
>
> +
>
> +/**
>
> + Common PchInit Module Entry Point
>
> +**/
>
> +VOID
>
> +PchInitEntryPointCommon (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_PEI_HOB_POINTERS HobPtr;
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() Start\n"));
>
> +
>
> + //
>
> + // Get PCH Config HOB.
>
> + //
>
> + HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid);
>
> + ASSERT (HobPtr.Guid != NULL);
>
> + mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA
> (HobPtr.Guid);
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchInitEntryPointCommon() End\n"));
>
> +
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + Lock SPI register before boot
>
> +**/
>
> +VOID
>
> +LockSpiConfiguration (
>
> + VOID
>
> + )
>
> +{
>
> + UINTN Index;
>
> + UINT16 Data16;
>
> + UINT16 Data16And;
>
> + UINT16 Data16Or;
>
> + UINT32 Data32;
>
> + UINT32 DlockValue;
>
> + UINT64 PciSpiRegBase;
>
> + UINT32 PchSpiBar0;
>
> + UINT32 Timer;
>
> +
>
> + PciSpiRegBase = SpiPciCfgBase ();
>
> +
>
> + //
>
> + // Check for SPI controller presence before programming
>
> + //
>
> + if (PciSegmentRead16 (PciSpiRegBase + PCI_VENDOR_ID_OFFSET) ==
> 0xFFFF) {
>
> + return;
>
> + }
>
> +
>
> + //
>
> + // Make sure SPI BAR0 has fixed address before writing to boot script.
>
> + // The same base address is set in PEI and will be used during resume.
>
> + //
>
> + PchSpiBar0 = PCH_SPI_BASE_ADDRESS;
>
> +
>
> + PciSegmentAnd8 (PciSpiRegBase + PCI_COMMAND_OFFSET, (UINT8)
> ~EFI_PCI_COMMAND_MEMORY_SPACE);
>
> + PciSegmentWrite32 (PciSpiRegBase + R_SPI_CFG_BAR0, PchSpiBar0);
>
> + PciSegmentOr8 (PciSpiRegBase + PCI_COMMAND_OFFSET,
> EFI_PCI_COMMAND_MEMORY_SPACE);
>
> +
>
> + //
>
> + // Locking for security reasons only if Extended BIOS Range Decode is
> supported
>
> + //
>
> + if (IsExtendedBiosRangeDecodeSupported ()) {
>
> + //
>
> + // Before setting FLOCKDN lock Extended BIOS Range configuration
>
> + // All configuration of this feature shall be done already at this moment
>
> + //
>
> + PciSegmentOr32 (PciSpiRegBase + R_SPI_CFG_BC, BIT28);
>
> + S3BootScriptSavePciCfgWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) PciSpiRegBase + R_SPI_CFG_BC,
>
> + 1,
>
> + (VOID *) (UINTN) (PciSpiRegBase + R_SPI_CFG_BC)
>
> + );
>
> + }
>
> +
>
> + //
>
> + // Program the Flash Protection Range Register based on policy
>
> + //
>
> + DlockValue = MmioRead32 (PchSpiBar0 + R_SPI_MEM_DLOCK);
>
> + for (Index = 0; Index < PCH_FLASH_PROTECTED_RANGES; ++Index) {
>
> + if ((mPchConfigHob->ProtectRange[Index].WriteProtectionEnable ||
>
> + mPchConfigHob->ProtectRange[Index].ReadProtectionEnable) !=
> TRUE) {
>
> + continue;
>
> + }
>
> +
>
> + //
>
> + // Proceed to program the register after ensure it is enabled
>
> + //
>
> + Data32 = 0;
>
> + Data32 |= (mPchConfigHob->ProtectRange[Index].WriteProtectionEnable
> == TRUE) ? B_SPI_MEM_PRX_WPE : 0;
>
> + Data32 |= (mPchConfigHob->ProtectRange[Index].ReadProtectionEnable
> == TRUE) ? B_SPI_MEM_PRX_RPE : 0;
>
> + Data32 |= ((UINT32) mPchConfigHob-
> >ProtectRange[Index].ProtectedRangeLimit << N_SPI_MEM_PRX_PRL) &
> B_SPI_MEM_PRX_PRL_MASK;
>
> + Data32 |= ((UINT32) mPchConfigHob-
> >ProtectRange[Index].ProtectedRangeBase << N_SPI_MEM_PRX_PRB) &
> B_SPI_MEM_PRX_PRB_MASK;
>
> + DEBUG ((DEBUG_INFO, "Protected range %d: 0x%08x \n", Index,
> Data32));
>
> +
>
> + DlockValue |= (UINT32) (B_SPI_MEM_DLOCK_PR0LOCKDN << Index);
>
> + MmioWrite32 ((UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index *
> S_SPI_MEM_PRX))), Data32);
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index *
> S_SPI_MEM_PRX))),
>
> + 1,
>
> + (VOID *) (UINTN) (PchSpiBar0 + (R_SPI_MEM_PR0 + (Index *
> S_SPI_MEM_PRX)))
>
> + );
>
> + }
>
> + //
>
> + // Program DLOCK register
>
> + //
>
> + MmioWrite32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK), DlockValue);
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK),
>
> + 1,
>
> + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_DLOCK)
>
> + );
>
> +
>
> + ///
>
> + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
>
> + /// In PCH SPI controller the BIOS should set the Flash Configuration Lock-
> Down bit
>
> + /// (SPI_BAR0 + 04[15]) at end of post. When set to 1, those Flash Program
> Registers
>
> + /// that are locked down by this FLOCKDN bit cannot be written.
>
> + /// Please refer to the EDS for which program registers are impacted.
>
> + /// Additionally BIOS must program SPI_BAR0 + 0x04 BIT11 (WRSDIS) to
> disable Write Status in HW sequencing
>
> + ///
>
> +
>
> + //
>
> + // Ensure there is no pending SPI trasaction before setting lock bits
>
> + //
>
> + Timer = 0;
>
> + while (MmioRead16 (PchSpiBar0 + R_SPI_MEM_HSFSC) &
> B_SPI_MEM_HSFSC_SCIP) {
>
> + if (Timer > SPI_WAIT_TIME) {
>
> + //
>
> + // SPI transaction is pending too long at this point, exit with error.
>
> + //
>
> + DEBUG ((DEBUG_ERROR, "SPI Cycle timeout\n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + MicroSecondDelay (SPI_WAIT_PERIOD);
>
> + Timer += SPI_WAIT_PERIOD;
>
> + }
>
> +
>
> + Data16And = B_SPI_MEM_HSFSC_SCIP;
>
> + Data16 = 0;
>
> + S3BootScriptSaveMemPoll (
>
> + S3BootScriptWidthUint16,
>
> + PchSpiBar0 + R_SPI_MEM_HSFSC,
>
> + &Data16And,
>
> + &Data16,
>
> + SPI_WAIT_PERIOD,
>
> + SPI_WAIT_TIME / SPI_WAIT_PERIOD
>
> + );
>
> +
>
> + //
>
> + // Clear any outstanding status
>
> + //
>
> + Data16Or = B_SPI_MEM_HSFSC_SAF_DLE
>
> + | B_SPI_MEM_HSFSC_SAF_ERROR
>
> + | B_SPI_MEM_HSFSC_AEL
>
> + | B_SPI_MEM_HSFSC_FCERR
>
> + | B_SPI_MEM_HSFSC_FDONE;
>
> + Data16And = 0xFFFF;
>
> + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And,
> Data16Or);
>
> + S3BootScriptSaveMemReadWrite (
>
> + S3BootScriptWidthUint16,
>
> + PchSpiBar0 + R_SPI_MEM_HSFSC,
>
> + &Data16Or,
>
> + &Data16And
>
> + );
>
> +
>
> + //
>
> + // Set WRSDIS
>
> + //
>
> + Data16Or = B_SPI_MEM_HSFSC_WRSDIS;
>
> + Data16And = 0xFFFF;
>
> + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And,
> Data16Or);
>
> + S3BootScriptSaveMemReadWrite (
>
> + S3BootScriptWidthUint16,
>
> + PchSpiBar0 + R_SPI_MEM_HSFSC,
>
> + &Data16Or,
>
> + &Data16And
>
> + );
>
> +
>
> + //
>
> + // Set FLOCKDN
>
> + //
>
> + Data16Or = B_SPI_MEM_HSFSC_FLOCKDN;
>
> + Data16And = 0xFFFF;
>
> + MmioAndThenOr16 (PchSpiBar0 + R_SPI_MEM_HSFSC, Data16And,
> Data16Or);
>
> + S3BootScriptSaveMemReadWrite (
>
> + S3BootScriptWidthUint16,
>
> + PchSpiBar0 + R_SPI_MEM_HSFSC,
>
> + &Data16Or,
>
> + &Data16And
>
> + );
>
> +
>
> + ///
>
> + /// SPI Flash Programming Guide Section 5.5.2 Vendor Component Lock
>
> + /// It is strongly recommended that BIOS sets the Vendor Component Lock
> (VCL) bits. VCL applies
>
> + /// the lock to both VSCC0 and VSCC1 even if VSCC0 is not used. Without
> the VCL bits set, it is
>
> + /// possible to make Host/GbE VSCC register(s) changes in that can cause
> undesired host and
>
> + /// integrated GbE Serial Flash functionality.
>
> + ///
>
> + MmioOr32 ((UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0),
> B_SPI_MEM_SFDP0_VSCC0_VCL);
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0),
>
> + 1,
>
> + (VOID *) (UINTN) (PchSpiBar0 + R_SPI_MEM_SFDP0_VSCC0)
>
> + );
>
> +}
>
> +
>
> +/**
>
> + Set HD Audio PME bit
>
> +**/
>
> +VOID
>
> +ConfigureHdAudioPme (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 HdaPciBase;
>
> +
>
> + HdaPciBase = HdaPciCfgBase ();
>
> +
>
> + if (PciSegmentRead16 (HdaPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF)
> {
>
> + return;
>
> + }
>
> +
>
> + ///
>
> + /// PME Enable for Audio controller
>
> + ///
>
> + if (mPchConfigHob->HdAudio.Pme == TRUE) {
>
> + PciSegmentOr32 (HdaPciBase + R_HDA_CFG_PCS, (UINT32)
> B_HDA_CFG_PCS_PMEE);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Set eSPI BME bit
>
> +**/
>
> +VOID
>
> +ConfigureEspiBme (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 EspiPciBase;
>
> +
>
> + EspiPciBase = EspiPciCfgBase ();
>
> +
>
> + if (PciSegmentRead16 (EspiPciBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF)
> {
>
> + return;
>
> + }
>
> + if ((PciSegmentRead32 (EspiPciBase + R_ESPI_CFG_PCBC) &
> B_ESPI_CFG_PCBC_ESPI_EN) == 0) {
>
> + return;
>
> + }
>
> +
>
> + //
>
> + // Refer to PCH BWG.
>
> + // To enable eSPI bus mastering BIOS must enable BME in eSPI controller
>
> + // and also set BME bit in the respective slave devices through
> Configuration
>
> + // and Capabilities register of each slave using Get_Configuration and
> Set_Configuration functionality.
>
> + //
>
> + // NOTE: The setting is also done in PEI, but might be cleared by PCI bus
> during PCI enumeration.
>
> + // Therefore, reeable it after PCI enumeration done.
>
> + //
>
> + if (mPchConfigHob->Espi.BmeMasterSlaveEnabled == TRUE) {
>
> + PciSegmentOr8 (EspiPciBase + PCI_COMMAND_OFFSET,
> EFI_PCI_COMMAND_BUS_MASTER);
>
> + }
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
> new file mode 100644
> index 0000000000..0d6647e3f3
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInit.h
> @@ -0,0 +1,122 @@
> +/** @file
>
> + Header file for PCH Initialization Driver.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _PCH_INIT_DXE_H_
>
> +#define _PCH_INIT_DXE_H_
>
> +
>
> +#include <SiConfigHob.h>
>
> +#include <PchConfigHob.h>
>
> +#include <Protocol/PchNvsArea.h>
>
> +
>
> +//
>
> +// Data definitions
>
> +//
>
> +extern EFI_HANDLE mImageHandle;
>
> +
>
> +//
>
> +// Pch NVS area definition
>
> +//
>
> +extern PCH_NVS_AREA_PROTOCOL mPchNvsAreaProtocol;
>
> +
>
> +extern PCH_CONFIG_HOB *mPchConfigHob;
>
> +extern SI_CONFIG_HOB_DATA *mSiConfigHobData;
>
> +
>
> +//
>
> +// Function Prototype
>
> +//
>
> +
>
> +//
>
> +// Local function prototypes
>
> +//
>
> +/**
>
> + Common PchInit Module Entry Point
>
> +**/
>
> +VOID
>
> +PchInitEntryPointCommon (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Calls Boot Os Hand off routine for each Serial IO Controller
>
> +**/
>
> +VOID
>
> +ConfigureSerialIoAtBoot (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Puts all SerialIo controllers (except UARTs in debug mode) in D3.
>
> + Clears MemoryEnable for all PCI-mode controllers on S3 resume
>
> +**/
>
> +VOID
>
> +ConfigureSerialIoAtS3Resume (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Add Serial Io UART Hidden Handles
>
> +**/
>
> +VOID
>
> +CreateSerialIoUartHiddenHandle (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Initialize Intel High Definition Audio ACPI Tables
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> + @retval EFI_LOAD_ERROR ACPI table cannot be installed
>
> + @retval EFI_UNSUPPORTED ACPI table not set because DSP is disabled
>
> +**/
>
> +EFI_STATUS
>
> +PchHdAudioAcpiInit (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Perform the remaining configuration on SATA to perform device detection,
>
> + then set the SATA SPD and PxE corresponding, and set the Register Lock
> on PCH SATA
>
> +**/
>
> +VOID
>
> +ConfigureSataOnEndOfDxe (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Update ASL data for CNVI Device.
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +UpdateCnviAcpiData (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Initialize Pch acpi
>
> + @param[in] ImageHandle Handle for the image of this driver
>
> +
>
> + @retval EFI_SUCCESS The function completed successfully
>
> + @retval EFI_OUT_OF_RESOURCES Do not have enough resources to
> initialize the driver
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiInit (
>
> + IN EFI_HANDLE ImageHandle
>
> + );
>
> +
>
> +/**
>
> + Update ASL object before Boot
>
> +
>
> + @retval EFI_STATUS
>
> + @retval EFI_NOT_READY The Acpi protocols are not ready.
>
> +**/
>
> +EFI_STATUS
>
> +PchUpdateNvsArea (
>
> + VOID
>
> + );
>
> +
>
> +#endif // _PCH_INIT_DXE_H_
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
> new file mode 100644
> index 0000000000..1d4f08a86c
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxe.c
> @@ -0,0 +1,354 @@
> +/** @file
>
> + This is the Uefi driver that initializes the Intel PCH.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiLib.h>
>
> +
>
> +#include "PchInit.h"
>
> +#include <PchPolicyCommon.h>
>
> +#include <Protocol/PcieIoTrap.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/PmcLib.h>
>
> +#include <Library/PchPcieRpLib.h>
>
> +#include <Library/PmcPrivateLib.h>
>
> +#include <Library/PciExpressHelpersLib.h>
>
> +#include <PcieRegs.h>
>
> +#include <Register/PchPcieRpRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE mImageHandle;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16
> mPcieIoTrapAddress;
>
> +
>
> +VOID
>
> +EFIAPI
>
> +PchOnBootToOs (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + );
>
> +
>
> +
>
> +VOID
>
> +EFIAPI
>
> +PchOnExitBootServices (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + );
>
> +
>
> +
>
> +VOID
>
> +EFIAPI
>
> +PchOnReadyToBoot (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + );
>
> +
>
> +/**
>
> + Process all the lock downs
>
> +**/
>
> +VOID
>
> +ProcessSmiLocks (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 Data32And;
>
> + UINT32 Data32Or;
>
> + UINT16 ABase;
>
> +
>
> + ///
>
> + /// PCH BIOS Spec Section 3.6 Flash Security Recommendation
>
> + /// BIOS needs to enables SMI_LOCK (PMC PCI offset A0h[4] = 1b) which
> prevent writes
>
> + /// to the Global SMI Enable bit (GLB_SMI_EN ABASE + 30h[0]). Enabling
> this bit will
>
> + /// mitigate malicious software attempts to gain system management
> mode privileges.
>
> + ///
>
> + if (mPchConfigHob->LockDown.GlobalSmi == TRUE) {
>
> + ///
>
> + /// Save Global SMI Enable bit setting before BIOS enables SMI_LOCK
> during S3 resume
>
> + ///
>
> + ABase = PmcGetAcpiBase ();
>
> + Data32Or = IoRead32 ((UINTN) (ABase + R_ACPI_IO_SMI_EN));
>
> + if ((Data32Or & B_ACPI_IO_SMI_EN_GBL_SMI) != 0) {
>
> + Data32And = 0xFFFFFFFF;
>
> + Data32Or |= B_ACPI_IO_SMI_EN_GBL_SMI;
>
> + S3BootScriptSaveIoReadWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) (ABase + R_ACPI_IO_SMI_EN),
>
> + &Data32Or, // Data to be ORed
>
> + &Data32And // Data to be ANDed
>
> + );
>
> + }
>
> + PmcLockSmiWithS3BootScript ();
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Do PCIE power management while resume from S3
>
> +**/
>
> +VOID
>
> +ReconfigurePciePowerManagementForS3 (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT32 Data32;
>
> + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol;
>
> +
>
> + Status = gBS->LocateProtocol (&gPchPcieIoTrapProtocolGuid, NULL, (VOID
> **) &PchPcieIoTrapProtocol);
>
> + if (EFI_ERROR (Status)) {
>
> + return;
>
> + }
>
> + mPcieIoTrapAddress = PchPcieIoTrapProtocol->PcieTrapAddress;
>
> + 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 = PchPciePmTrap;
>
> + S3BootScriptSaveIoWrite (
>
> + S3BootScriptWidthUint32,
>
> + (UINTN) (mPcieIoTrapAddress),
>
> + 1,
>
> + &Data32
>
> + );
>
> + } else {
>
> + ASSERT (FALSE);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + This is the callback function for PCI ENUMERATION COMPLETE.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchOnPciEnumComplete (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + VOID *ProtocolPointer;
>
> +
>
> + ///
>
> + /// 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);
>
> +
>
> + ReconfigurePciePowerManagementForS3 ();
>
> + ProcessSmiLocks ();
>
> + ConfigureSerialIoAtS3Resume ();
>
> +}
>
> +
>
> +/**
>
> + Register callback functions for PCH DXE.
>
> +**/
>
> +VOID
>
> +PchRegisterNotifications (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_EVENT ReadyToBoot;
>
> + EFI_EVENT LegacyBootEvent;
>
> + EFI_EVENT ExitBootServicesEvent;
>
> + VOID *Registration;
>
> +
>
> + ///
>
> + /// Create PCI Enumeration Completed callback for PCH
>
> + ///
>
> + EfiCreateProtocolNotifyEvent (
>
> + &gEfiPciEnumerationCompleteProtocolGuid,
>
> + TPL_CALLBACK,
>
> + PchOnPciEnumComplete,
>
> + NULL,
>
> + &Registration
>
> + );
>
> +
>
> + //
>
> + // Register a Ready to boot event to config PCIE power management
> setting after OPROM executed
>
> + //
>
> + Status = EfiCreateEventReadyToBootEx (
>
> + TPL_CALLBACK,
>
> + PchOnReadyToBoot,
>
> + NULL,
>
> + &ReadyToBoot
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Create events for PCH to do the task before
> ExitBootServices/LegacyBoot.
>
> + // It is guaranteed that only one of two events below will be signalled
>
> + //
>
> + Status = gBS->CreateEvent (
>
> + EVT_SIGNAL_EXIT_BOOT_SERVICES,
>
> + TPL_CALLBACK,
>
> + PchOnExitBootServices,
>
> + NULL,
>
> + &ExitBootServicesEvent
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = EfiCreateEventLegacyBootEx (
>
> + TPL_CALLBACK,
>
> + PchOnBootToOs,
>
> + NULL,
>
> + &LegacyBootEvent
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +}
>
> +
>
> +/**
>
> + <b>PchInit DXE Module Entry Point</b>\n
>
> + - <b>Introduction</b>\n
>
> + The PchInit module is a DXE driver that initializes the Intel Platform
> Controller Hub
>
> + following the PCH BIOS specification and EDS requirements and
> recommendations. It consumes
>
> + the PCH_POLICY_HOB SI_POLICY_HOB for expected configurations per
> policy.
>
> + This is the standard EFI driver point that detects whether there is an
> supported PCH in
>
> + the system and if so, initializes the chipset.
>
> +
>
> + - <b>Details</b>\n
>
> + This module is required for initializing the Intel Platform Controller Hub to
>
> + follow the PCH BIOS specification and EDS.
>
> + This includes some initialization sequences, enabling and disabling PCH
> devices,
>
> + configuring clock gating, RST PCIe Storage Remapping, SATA controller,
> ASPM of PCIE devices. Right before end of DXE,
>
> + it's responsible to lock down registers for security requirement.
>
> +
>
> + - @pre
>
> + - PCH PCR base address configured
>
> + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
>
> + - This is to ensure that PCI MMIO and IO resource has been prepared
> and available for this driver to allocate.
>
> +
>
> + - @result
>
> + - Publishes the @link _PCH_INFO_PROTOCOL PCH_INFO_PROTOCOL
> @endlink
>
> + - Publishes the @link _PCH_EMMC_TUNING_PROTOCOL
> PCH_EMMC_TUNING_PROTOCOL @endlink
>
> +
>
> + - <b>References</b>\n
>
> + - @link _PCH_POLICY PCH_POLICY_HOB @endlink.
>
> + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.
>
> +
>
> + - <b>Integration Checklists</b>\n
>
> + - Verify prerequisites are met. Porting Recommendations.
>
> + - No modification of this module should be necessary
>
> + - Any modification of this module should follow the PCH BIOS
> Specification and EDS
>
> +
>
> + @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 Do not have enough resources to
> initialize the driver
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchInitEntryPointDxe (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() Start\n"));
>
> +
>
> + mImageHandle = ImageHandle;
>
> +
>
> + PchInitEntryPointCommon ();
>
> +
>
> + Status = PchAcpiInit (ImageHandle);
>
> +
>
> + PchRegisterNotifications ();
>
> +
>
> + CreateSerialIoUartHiddenHandle ();
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchInitEntryPointDxe() End\n"));
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + PCH initialization before ExitBootServices / LegacyBoot events
>
> + Useful for operations which must happen later than at EndOfPost event
>
> +
>
> + @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
>
> +PchOnBootToOs (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + ///
>
> + /// Closed the event to avoid call twice
>
> + ///
>
> + if (Event != NULL) {
>
> + gBS->CloseEvent (Event);
>
> + }
>
> +
>
> + ConfigureSerialIoAtBoot ();
>
> +
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + PCH initialization on ExitBootService. This event is used if only
> ExitBootService is used
>
> + and not in legacy boot
>
> +
>
> + @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.
>
> +
>
> + @retval None
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchOnExitBootServices (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + PchOnBootToOs (NULL, NULL);
>
> +
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + PCH 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
>
> +PchOnReadyToBoot (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() Start\n"));
>
> +
>
> + if (Event != NULL) {
>
> + gBS->CloseEvent (Event);
>
> + }
>
> +
>
> + //
>
> + // Trigger an Iotrap SMI to config PCIE power management setting after
> PCI enumrate is done
>
> + //
>
> + if (mPcieIoTrapAddress != 0) {
>
> + IoWrite32 ((UINTN) mPcieIoTrapAddress, PchPciePmTrap);
>
> + } else {
>
> + ASSERT (FALSE);
>
> + }
>
> +
>
> + DEBUG ((DEBUG_INFO, "Uefi PchOnReadyToBoot() End\n"));
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf
> new file mode 100644
> index 0000000000..4941ff0f49
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchInitDxeTgl.inf
> @@ -0,0 +1,96 @@
> +## @file
>
> +# Component description file for Pch Initialization driver
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = PchInitDxeTgl
>
> +FILE_GUID = 4BD0EB2F-3A2D-442E-822D-753516F75424
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = DXE_DRIVER
>
> +ENTRY_POINT = PchInitEntryPointDxe
>
> +
>
> +
>
> +[LibraryClasses]
>
> +S3BootScriptLib
>
> +PchCycleDecodingLib
>
> +PchPcieRpLib
>
> +PchPcrLib
>
> +PchInfoLib
>
> +PciExpressHelpersLib
>
> +UefiBootServicesTableLib
>
> +DebugLib
>
> +IoLib
>
> +TimerLib
>
> +HobLib
>
> +BaseMemoryLib
>
> +MemoryAllocationLib
>
> +UefiLib
>
> +DxeServicesTableLib
>
> +UefiDriverEntryPoint
>
> +UefiRuntimeServicesTableLib
>
> +GpioLib
>
> +SerialIoAccessLib
>
> +ConfigBlockLib
>
> +PmcLib
>
> +PmcPrivateLibWithS3
>
> +SataLib
>
> +PchDmiWithS3Lib
>
> +GbeLib
>
> +SiScheduleResetLib
>
> +DxeHdaNhltLib
>
> +SpiAccessPrivateLib
>
> +PchPciBdfLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +
>
> +[Pcd]
>
> +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress
>
> +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr ## CONSUMES
>
> +gSiPkgTokenSpaceGuid.PcdEmbeddedEnable ## CONSUMES
>
> +
>
> +[Sources]
>
> +PchInitDxe.c
>
> +PchInit.h
>
> +PchInit.c
>
> +PchSata.c
>
> +PchSerialIo.c
>
> +PchSerialIoDxe.c
>
> +PchHdaAcpi.c
>
> +PchCnviAcpi.c
>
> +PchAcpi.c
>
> +
>
> +
>
> +[Protocols]
>
> +gPchNvsAreaProtocolGuid ## PRODUCES
>
> +gEfiPciIoProtocolGuid ## CONSUMES
>
> +gEfiAcpiTableProtocolGuid ## CONSUMES
>
> +gEfiBlockIoProtocolGuid ## CONSUMES
>
> +gHeciProtocolGuid
>
> +gEfiPciEnumerationCompleteProtocolGuid ## CONSUMES
>
> +gPchPcieIoTrapProtocolGuid ## CONSUMES
>
> +gPchPolicyProtocolGuid ## CONSUMES
>
> +
>
> +
>
> +[Guids]
>
> +gEfiEndOfDxeEventGroupGuid
>
> +gEfiAcpiTableGuid
>
> +gEmmcDxeConfigGuid ## CONSUMES
>
> +gSiConfigHobGuid ## CONSUMES
>
> +gPchConfigHobGuid ## CONSUMES
>
> +gPchRstHobGuid ## CONSUMES
>
> +gHdAudioDxeConfigGuid ## CONSUMES
>
> +gGpioDxeConfigGuid ## CONSUMES
>
> +gCnviConfigHobGuid ## CONSUMES
>
> +gHybridStorageHobGuid ## CONSUMES
>
> +
>
> +[Depex]
>
> +gEfiPciHostBridgeResourceAllocationProtocolGuid ## This is to ensure that
> PCI MMIO and IO resource has been prepared and available for this driver to
> allocate.
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
> new file mode 100644
> index 0000000000..886f3b4bc0
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSata.c
> @@ -0,0 +1,89 @@
> +/** @file
>
> + Perform related functions for PCH Sata in DXE phase
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +
>
> +#include "PchInit.h"
>
> +#include <Library/SataLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <Register/SataRegs.h>
>
> +
>
> +/**
>
> + Perform the remaining configuration on SATA to perform device detection,
>
> + then set the SATA SPD and PxE corresponding, and set the Register Lock
> on PCH SATA
>
> +
>
> + @retval None
>
> +**/
>
> +VOID
>
> +ConfigureSataOnEndOfDxe (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 PciSataRegBase;
>
> + UINT16 SataPortsEnabled;
>
> + UINT32 DwordReg;
>
> + UINTN Index;
>
> + UINT32 SataCtrlIndex;
>
> +
>
> + for (SataCtrlIndex = 0; SataCtrlIndex < MaxSataControllerNum ();
> SataCtrlIndex++) {
>
> + ///
>
> + /// SATA PCS: Enable the port in any of below condition:
>
> + /// i.) Hot plug is enabled
>
> + /// ii.) A device is attached
>
> + /// iii.) Test mode is enabled
>
> + /// iv.) Configured as eSATA port
>
> + ///
>
> + PciSataRegBase = SataPciCfgBase (SataCtrlIndex);
>
> + SataPortsEnabled = 0;
>
> +
>
> + DwordReg = PciSegmentRead32 (PciSataRegBase + R_SATA_CFG_PCS);
>
> + for (Index = 0; Index < MaxSataPortNum (SataCtrlIndex); Index++) {
>
> + if ((mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].HotPlug
> == TRUE) ||
>
> + (DwordReg & (B_SATA_CFG_PCS_P0P << Index)) ||
>
> + (mPchConfigHob->Sata[SataCtrlIndex].TestMode == TRUE) ||
>
> + (mPchConfigHob->Sata[SataCtrlIndex].PortSettings[Index].External
> == TRUE)) {
>
> + SataPortsEnabled |= (mPchConfigHob-
> >Sata[SataCtrlIndex].PortSettings[Index].Enable << Index);
>
> + }
>
> + }
>
> +
>
> + ///
>
> + /// Set MAP."Sata PortX Disable", SATA PCI offset 90h[23:16] to 1b if SATA
> Port 0/1/2/3/4/5/6/7 is disabled
>
> + ///
>
> + PciSegmentOr32 (PciSataRegBase + R_SATA_CFG_MAP,
> (~SataPortsEnabled << N_SATA_CFG_MAP_SPD));
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint32,
>
> + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase +
> R_SATA_CFG_MAP,
>
> + 1,
>
> + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) +
> PciSataRegBase + R_SATA_CFG_MAP)
>
> + );
>
> +
>
> + ///
>
> + /// Program PCS "Port X Enabled", SATA PCI offset 94h[7:0] = Port 0~7
> Enabled bit as per SataPortsEnabled value.
>
> + ///
>
> + PciSegmentOr16 (PciSataRegBase + R_SATA_CFG_PCS,
> SataPortsEnabled);
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint16,
>
> + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase +
> R_SATA_CFG_PCS,
>
> + 1,
>
> + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) +
> PciSataRegBase + R_SATA_CFG_PCS)
>
> + );
>
> +
>
> + ///
>
> + /// Step 14
>
> + /// Program SATA PCI offset 9Ch [31] to 1b
>
> + ///
>
> + PciSegmentOr32 ((UINTN) (PciSataRegBase + R_SATA_CFG_SATAGC),
> BIT31);
>
> + S3BootScriptSaveMemWrite (
>
> + S3BootScriptWidthUint32,
>
> + PcdGet64 (PcdSiPciExpressBaseAddress) + PciSataRegBase +
> R_SATA_CFG_SATAGC,
>
> + 1,
>
> + (VOID *) (UINTN) (PcdGet64 (PcdSiPciExpressBaseAddress) +
> PciSataRegBase + R_SATA_CFG_SATAGC)
>
> + );
>
> + }
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
> new file mode 100644
> index 0000000000..9409a9a387
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIo.c
> @@ -0,0 +1,33 @@
> +/** @file
>
> + Initializes Serial IO Controllers.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchInit.h"
>
> +#include <Library/SerialIoPrivateLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +
>
> +/**
>
> + Calls Boot Os Hand off routine for each Serial IO Controller
>
> +**/
>
> +VOID
>
> +ConfigureSerialIoAtBoot (
>
> + VOID
>
> + )
>
> +{
>
> + UINT8 Index;
>
> +
>
> + for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
>
> + SerialIoSpiBootHandler (Index, &mPchConfigHob-
> >SerialIo.SpiDeviceConfig[Index]);
>
> + }
>
> +
>
> + for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
>
> + SerialIoI2cBootHandler (Index, &mPchConfigHob-
> >SerialIo.I2cDeviceConfig[Index]);
>
> + }
>
> +
>
> + for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++)
> {
>
> + SerialIoUartBootHandler (Index, &mPchConfigHob-
> >SerialIo.UartDeviceConfig[Index]);
>
> + }
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
> new file mode 100644
> index 0000000000..fde7da6b96
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Dxe/PchSerialIoDxe.c
> @@ -0,0 +1,134 @@
> +/** @file
>
> + Initializes Serial IO Controllers.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/DevicePathLib.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/DxeServicesTableLib.h>
>
> +#include <Library/SerialIoPrivateLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Register/SerialIoRegs.h>
>
> +#include <PchInit.h>
>
> +
>
> +typedef struct {
>
> + ACPI_HID_DEVICE_PATH RootPort;
>
> + ACPI_EXTENDED_HID_DEVICE_PATH AcpiDev;
>
> + CHAR8 HidString[8];
>
> + UINT16 DeviceId;
>
> + UINT8 UartIndex;
>
> + EFI_DEVICE_PATH_PROTOCOL End;
>
> +} SERIALIO_UART_DEVICE_PATH;
>
> +
>
> +#define mPciRootBridge {{ACPI_DEVICE_PATH, ACPI_DP, {(UINT8)(sizeof
> (ACPI_HID_DEVICE_PATH)), 0}}, EISA_PNP_ID (0x0A03), 0}
>
> +#define mAcpiDev {{ACPI_DEVICE_PATH, ACPI_EXTENDED_DP,
> {(UINT8)(sizeof (ACPI_EXTENDED_HID_DEVICE_PATH) + (sizeof(CHAR8) * 8)
> + sizeof (UINT16) + sizeof (UINT8)), 0}},0,0,0}
>
> +#define mEndEntire {END_DEVICE_PATH_TYPE,
> END_ENTIRE_DEVICE_PATH_SUBTYPE, {END_DEVICE_PATH_LENGTH, 0}}
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED SERIALIO_UART_DEVICE_PATH
> mSerialIoUartPath = {
>
> + mPciRootBridge,
>
> + mAcpiDev,
>
> + "UART\0\0\0",
>
> + 0xFFFF,
>
> + 0xFF,
>
> + mEndEntire
>
> +};
>
> +
>
> +/**
>
> + Add Serial Io UART Hidden Handles
>
> +**/
>
> +VOID
>
> +CreateSerialIoUartHiddenHandle (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_HANDLE NewHandle;
>
> + EFI_DEVICE_PATH_PROTOCOL *NewPath;
>
> + EFI_STATUS Status;
>
> + UINT8 Index;
>
> + UINT16 DeviceId;
>
> +
>
> + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle\n"));
>
> +
>
> + for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++)
> {
>
> + DEBUG ((DEBUG_INFO, "UART Index: %d Mode: %d\n", Index,
> mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode));
>
> + if (mPchConfigHob->SerialIo.UartDeviceConfig[Index].Mode ==
> SerialIoUartHidden) {
>
> + NewHandle = NULL;
>
> + DeviceId = MmioRead16 (GetSerialIoUartFixedPciCfgAddress (Index) +
> PCI_DEVICE_ID_OFFSET);
>
> + DEBUG ((DEBUG_INFO, "Creating Handle for UART DEVICE_ID: 0x%X \n",
> DeviceId));
>
> + mSerialIoUartPath.AcpiDev.HID = 0x5432 + (Index << 16); //UAR
>
> + mSerialIoUartPath.HidString[4] = (CHAR8)('0' + Index);
>
> + mSerialIoUartPath.DeviceId = DeviceId;
>
> + mSerialIoUartPath.UartIndex = Index;
>
> + NewPath = DuplicateDevicePath ((EFI_DEVICE_PATH_PROTOCOL*)
> &mSerialIoUartPath);
>
> + Status = gBS->InstallMultipleProtocolInterfaces (
>
> + &NewHandle,
>
> + &gEfiDevicePathProtocolGuid,
>
> + NewPath,
>
> + NULL
>
> + );
>
> + DEBUG ((DEBUG_INFO, "CreateSerialIoUartHandle Status: %r\n",
> Status));
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Stores Pme Control Status and Command register values in S3 Boot Script
>
> +
>
> + @param[in] S3PciCfgBase S3 Boot Script Pci Config Base
>
> + @param[in] Command Pci Command register data to save
>
> + @param[in] Pme Pci Pme Control register data to save
>
> +
>
> +**/
>
> +VOID
>
> +STATIC
>
> +SerialIoS3Save (
>
> + IN UINTN S3PciCfgBase,
>
> + IN UINTN Command,
>
> + IN UINTN Pme
>
> + )
>
> +{
>
> + if (S3PciCfgBase != 0) {
>
> + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase +
> R_SERIAL_IO_CFG_PME_CTRL_STS, 1, &Pme);
>
> + S3BootScriptSavePciCfgWrite (S3BootScriptWidthUint32, S3PciCfgBase +
> PCI_COMMAND_OFFSET, 1, &Command);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Puts all SerialIo controllers (except UARTs in debug mode) in D3.
>
> + Clears MemoryEnable for all PCI-mode controllers on S3 resume
>
> +**/
>
> +VOID
>
> +ConfigureSerialIoAtS3Resume (
>
> + VOID
>
> + )
>
> +{
>
> + UINT8 Index;
>
> + UINTN S3PciCfgBase;
>
> + UINT32 Command;
>
> + UINT32 Pme;
>
> +
>
> + S3PciCfgBase = 0;
>
> + for (Index = 0; Index < GetPchMaxSerialIoSpiControllersNum (); Index++) {
>
> + SerialIoSpiS3Handler (Index, &mPchConfigHob-
> >SerialIo.SpiDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
>
> + SerialIoS3Save (S3PciCfgBase, Command, Pme);
>
> + }
>
> +
>
> + S3PciCfgBase = 0;
>
> + for (Index = 0; Index < GetPchMaxSerialIoI2cControllersNum (); Index++) {
>
> + SerialIoI2cS3Handler (Index, &mPchConfigHob-
> >SerialIo.I2cDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
>
> + SerialIoS3Save (S3PciCfgBase, Command, Pme);
>
> + }
>
> +
>
> + S3PciCfgBase = 0;
>
> + for (Index = 0; Index < GetPchMaxSerialIoUartControllersNum (); Index++)
> {
>
> + SerialIoUartS3Handler (Index, &mPchConfigHob-
> >SerialIo.UartDeviceConfig[Index], &S3PciCfgBase, &Command, &Pme);
>
> + SerialIoS3Save (S3PciCfgBase, Command, Pme);
>
> + }
>
> +}
>
> +
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c
> new file mode 100644
> index 0000000000..786ce13915
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/GbeSxSmm.c
> @@ -0,0 +1,266 @@
> +/** @file
>
> + Gbe Sx handler implementation.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include <Library/TimerLib.h>
>
> +#include "PchInitSmm.h"
>
> +#include <Library/PmcPrivateLib.h>
>
> +#include <Library/GbeMdiLib.h>
>
> +#include <Library/GbeLib.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/GbeRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +
>
> +
>
> +/**
>
> + Configure WOL during Sx entry.
>
> +
>
> + @param [in] GbeBar GbE MMIO space
>
> +**/
>
> +VOID
>
> +GbeWolWorkaround (
>
> + IN UINT32 GbeBar
>
> + )
>
> +{
>
> + UINT32 RAL0;
>
> + UINT32 RAH0;
>
> + UINT16 WUC;
>
> + EFI_STATUS Status;
>
> + UINT16 Data16;
>
> +
>
> + //
>
> + // 1. Set page to 769 Port Control Registers
>
> + // 2. Wait 4 mSec
>
> + //
>
> + Status = GbeMdiSetPage (GbeBar,
> PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 3. Set registry to 17 Port General Configuration
>
> + // 4. Copy all settings from Port General Configuration
>
> + //
>
> + Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 5. Modify BIT 4 and BIT 2 to disable host wake up and set MACPD
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 |
> B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE) &
> (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP));
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 6. Read Receive Address Low and Receive Address High from MMIO
>
> + //
>
> + RAL0 = MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAL);
>
> + RAH0 = MmioRead32 (GbeBar + R_GBE_MEM_CSR_RAH);
>
> +
>
> + //
>
> + // 7. Set page to 800 Wake Up Registers
>
> + // 8. Wait 4 mSec
>
> + //
>
> + Status = GbeMdiSetPage (GbeBar,
> PHY_MDI_PAGE_800_WAKE_UP_REGISTERS);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 9. Set registry to 16 Receive Address Low 1/2
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_800_REGISETER_16_RAL0);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 10. Program first 16 bits [0:15] out of 48 in Receive Address Low 1/2
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 & 0xFFFF));
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 11. Set registry to 17 Receive Address Low 2/2
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_800_REGISETER_17_RAL1);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 12. Program second 16 bits [16:31] out of 48 in Receive Address Low 2/2
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAL0 >> 16));
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 13. Set registry to 18 Receive Address High 1/2
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_800_REGISETER_18_RAH0);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 14. Program last 16 bits [32:47] out of 48
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (RAH0 &
> B_GBE_MEM_CSR_RAH_RAH));
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 15. Set registry to 19 Receive Address High 2/2
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_800_REGISETER_19_RAH1);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 16. Set Address Valid
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE,
> B_PHY_MDI_PAGE_800_REGISETER_19_RAH1_ADDRESS_VALID);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 17. Set Wake Up Control Register 1
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_800_REGISETER_1_WUC);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 18. Copy WakeUp Control from MAC MMIO
>
> + //
>
> + WUC = (UINT16) MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC);
>
> +
>
> + //
>
> + // 19. Store WakeUp Contorl into LCD
>
> + // Modify APME bit to enable APM wake up
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE, (WUC & 0xFFFF));
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 20. Set page to 803 Host Wol Packet
>
> + // 21. Wait 4 mSec
>
> + //
>
> + Status = GbeMdiSetPage (GbeBar,
> PHY_MDI_PAGE_803_HOST_WOL_PACKET);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 22. Set registry to 66 Host WoL Packet Clear
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_803_REGISETER_66_HWPC);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 23. Clear WOL Packet
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> R_PHY_MDI_PHY_REG_DATA_READ_WRITE, 0);
>
> + if (EFI_ERROR (Status)) return;
>
> + //
>
> + // 24. Set page to 769 Port Control Registers
>
> + // 25. Wait 4 mSec
>
> + //
>
> + Status = GbeMdiSetPage (GbeBar,
> PHY_MDI_PAGE_769_PORT_CONTROL_REGISTERS);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 26. Set registry to 17 Port General Configuration
>
> + //
>
> + Status = GbeMdiSetRegister (GbeBar,
> R_PHY_MDI_PAGE_769_REGISETER_17_PGC);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 27. Copy all settings from Port General Configuration
>
> + //
>
> + Status = GbeMdiRead (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), &Data16);
>
> + if (EFI_ERROR (Status)) return;
>
> +
>
> + //
>
> + // 28. Modify BIT 4 and BIT 2 to enable host wake up and clear MACPD
>
> + //
>
> + Status = GbeMdiWrite (GbeBar, B_PHY_MDI_PHY_ADDRESS_01,
> MDI_REG_SHIFT (R_PHY_MDI_PAGE_769_REGISETER_17_PGC), (Data16 |
> B_PHY_MDI_PAGE_769_REGISETER_17_PGC_HOST_WAKE_UP) &
> (~B_PHY_MDI_PAGE_769_REGISETER_17_PGC_MACPD_ENABLE));
>
> + if (EFI_ERROR (Status)) return;
>
> +}
>
> +
>
> +/**
>
> + Additional Internal GbE Controller special cases WOL Support.
>
> +
>
> + System BIOS is required perform additional steps upon S0 to S3,4,5
> transition
>
> + when ME is off and GbE device in D0. This is needed to enable LAN wake
>
> + in particular when platform is shut-down from EFI.
>
> +**/
>
> +VOID
>
> +GbeSxWorkaround (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 LanRegBase;
>
> + UINT32 GbeBar;
>
> + EFI_STATUS Status;
>
> +
>
> + LanRegBase = GbePciCfgBase ();
>
> +
>
> + if (PciSegmentRead16 (LanRegBase + PCI_VENDOR_ID_OFFSET) ==
> 0xFFFF) {
>
> + return;
>
> + }
>
> +
>
> + //
>
> + // Check if GbE device is in D0
>
> + //
>
> + if ((PciSegmentRead16 (LanRegBase + R_GBE_CFG_PMCS) &
> B_GBE_CFG_PMCS_PS) != V_GBE_CFG_PMCS_PS0) {
>
> + return;
>
> + }
>
> +
>
> + ASSERT (mResvMmioSize >= (1 << N_GBE_CFG_MBARA_ALIGN));
>
> + GbeBar = (UINT32) mResvMmioBaseAddr;
>
> + if (GbeBar == 0) {
>
> + ASSERT (FALSE);
>
> + return;
>
> + }
>
> +
>
> + //
>
> + // Enable MMIO decode using reserved range.
>
> + //
>
> + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16)
> ~EFI_PCI_COMMAND_MEMORY_SPACE);
>
> + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, GbeBar);
>
> + PciSegmentOr16 (LanRegBase + PCI_COMMAND_OFFSET,
> EFI_PCI_COMMAND_MEMORY_SPACE);
>
> +
>
> + //
>
> + // If MBARA offset 5800h [0] = 1b then proceed with the w/a
>
> + //
>
> + if (MmioRead32 (GbeBar + R_GBE_MEM_CSR_WUC) &
> B_GBE_MEM_CSR_WUC_APME) {
>
> + Status = GbeMdiAcquireMdio (GbeBar);
>
> + ASSERT_EFI_ERROR (Status);
>
> + if (!EFI_ERROR (Status)) {
>
> + GbeWolWorkaround (GbeBar);
>
> + GbeMdiReleaseMdio (GbeBar);
>
> + }
>
> + }
>
> +
>
> + //
>
> + // Disable MMIO decode.
>
> + //
>
> + PciSegmentAnd16 (LanRegBase + PCI_COMMAND_OFFSET, (UINT16)
> ~EFI_PCI_COMMAND_MEMORY_SPACE);
>
> + PciSegmentWrite32 (LanRegBase + R_GBE_CFG_MBARA, 0);
>
> +}
>
> +
>
> +/**
>
> + Enable platform wake from LAN when in DeepSx if platform supports it.
>
> + Called upon Sx entry.
>
> +**/
>
> +VOID
>
> +GbeConfigureDeepSxWake (
>
> + VOID
>
> + )
>
> +{
>
> + if (PmcIsLanDeepSxWakeEnabled ()) {
>
> + IoOr32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_EN_127_96),
> (UINT32) B_ACPI_IO_GPE0_EN_127_96_LAN_WAKE);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + GbE Sx entry handler
>
> +**/
>
> +VOID
>
> +PchLanSxCallback (
>
> + VOID
>
> + )
>
> +{
>
> + if (IsGbeEnabled ()) {
>
> + GbeSxWorkaround ();
>
> + GbeConfigureDeepSxWake ();
>
> +
>
> + }
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
> new file mode 100644
> index 0000000000..f435af434a
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchBiosWriteProtect.c
> @@ -0,0 +1,137 @@
> +/** @file
>
> + PCH BIOS Write Protect Driver.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchInitSmm.h"
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/SpiRegs.h>
>
> +#include <Library/SpiAccessPrivateLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +
>
> +//
>
> +// Global variables
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> PCH_TCO_SMI_DISPATCH_PROTOCOL *mPchTcoSmiDispatchProtocol;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> PCH_ESPI_SMI_DISPATCH_PROTOCOL *mEspiSmmDispatchProtocol;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mLpcRegBase;
>
> +
>
> +/**
>
> + This hardware SMI handler will be run every time the BIOS Write Enable bit
> is set.
>
> +
>
> + @param[in] DispatchHandle Not used
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchSpiBiosWpCallback (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + SpiClearBiosWriteProtectDisable ();
>
> +}
>
> +
>
> +/**
>
> + This hardware SMI handler will be run every time the BIOS Write Enable bit
> is set.
>
> +
>
> + @param[in] DispatchHandle Not used
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchLpcBiosWpCallback (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + //
>
> + // Disable BIOSWE bit to protect BIOS
>
> + //
>
> + PciSegmentAnd8 ((UINTN) (mLpcRegBase + R_LPC_CFG_BC), (UINT8)
> ~B_LPC_CFG_BC_WPD);
>
> +}
>
> +
>
> +/**
>
> + Entry point for Pch Bios Write Protect driver.
>
> +
>
> + @param[in] ImageHandle Image handle of this driver.
>
> + @param[in] SystemTable Global system service table.
>
> +
>
> + @retval EFI_SUCCESS Initialization complete.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchBiosWriteProtect (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_HANDLE Handle;
>
> +
>
> + DEBUG ((DEBUG_INFO, "InstallPchBiosWriteProtect()\n"));
>
> +
>
> + if (mPchConfigHob->LockDown.BiosLock != TRUE) {
>
> + return EFI_SUCCESS;
>
> + }
>
> +
>
> + mLpcRegBase = LpcPciCfgBase ();
>
> +
>
> + DEBUG ((DEBUG_INFO, "Installing BIOS Write Protect SMI handler\n"));
>
> + //
>
> + // Get the PCH TCO SMM dispatch protocol
>
> + //
>
> + mPchTcoSmiDispatchProtocol = NULL;
>
> + Status = gSmst->SmmLocateProtocol (&gPchTcoSmiDispatchProtocolGuid,
> NULL, (VOID **) &mPchTcoSmiDispatchProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> + //
>
> + // Always register an SPI BiosWp callback function to handle TCO BIOSWR
> SMI
>
> + // NOTE: No matter the BIOS resides behind SPI or not, it needs to handle
> the SPI BIOS WP SMI
>
> + // to avoid SMI deadloop on SPI WPD write.
>
> + //
>
> + Handle = NULL;
>
> + Status = mPchTcoSmiDispatchProtocol->SpiBiosWpRegister (
>
> + mPchTcoSmiDispatchProtocol,
>
> + PchSpiBiosWpCallback,
>
> + &Handle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Always register an LPC/eSPI BiosWp callback function to handle TCO
> BIOSWR SMI
>
> + // NOTE: No matter the BIOS resides behind LPC/eSPI or not, it needs to
> handle the BIOS WP SMI
>
> + // to avoid SMI deadloop on LPC/eSPI WPD write.
>
> + //
>
> + if (IsEspiEnabled ()) {
>
> + //
>
> + // Get the PCH ESPI SMM dispatch protocol
>
> + //
>
> + mEspiSmmDispatchProtocol = NULL;
>
> + Status = gSmst->SmmLocateProtocol
> (&gPchEspiSmiDispatchProtocolGuid, NULL, (VOID **)
> &mEspiSmmDispatchProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Register an ESpiBiosWp callback function to handle BIOSWR SMI
>
> + //
>
> + Handle = NULL;
>
> + Status = mEspiSmmDispatchProtocol->BiosWrProtectRegister (
>
> + mEspiSmmDispatchProtocol,
>
> + PchLpcBiosWpCallback,
>
> + &Handle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + } else {
>
> + //
>
> + // Register an LPC BiosWp callback function to handle TCO BIOSWR SMI
>
> + //
>
> + Handle = NULL;
>
> + Status = mPchTcoSmiDispatchProtocol->LpcBiosWpRegister (
>
> + mPchTcoSmiDispatchProtocol,
>
> + PchLpcBiosWpCallback,
>
> + &Handle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
> new file mode 100644
> index 0000000000..f3d11ab204
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchHdaSxSmm.c
> @@ -0,0 +1,33 @@
> +/** @file
>
> + PCH HD Audio Sx handler implementation.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include "PchInitSmm.h"
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/HdaRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT64 mHdaPciBase;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN
> mHdaCodecSxWakeCapability = FALSE;
>
> +
>
> +/**
>
> + Updates Codec Sx Wake Capability setting: disabled/enabled
>
> +**/
>
> +VOID
>
> +UpdateHdaCodecSxWakeCapabilitySetting (
>
> + VOID
>
> + )
>
> +{
>
> + mHdaPciBase = HdaPciCfgBase ();
>
> +
>
> + if ((mPchConfigHob->HdAudio.CodecSxWakeCapability == FALSE) ||
>
> + (PciSegmentRead16 (mHdaPciBase + PCI_VENDOR_ID_OFFSET) ==
> 0xFFFF)) {
>
> + mHdaCodecSxWakeCapability = FALSE;
>
> + } else {
>
> + mHdaCodecSxWakeCapability = TRUE;
>
> + }
>
> +}
>
> +
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
> new file mode 100644
> index 0000000000..9c2475e3a1
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.c
> @@ -0,0 +1,285 @@
> +/** @file
>
> + PCH Init Smm module for PCH specific SMI handlers.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchInitSmm.h"
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/UsbRegs.h>
>
> +#include <Register/SmbusRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA
> *mPchNvsArea;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16
> mAcpiBaseAddr;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED FIVR_EXT_RAIL_CONFIG
> mFivrExtVnnRailSxConfig;
>
> +
>
> +//
>
> +// NOTE: The module variables of policy here are only valid in post time, but
> not runtime time.
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_CONFIG_HOB
> *mPchConfigHob;
>
> +
>
> +//
>
> +// The reserved MMIO range to be used in Sx handler
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_PHYSICAL_ADDRESS
> mResvMmioBaseAddr;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINTN
> mResvMmioSize;
>
> +
>
> +/**
>
> + SMBUS Sx entry SMI handler.
>
> +**/
>
> +VOID
>
> +SmbusSxCallback (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 SmbusRegBase;
>
> + UINT16 SmbusIoBase;
>
> +
>
> + SmbusRegBase = SmbusPciCfgBase ();
>
> +
>
> + if (PciSegmentRead32 (SmbusRegBase) == 0xFFFFFFFF) {
>
> + return;
>
> + }
>
> +
>
> + SmbusIoBase = PciSegmentRead16 (SmbusRegBase +
> R_SMBUS_CFG_BASE) & B_SMBUS_CFG_BASE_BAR;
>
> + if (SmbusIoBase == 0) {
>
> + return;
>
> + }
>
> +
>
> + PciSegmentOr8 (SmbusRegBase + PCI_COMMAND_OFFSET,
> EFI_PCI_COMMAND_IO_SPACE);
>
> + //
>
> + // Clear SMBUS status and SMB_WAK_STS of GPE0
>
> + //
>
> + IoWrite8 (SmbusIoBase + R_SMBUS_IO_HSTS,
> B_SMBUS_IO_SMBALERT_STS);
>
> + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96,
> B_ACPI_IO_GPE0_STS_127_96_SMB_WAK);
>
> +}
>
> +
>
> +/*
>
> + PCH xHCI Sx entry SMI handler
>
> +*/
>
> +VOID
>
> +PchXhciSxCallback (
>
> + VOID
>
> + )
>
> +{
>
> + UINTN XhciPciBase;
>
> +
>
> + XhciPciBase = PchXhciPciCfgBase ();
>
> +
>
> + //
>
> + // Safety check for xHCI existense
>
> + //
>
> + if (PciSegmentRead32 (XhciPciBase) == 0xFFFFFFFF) {
>
> + return;
>
> + }
>
> +
>
> + //
>
> + // If xHCI is in D0 that means OS didn't put it to D3 during Sx entry i.e. USB
> kernel debug is enabled.
>
> + // Unless it is put manually to D3, USB wake functionality will not work.
>
> + //
>
> + if ((PciSegmentRead8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS) &
> V_XHCI_CFG_PWR_CNTL_STS_PWR_STS_D3) == 0) {
>
> + //
>
> + // Put device to D3 to enable wake functionality for USB devices
>
> + //
>
> + PciSegmentOr8 (XhciPciBase + R_XHCI_CFG_PWR_CNTL_STS,
> (UINT8)(B_XHCI_CFG_PWR_CNTL_STS_PWR_STS));
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Cache PCH FIVR policy.
>
> +**/
>
> +VOID
>
> +UpdatePchFivrSettings (
>
> + VOID
>
> + )
>
> +{
>
> + CopyMem (
>
> + &mFivrExtVnnRailSxConfig,
>
> + &mPchConfigHob->Fivr.ExtVnnRailSx,
>
> + sizeof (mFivrExtVnnRailSxConfig)
>
> + );
>
> +}
>
> +
>
> +/**
>
> + PCH Sx entry SMI handler.
>
> +
>
> + @param[in] Handle Handle of the callback
>
> + @param[in] Context The dispatch context
>
> + @param[in,out] CommBuffer A pointer to a collection of data in
> memory that will
>
> + be conveyed from a non-SMM environment into an SMM
> environment.
>
> + @param[in,out] CommBufferSize The size of the CommBuffer.
>
> +
>
> + @retval EFI_SUCCESS
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSxHandler (
>
> + IN EFI_HANDLE Handle,
>
> + IN CONST VOID *Context OPTIONAL,
>
> + IN OUT VOID *CommBuffer OPTIONAL,
>
> + IN OUT UINTN *CommBufferSize OPTIONAL
>
> + )
>
> +{
>
> + PchLanSxCallback ();
>
> + PchXhciSxCallback ();
>
> +
>
> + SmbusSxCallback ();
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Initialize PCH Sx entry SMI handler.
>
> +
>
> + @param[in] ImageHandle - Handle for the image of this driver
>
> +**/
>
> +VOID
>
> +InitializeSxHandler (
>
> + IN EFI_HANDLE ImageHandle
>
> + )
>
> +{
>
> + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;
>
> + EFI_HANDLE SxDispatchHandle;
>
> + EFI_SLEEP_TYPE SxType;
>
> + EFI_STATUS Status;
>
> +
>
> + DEBUG ((DEBUG_INFO, "InitializeSxHandler() Start\n"));
>
> +
>
> + //
>
> + // Register the callback for S3/S4/S5 entry
>
> + //
>
> + SxDispatchContext.Phase = SxEntry;
>
> + for (SxType = SxS3; SxType <= SxS5; SxType++) {
>
> + SxDispatchContext.Type = SxType;
>
> + Status = mSxDispatch->Register (
>
> + mSxDispatch,
>
> + PchSxHandler,
>
> + &SxDispatchContext,
>
> + &SxDispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + }
>
> +
>
> + DEBUG ((DEBUG_INFO, "InitializeSxHandler() End\n"));
>
> +}
>
> +
>
> +/**
>
> + Allocates reserved MMIO for Sx SMI handler use.
>
> +**/
>
> +VOID
>
> +AllocateReservedMmio (
>
> + VOID
>
> + )
>
> +{
>
> + mResvMmioBaseAddr = PcdGet32 (PcdSiliconInitTempMemBaseAddr);
>
> + mResvMmioSize = PcdGet32 (PcdSiliconInitTempMemSize);
>
> + DEBUG ((DEBUG_INFO, "mResvMmioBaseAddr %x, mResvMmioSize
> %x\n", mResvMmioBaseAddr, mResvMmioSize));
>
> +}
>
> +
>
> +/**
>
> + Initializes the PCH SMM handler for for PCIE hot plug support
>
> + <b>PchInit SMM Module Entry Point</b>\n
>
> + - <b>Introduction</b>\n
>
> + The PchInitSmm module is a SMM driver that initializes the Intel Platform
> Controller Hub
>
> + SMM requirements and services. It consumes the PCH_POLICY_HOB and
> SI_POLICY_HOB for expected
>
> + configurations per policy.
>
> +
>
> + - <b>Details</b>\n
>
> + This module provides SMI handlers to services PCIE HotPlug SMI,
> LinkActive SMI, and LinkEq SMI.
>
> + And also provides port 0x61 emulation support, registers BIOS WP handler
> to process BIOSWP status,
>
> + and registers SPI Async SMI handler to handler SPI Async SMI.
>
> + This module also registers Sx SMI callback function to detail with GPIO Sx
> Isolation and LAN requirement.
>
> +
>
> + - @pre
>
> + - PCH PCR base address configured
>
> + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
>
> + - This is to ensure that PCI MMIO and IO resource has been prepared
> and available for this driver to allocate.
>
> + - EFI_SMM_BASE2_PROTOCOL
>
> + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_SX_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_CPU_PROTOCOL
>
> + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink
>
> + - @link _PCH_SMI_DISPATCH_PROTOCOL
> PCH_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL
> PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL
> PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL
> PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink
>
> +
>
> + - <b>References</b>\n
>
> + - @link _PCH_POLICY PCH_POLICY_HOB @endlink.
>
> + - @link _SI_POLICY_STRUCT SI_POLICY_HOB @endlink.
>
> +
>
> + - <b>Integration Checklists</b>\n
>
> + - Verify prerequisites are met. Porting Recommendations.
>
> + - No modification of this module should be necessary
>
> + - Any modification of this module should follow the PCH BIOS
> Specification and EDS
>
> +
>
> + @param[in] ImageHandle - Handle for the image of this driver
>
> + @param[in] SystemTable - Pointer to the EFI System Table
>
> +
>
> + @retval EFI_SUCCESS - PCH SMM handler was installed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchInitSmmEntryPoint (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol;
>
> + EFI_PEI_HOB_POINTERS HobPtr;
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchInitSmmEntryPoint()\n"));
>
> +
>
> + Status = gSmst->SmmLocateProtocol (
>
> + &gEfiSmmIoTrapDispatch2ProtocolGuid,
>
> + NULL,
>
> + (VOID **) &mPchIoTrap
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = gSmst->SmmLocateProtocol (
>
> + &gEfiSmmSxDispatch2ProtocolGuid,
>
> + NULL,
>
> + (VOID**) &mSxDispatch
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID
> **) &PchNvsAreaProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> + mPchNvsArea = PchNvsAreaProtocol->Area;
>
> +
>
> + //
>
> + // Get PCH Data HOB.
>
> + //
>
> + HobPtr.Guid = GetFirstGuidHob (&gPchConfigHobGuid);
>
> + ASSERT (HobPtr.Guid != NULL);
>
> + mPchConfigHob = (PCH_CONFIG_HOB *) GET_GUID_HOB_DATA
> (HobPtr.Guid);
>
> +
>
> + mAcpiBaseAddr = PmcGetAcpiBase ();
>
> +
>
> + AllocateReservedMmio ();
>
> +
>
> + InitializeSxHandler (ImageHandle);
>
> +
>
> + Status = InitializePchPcieSmm (ImageHandle, SystemTable);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = InstallPchBiosWriteProtect (ImageHandle, SystemTable);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = InstallPchSpiAsyncSmiHandler ();
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + UpdateHdaCodecSxWakeCapabilitySetting ();
>
> +
>
> + UpdatePchFivrSettings ();
>
> +
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
> new file mode 100644
> index 0000000000..c2a09acd11
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.h
> @@ -0,0 +1,254 @@
> +/** @file
>
> + Header file for PCH Init SMM Handler
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#ifndef _PCH_INIT_SMM_H_
>
> +#define _PCH_INIT_SMM_H_
>
> +
>
> +#include <PiDxe.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/UefiDriverEntryPoint.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiRuntimeServicesTableLib.h>
>
> +#include <Library/SmmServicesTableLib.h>
>
> +#include <Library/DxeServicesTableLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Protocol/SmmSxDispatch2.h>
>
> +#include <Protocol/SmmIoTrapDispatch2.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <Library/HobLib.h>
>
> +#include <Protocol/SmmCpu.h>
>
> +#include <Library/TimerLib.h>
>
> +
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Library/PmcLib.h>
>
> +#include <Library/PchPcieRpLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/SataLib.h>
>
> +#include <Library/GpioLib.h>
>
> +#include <Library/GpioNativeLib.h>
>
> +#include <Library/EspiLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/ConfigBlockLib.h>
>
> +#include <Library/PciExpressHelpersLib.h>
>
> +#include <Protocol/PchPcieSmiDispatch.h>
>
> +#include <Protocol/PchTcoSmiDispatch.h>
>
> +#include <Protocol/PchSmiDispatch.h>
>
> +#include <Protocol/PchEspiSmiDispatch.h>
>
> +#include <Protocol/PchSmmIoTrapControl.h>
>
> +#include <Protocol/PchNvsArea.h>
>
> +#include <Protocol/PcieIoTrap.h>
>
> +#include <SiConfigHob.h>
>
> +#include <PchConfigHob.h>
>
> +#include <Library/PmcPrivateLib.h>
>
> +
>
> +extern EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *mPchIoTrap;
>
> +extern EFI_SMM_SX_DISPATCH2_PROTOCOL *mSxDispatch;
>
> +
>
> +extern PCH_NVS_AREA *mPchNvsArea;
>
> +extern UINT16 mAcpiBaseAddr;
>
> +
>
> +extern EFI_PHYSICAL_ADDRESS mResvMmioBaseAddr;
>
> +extern UINTN mResvMmioSize;
>
> +
>
> +//
>
> +// NOTE: The module variables of policy here are only valid in post time, but
> not runtime time.
>
> +//
>
> +extern PCH_CONFIG_HOB *mPchConfigHob;
>
> +extern SI_CONFIG_HOB_DATA *mSiConfigHobData;
>
> +
>
> +/**
>
> + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling
>
> +
>
> + @param[in] ImageHandle The image handle of this module
>
> + @param[in] SystemTable The EFI System Table
>
> +
>
> + @retval EFI_SUCCESS The function completes successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InitializePchPcieSmm (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + );
>
> +
>
> +/**
>
> + Program Common Clock and ASPM of Downstream Devices
>
> +
>
> + @param[in] PortIndex Pcie Root Port Number
>
> + @param[in] RpDevice Pcie Root Pci Device Number
>
> + @param[in] RpFunction Pcie Root Pci Function Number
>
> +
>
> + @retval EFI_SUCCESS Root port complete successfully
>
> + @retval EFI_UNSUPPORTED PMC has invalid vendor ID
>
> +**/
>
> +EFI_STATUS
>
> +PchPcieSmi (
>
> + IN UINT8 PortIndex,
>
> + IN UINT8 RpDevice,
>
> + IN UINT8 RpFunction
>
> + );
>
> +
>
> +/**
>
> + PCIE Hotplug SMI call back function for each Root port
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieSmiRpHandlerFunction (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + );
>
> +
>
> +/**
>
> + PCIE Link Active State Change Hotplug SMI call back function for all Root
> ports
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieLinkActiveStateChange (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + );
>
> +
>
> +/**
>
> + PCIE Link Equalization Request SMI call back function for all Root ports
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieLinkEqHandlerFunction (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + );
>
> +
>
> +/**
>
> + An IoTrap callback to config PCIE power management settings
>
> +
>
> + @param[in] DispatchHandle - The handle of this callback, obtained when
> registering
>
> + @param[in] DispatchContext - Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieIoTrapSmiCallback (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,
>
> + IN OUT VOID *CommBuffer,
>
> + IN OUT UINTN *CommBufferSize
>
> + );
>
> +
>
> +/**
>
> + Initializes the PCH SMM handler for PCH save and restore
>
> +
>
> + @param[in] ImageHandle - Handle for the image of this driver
>
> + @param[in] SystemTable - Pointer to the EFI System Table
>
> +
>
> + @retval EFI_SUCCESS - PCH SMM handler was installed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchInitLateSmm (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + );
>
> +
>
> +/**
>
> + Initialize PCH Sx entry SMI handler.
>
> +
>
> + @param[in] ImageHandle - Handle for the image of this driver
>
> +**/
>
> +VOID
>
> +InitializeSxHandler (
>
> + IN EFI_HANDLE ImageHandle
>
> + );
>
> +
>
> +/**
>
> + PCH Sx entry SMI handler.
>
> +
>
> + @param[in] Handle Handle of the callback
>
> + @param[in] Context The dispatch context
>
> + @param[in,out] CommBuffer A pointer to a collection of data in
> memory that will
>
> + be conveyed from a non-SMM environment into an SMM
> environment.
>
> + @param[in,out] CommBufferSize The size of the CommBuffer.
>
> +
>
> + @retval EFI_SUCCESS
>
> +**/
>
> +
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSxHandler (
>
> + IN EFI_HANDLE Handle,
>
> + IN CONST VOID *Context OPTIONAL,
>
> + IN OUT VOID *CommBuffer OPTIONAL,
>
> + IN OUT UINTN *CommBufferSize OPTIONAL
>
> + );
>
> +
>
> +/**
>
> + GbE Sx entry handler
>
> +**/
>
> +VOID
>
> +PchLanSxCallback (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Updates Codec Sx Wake Capability setting: disabled/enabled
>
> +**/
>
> +VOID
>
> +UpdateHdaCodecSxWakeCapabilitySetting (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Register dispatch function to handle GPIO pads Sx isolation
>
> +**/
>
> +VOID
>
> +InitializeGpioSxIsolationSmm (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Entry point for Pch Bios Write Protect driver.
>
> +
>
> + @param[in] ImageHandle Image handle of this driver.
>
> + @param[in] SystemTable Global system service table.
>
> +
>
> + @retval EFI_SUCCESS Initialization complete.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchBiosWriteProtect (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + );
>
> +
>
> +/**
>
> + This fuction install SPI ASYNC SMI handler.
>
> +
>
> + @retval EFI_SUCCESS Initialization complete.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchSpiAsyncSmiHandler (
>
> + VOID
>
> + );
>
> +
>
> +
>
> +
>
> +
>
> +
>
> +#endif
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
> new file mode 100644
> index 0000000000..aaf36a7b2a
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchInitSmm.inf
> @@ -0,0 +1,110 @@
> +## @file
>
> +# Component description file for PchInitSmm driver
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = PchInitSmm
>
> +FILE_GUID = D7B10D4E-67E6-4C74-83E9-F9AF0ACC33CC
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = DXE_SMM_DRIVER
>
> +PI_SPECIFICATION_VERSION = 1.10
>
> +ENTRY_POINT = PchInitSmmEntryPoint
>
> +#
>
> +# The following information is for reference only and not required by the
> build tools.
>
> +#
>
> +# VALID_ARCHITECTURES = IA32 X64
>
> +#
>
> +
>
> +
>
> +[LibraryClasses]
>
> +UefiBootServicesTableLib
>
> +UefiDriverEntryPoint
>
> +DxeServicesTableLib
>
> +IoLib
>
> +DebugLib
>
> +BaseLib
>
> +BaseMemoryLib
>
> +S3BootScriptLib
>
> +PciExpressHelpersLib
>
> +SmmServicesTableLib
>
> +PciSegmentLib
>
> +HobLib
>
> +GpioLib
>
> +GpioPrivateLib
>
> +ReportStatusCodeLib
>
> +DevicePathLib
>
> +PmcLib
>
> +PchPcieRpLib
>
> +PchInfoLib
>
> +EspiLib
>
> +TimerLib
>
> +ConfigBlockLib
>
> +PmcPrivateLib
>
> +SataLib
>
> +GbeLib
>
> +GbeMdiLib
>
> +SpiAccessPrivateLib
>
> +PchPciBdfLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +
>
> +[Pcd]
>
> +gSiPkgTokenSpaceGuid.PcdSiPciExpressBaseAddress
>
> +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMin
>
> +gSiPkgTokenSpaceGuid.PcdSiliconInitTempPciBusMax
>
> +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemBaseAddr
>
> +gSiPkgTokenSpaceGuid.PcdSiliconInitTempMemSize
>
> +
>
> +
>
> +[Sources]
>
> +PchInitSmm.c
>
> +PchPcieSmm.c
>
> +GbeSxSmm.c
>
> +PchInitSmm.h
>
> +PchBiosWriteProtect.c
>
> +PchSpiAsync.c
>
> +PchHdaSxSmm.c
>
> +
>
> +
>
> +[Protocols]
>
> +gEfiSmmIoTrapDispatch2ProtocolGuid ## CONSUMES
>
> +gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
>
> +gPchSmmIoTrapControlGuid ## CONSUMES
>
> +gEfiSmmCpuProtocolGuid ## CONSUMES
>
> +gPchNvsAreaProtocolGuid ## CONSUMES
>
> +gPchPcieSmiDispatchProtocolGuid ## CONSUMES
>
> +gPchTcoSmiDispatchProtocolGuid ## CONSUMES
>
> +gPchSmiDispatchProtocolGuid ## CONSUMES
>
> +gPchEspiSmiDispatchProtocolGuid ## CONSUMES
>
> +gPchPcieIoTrapProtocolGuid ## PRODUCES
>
> +gPchPolicyProtocolGuid ##CONSUMES
>
> +
>
> +
>
> +[Guids]
>
> +gSiConfigHobGuid ## CONSUMES
>
> +gPchConfigHobGuid ## CONSUMES
>
> +gPchDeviceTableHobGuid
>
> +gPchPcieRpDxeConfigGuid ## CONSUMES
>
> +
>
> +
>
> +[Depex]
>
> +gEfiSmmIoTrapDispatch2ProtocolGuid AND
>
> +gEfiSmmSxDispatch2ProtocolGuid AND
>
> +gPchSmmIoTrapControlGuid AND
>
> +gPchPcieSmiDispatchProtocolGuid AND
>
> +gPchTcoSmiDispatchProtocolGuid AND
>
> +gEfiSmmCpuProtocolGuid AND
>
> +gPchNvsAreaProtocolGuid AND
>
> +gEfiPciHostBridgeResourceAllocationProtocolGuid AND # This is to ensure
> that PCI MMIO resource has been prepared and available for this driver to
> allocate.
>
> +gEfiSmmBase2ProtocolGuid AND # This is for SmmServicesTableLib
>
> +gPchPolicyProtocolGuid
>
> +
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
> new file mode 100644
> index 0000000000..e885a342a7
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchPcieSmm.c
> @@ -0,0 +1,451 @@
> +/** @file
>
> + PCH Pcie SMM Driver Entry
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchInitSmm.h"
>
> +#include <PcieRegs.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PchPcieRpRegs.h>
>
> +#include <Library/PcieHelperLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <Protocol/PchPolicy.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE
> *mDevAspmOverride;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT32
> mNumOfDevAspmOverride;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT8
> mPchBusNumber;
>
> +//
>
> +// @note:
>
> +// These temp bus numbers cannot be used in runtime (hot-plug).
>
> +// These can be used only during boot.
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT8
> mTempRootPortBusNumMin;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT8
> mTempRootPortBusNumMax;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_ROOT_PORT_CONFIG
> mPcieRootPortConfig[PCH_MAX_PCIE_ROOT_PORTS];
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN
> mPchPciePmTrapExecuted = FALSE;
>
> +
>
> +extern EFI_GUID gPchDeviceTableHobGuid;
>
> +
>
> +/**
>
> + Program Common Clock and ASPM of Downstream Devices
>
> +
>
> + @param[in] PortIndex Pcie Root Port Number
>
> + @param[in] RpDevice Pcie Root Pci Device Number
>
> + @param[in] RpFunction Pcie Root Pci Function Number
>
> +
>
> + @retval EFI_SUCCESS Root port complete successfully
>
> + @retval EFI_UNSUPPORTED PMC has invalid vendor ID
>
> +**/
>
> +EFI_STATUS
>
> +PchPcieSmi (
>
> + IN UINT8 PortIndex,
>
> + IN UINT8 RpDevice,
>
> + IN UINT8 RpFunction
>
> + )
>
> +{
>
> + UINT8 SecBus;
>
> + UINT8 SubBus;
>
> + UINT64 RpBase;
>
> + UINT64 EpBase;
>
> + UINT8 EpPcieCapPtr;
>
> + UINT8 EpMaxSpeed;
>
> + BOOLEAN DownstreamDevicePresent;
>
> + UINT32 Timeout;
>
> +
>
> + RpBase = PCI_SEGMENT_LIB_ADDRESS (
>
> + DEFAULT_PCI_SEGMENT_NUMBER_PCH,
>
> + mPchBusNumber,
>
> + (UINT32) RpDevice,
>
> + (UINT32) RpFunction,
>
> + 0
>
> + );
>
> +
>
> + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
>
> + return EFI_SUCCESS;
>
> + }
>
> + //
>
> + // Check presence detect state. Here the endpoint must be detected using
> PDS rather than
>
> + // the usual LinkActive check, because PDS changes immediately and LA
> takes a few milliseconds to stabilize
>
> + //
>
> + DownstreamDevicePresent = !!(PciSegmentRead16 (RpBase +
> R_PCH_PCIE_CFG_SLSTS) & B_PCIE_SLSTS_PDS);
>
> +
>
> + if (DownstreamDevicePresent) {
>
> + ///
>
> + /// Make sure the link is active before trying to talk to device behind it
>
> + /// Wait up to 100ms, according to PCIE spec chapter 6.7.3.3
>
> + ///
>
> + Timeout = 100 * 1000;
>
> + while ((PciSegmentRead16 (RpBase + R_PCH_PCIE_CFG_LSTS) &
> B_PCIE_LSTS_LA) == 0 ) {
>
> + MicroSecondDelay (10);
>
> + Timeout-=10;
>
> + if (Timeout == 0) {
>
> + return EFI_NOT_FOUND;
>
> + }
>
> + }
>
> + SecBus = PciSegmentRead8 (RpBase +
> PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
>
> + SubBus = PciSegmentRead8 (RpBase +
> PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
>
> + ASSERT (SecBus != 0 && SubBus != 0);
>
> + RootportDownstreamConfiguration (
>
> + DEFAULT_PCI_SEGMENT_NUMBER_PCH,
>
> + DEFAULT_PCI_BUS_NUMBER_PCH,
>
> + RpDevice,
>
> + RpFunction,
>
> + mTempRootPortBusNumMin,
>
> + mTempRootPortBusNumMax,
>
> + EnumPchPcie
>
> + );
>
> + RootportDownstreamPmConfiguration (
>
> + DEFAULT_PCI_SEGMENT_NUMBER_PCH,
>
> + DEFAULT_PCI_BUS_NUMBER_PCH,
>
> + RpDevice,
>
> + RpFunction,
>
> + mTempRootPortBusNumMin,
>
> + mTempRootPortBusNumMax,
>
> + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,
>
> + mNumOfDevAspmOverride,
>
> + mDevAspmOverride
>
> + );
>
> + //
>
> + // Perform Equalization
>
> + //
>
> + EpBase = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, SecBus, 0, 0, 0);
>
> + EpPcieCapPtr = PcieFindCapId (DEFAULT_PCI_SEGMENT_NUMBER_PCH,
> SecBus, 0, 0, EFI_PCI_CAPABILITY_ID_PCIEXP);
>
> + EpMaxSpeed = PciSegmentRead8 (EpBase + EpPcieCapPtr +
> R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_MLS;
>
> + if (EpMaxSpeed >= 3) {
>
> + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_EX_LCTL3,
> B_PCIE_EX_LCTL3_PE);
>
> + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_LCTL, B_PCIE_LCTL_RL);
>
> + }
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + PCIE Hotplug SMI call back function for each Root port
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieSmiRpHandlerFunction (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + )
>
> +{
>
> + PchPcieSmi (RpContext->RpIndex, RpContext->DevNum, RpContext-
> >FuncNum);
>
> +}
>
> +
>
> +/**
>
> + PCIE Link Active State Change Hotplug SMI call back function for all Root
> ports
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieLinkActiveStateChange (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + )
>
> +{
>
> + return;
>
> +}
>
> +
>
> +/**
>
> + PCIE Link Equalization Request SMI call back function for all Root ports
>
> +
>
> + @param[in] DispatchHandle Handle of this dispatch function
>
> + @param[in] RpContext Rootport context, which contains RootPort
> Index,
>
> + and RootPort PCI BDF.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieLinkEqHandlerFunction (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN PCH_PCIE_SMI_RP_CONTEXT *RpContext
>
> + )
>
> +{
>
> + ///
>
> + /// From PCI Express specification, the PCIe device can request for Link
> Equalization. When the
>
> + /// Link Equalization is requested by the device, an SMI will be generated
> by PCIe RP when
>
> + /// enabled and the SMI subroutine would invoke the Software
> Preset/Coefficient Search
>
> + /// software to re-equalize the link.
>
> + ///
>
> +
>
> + return;
>
> +
>
> +}
>
> +
>
> +/**
>
> + An IoTrap callback to config PCIE power management settings
>
> +**/
>
> +VOID
>
> +PchPciePmIoTrapSmiCallback (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 PortIndex;
>
> + UINT64 RpBase;
>
> + UINT8 MaxPciePortNum;
>
> +
>
> + MaxPciePortNum = GetPchMaxPciePortNum ();
>
> +
>
> + for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
>
> + RpBase = PchPcieRpPciCfgBase (PortIndex);
>
> +
>
> + if (PciSegmentRead16 (RpBase) != 0xFFFF) {
>
> + RootportDownstreamPmConfiguration (
>
> + DEFAULT_PCI_SEGMENT_NUMBER_PCH,
>
> + DEFAULT_PCI_BUS_NUMBER_PCH,
>
> + PchPcieRpDevNumber (PortIndex),
>
> + PchPcieRpFuncNumber (PortIndex),
>
> + mTempRootPortBusNumMin,
>
> + mTempRootPortBusNumMax,
>
> + &mPcieRootPortConfig[PortIndex].PcieRpCommonConfig,
>
> + mNumOfDevAspmOverride,
>
> + mDevAspmOverride
>
> + );
>
> +
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + An IoTrap callback to config PCIE power management settings
>
> +
>
> + @param[in] DispatchHandle - The handle of this callback, obtained when
> registering
>
> + @param[in] DispatchContext - Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH_CALLBACK_CONTEXT
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchPcieIoTrapSmiCallback (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN EFI_SMM_IO_TRAP_CONTEXT *CallbackContext,
>
> + IN OUT VOID *CommBuffer,
>
> + IN OUT UINTN *CommBufferSize
>
> + )
>
> +{
>
> + if (CallbackContext->WriteData == PchPciePmTrap) {
>
> + if (mPchPciePmTrapExecuted == FALSE) {
>
> + PchPciePmIoTrapSmiCallback ();
>
> + mPchPciePmTrapExecuted = TRUE;
>
> + }
>
> + } else {
>
> + ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + This function clear the Io trap executed flag before enter S3
>
> +
>
> + @param[in] Handle Handle of the callback
>
> + @param[in] Context The dispatch context
>
> +
>
> + @retval EFI_SUCCESS PCH register saved
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPcieS3EntryCallBack (
>
> + IN EFI_HANDLE Handle,
>
> + IN CONST VOID *Context OPTIONAL,
>
> + IN OUT VOID *CommBuffer OPTIONAL,
>
> + IN OUT UINTN *CommBufferSize OPTIONAL
>
> + )
>
> +{
>
> + mPchPciePmTrapExecuted = FALSE;
>
> + return EFI_SUCCESS;
>
> +}
>
> +/**
>
> + Register PCIE Hotplug SMI dispatch function to handle Hotplug enabling
>
> +
>
> + @param[in] ImageHandle The image handle of this module
>
> + @param[in] SystemTable The EFI System Table
>
> +
>
> + @retval EFI_SUCCESS The function completes successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InitializePchPcieSmm (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT8 PortIndex;
>
> + UINT8 Data8;
>
> + UINT32 Data32Or;
>
> + UINT32 Data32And;
>
> + UINT64 RpBase;
>
> + EFI_HANDLE PcieHandle;
>
> + PCH_PCIE_SMI_DISPATCH_PROTOCOL *PchPcieSmiDispatchProtocol;
>
> + EFI_HANDLE PchIoTrapHandle;
>
> + EFI_SMM_IO_TRAP_REGISTER_CONTEXT PchIoTrapContext;
>
> + EFI_SMM_SX_REGISTER_CONTEXT SxDispatchContext;
>
> + PCH_PCIE_IOTRAP_PROTOCOL *PchPcieIoTrapProtocol;
>
> + EFI_HANDLE SxDispatchHandle;
>
> + UINT8 MaxPciePortNum;
>
> + PCH_POLICY_PROTOCOL *PchPolicy;
>
> + PCIE_RP_DXE_CONFIG *PchPcieRpDxeConfig;
>
> + UINTN PcieDeviceTableSize;
>
> + PCH_PCIE_DEVICE_OVERRIDE *DevAspmOverride;
>
> + UINTN Count;
>
> +
>
> + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm () Start\n"));
>
> +
>
> + MaxPciePortNum = GetPchMaxPciePortNum ();
>
> +
>
> + //
>
> + // Locate Pch Pcie Smi Dispatch Protocol
>
> + //
>
> + Status = gSmst->SmmLocateProtocol (&gPchPcieSmiDispatchProtocolGuid,
> NULL, (VOID**) &PchPcieSmiDispatchProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + mPchBusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
>
> + mTempRootPortBusNumMin = PcdGet8 (PcdSiliconInitTempPciBusMin);
>
> + mTempRootPortBusNumMax = PcdGet8 (PcdSiliconInitTempPciBusMax);
>
> +
>
> + ASSERT (sizeof mPcieRootPortConfig == sizeof mPchConfigHob-
> >PcieRp.RootPort);
>
> + CopyMem (
>
> + mPcieRootPortConfig,
>
> + &(mPchConfigHob->PcieRp.RootPort),
>
> + sizeof (mPcieRootPortConfig)
>
> + );
>
> +
>
> + DevAspmOverride = NULL;
>
> + mDevAspmOverride = NULL;
>
> + mNumOfDevAspmOverride = 0;
>
> +
>
> + Status = gBS->LocateProtocol (&gPchPolicyProtocolGuid, NULL, (VOID **)
> &PchPolicy);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = GetConfigBlock ((VOID*) PchPolicy, &gPchPcieRpDxeConfigGuid,
> (VOID*) &PchPcieRpDxeConfig);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + DevAspmOverride = PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr;
>
> +
>
> + Count = 0;
>
> + if (DevAspmOverride != NULL) {
>
> + for (Count = 0; DevAspmOverride[Count].DeviceId != 0; Count++) {}
>
> + }
>
> +
>
> + if (Count !=0) {
>
> + PcieDeviceTableSize = Count * sizeof (PCH_PCIE_DEVICE_OVERRIDE);
>
> + Status = gSmst->SmmAllocatePool (
>
> + EfiRuntimeServicesData,
>
> + PcieDeviceTableSize,
>
> + (VOID **) &mDevAspmOverride
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + CopyMem (mDevAspmOverride, DevAspmOverride,
> PcieDeviceTableSize);
>
> + mNumOfDevAspmOverride = (UINT32) Count;
>
> + }
>
> + //
>
> + // Throught all PCIE root port function and register the SMI Handler for
> enabled ports.
>
> + //
>
> + for (PortIndex = 0; PortIndex < MaxPciePortNum; PortIndex++) {
>
> + RpBase = PchPcieRpPciCfgBase (PortIndex);
>
> + //
>
> + // Skip the root port function which is not enabled
>
> + //
>
> + if (PciSegmentRead32 (RpBase) == 0xFFFFFFFF) {
>
> + continue;
>
> + }
>
> +
>
> + //
>
> + // Register SMI Handlers for Hot Plug and Link Active State Change
>
> + //
>
> + Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_SLCAP);
>
> + if (Data8 & B_PCIE_SLCAP_HPC) {
>
> + PcieHandle = NULL;
>
> + Status = PchPcieSmiDispatchProtocol->HotPlugRegister (
>
> + PchPcieSmiDispatchProtocol,
>
> + PchPcieSmiRpHandlerFunction,
>
> + PortIndex,
>
> + &PcieHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = PchPcieSmiDispatchProtocol->LinkActiveRegister (
>
> + PchPcieSmiDispatchProtocol,
>
> + PchPcieLinkActiveStateChange,
>
> + PortIndex,
>
> + &PcieHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Data32Or = B_PCH_PCIE_CFG_MPC_HPME;
>
> + Data32And = (UINT32) ~B_PCH_PCIE_CFG_MPC_HPME;
>
> + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC, Data32Or);
>
> + S3BootScriptSaveMemReadWrite (
>
> + S3BootScriptWidthUint32,
>
> + PcdGet64 (PcdSiPciExpressBaseAddress) + RpBase +
> R_PCH_PCIE_CFG_MPC,
>
> + &Data32Or, /// Data to be ORed
>
> + &Data32And /// Data to be ANDed
>
> + );
>
> + }
>
> +
>
> + //
>
> + // Register SMI Handler for Link Equalization Request from Gen 3 Devices.
>
> + //
>
> + Data8 = PciSegmentRead8 (RpBase + R_PCH_PCIE_CFG_LCAP);
>
> + if ((Data8 & B_PCIE_LCAP_MLS) == V_PCIE_LCAP_MLS_GEN3) {
>
> + Status = PchPcieSmiDispatchProtocol->LinkEqRegister (
>
> + PchPcieSmiDispatchProtocol,
>
> + PchPcieLinkEqHandlerFunction,
>
> + PortIndex,
>
> + &PcieHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + }
>
> + }
>
> +
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + PchIoTrapContext.Type = WriteTrap;
>
> + PchIoTrapContext.Length = 4;
>
> + PchIoTrapContext.Address = 0;
>
> + Status = mPchIoTrap->Register (
>
> + mPchIoTrap,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2)
> PchPcieIoTrapSmiCallback,
>
> + &PchIoTrapContext,
>
> + &PchIoTrapHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Install the PCH Pcie IoTrap protocol
>
> + //
>
> + (gBS->AllocatePool) (EfiBootServicesData, sizeof
> (PCH_PCIE_IOTRAP_PROTOCOL), (VOID **)&PchPcieIoTrapProtocol);
>
> + PchPcieIoTrapProtocol->PcieTrapAddress = PchIoTrapContext.Address;
>
> +
>
> + Status = gBS->InstallMultipleProtocolInterfaces (
>
> + &ImageHandle,
>
> + &gPchPcieIoTrapProtocolGuid,
>
> + PchPcieIoTrapProtocol,
>
> + NULL
>
> + );
>
> +
>
> + //
>
> + // Register the callback for S3 entry
>
> + //
>
> + SxDispatchContext.Type = SxS3;
>
> + SxDispatchContext.Phase = SxEntry;
>
> + Status = mSxDispatch->Register (
>
> + mSxDispatch,
>
> + PchPcieS3EntryCallBack,
>
> + &SxDispatchContext,
>
> + &SxDispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + DEBUG ((DEBUG_INFO, "InitializePchPcieSmm, IoTrap @ %x () End\n",
> PchIoTrapContext.Address));
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
> new file mode 100644
> index 0000000000..bdae6fe918
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchInit/Smm/PchSpiAsync.c
> @@ -0,0 +1,67 @@
> +/** @file
>
> + PCH SPI Async SMI handler.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchInitSmm.h"
>
> +
>
> +///
>
> +/// Global variables
>
> +///
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMI_DISPATCH_PROTOCOL
> *mPchSmiDispatchProtocol;
>
> +
>
> +/**
>
> + This hardware SMI handler will be run every time the flash write/earse
> happens.
>
> +
>
> + @param[in] DispatchHandle Not used
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchSpiAsyncCallback (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + //
>
> + // Dummy SMI handler
>
> + //
>
> +}
>
> +
>
> +/**
>
> + This fuction install SPI ASYNC SMI handler.
>
> +
>
> + @retval EFI_SUCCESS Initialization complete.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchSpiAsyncSmiHandler (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_HANDLE Handle;
>
> +
>
> + DEBUG ((DEBUG_INFO, "InstallPchSpiAsyncSmiHandler()\n"));
>
> +
>
> + ///
>
> + /// Get the PCH SMM dispatch protocol
>
> + ///
>
> + mPchSmiDispatchProtocol = NULL;
>
> + Status = gSmst->SmmLocateProtocol (&gPchSmiDispatchProtocolGuid,
> NULL, (VOID **) &mPchSmiDispatchProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + ///
>
> + /// Register an SpiAsync callback function
>
> + ///
>
> + Handle = NULL;
>
> + Status = mPchSmiDispatchProtocol->SpiAsyncRegister (
>
> + mPchSmiDispatchProtocol,
>
> + PchSpiAsyncCallback,
>
> + &Handle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
> new file mode 100644
> index 0000000000..54a1575f2c
> --- /dev/null
> +++ b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.c
> @@ -0,0 +1,1284 @@
> +/** @file
>
> + Main implementation source file for the Io Trap SMM driver
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Protocol/PchNvsArea.h>
>
> +#include <Library/SmiHandlerProfileLib.h>
>
> +#include <Register/PchPcrRegs.h>
>
> +#include <Register/PchRegsPsth.h>
>
> +#include <Register/PchDmiRegs.h>
>
> +
>
> +#define GENERIC_IOTRAP_SIZE 0x100
>
> +
>
> +//
>
> +// Module global variables
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE
> mDriverImageHandle;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_HANDLE
> mIoTrapHandle;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_INSTANCE
> mIoTrapData;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED IO_TRAP_RECORD
> *mIoTrapRecord;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_NVS_AREA
> *mPchNvsArea;
>
> +
>
> +
>
> +static CONST UINT16 mLengthTable[10] = { 1, 2, 3, 4, 8, 16, 32, 64, 128,
> 256 };
>
> +
>
> +/**
>
> + Helper function that encapsulates IoTrap register access.
>
> + IO trap related register updates must be made in 2 registers, IOTRAP and
> DMI source decode.
>
> +
>
> + @param[in] TrapHandlerNum trap number (0-3)
>
> + @param[in] Value value to be written in both registers
>
> + @param[in] SaveToBootscript if true, this register write will be saved to
> bootscript
>
> +
>
> +**/
>
> +VOID
>
> +SetIoTrapLowDword (
>
> + IN UINT8 TrapHandlerNum,
>
> + IN UINT32 Value,
>
> + IN BOOLEAN SaveToBootscript
>
> + )
>
> +{
>
> + UINT32 BitMask;
>
> + UINT32 BitValue;
>
> + //
>
> + // To provide sequentially consistent programming model for IO trap
>
> + // all pending IO cycles must be flushed before enabling and before
> disabling a trap.
>
> + // Without this the trap may trigger due to IO cycle issued before the trap
> is enabled or a cycle issued before the trap is disabled might be missed.
>
> + // a. Issues a MemRd to PSTH IO Trap Enable bit -> This serves to flush all
> previous IO cycles.
>
> + // b. Then only issues a MemWr to PSTH IO Trap Enable == Value
>
> + // c. Issues another MemRd to PSTH IO Trap Enable bit -> This serves to
> push the MemWr to PSTH and confirmed that IO Trap is in fact enabled
>
> + //
>
> + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
>
> + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8,
> Value);
>
> + PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8);
>
> +
>
> + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8,
> Value);
>
> + //
>
> + // Read back DMI IOTRAP register to enforce ordering so DMI write is
> completed before any IO reads
>
> + // from other threads which may occur after this point (after SMI exit).
>
> + //
>
> + PchPcrRead32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8);
>
> + if (SaveToBootscript) {
>
> + //
>
> + // Ignore the value check of PCH_PCR_BOOT_SCRIPT_READ
>
> + //
>
> + BitMask = 0;
>
> + BitValue = 0;
>
> +
>
> + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH,
> R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
>
> + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH,
> R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, 1, &Value);
>
> + PCH_PCR_BOOT_SCRIPT_READ (S3BootScriptWidthUint32, PID_PSTH,
> R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8, &BitMask, &BitValue);
>
> + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI,
> R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8, 1, &Value);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Helper function that encapsulates IoTrap register access.
>
> + IO trap related register updates must be made in 2 registers, IOTRAP and
> DMI source decode.
>
> +
>
> + @param[in] TrapHandlerNum trap number (0-3)
>
> + @param[in] Value value to be written in both registers
>
> + @param[in] SaveToBootscript if true, this register write will be saved to
> bootscript
>
> +
>
> +**/
>
> +VOID
>
> +SetIoTrapHighDword (
>
> + IN UINT8 TrapHandlerNum,
>
> + IN UINT32 Value,
>
> + IN BOOLEAN SaveToBootscript
>
> + )
>
> +{
>
> + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8
> + 4, Value);
>
> + PchPcrWrite32 (PID_DMI, R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 +
> 4, Value);
>
> + if (SaveToBootscript) {
>
> + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_PSTH,
> R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4, 1, &Value);
>
> + PCH_PCR_BOOT_SCRIPT_WRITE (S3BootScriptWidthUint32, PID_DMI,
> R_PCH_DMI_PCR_IOT1 + TrapHandlerNum * 8 + 4, 1, &Value);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Clear pending IOTRAP status.
>
> + If IOTRAP status is pending and IOTRAP is disabled, then BIOS will not find a
> match SMI source
>
> + and will not dispatch any SMI handler for it. The pending status will lead to
> SMI storm.
>
> + This prevents that IOTRAP gets triggered by pending IO cycles even after
> it's disabled.
>
> +
>
> + @param[in] TrapHandlerNum trap number (0-3)
>
> +
>
> +**/
>
> +VOID
>
> +ClearPendingIoTrapStatus (
>
> + IN UINT8 TrapHandlerNum
>
> + )
>
> +{
>
> + PchPcrWrite32 (PID_PSTH, R_PSTH_PCR_TRPST, (UINT32)(1 <<
> TrapHandlerNum));
>
> +}
>
> +
>
> +/**
>
> + IO resources allocated to IO traps need to be reported to OS so that they
> don't get reused.
>
> + This function makes IO trap allocation data available to ACPI
>
> +
>
> + @param[in] TrapHandlerNum trap number (0-3)
>
> + @param[in] BaseAddress address of allocated IO resource
>
> + @param[in] Track TRUE = resource allocated, FALSE = resource freed
>
> +
>
> +**/
>
> +VOID
>
> +UpdateIoTrapAcpiResources (
>
> + IN UINT8 TrapHandlerNum,
>
> + IN EFI_PHYSICAL_ADDRESS BaseAddress,
>
> + IN BOOLEAN Track
>
> + )
>
> +{
>
> +
>
> + if (Track == TRUE) {
>
> + mPchNvsArea->IoTrapAddress[TrapHandlerNum] = (UINT16)
> BaseAddress;
>
> + mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 1;
>
> + } else {
>
> + mPchNvsArea->IoTrapStatus[TrapHandlerNum] = 0;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Get address from IOTRAP low dword.
>
> +
>
> + @param[in] IoTrapRegLowDword IOTRAP register low dword
>
> +
>
> + @retval Address of IOTRAP setting.
>
> +**/
>
> +STATIC
>
> +UINT16
>
> +AddressFromLowDword (
>
> + UINT32 IoTrapRegLowDword
>
> + )
>
> +{
>
> + return (UINT16) (IoTrapRegLowDword & B_PSTH_PCR_TRPREG_AD);
>
> +}
>
> +
>
> +/**
>
> + Get length from IOTRAP low dword.
>
> +
>
> + @param[in] IoTrapRegLowDword IOTRAP register low dword
>
> +
>
> + @retval Length of IOTRAP setting.
>
> +**/
>
> +STATIC
>
> +UINT16
>
> +LengthFromLowDword (
>
> + UINT32 IoTrapRegLowDword
>
> + )
>
> +{
>
> + return (UINT16) (((IoTrapRegLowDword >> 16) & 0xFC) + 4);
>
> +}
>
> +
>
> +/**
>
> + Get ByteEnable from IOTRAP high dword.
>
> +
>
> + @param[in] IoTrapRegHighDword IOTRAP register high dword
>
> +
>
> + @retval ByteEnable of IOTRAP setting.
>
> +**/
>
> +STATIC
>
> +UINT8
>
> +ByteEnableFromHighDword (
>
> + UINT32 IoTrapRegHighDword
>
> + )
>
> +{
>
> + return (UINT8) (IoTrapRegHighDword & 0x0F);
>
> +}
>
> +
>
> +/**
>
> + Get ByteEnableMask from IOTRAP high dword.
>
> +
>
> + @param[in] IoTrapRegHighDword IOTRAP register high dword
>
> +
>
> + @retval ByteEnableMask of IOTRAP setting.
>
> +**/
>
> +STATIC
>
> +UINT8
>
> +ByteEnableMaskFromHighDword (
>
> + UINT32 IoTrapRegHighDword
>
> + )
>
> +{
>
> + return (UINT8) ((IoTrapRegHighDword & 0xF0) >> 4);
>
> +}
>
> +
>
> +/**
>
> + Check the IoTrap register matches the IOTRAP EX content.
>
> +
>
> + @param[in] IoTrapRecord IOTRAP registration record structure
>
> + @param[in] IoTrapRegLowDword IOTRAP register low dword
>
> + @param[in] IoTrapRegHighDword IOTRAP register high dword
>
> +
>
> + @retval TRUE Content matched
>
> + FALSE Content mismatched
>
> +**/
>
> +STATIC
>
> +BOOLEAN
>
> +IsIoTrapExContentMatched (
>
> + IO_TRAP_RECORD *IoTrapRecord,
>
> + UINT32 IoTrapRegLowDword,
>
> + UINT32 IoTrapRegHighDword
>
> + )
>
> +{
>
> + if ((IoTrapRecord->Context.Address == AddressFromLowDword
> (IoTrapRegLowDword)) &&
>
> + (IoTrapRecord->Context.Length == LengthFromLowDword
> (IoTrapRegLowDword)) &&
>
> + (IoTrapRecord->Context.ByteEnable == ByteEnableFromHighDword
> (IoTrapRegHighDword)) &&
>
> + (IoTrapRecord->Context.ByteEnableMask ==
> ByteEnableMaskFromHighDword (IoTrapRegHighDword)))
>
> + {
>
> + return TRUE;
>
> + }
>
> + return FALSE;
>
> +}
>
> +
>
> +
>
> +/**
>
> + The helper function for IoTrap callback dispacther
>
> +
>
> + @param[in] TrapHandlerNum trap number (0-3)
>
> +**/
>
> +VOID
>
> +IoTrapDispatcherHelper (
>
> + UINTN TrapHandlerNum
>
> + )
>
> +{
>
> + IO_TRAP_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> + EFI_SMM_IO_TRAP_REGISTER_CONTEXT CurrentIoTrapRegisterData;
>
> + EFI_SMM_IO_TRAP_CONTEXT CurrentIoTrapContextData;
>
> + UINT16 BaseAddress;
>
> + UINT16 StartAddress;
>
> + UINT16 EndAddress;
>
> + UINT32 Data32;
>
> + UINT8 ActiveHighByteEnable;
>
> + BOOLEAN ReadCycle;
>
> + UINT32 WriteData;
>
> +
>
> + if (!IsListEmpty
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase))) {
>
> + Data32 = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPC);
>
> + WriteData = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPD);
>
> +
>
> + BaseAddress = (UINT16) (Data32 & B_PSTH_PCR_TRPC_IOA);
>
> + ActiveHighByteEnable = (UINT8)((Data32 & B_PSTH_PCR_TRPC_AHBE) >>
> 16);
>
> + ReadCycle = (BOOLEAN) ((Data32 & B_PSTH_PCR_TRPC_RW) ==
> B_PSTH_PCR_TRPC_RW);
>
> + //
>
> + // StartAddress and EndAddress will be equal if it's byte access
>
> + //
>
> + EndAddress = (UINT16) (HighBitSet32 ((UINT32)
> (ActiveHighByteEnable))) + BaseAddress;
>
> + StartAddress = (UINT16) (LowBitSet32 ((UINT32)
> (ActiveHighByteEnable))) + BaseAddress;
>
> +
>
> + CurrentIoTrapRegisterData.Type =
> (EFI_SMM_IO_TRAP_DISPATCH_TYPE)ReadCycle;
>
> + CurrentIoTrapContextData.WriteData = WriteData;
>
> +
>
> + LinkInDb = GetFirstNode
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
>
> +
>
> + while (!IsNull
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), LinkInDb)) {
>
> + RecordInDb = IO_TRAP_RECORD_FROM_LINK (LinkInDb);
>
> +
>
> + //
>
> + // If MergeDisable is TRUE, no need to check the address range, dispatch
> the callback function directly.
>
> + //
>
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
>
> + if (RecordInDb->IoTrapCallback != NULL) {
>
> + RecordInDb->IoTrapCallback (&RecordInDb->Link,
> &CurrentIoTrapContextData, NULL, NULL);
>
> + }
>
> + if (RecordInDb->IoTrapExCallback != NULL) {
>
> + RecordInDb->IoTrapExCallback (BaseAddress, ActiveHighByteEnable,
> !ReadCycle, WriteData);
>
> + }
>
> + //
>
> + // Expect only one callback available. So break immediately.
>
> + //
>
> + break;
>
> + //
>
> + // If MergeDisable is FALSE, check the address range and trap type.
>
> + //
>
> + } else {
>
> + if ((RecordInDb->Context.Address <= StartAddress) &&
>
> + (RecordInDb->Context.Address + RecordInDb->Context.Length >
> EndAddress)) {
>
> + if ((RecordInDb->Context.Type == IoTrapExTypeReadWrite) ||
> (RecordInDb->Context.Type == (IO_TRAP_EX_DISPATCH_TYPE)
> CurrentIoTrapRegisterData.Type)) {
>
> + //
>
> + // Pass the IO trap context information
>
> + //
>
> + RecordInDb->IoTrapCallback (&RecordInDb->Link,
> &CurrentIoTrapContextData, NULL, NULL);
>
> + }
>
> + //
>
> + // Break if the address is match
>
> + //
>
> + break;
>
> + } else {
>
> + LinkInDb = GetNextNode
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase), &RecordInDb-
> >Link);
>
> + if (IsNull (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),
> LinkInDb)) {
>
> + //
>
> + // An IO access was trapped that does not have a handler registered.
>
> + // This indicates an error condition.
>
> + //
>
> + ASSERT (FALSE);
>
> + }
>
> + }
>
> + } // end of if else block
>
> + } // end of while loop
>
> + } // end of if else block
>
> +}
>
> +
>
> +/**
>
> + IoTrap dispatcher for IoTrap register 0.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +IoTrapDispatcher0 (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IoTrapDispatcherHelper (0);
>
> +}
>
> +
>
> +/**
>
> + IoTrap dispatcher for IoTrap register 1.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +IoTrapDispatcher1 (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IoTrapDispatcherHelper (1);
>
> +}
>
> +
>
> +/**
>
> + IoTrap dispatcher for IoTrap register 2.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +IoTrapDispatcher2 (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IoTrapDispatcherHelper (2);
>
> +}
>
> +
>
> +/**
>
> + IoTrap dispatcher for IoTrap register 3.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +IoTrapDispatcher3 (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IoTrapDispatcherHelper (3);
>
> +}
>
> +
>
> +/**
>
> + IoTrap registratrion helper fucntion.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> + @param[in] IoTrapDispatchFunction Dispatch function of
> IoTrapDispatch2Protocol.
>
> + This could be NULL if it's not from
> IoTrapDispatch2Protocol.
>
> + @param[in] IoTrapExDispatchFunction Dispatch function of
> IoTrapExDispatchProtocol.
>
> + This could be NULL if it's not from
> IoTrapExDispatchProtocol.
>
> + @param[in out] Address The pointer of IO Address.
>
> + If the input Addres is 0, it will return the address
> assigned
>
> + by registration to this caller.
>
> + @param[in] Length Length of IO address range.
>
> + @param[in] Type Read/Write type of IO trap.
>
> + @param[in] ByteEnable Bitmap to enable trap for each byte of
> every dword alignment address.
>
> + @param[in] ByteEnableMask ByteEnableMask bitwise to ignore the
> ByteEnable setting.
>
> +
>
> + @retval EFI_INVALID_PARAMETER If Type is invalid,
>
> + If Length is invalid,
>
> + If Address is invalid,
>
> + EFI_ACCESS_DENIED If the SmmReadyToLock event has been
> triggered,
>
> + EFI_OUT_OF_RESOURCES If run out of IoTrap register resource,
>
> + If run out of SMM memory pool,
>
> + EFI_SUCCESS IoTrap register successfully.
>
> +**/
>
> +EFI_STATUS
>
> +IoTrapRegisterHelper (
>
> + OUT EFI_HANDLE *DispatchHandle,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapDispatchFunction,
>
> + IN IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExDispatchFunction,
>
> + IN OUT UINT16 *Address,
>
> + IN UINT16 Length,
>
> + IN IO_TRAP_EX_DISPATCH_TYPE Type,
>
> + IN UINT8 ByteEnable,
>
> + IN UINT8 ByteEnableMask
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_PHYSICAL_ADDRESS BaseAddress;
>
> + UINT32 UsedLength;
>
> + UINT8 TrapHandlerNum;
>
> + UINT32 IoTrapRegLowDword;
>
> + UINT32 IoTrapRegHighDword;
>
> + BOOLEAN TempMergeDisable;
>
> +
>
> + DEBUG ((DEBUG_INFO, "IoTrapRegisterHelper\n"));
>
> + DEBUG ((DEBUG_INFO, "Address:%x \n", *Address));
>
> + DEBUG ((DEBUG_INFO, "Length:%x \n", Length));
>
> + DEBUG ((DEBUG_INFO, "Type:%x \n", Type));
>
> + DEBUG ((DEBUG_INFO, "ByteEnable:%x \n", ByteEnable));
>
> + DEBUG ((DEBUG_INFO, "ByteEnableMask:%x \n", ByteEnableMask));
>
> +
>
> + //
>
> + // Return error if the type is invalid
>
> + //
>
> + if (Type >= IoTrapExTypeMaximum) {
>
> + DEBUG ((DEBUG_ERROR, "The Dispatch Type %0X is invalid! \n", Type));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + //
>
> + // Return error if the Length is invalid
>
> + //
>
> + if (Length < 1 || Length > GENERIC_IOTRAP_SIZE) {
>
> + DEBUG ((DEBUG_ERROR, "The Dispatch Length %0X is invalid! \n",
> Length));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + //
>
> + // Return error if the address is invalid
>
> + // PCH supports non-aligned address but (Address % 4 + Length) must not
> be more than 4
>
> + //
>
> + if (((Length & (Length - 1)) != 0) && (Length != 3)) {
>
> + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + if (((Length >= 4) && (*Address & 0x3)) ||
>
> + ((Length < 4) && (((*Address & 0x3) + Length) > 4))) {
>
> + DEBUG ((DEBUG_ERROR, "PCH does not support Dispatch Address %0X
> and Length %0X combination \n", *Address, Length));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + if ((Length >= 4) && ((*Address & (Length - 1)) != 0)) {
>
> + DEBUG ((DEBUG_ERROR, "Dispatch Address %0X is not aligned to the
> Length %0X \n", *Address, Length));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + if (*Address) {
>
> + TempMergeDisable = TRUE;
>
> + }else {
>
> + TempMergeDisable = FALSE;
>
> + }
>
> + //
>
> + // Loop through the first IO Trap handler, looking for the suitable handler
>
> + //
>
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
>
> + //
>
> + // Get information from Io Trap handler register
>
> + //
>
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8);
>
> +
>
> + //
>
> + // Check if the IO Trap handler is not used
>
> + //
>
> + if (AddressFromLowDword (IoTrapRegLowDword) == 0) {
>
> + //
>
> + // Search available IO address and allocate it if the IO address is 0
>
> + //
>
> + BaseAddress = *Address;
>
> + if (BaseAddress == 0) {
>
> + //
>
> + // Allocate 256 byte range from GCD for common pool usage
>
> + //
>
> + if ((PcdGet8 (PcdEfiGcdAllocateType) ==
> EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8
> (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
>
> + BaseAddress = 0xFFFF;
>
> + }
>
> + Status = gDS->AllocateIoSpace (
>
> + PcdGet8 (PcdEfiGcdAllocateType),
>
> + EfiGcdIoTypeIo,
>
> + 8,
>
> + GENERIC_IOTRAP_SIZE,
>
> + &BaseAddress,
>
> + mDriverImageHandle,
>
> + NULL
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Can't find any available IO address! \n"));
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> +
>
> + *Address = (UINT16) BaseAddress;
>
> + UsedLength = GENERIC_IOTRAP_SIZE;
>
> + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength = Length;
>
> + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = TRUE;
>
> + UpdateIoTrapAcpiResources (TrapHandlerNum, BaseAddress, TRUE);
>
> + } else {
>
> + BaseAddress &= B_PSTH_PCR_TRPREG_AD;
>
> + UsedLength = Length;
>
> + }
>
> +
>
> + Status = PchInternalIoTrapSmiRegister (
>
> + mIoTrapData.Entry[TrapHandlerNum].CallbackDispatcher,
>
> + TrapHandlerNum,
>
> + &mIoTrapHandle
>
> + );
>
> +
>
> + ASSERT_EFI_ERROR (Status);
>
> + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = mIoTrapHandle;
>
> +
>
> + //
>
> + // Fill in the Length, address and Enable the IO Trap SMI
>
> + //
>
> + IoTrapRegLowDword = (UINT32) (((UsedLength - 1) & ~(BIT1 + BIT0)) <<
> 16) |
>
> + (UINT16) BaseAddress |
>
> + B_PSTH_PCR_TRPREG_TSE;
>
> +
>
> + if (UsedLength < 4) {
>
> + //
>
> + // The 4 bits is the Byte Enable Mask bits to indicate which byte that are
> trapped.
>
> + // The input ByteEnable and ByteEnableMask are ignored in this case.
>
> + //
>
> + IoTrapRegHighDword = (((1 << UsedLength) - 1) << ((*Address & 0x3) +
> (N_PSTH_PCR_TRPREG_BEM - 32))) |
>
> + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
>
> + } else {
>
> + //
>
> + // Fill in the ByteEnable, ByteEnableMask, and Type of Io Trap register
>
> + //
>
> + IoTrapRegHighDword = ((ByteEnableMask & 0xF) <<
> (N_PSTH_PCR_TRPREG_BEM - 32)) |
>
> + ((ByteEnable & 0xF) << (N_PSTH_PCR_TRPREG_BE - 32)) |
>
> + (UINT32) (Type << N_PSTH_PCR_TRPREG_RWIO);
>
> + }
>
> + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
>
> + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
>
> + //
>
> + // Set MergeDisable flag of the registered IoTrap
>
> + //
>
> + mIoTrapData.Entry[TrapHandlerNum].MergeDisable =
> TempMergeDisable;
>
> + } else {
>
> + //
>
> + // Check next handler if MergeDisable is TRUE or the registered IoTrap if
> MergeDisable is TRUE
>
> + // If the Io Trap register is used by IoTrapEx protocol, then the
> MergeDisable will be FALSE.
>
> + //
>
> + if ((TempMergeDisable == TRUE) ||
> (mIoTrapData.Entry[TrapHandlerNum].MergeDisable == TRUE)) {
>
> + continue;
>
> + }
>
> + //
>
> + // The IO Trap handler is used, calculate the Length
>
> + //
>
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
>
> + //
>
> + // Assign an addfress from common pool if the caller's address is 0
>
> + //
>
> + if (*Address == 0) {
>
> + //
>
> + // Check next handler if it's fully used
>
> + //
>
> + if (mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength >=
> GENERIC_IOTRAP_SIZE) {
>
> + continue;
>
> + }
>
> + //
>
> + // Check next handler if it's not for a common pool
>
> + //
>
> + if (UsedLength < GENERIC_IOTRAP_SIZE) {
>
> + continue;
>
> + }
>
> + //
>
> + // Check next handler if the size is too big
>
> + //
>
> + if (Length >= (UINT16) GENERIC_IOTRAP_SIZE -
> mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength) {
>
> + continue;
>
> + }
>
> + //
>
> + // For common pool, we don't need to change the BaseAddress and
> UsedLength
>
> + //
>
> + *Address = (UINT16) (BaseAddress +
> mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength);
>
> + mIoTrapData.Entry[TrapHandlerNum].TrapUsedLength += Length;
>
> + }
>
> + //
>
> + // Only set RWM bit when we need both read and write cycles.
>
> + //
>
> + IoTrapRegHighDword = PchPcrRead32 (PID_PSTH,
> R_PSTH_PCR_TRPREG0 + TrapHandlerNum * 8 + 4);
>
> + if ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWM) == 0 &&
>
> + (UINT32) ((IoTrapRegHighDword & B_PSTH_PCR_TRPREG_RWIO) >>
> N_PSTH_PCR_TRPREG_RWIO) !=
>
> + (UINT32) Type) {
>
> + IoTrapRegHighDword = ((IoTrapRegHighDword |
> B_PSTH_PCR_TRPREG_RWM) & ~B_PSTH_PCR_TRPREG_RWIO);
>
> + SetIoTrapHighDword (TrapHandlerNum, IoTrapRegHighDword, TRUE);
>
> + }
>
> + }
>
> + break;
>
> + }
>
> +
>
> + if (TrapHandlerNum >= IO_TRAP_HANDLER_NUM) {
>
> + DEBUG ((DEBUG_ERROR, "All IO Trap handler is used, no available IO Trap
> handler! \n"));
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + //
>
> + // Create database record and add to database
>
> + //
>
> + Status = gSmst->SmmAllocatePool (
>
> + EfiRuntimeServicesData,
>
> + sizeof (IO_TRAP_RECORD),
>
> + (VOID **) &mIoTrapRecord
>
> + );
>
> +
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for mIoTrapRecord!
> \n"));
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + //
>
> + // Gather information about the registration request
>
> + //
>
> + mIoTrapRecord->Signature = IO_TRAP_RECORD_SIGNATURE;
>
> + mIoTrapRecord->Context.Address = *Address;
>
> + mIoTrapRecord->Context.Length = Length;
>
> + mIoTrapRecord->Context.Type = Type;
>
> + mIoTrapRecord->Context.ByteEnable = ByteEnable;
>
> + mIoTrapRecord->Context.ByteEnableMask = ByteEnableMask;
>
> + mIoTrapRecord->IoTrapCallback = IoTrapDispatchFunction;
>
> + mIoTrapRecord->IoTrapExCallback = IoTrapExDispatchFunction;
>
> + mIoTrapRecord->IoTrapNumber = TrapHandlerNum;
>
> +
>
> + InsertTailList (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase),
> &mIoTrapRecord->Link);
>
> +
>
> + //
>
> + // Child's handle will be the address linked list link in the record
>
> + //
>
> + *DispatchHandle = (EFI_HANDLE) (&mIoTrapRecord->Link);
>
> +
>
> + DEBUG ((DEBUG_INFO, "Result Address:%x \n", *Address));
>
> + DEBUG ((DEBUG_INFO, "Result Length:%x \n", Length));
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + IoTrap unregistratrion helper fucntion.
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function
>
> +
>
> + @retval EFI_INVALID_PARAMETER If DispatchHandle is invalid,
>
> + EFI_ACCESS_DENIED If the SmmReadyToLock event has been
> triggered,
>
> + EFI_SUCCESS IoTrap unregister successfully.
>
> +**/
>
> +EFI_STATUS
>
> +IoTrapUnRegisterHelper (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + IO_TRAP_RECORD *RecordToDelete;
>
> + UINT32 IoTrapRegLowDword;
>
> + EFI_PHYSICAL_ADDRESS BaseAddress;
>
> + UINT32 UsedLength;
>
> + UINT8 TrapHandlerNum;
>
> + UINT8 LengthIndex;
>
> + BOOLEAN RequireToDisableIoTrapHandler;
>
> +
>
> + if (DispatchHandle == 0) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
>
> + //
>
> + // Take the entry out of the linked list
>
> + //
>
> + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *)
> EFI_BAD_POINTER) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + RequireToDisableIoTrapHandler = FALSE;
>
> + //
>
> + // Loop through the first IO Trap handler, looking for the suitable handler
>
> + //
>
> + TrapHandlerNum = RecordToDelete->IoTrapNumber;
>
> +
>
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable) {
>
> + //
>
> + // Disable the IO Trap handler if it's the only child of the Trap handler
>
> + //
>
> + RequireToDisableIoTrapHandler = TRUE;
>
> + } else {
>
> + //
>
> + // Get information from Io Trap handler register
>
> + //
>
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8);
>
> +
>
> + //
>
> + // Check next Io Trap handler if the IO Trap handler is not used
>
> + //
>
> + if (AddressFromLowDword (IoTrapRegLowDword) != 0) {
>
> +
>
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
>
> +
>
> + //
>
> + // Check if it's the maximum address of the Io Trap handler
>
> + //
>
> + if ((UINTN)(BaseAddress + UsedLength) == (UINTN)(RecordToDelete-
> >Context.Address + RecordToDelete->Context.Length)) {
>
> +
>
> + if (BaseAddress == RecordToDelete->Context.Address) {
>
> + //
>
> + // Disable the IO Trap handler if it's the only child of the Trap handler
>
> + //
>
> + RequireToDisableIoTrapHandler = TRUE;
>
> + } else {
>
> + //
>
> + // Calculate the new IO Trap handler Length
>
> + //
>
> + UsedLength = UsedLength - RecordToDelete->Context.Length;
>
> + //
>
> + // Check the alignment is dword * power of 2 or not
>
> + //
>
> + for (LengthIndex = 0; LengthIndex < sizeof (mLengthTable) / sizeof
> (UINT16); LengthIndex++) {
>
> + if (UsedLength == mLengthTable[LengthIndex]) {
>
> + break;
>
> + }
>
> + }
>
> + //
>
> + // Do not decrease the length if the alignment is not dword * power of
> 2
>
> + //
>
> + if (LengthIndex < sizeof (mLengthTable) / sizeof (UINT16)) {
>
> + //
>
> + // Decrease the length to prevent the IO trap SMI
>
> + //
>
> + IoTrapRegLowDword = (UINT32) ((((UsedLength - 1) &~(BIT1 + BIT0))
> << 16) | BaseAddress | B_PSTH_PCR_TRPREG_TSE);
>
> + }
>
> + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, TRUE);
>
> + }
>
> + }
>
> + }
>
> + }
>
> +
>
> + if (RequireToDisableIoTrapHandler) {
>
> + mIoTrapHandle = mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle;
>
> + Status = PchInternalIoTrapSmiUnRegister (mIoTrapHandle);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + SetIoTrapLowDword (TrapHandlerNum, 0, TRUE);
>
> + SetIoTrapHighDword (TrapHandlerNum, 0, TRUE);
>
> + //
>
> + // Also clear pending IOTRAP status.
>
> + //
>
> + ClearPendingIoTrapStatus (TrapHandlerNum);
>
> +
>
> + mIoTrapData.Entry[TrapHandlerNum].IoTrapHandle = 0;
>
> + mIoTrapData.Entry[TrapHandlerNum].MergeDisable = FALSE;
>
> + if (mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource ==
> TRUE) {
>
> + mIoTrapData.Entry[TrapHandlerNum].ReservedAcpiIoResource = FALSE;
>
> + UpdateIoTrapAcpiResources (TrapHandlerNum, 0, FALSE);
>
> + }
>
> + }
>
> +
>
> + RemoveEntryList (&RecordToDelete->Link);
>
> + Status = gSmst->SmmFreePool (RecordToDelete);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Register a new IO Trap SMI dispatch function with a parent SMM driver.
>
> + The caller will provide information about the IO trap characteristics via
>
> + the context. This includes base address, length, read vs. r/w, etc.
>
> + This function will autoallocate IO base address from a common pool if the
> base address is 0,
>
> + and the RegisterContext Address field will be updated.
>
> + The service will not perform GCD allocation if the base address is non-zero.
>
> + In this case, the caller is responsible for the existence and allocation of the
>
> + specific IO range.
>
> + This function looks for the suitable handler and Register a new IoTrap
> handler
>
> + if the IO Trap handler is not used. It also enable the IO Trap Range to
> generate
>
> + SMI.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Pointer to dispatch function to be invoked
> for
>
> + this SMI source.
>
> + @param[in, out] RegisterContext Pointer to the dispatch function's
> context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function the IO trap SMI source for which the dispatch
>
> + function should be invoked. This may not be NULL.
>
> + If the registration address is not 0, it's caller's responsibility
>
> + to reserve the IO resource in ACPI.
>
> + @param[out] DispatchHandle Handle of dispatch function, for when
> interfacing
>
> + with the parent SMM driver, will be the address of linked
>
> + list link in the call back record. This may not be NULL.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI
> source.
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available
>
> + @retval EFI_INVALID_PARAMETER Address requested is already in use.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapRegister (
>
> + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + DEBUG ((DEBUG_INFO, "IoTrapRegister\n"));
>
> + Status = IoTrapRegisterHelper (
>
> + DispatchHandle,
>
> + DispatchFunction,
>
> + NULL,
>
> + &(RegisterContext->Address),
>
> + RegisterContext->Length,
>
> + (IO_TRAP_EX_DISPATCH_TYPE) RegisterContext->Type,
>
> + 0x00,
>
> + 0x0F);
>
> +
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gEfiSmmIoTrapDispatch2ProtocolGuid,
>
> + DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + RegisterContext,
>
> + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
>
> + );
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapUnRegister (
>
> + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IO_TRAP_RECORD *RecordToDelete;
>
> +
>
> + RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
>
> + SmiHandlerProfileUnregisterHandler (
>
> + &gIoTrapExDispatchProtocolGuid,
>
> + RecordToDelete->IoTrapCallback,
>
> + &RecordToDelete->Context,
>
> + sizeof (EFI_SMM_IO_TRAP_REGISTER_CONTEXT)
>
> + );
>
> + return IoTrapUnRegisterHelper (DispatchHandle);
>
> +}
>
> +
>
> +/**
>
> + Register a new IO Trap Ex SMI dispatch function.
>
> +
>
> + @param[in] This Pointer to the
> IO_TRAP_EX_DISPATCH_PROTOCOL instance.
>
> + @param[in] DispatchFunction Pointer to dispatch function to be invoked
> for
>
> + this SMI source.
>
> + @param[in] RegisterContext Pointer to the dispatch function's context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function the IO trap Ex SMI source for which the dispatch
>
> + function should be invoked. This MUST not be NULL.
>
> + @param[out] DispatchHandle Handle of dispatch function.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available
>
> + @retval EFI_INVALID_PARAMETER Address requested is already in use.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapExRegister (
>
> + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This,
>
> + IN IO_TRAP_EX_DISPATCH_CALLBACK DispatchFunction,
>
> + IN IO_TRAP_EX_REGISTER_CONTEXT *RegisterContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + DEBUG ((DEBUG_INFO, "PchSmmIoTrapExRegister\n"));
>
> + //
>
> + // Return error if length is less than 4 and not power of 2.
>
> + //
>
> + if ((RegisterContext->Length < 4) || ((RegisterContext->Length &
> (RegisterContext->Length - 1)) != 0)) {
>
> + DEBUG ((DEBUG_ERROR, "The Dispatch Length is not power of 2 \n"));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + Status = IoTrapRegisterHelper (
>
> + DispatchHandle,
>
> + NULL,
>
> + DispatchFunction,
>
> + &(RegisterContext->Address),
>
> + RegisterContext->Length,
>
> + RegisterContext->Type,
>
> + RegisterContext->ByteEnable,
>
> + RegisterContext->ByteEnableMask);
>
> +
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gIoTrapExDispatchProtocolGuid,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + RegisterContext,
>
> + sizeof (*RegisterContext)
>
> + );
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a SMI source dispatch function.
>
> + This function is unsupported.
>
> +
>
> + @param[in] This Pointer to the
> IO_TRAP_EX_DISPATCH_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_UNSUPPORTED The function is unsupported.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapExUnRegister (
>
> + IN IO_TRAP_EX_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IO_TRAP_RECORD *RecordToDelete;
>
> +
>
> + RecordToDelete = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
>
> + SmiHandlerProfileUnregisterHandler (
>
> + &gIoTrapExDispatchProtocolGuid,
>
> + RecordToDelete->IoTrapCallback,
>
> + &RecordToDelete->Context,
>
> + sizeof (RecordToDelete->Context)
>
> + );
>
> + return IoTrapUnRegisterHelper (DispatchHandle);
>
> +}
>
> +
>
> +/**
>
> + Pause IoTrap callback function.
>
> +
>
> + This function disables the SMI enable of IoTrap according to the
> DispatchHandle,
>
> + which is returned by IoTrap callback registration. It only supports the
> DispatchHandle
>
> + with MergeDisable TRUE and address not zero.
>
> +
>
> + NOTE: This call does not guarantee all pending IO cycles to be synchronized
>
> + and pending IO cycles issued before this call might not be trapped.
>
> +
>
> + @param[in] This Pointer to the
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of the child service to change state.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapControlPause (
>
> + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IO_TRAP_RECORD *IoTrapRecord;
>
> + UINT32 IoTrapRegLowDword;
>
> + UINT32 IoTrapRegHighDword;
>
> + EFI_PHYSICAL_ADDRESS BaseAddress;
>
> + UINT32 UsedLength;
>
> + UINT8 TrapHandlerNum;
>
> + BOOLEAN TempMergeDisable;
>
> + BOOLEAN DisableIoTrap;
>
> +
>
> + if (DispatchHandle == 0) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
>
> +
>
> + if (IoTrapRecord->Context.Address) {
>
> + TempMergeDisable =TRUE;
>
> + }else {
>
> + TempMergeDisable = FALSE;
>
> + }
>
> +
>
> + if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
>
> + (TempMergeDisable != TRUE) ||
>
> + (IoTrapRecord->Context.Address == 0) ||
>
> + (IoTrapRecord->Context.Length == 0)) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
>
> + //
>
> + // This IoTrap register should be merge disabled.
>
> + //
>
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
>
> + continue;
>
> + }
>
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8);
>
> + IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8 + 4);
>
> + //
>
> + // Depending on the usage, we will obtain the UsedLength and
> BaseAddress differently
>
> + // If the registered trap length is less than 4, we obtain the length from
> Byte Enable Mask
>
> + // In the other hand, we obtain the length from Address Mask
>
> + //
>
> + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
>
> + UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) -
> LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword) +
> LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
>
> + } else {
>
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
>
> + }
>
> +
>
> + //
>
> + // The address and length of record matches the IoTrap register's.
>
> + //
>
> + DisableIoTrap = FALSE;
>
> + if ((IoTrapRecord->IoTrapExCallback != NULL) &&
>
> + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword,
> IoTrapRegHighDword)) {
>
> + DisableIoTrap = TRUE;
>
> + } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
>
> + (UsedLength == IoTrapRecord->Context.Length )) {
>
> + DisableIoTrap = TRUE;
>
> + }
>
> +
>
> + if (DisableIoTrap) {
>
> + //
>
> + // Check if status matched.
>
> + // If this is already Paused, return warning status.
>
> + //
>
> + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) == 0) {
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> + //
>
> + // Clear IoTrap register SMI enable bit
>
> + //
>
> + IoTrapRegLowDword &= (~B_PSTH_PCR_TRPREG_TSE);
>
> + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
>
> + //
>
> + // Also clear pending IOTRAP status.
>
> + //
>
> + ClearPendingIoTrapStatus (TrapHandlerNum);
>
> + return EFI_SUCCESS;
>
> + }
>
> + }
>
> + return EFI_INVALID_PARAMETER;
>
> +}
>
> +
>
> +/**
>
> + Resume IoTrap callback function.
>
> +
>
> + This function enables the SMI enable of IoTrap according to the
> DispatchHandle,
>
> + which is returned by IoTrap callback registration. It only supports the
> DispatchHandle
>
> + with MergeDisable TRUE and address not zero.
>
> +
>
> + @param[in] This Pointer to the
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of the child service to change state.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapControlResume (
>
> + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + IO_TRAP_RECORD *IoTrapRecord;
>
> + UINT32 IoTrapRegLowDword;
>
> + UINT32 IoTrapRegHighDword;
>
> + EFI_PHYSICAL_ADDRESS BaseAddress;
>
> + UINT32 UsedLength;
>
> + UINT8 TrapHandlerNum;
>
> + BOOLEAN TempMergeDisable;
>
> + BOOLEAN EnableIoTrap;
>
> +
>
> + if (DispatchHandle == 0) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + IoTrapRecord = IO_TRAP_RECORD_FROM_LINK (DispatchHandle);
>
> +
>
> + if (IoTrapRecord->Context.Address) {
>
> + TempMergeDisable = TRUE;
>
> + }else {
>
> + TempMergeDisable = FALSE;
>
> + }
>
> +
>
> + if ((IoTrapRecord->Signature != IO_TRAP_RECORD_SIGNATURE) ||
>
> + (TempMergeDisable != TRUE) ||
>
> + (IoTrapRecord->Context.Address == 0) ||
>
> + (IoTrapRecord->Context.Length == 0)) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
>
> + //
>
> + // This IoTrap register should be merge disabled.
>
> + //
>
> + if (mIoTrapData.Entry[TrapHandlerNum].MergeDisable != TRUE) {
>
> + continue;
>
> + }
>
> + IoTrapRegLowDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8);
>
> + IoTrapRegHighDword = PchPcrRead32 (PID_PSTH, R_PSTH_PCR_TRPREG0
> + TrapHandlerNum * 8 + 4);
>
> + //
>
> + // Depending on the usage, we will obtain the UsedLength and
> BaseAddress differently
>
> + // If the registered trap length is less than 4, we obtain the length from
> Byte Enable Mask
>
> + // In the other hand, we obtain the length from Address Mask
>
> + //
>
> + if (ByteEnableMaskFromHighDword (IoTrapRegHighDword) != 0xF) {
>
> + UsedLength = (UINT32) (HighBitSet32 (IoTrapRegHighDword & 0xF0) -
> LowBitSet32 (IoTrapRegHighDword & 0xF0) + 1);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword) +
> LowBitSet32 (ByteEnableMaskFromHighDword (IoTrapRegHighDword));
>
> + } else {
>
> + UsedLength = LengthFromLowDword (IoTrapRegLowDword);
>
> + BaseAddress = AddressFromLowDword (IoTrapRegLowDword);
>
> + }
>
> +
>
> + //
>
> + // The address and length of record matches the IoTrap register's.
>
> + //
>
> + EnableIoTrap = FALSE;
>
> + if ((IoTrapRecord->IoTrapExCallback != NULL) &&
>
> + IsIoTrapExContentMatched (IoTrapRecord, IoTrapRegLowDword,
> IoTrapRegHighDword)) {
>
> + EnableIoTrap = TRUE;
>
> + } else if ((BaseAddress == IoTrapRecord->Context.Address) &&
>
> + (UsedLength == IoTrapRecord->Context.Length )) {
>
> + EnableIoTrap = TRUE;
>
> + }
>
> +
>
> + if (EnableIoTrap) {
>
> + //
>
> + // Check if status matched.
>
> + // If this is already Resume, return warning status.
>
> + //
>
> + if ((IoTrapRegLowDword & B_PSTH_PCR_TRPREG_TSE) != 0) {
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> + //
>
> + // Set IoTrap register SMI enable bit
>
> + //
>
> + IoTrapRegLowDword |= (B_PSTH_PCR_TRPREG_TSE);
>
> + SetIoTrapLowDword (TrapHandlerNum, IoTrapRegLowDword, FALSE);
>
> + return EFI_SUCCESS;
>
> + }
>
> + }
>
> + return EFI_INVALID_PARAMETER;
>
> +}
>
> +
>
> +/**
>
> + The IoTrap module abstracts PCH I/O trapping capabilities for other drivers.
>
> + This driver manages the limited I/O trap resources.
>
> +
>
> + @param[in] ImageHandle Image handle for this driver image
>
> +
>
> + @retval EFI_SUCCESS Driver initialization completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallIoTrap (
>
> + IN EFI_HANDLE ImageHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + PCH_NVS_AREA_PROTOCOL *PchNvsAreaProtocol;
>
> + UINTN TrapHandlerNum;
>
> +
>
> + //
>
> + // Initialize the EFI SMM driver library
>
> + //
>
> + mDriverImageHandle = ImageHandle;
>
> +
>
> + //
>
> + // Initialize the IO TRAP protocol we produce
>
> + //
>
> + mIoTrapData.Signature = IO_TRAP_INSTANCE_SIGNATURE;
>
> + mIoTrapData.EfiSmmIoTrapDispatchProtocol.Register = IoTrapRegister;
>
> + mIoTrapData.EfiSmmIoTrapDispatchProtocol.UnRegister =
> IoTrapUnRegister;
>
> +
>
> + //
>
> + // Initialize the IO TRAP EX protocol
>
> + //
>
> + mIoTrapData.IoTrapExDispatchProtocol.Register = IoTrapExRegister;
>
> + mIoTrapData.IoTrapExDispatchProtocol.UnRegister =
> IoTrapExUnRegister;
>
> +
>
> + //
>
> + // Initialize the IO TRAP control protocol.
>
> + //
>
> + mIoTrapData.PchSmmIoTrapControlProtocol.Pause =
> IoTrapControlPause;
>
> + mIoTrapData.PchSmmIoTrapControlProtocol.Resume =
> IoTrapControlResume;
>
> +
>
> + for (TrapHandlerNum = 0; TrapHandlerNum < IO_TRAP_HANDLER_NUM;
> TrapHandlerNum++) {
>
> + //
>
> + // Initialize IO TRAP Callback DataBase
>
> + //
>
> + InitializeListHead
> (&(mIoTrapData.Entry[TrapHandlerNum].CallbackDataBase));
>
> + }
>
> + mIoTrapData.Entry[0].CallbackDispatcher = IoTrapDispatcher0;
>
> + mIoTrapData.Entry[1].CallbackDispatcher = IoTrapDispatcher1;
>
> + mIoTrapData.Entry[2].CallbackDispatcher = IoTrapDispatcher2;
>
> + mIoTrapData.Entry[3].CallbackDispatcher = IoTrapDispatcher3;
>
> +
>
> + //
>
> + // Get address of PchNvs structure for later use
>
> + //
>
> + Status = gBS->LocateProtocol (&gPchNvsAreaProtocolGuid, NULL, (VOID
> **) &PchNvsAreaProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> + mPchNvsArea = PchNvsAreaProtocol->Area;
>
> +
>
> + //
>
> + // Install protocol interface
>
> + //
>
> + mIoTrapData.Handle = NULL;
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &mIoTrapData.Handle,
>
> + &gEfiSmmIoTrapDispatch2ProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mIoTrapData.EfiSmmIoTrapDispatchProtocol
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &mIoTrapData.Handle,
>
> + &gIoTrapExDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mIoTrapData.IoTrapExDispatchProtocol
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &mIoTrapData.Handle,
>
> + &gPchSmmIoTrapControlGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mIoTrapData.PchSmmIoTrapControlProtocol
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
> new file mode 100644
> index 0000000000..e69d2e2d4d
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/IoTrap.h
> @@ -0,0 +1,226 @@
> +/** @file
>
> + Defines and prototypes for the IoTrap SMM driver
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _IO_TRAP_H_
>
> +#define _IO_TRAP_H_
>
> +
>
> +//
>
> +// Include files
>
> +//
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <Library/UefiDriverEntryPoint.h>
>
> +#include <Protocol/SmmIoTrapDispatch2.h>
>
> +#include <Protocol/PchSmmIoTrapControl.h>
>
> +#include <Protocol/IoTrapExDispatch.h>
>
> +
>
> +#define IO_TRAP_HANDLER_NUM 4
>
> +
>
> +//
>
> +// Driver private data
>
> +//
>
> +#define IO_TRAP_INSTANCE_SIGNATURE SIGNATURE_32 ('I', 'O', 'T', 'P')
>
> +
>
> +typedef struct {
>
> + EFI_HANDLE IoTrapHandle;
>
> + /**
>
> + The callback linked list for all "merged" IoTrap callbacks.
>
> + **/
>
> + LIST_ENTRY CallbackDataBase;
>
> + /**
>
> + The IoTrap IO range used length tracking for "merged" IoTrap register.
>
> + **/
>
> + UINT32 TrapUsedLength;
>
> + /**
>
> + Determine if IoTrap can be merged with other IoTrap callbacks.
>
> + If MergeDisable is TRUE, then there is only one callback function for one
> IoTrap register.
>
> + If MergeDisable is FALSE, then there are multiple callbacks in the
> "CallbackDataBase" for one IoTrap register.
>
> + **/
>
> + BOOLEAN MergeDisable;
>
> + /**
>
> + Indicator of the resource tracking in ACPI.
>
> + If the registration address is not 0, it's caller's responsibility to reserve the
> IO resource in ACPI.
>
> + **/
>
> + BOOLEAN ReservedAcpiIoResource;
>
> + /**
>
> + Dispatcher for each IoTrap register.
>
> + **/
>
> + PCH_SMI_DISPATCH_CALLBACK CallbackDispatcher;
>
> +} IO_TRAP_ENTRY_ATTRIBUTES;
>
> +
>
> +typedef struct {
>
> + UINT32 Signature;
>
> + EFI_HANDLE Handle;
>
> + EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL
> EfiSmmIoTrapDispatchProtocol;
>
> + PCH_SMM_IO_TRAP_CONTROL_PROTOCOL
> PchSmmIoTrapControlProtocol; ///< Protocol for runtime control the
> IoTrap state
>
> + IO_TRAP_EX_DISPATCH_PROTOCOL IoTrapExDispatchProtocol;
> ///< Protocol for IoTrap Extension
>
> + IO_TRAP_ENTRY_ATTRIBUTES Entry[IO_TRAP_HANDLER_NUM];
>
> +} IO_TRAP_INSTANCE;
>
> +
>
> +#define IO_TRAP_INSTANCE_FROM_THIS(a) CR (a, IO_TRAP_INSTANCE,
> EfiSmmIoTrapDispatchProtocol, IO_TRAP_INSTANCE_SIGNATURE)
>
> +
>
> +///
>
> +/// "IOTRAP" RECORD
>
> +/// Linked list data structures
>
> +///
>
> +#define IO_TRAP_RECORD_SIGNATURE SIGNATURE_32 ('I', 'T', 'R', 'C')
>
> +
>
> +typedef struct _IO_TRAP_RECORD {
>
> + UINT32 Signature;
>
> + LIST_ENTRY Link;
>
> + IO_TRAP_EX_REGISTER_CONTEXT Context;
>
> + /**
>
> + The callback function of IoTrap protocol.
>
> + This also indicate it's the record for IoTrapProtocol.
>
> + Only one of IoTrapCallback or IoTrapExCallback is valid at a time.
>
> + **/
>
> + EFI_SMM_HANDLER_ENTRY_POINT2 IoTrapCallback;
>
> + /**
>
> + The callback function of IoTrapEx protocol
>
> + This also indicate it's the record for IoTrapExProtocol.
>
> + Only one of IoTrapCallback or IoTrapExCallback is valid at a time.
>
> + **/
>
> + IO_TRAP_EX_DISPATCH_CALLBACK IoTrapExCallback;
>
> + UINT8 IoTrapNumber;
>
> +} IO_TRAP_RECORD;
>
> +
>
> +#define IO_TRAP_RECORD_FROM_LINK(_record) CR (_record,
> IO_TRAP_RECORD, Link, IO_TRAP_RECORD_SIGNATURE)
>
> +
>
> +//
>
> +// Prototypes
>
> +//
>
> +/**
>
> + The IoTrap module abstracts PCH I/O trapping capabilities for other drivers.
>
> + This driver manages the limited I/O trap resources.
>
> +
>
> + @param[in] ImageHandle Image handle for this driver image
>
> +
>
> + @retval EFI_SUCCESS Driver initialization completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallIoTrap (
>
> + IN EFI_HANDLE ImageHandle
>
> + );
>
> +
>
> +/**
>
> + Register a new IO Trap SMI dispatch function with a parent SMM driver.
>
> + The caller will provide information about the IO trap characteristics via
>
> + the context. This includes base address, length, read vs. r/w, etc.
>
> + This function will autoallocate IO base address from a common pool if the
> base address is 0,
>
> + and the RegisterContext Address field will be updated.
>
> + The service will not perform GCD allocation if the base address is non-zero.
>
> + In this case, the caller is responsible for the existence and allocation of the
>
> + specific IO range.
>
> + This function looks for the suitable handler and Register a new IoTrap
> handler
>
> + if the IO Trap handler is not used. It also enable the IO Trap Range to
> generate
>
> + SMI.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Pointer to dispatch function to be invoked
> for
>
> + this SMI source.
>
> + @param[in, out] RegisterContext Pointer to the dispatch function's
> context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function the IO trap SMI source for which the dispatch
>
> + function should be invoked. This may not be NULL.
>
> + If the registration address is not 0, it's caller's responsibility
>
> + to reserve the IO resource in ACPI.
>
> + @param[out] DispatchHandle Handle of dispatch function, for when
> interfacing
>
> + with the parent SMM driver, will be the address of linked
>
> + list link in the call back record. This may not be NULL.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_DEVICE_ERROR The driver was unable to enable the SMI
> source.
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources are available
>
> + @retval EFI_INVALID_PARAMETER Address requested is already in use.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapRegister (
>
> + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN OUT EFI_SMM_IO_TRAP_REGISTER_CONTEXT *RegisterContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapUnRegister (
>
> + IN CONST EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + This I/O Trap SMI handler invokes the ACPI reference code to handle the
> SMI.
>
> + It currently assumes it owns all of the IO trap SMI.
>
> +
>
> + @param[in] DispatchHandle Not used
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +IoTrapCallback (
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Pause IoTrap callback function.
>
> +
>
> + This function disables the SMI enable of IoTrap according to the
> DispatchHandle,
>
> + which is returned by IoTrap callback registration. It only supports the
> DispatchHandle
>
> + with MergeDisable TRUE and address not zero.
>
> +
>
> + @param[in] This Pointer to the
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of the child service to change state.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> + @retval EFI_ACCESS_DENIED The SMI status is alrady PAUSED.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapControlPause (
>
> + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Resume IoTrap callback function.
>
> +
>
> + This function enables the SMI enable of IoTrap according to the
> DispatchHandle,
>
> + which is returned by IoTrap callback registration. It only supports the
> DispatchHandle
>
> + with MergeDisable TRUE and address not zero.
>
> +
>
> + @param[in] This Pointer to the
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of the child service to change state.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> + @retval EFI_ACCESS_DENIED The SMI status is alrady RESUMED.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +IoTrapControlResume (
>
> + IN PCH_SMM_IO_TRAP_CONTROL_PROTOCOL * This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tch.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tch.c
> new file mode 100644
> index 0000000000..affbe94eb7
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tch.c
> @@ -0,0 +1,2442 @@
> +/** @file
>
> + This function handle the register/unregister of PCH specific SMI events.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Library/SmiHandlerProfileLib.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PchPcrRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/SpiRegs.h>
>
> +#include <Register/PchPcieRpRegs.h>
>
> +#include <Register/PchRegsPsth.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <Library/S3BootScriptLib.h>
>
> +#include <PchBdfAssignment.h>
>
> +#include "PchSmiHelper.h"
>
> +
>
> +/**
>
> + The internal function used to create and insert a database record
>
> + for SMI record of Pch Smi types.
>
> +
>
> + @param[in] SrcDesc The pointer to the SMI source description
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] PchSmiType Specific SMI type of PCH SMI
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmiRecordInsert (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc,
>
> + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction,
>
> + IN PCH_SMI_TYPES PchSmiType,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD Record;
>
> +
>
> + if (SrcDesc == NULL) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + ZeroMem (&Record, sizeof (DATABASE_RECORD));
>
> + //
>
> + // Gather information about the registration request
>
> + //
>
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
>
> + Record.PchSmiCallback = DispatchFunction;
>
> + Record.ProtocolType = PchSmiDispatchType;
>
> + Record.PchSmiType = PchSmiType;
>
> +
>
> + CopyMem (&Record.SrcDesc, SrcDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
>
> + Status = SmmCoreInsertRecord (
>
> + &Record,
>
> + DispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +
>
> +//
>
> +// TCO_STS bit that needs to be cleared
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mDescSrcTcoSts = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + NULL_BIT_DESC_INITIALIZER,
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> +};
>
> +
>
> +/**
>
> + Clear the TCO SMI status bit and block after the SMI handling is done
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchTcoSmiClearSourceAndBlock (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + PchSmmClearSourceAndBlock (SrcDesc);
>
> + //
>
> + // Any TCO-based status bits require special handling.
>
> + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the
> TCO registers
>
> + //
>
> + PchSmmClearSource (&mDescSrcTcoSts);
>
> +}
>
> +
>
> +/**
>
> + Clear the TCO SMI status bit after the SMI handling is done
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchTcoSmiClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + PchSmmClearSource (SrcDesc);
>
> + //
>
> + // Any TCO-based status bits require special handling.
>
> + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the
> TCO registers
>
> + //
>
> + PchSmmClearSource (&mDescSrcTcoSts);
>
> +}
>
> +
>
> +/**
>
> + Initialize Source descriptor structure
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NullInitSourceDesc (
>
> + PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + ZeroMem (SrcDesc, sizeof (PCH_SMM_SOURCE_DESC));
>
> + SrcDesc->En[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
>
> + SrcDesc->En[1].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
>
> + SrcDesc->Sts[0].Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
>
> + SrcDesc->PmcSmiSts.Reg.Type = PCH_SMM_ADDR_TYPE_NULL;
>
> +}
>
> +
>
> +//
>
> +// Mch srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescMch = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_DMISMI
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of MCH event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiMchRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescMch,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiMchType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// TcoTimeout srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescTcoTimeout = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_TIMEOUT
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of TcoTimeout event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiTcoTimeoutRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescTcoTimeout,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiTcoTimeoutType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// OsTco srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescOsTco = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_SW_TCO_SMI
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of OS TCO event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiOsTcoRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescOsTco,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiOsTcoType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// Nmi
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescNmi = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_CNT}
>
> + },
>
> + S_TCO_IO_TCO1_CNT,
>
> + N_TCO_IO_TCO1_CNT_NMI2SMI_EN
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_NMI2SMI
>
> + }
>
> + },
>
> + //
>
> + // NOTE: The status of NMI2SMI won't reflect to PMC SMI_STS.
>
> + // So skip the top level status check and check the TCO1_STS directly.
>
> + //
>
> + NULL_BIT_DESC_INITIALIZER
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of NMI event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiNmiRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescNmi,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiNmiType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// IntruderDetect srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescIntruderDet = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO2_CNT}
>
> + },
>
> + S_TCO_IO_TCO2_CNT,
>
> + N_TCO_IO_TCO2_CNT_INTRD_SEL
>
> + }
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO2_STS}
>
> + },
>
> + S_TCO_IO_TCO2_STS,
>
> + N_TCO_IO_TCO2_STS_INTRD_DET
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of Intruder Detect
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiIntruderDetRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescIntruderDet,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiIntruderDetectType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSourceAndBlock;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// SpiBiosWp srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescSpiBiosWp = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
>
> + R_SPI_CFG_BC
>
> + ) }
>
> + },
>
> + S_SPI_CFG_BC,
>
> + N_SPI_CFG_BC_BLE
>
> + },
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
>
> + R_SPI_CFG_BC
>
> + ) }
>
> + },
>
> + S_SPI_CFG_BC,
>
> + N_SPI_CFG_BC_SYNC_SS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Special handling for SPI Write Protect
>
> +
>
> + @param[in] SrcDesc Not used
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchTcoSpiWpClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINT64 SpiRegBase;
>
> + UINT32 BiosControl;
>
> + UINT32 Timeout;
>
> +
>
> + SpiRegBase = SpiPciCfgBase ();
>
> + PciSegmentAndThenOr32 (
>
> + SpiRegBase + R_SPI_CFG_BC,
>
> + (UINT32) ~B_SPI_CFG_BC_ASYNC_SS,
>
> + B_SPI_CFG_BC_SYNC_SS
>
> + );
>
> + //
>
> + // Ensure the SYNC is cleared
>
> + //
>
> + Timeout = 1000;
>
> + do {
>
> + BiosControl = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BC);
>
> + Timeout--;
>
> + } while ((BiosControl & B_SPI_CFG_BC_SYNC_SS) && (Timeout > 0));
>
> +
>
> + //
>
> + // Any TCO-based status bits require special handling.
>
> + // SMI_STS.TCO_STS must be cleared in addition to the status bit in the
> TCO registers
>
> + //
>
> + PchSmmClearSource (&mDescSrcTcoSts);
>
> +}
>
> +
>
> +/**
>
> + Set SMI_EN_TCO to enable TCO SMI.
>
> +**/
>
> +STATIC
>
> +VOID
>
> +PchSetSmiEnTco (
>
> + VOID
>
> + )
>
> +{
>
> + IoOr32 (mAcpiBaseAddr + R_ACPI_IO_SMI_EN,
> B_ACPI_IO_SMI_EN_TCO);
>
> +}
>
> +
>
> +/**
>
> + The register function used to register SMI handler of BIOS write protect
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiSpiBiosWpRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescSpiBiosWp,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiSpiBiosWpType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSpiWpClearSource;
>
> + PchTcoSpiWpClearSource (NULL);
>
> + //
>
> + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
>
> + // Only enable SMI_EN_TCO.
>
> + //
>
> + PchSetSmiEnTco ();
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// LpcBiosWp srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescLpcBiosWp = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
>
> + R_LPC_CFG_BC
>
> + ) }
>
> + },
>
> + S_LPC_CFG_BC,
>
> + N_LPC_CFG_BC_LE
>
> + }
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_BIOSWR
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of LPC BIOS write
> protect event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiLpcBiosWpRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + if (IsEspiEnabled ()) {
>
> + //
>
> + // Status is D31F0's PCBC.BWPDS
>
> + //
>
> + ASSERT (FALSE);
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescLpcBiosWp,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiLpcBiosWpType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + //
>
> + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
>
> + // Only enable SMI_EN_TCO.
>
> + //
>
> + PchSetSmiEnTco ();
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// NEWCENTURY_STS bit that needs to be cleared
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescNewCentury = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + TCO_ADDR_TYPE,
>
> + {R_TCO_IO_TCO1_STS}
>
> + },
>
> + S_TCO_IO_TCO1_STS,
>
> + N_TCO_IO_TCO1_STS_NEWCENTURY
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of NEW CENTURY event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiNewCenturyRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_TCO_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescNewCentury,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchTcoSmiNewCenturyType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchTcoSmiClearSourceAndBlock;
>
> + PchSmmClearSource (&Record->SrcDesc);
>
> + PchSmmEnableSource (&Record->SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchTcoSmiUnRegister (
>
> + IN PCH_TCO_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *Record;
>
> + EFI_STATUS Status;
>
> +
>
> + Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == SpiDevNumber ())
> &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ())
> &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
>
> + (Record->SrcDesc.En[1].Bit == N_SPI_CFG_BC_BLE)) {
>
> + //
>
> + // SPI Write Protect cannot be disabled
>
> + //
>
> + return EFI_ACCESS_DENIED;
>
> + } else if ((Record->SrcDesc.En[1].Reg.Type == ACPI_ADDR_TYPE) &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Dev == LpcDevNumber
> ()) &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Fnc == LpcFuncNumber
> ()) &&
>
> + (Record->SrcDesc.En[1].Reg.Data.pcie.Fields.Reg == R_LPC_CFG_BC)
> &&
>
> + (Record->SrcDesc.En[1].Bit == N_LPC_CFG_BC_LE)) {
>
> + //
>
> + // eSPI/LPC Write Protect cannot be disabled
>
> + //
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler (&gPchTcoSmiDispatchProtocolGuid,
> Record->Callback, NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +
>
> +//
>
> +// PcieRpHotPlug srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC
> PchPcieSmiRpHotPlugTemplate = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_MPC}
>
> + },
>
> + S_PCH_PCIE_CFG_MPC,
>
> + N_PCH_PCIE_CFG_MPC_HPME
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_SMSCS}
>
> + },
>
> + S_PCH_PCIE_CFG_SMSCS,
>
> + N_PCH_PCIE_CFG_SMSCS_HPPDM
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PCI_EXP
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of PCIE RP hotplug
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PCH
> RP index and CPU RP index.
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPcieSmiHotPlugRegister (
>
> + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
>
> + IN UINTN RpIndex,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINTN RpDev;
>
> + UINTN RpFun;
>
> + PCH_SMM_PCIE_REGISTER_CONTEXT Context;
>
> + DATABASE_RECORD *Record;
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
>
> +
>
> + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
>
> + PchPcieSmiRpHotPlugTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
>
> + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
>
> + PchPcieSmiRpHotPlugTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &PchPcieSmiRpHotPlugTemplate,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchPcieSmiRpHotplugType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpHotplugType;
>
> + Record->ChildContext.Pcie.RpIndex = RpIndex;
>
> + Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gPchPcieSmiDispatchProtocolGuid,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + &Context,
>
> + sizeof (Context)
>
> + );
>
> + }
>
> + PchSmmClearSource (&PchPcieSmiRpHotPlugTemplate);
>
> + PchSmmEnableSource (&PchPcieSmiRpHotPlugTemplate);
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// PcieRpLinkActive srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC
> PchPcieSmiRpLinkActiveTemplate = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_MPC}
>
> + },
>
> + S_PCH_PCIE_CFG_MPC,
>
> + N_PCH_PCIE_CFG_MPC_HPME
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_SMSCS}
>
> + },
>
> + S_PCH_PCIE_CFG_SMSCS,
>
> + N_PCH_PCIE_CFG_SMSCS_HPLAS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PCI_EXP
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of PCIE RP link active
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PCH
> RP index and CPU RP index.
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPcieSmiLinkActiveRegister (
>
> + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
>
> + IN UINTN RpIndex,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINTN RpDev;
>
> + UINTN RpFun;
>
> + PCH_SMM_PCIE_REGISTER_CONTEXT Context;
>
> + DATABASE_RECORD *Record;
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
>
> +
>
> +
>
> + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Dev =
> (UINT8) RpDev;
>
> + PchPcieSmiRpLinkActiveTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
>
> + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Dev =
> (UINT8) RpDev;
>
> + PchPcieSmiRpLinkActiveTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc =
> (UINT8) RpFun;
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &PchPcieSmiRpLinkActiveTemplate,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchPcieSmiRpLinkActiveType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkActiveType;
>
> + Record->ChildContext.Pcie.RpIndex = RpIndex;
>
> + Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gPchPcieSmiDispatchProtocolGuid,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + &Context,
>
> + sizeof (Context)
>
> + );
>
> + }
>
> + PchSmmClearSource (&PchPcieSmiRpLinkActiveTemplate);
>
> + PchSmmEnableSource (&PchPcieSmiRpLinkActiveTemplate);
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// PcieRpLinkEq srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_SMM_SOURCE_DESC
> PchPcieSmiRpLinkEqTemplate = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_EQCFG1}
>
> + },
>
> + S_PCH_PCIE_CFG_EQCFG1,
>
> + N_PCH_PCIE_CFG_EQCFG1_LERSMIE
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + {R_PCH_PCIE_CFG_SMSCS}
>
> + },
>
> + S_PCH_PCIE_CFG_SMSCS,
>
> + N_PCH_PCIE_CFG_SMSCS_LERSMIS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PCI_EXP
>
> + }
>
> +};
>
> +/**
>
> + The register function used to register SMI handler of PCIE RP Link
> Equalization Request event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] RpIndex Refer PCIE_COMBINED_RPINDEX for PCH
> RP index and CPU RP index.
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPcieSmiLinkEqRegister (
>
> + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_PCIE_SMI_RP_DISPATCH_CALLBACK DispatchFunction,
>
> + IN UINTN RpIndex,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + UINTN RpDev;
>
> + UINTN RpFun;
>
> + EFI_STATUS Status;
>
> + PCH_SMM_PCIE_REGISTER_CONTEXT Context;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + GetPcieRpDevFun (RpIndex, &RpDev, &RpFun);
>
> +
>
> + //
>
> + // Patch the RP device number and function number of srcdesc.
>
> + //
>
> + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
>
> + PchPcieSmiRpLinkEqTemplate.En[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
>
> + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Dev = (UINT8)
> RpDev;
>
> + PchPcieSmiRpLinkEqTemplate.Sts[0].Reg.Data.pcie.Fields.Fnc = (UINT8)
> RpFun;
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &PchPcieSmiRpLinkEqTemplate,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchPcieSmiRpLinkEqType,
>
> + DispatchHandle
>
> + );
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ChildContext.Pcie.PchSmiType = PchPcieSmiRpLinkEqType;
>
> + Record->ChildContext.Pcie.RpIndex = RpIndex;
>
> + Record->ContextSize = sizeof (PCH_SMM_PCIE_REGISTER_CONTEXT);
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gPchPcieSmiDispatchProtocolGuid,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + &Context,
>
> + sizeof (Context)
>
> + );
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPcieSmiUnRegister (
>
> + IN PCH_PCIE_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordToDelete;
>
> + EFI_STATUS Status;
>
> +
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler (
>
> + &gPchPcieSmiDispatchProtocolGuid,
>
> + RecordToDelete->Callback,
>
> + &RecordToDelete->ChildContext,
>
> + sizeof (RecordToDelete->ContextSize)
>
> + );
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// Pme srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescPme = {
>
> + PCH_SMM_SCI_EN_DEPENDENT,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_GPE0_EN_127_96}
>
> + },
>
> + S_ACPI_IO_GPE0_EN_127_96,
>
> + N_ACPI_IO_GPE0_EN_127_96_PME
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_GPE0_STS_127_96}
>
> + },
>
> + S_ACPI_IO_GPE0_STS_127_96,
>
> + N_ACPI_IO_GPE0_STS_127_96_PME
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_GPE0
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of PME event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiSmiPmeRegister (
>
> + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescPme,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchAcpiSmiPmeType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescPme);
>
> + PchSmmEnableSource (&mSrcDescPme);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// PmeB0 srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescPmeB0 = {
>
> + PCH_SMM_SCI_EN_DEPENDENT,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_GPE0_EN_127_96}
>
> + },
>
> + S_ACPI_IO_GPE0_EN_127_96,
>
> + N_ACPI_IO_GPE0_EN_127_96_PME_B0
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_GPE0_STS_127_96}
>
> + },
>
> + S_ACPI_IO_GPE0_STS_127_96,
>
> + N_ACPI_IO_GPE0_STS_127_96_PME_B0
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_GPE0
>
> + }
>
> +};
>
> +/**
>
> + The register function used to register SMI handler of PME B0 event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiSmiPmeB0Register (
>
> + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescPmeB0,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchAcpiSmiPmeB0Type,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescPmeB0);
>
> + PchSmmEnableSource (&mSrcDescPmeB0);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// RtcAlarm srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescRtcAlarm = {
>
> + PCH_SMM_SCI_EN_DEPENDENT,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_EN}
>
> + },
>
> + S_ACPI_IO_PM1_EN,
>
> + N_ACPI_IO_PM1_EN_RTC
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_STS}
>
> + },
>
> + S_ACPI_IO_PM1_STS,
>
> + N_ACPI_IO_PM1_STS_RTC
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PM1_STS_REG
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of RTC alarm event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiSmiRtcAlarmRegister (
>
> + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescRtcAlarm,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchAcpiSmiRtcAlarmType,
>
> + DispatchHandle
>
> + );
>
> +
>
> + PchSmmClearSource (&mSrcDescRtcAlarm);
>
> + PchSmmEnableSource (&mSrcDescRtcAlarm);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// TmrOverflow srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescTmrOverflow = {
>
> + PCH_SMM_SCI_EN_DEPENDENT,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_EN}
>
> + },
>
> + S_ACPI_IO_PM1_EN,
>
> + N_ACPI_IO_PM1_EN_TMROF
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_STS}
>
> + },
>
> + S_ACPI_IO_PM1_STS,
>
> + N_ACPI_IO_PM1_STS_TMROF
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PM1_STS_REG
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of Timer Overflow
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiSmiTmrOverflowRegister (
>
> + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ACPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescTmrOverflow,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchAcpiSmiTmrOverflowType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescTmrOverflow);
>
> + PchSmmEnableSource (&mSrcDescTmrOverflow);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchAcpiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchAcpiSmiUnRegister (
>
> + IN PCH_ACPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordToDelete;
>
> + EFI_STATUS Status;
>
> +
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler
> (&gPchAcpiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// SerialIrq srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescSerialIrq = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + NULL_BIT_DESC_INITIALIZER,
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SERIRQ
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SERIRQ
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of Serial IRQ event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmiSerialIrqRegister (
>
> + IN PCH_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescSerialIrq,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchSmiSerialIrqType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescSerialIrq);
>
> + PchSmmEnableSource (&mSrcDescSerialIrq);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// McSmi srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescMcSmi = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_MCSMI
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MCSMI
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MCSMI
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of MCSMI event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmiMcSmiRegister (
>
> + IN PCH_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescMcSmi,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchSmiMcSmiType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescMcSmi);
>
> + PchSmmEnableSource (&mSrcDescMcSmi);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// SmBus srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescSmbus = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + NULL_BIT_DESC_INITIALIZER,
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SMBUS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SMBUS
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of SMBUS event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmiSmbusRegister (
>
> + IN PCH_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescSmbus,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchSmiSmBusType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescSmbus);
>
> + PchSmmEnableSource (&mSrcDescSmbus);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// SpiAsyncSmi srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescSpiAsyncSmi = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
>
> + R_SPI_CFG_BC
>
> + ) }
>
> + },
>
> + S_SPI_CFG_BC,
>
> + N_SPI_CFG_BC_ASE_BWP
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_SPI << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_SPI << 16) |
>
> + R_SPI_CFG_BC
>
> + ) }
>
> + },
>
> + S_SPI_CFG_BC,
>
> + N_SPI_CFG_BC_ASYNC_SS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SPI
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Special handling for SPI Asynchronous SMI.
>
> + If SPI ASYNC SMI is enabled, De-assert SMI is sent when Flash Cycle Done
>
> + transitions from 1 to 0 or when the SMI enable becomes false.
>
> +
>
> + @param[in] SrcDesc Not used
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchSmiSpiAsyncClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINT64 SpiRegBase;
>
> + UINT32 SpiBar0;
>
> +
>
> + SpiRegBase = SpiPciCfgBase ();
>
> + SpiBar0 = PciSegmentRead32 (SpiRegBase + R_SPI_CFG_BAR0) &
> ~(B_SPI_CFG_BAR0_MASK);
>
> + if (SpiBar0 != PCH_SPI_BASE_ADDRESS) {
>
> + //
>
> + // Temporary disable MSE, and override with SPI reserved MMIO
> address, then enable MSE.
>
> + //
>
> + SpiBar0 = PCH_SPI_BASE_ADDRESS;
>
> + PciSegmentAnd8 (SpiRegBase + PCI_COMMAND_OFFSET, (UINT8)
> ~EFI_PCI_COMMAND_MEMORY_SPACE);
>
> + PciSegmentWrite32 (SpiRegBase + R_SPI_CFG_BAR0, SpiBar0);
>
> + PciSegmentOr8 (SpiRegBase + PCI_COMMAND_OFFSET,
> EFI_PCI_COMMAND_MEMORY_SPACE);
>
> + }
>
> +
>
> + MmioOr32 (SpiBar0 + R_SPI_MEM_HSFSC, B_SPI_MEM_HSFSC_FDONE);
>
> +}
>
> +
>
> +/**
>
> + Special handling to enable SPI Asynchronous SMI
>
> +**/
>
> +VOID
>
> +PchSmiSpiAsyncEnableSource (
>
> + VOID
>
> + )
>
> +{
>
> + UINT64 SpiRegBase;
>
> + UINT32 Data32And;
>
> + UINT32 Data32Or;
>
> +
>
> + SpiRegBase = SpiPciCfgBase ();
>
> + Data32And = (UINT32) ~B_SPI_CFG_BC_SYNC_SS;
>
> + Data32Or = B_SPI_CFG_BC_ASE_BWP;
>
> +
>
> + PciSegmentAndThenOr32 (
>
> + SpiRegBase + R_SPI_CFG_BC,
>
> + Data32And,
>
> + Data32Or
>
> + );
>
> + S3BootScriptSavePciCfgReadWrite (
>
> + S3BootScriptWidthUint32,
>
> + SpiRegBase + R_SPI_CFG_BC,
>
> + (VOID*) &Data32Or,
>
> + (VOID*) &Data32And
>
> + );
>
> +
>
> + //
>
> + // Clear the source
>
> + //
>
> + PchSmiSpiAsyncClearSource (NULL);
>
> +}
>
> +
>
> +/**
>
> + The register function used to register SMI handler of SPI Asynchronous
> event.
>
> +
>
> + @param[in] This The pointer to the protocol itself
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmiSpiAsyncRegister (
>
> + IN PCH_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescSpiAsyncSmi,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchSmiSpiAsyncType,
>
> + DispatchHandle
>
> + );
>
> +
>
> + if (!EFI_ERROR (Status)) {
>
> + Record = DATABASE_RECORD_FROM_LINK (*DispatchHandle);
>
> + Record->ClearSource = PchSmiSpiAsyncClearSource;
>
> + PchSmiSpiAsyncClearSource (NULL);
>
> + PchSmiSpiAsyncEnableSource ();
>
> + SmiHandlerProfileRegisterHandler (&gPchSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval EFI_ACCESS_DENIED Return access denied since SPI aync
> SMI handler is not able to disabled.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmiUnRegister (
>
> + IN PCH_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *Record;
>
> + UINT64 SpiRegBase;
>
> + EFI_STATUS Status;
>
> +
>
> + Record = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + if ((Record->SrcDesc.En[0].Reg.Type == PCIE_ADDR_TYPE) &&
>
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Dev == SpiDevNumber ())
> &&
>
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc == SpiFuncNumber ())
> &&
>
> + (Record->SrcDesc.En[0].Reg.Data.pcie.Fields.Reg == R_SPI_CFG_BC) &&
>
> + (Record->SrcDesc.En[0].Bit == N_SPI_CFG_BC_ASE_BWP)) {
>
> + SpiRegBase = SpiPciCfgBase ();
>
> + if (PciSegmentRead8 (SpiRegBase + R_SPI_CFG_BC) &
> B_SPI_CFG_BC_BILD) {
>
> + //
>
> + // SPI Asynchronous SMI cannot be disabled
>
> + //
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> + }
>
> + Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler (&gPchSmiDispatchProtocolGuid,
> Record->Callback, NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +
>
> +/**
>
> + Declaration of PCH TCO SMI DISPATCH PROTOCOL instance
>
> +**/
>
> +PCH_TCO_SMI_DISPATCH_PROTOCOL mPchTcoSmiDispatchProtocol = {
>
> + PCH_TCO_SMI_DISPATCH_REVISION, // Revision
>
> + PchTcoSmiUnRegister, // Unregister
>
> + PchTcoSmiMchRegister, // Mch
>
> + PchTcoSmiTcoTimeoutRegister, // TcoTimeout
>
> + PchTcoSmiOsTcoRegister, // OsTco
>
> + PchTcoSmiNmiRegister, // Nmi
>
> + PchTcoSmiIntruderDetRegister, // IntruderDectect
>
> + PchTcoSmiSpiBiosWpRegister, // SpiBiosWp
>
> + PchTcoSmiLpcBiosWpRegister, // LpcBiosWp
>
> + PchTcoSmiNewCenturyRegister // NewCentury
>
> +};
>
> +
>
> +/**
>
> + Declaration of PCH PCIE SMI DISPATCH PROTOCOL instance
>
> +**/
>
> +PCH_PCIE_SMI_DISPATCH_PROTOCOL mPchPcieSmiDispatchProtocol = {
>
> + PCH_PCIE_SMI_DISPATCH_REVISION, // Revision
>
> + PchPcieSmiUnRegister, // Unregister
>
> + PchPcieSmiHotPlugRegister, // PcieRpXHotPlug
>
> + PchPcieSmiLinkActiveRegister, // PcieRpXLinkActive
>
> + PchPcieSmiLinkEqRegister // PcieRpXLinkEq
>
> +};
>
> +
>
> +/**
>
> + Declaration of PCH ACPI SMI DISPATCH PROTOCOL instance
>
> +**/
>
> +PCH_ACPI_SMI_DISPATCH_PROTOCOL mPchAcpiSmiDispatchProtocol = {
>
> + PCH_ACPI_SMI_DISPATCH_REVISION, // Revision
>
> + PchAcpiSmiUnRegister, // Unregister
>
> + PchAcpiSmiPmeRegister, // Pme
>
> + PchAcpiSmiPmeB0Register, // PmeB0
>
> + PchAcpiSmiRtcAlarmRegister, // RtcAlarm
>
> + PchAcpiSmiTmrOverflowRegister // TmrOverflow
>
> +};
>
> +
>
> +/**
>
> + Declaration of MISC PCH SMI DISPATCH PROTOCOL instance
>
> +**/
>
> +PCH_SMI_DISPATCH_PROTOCOL mPchSmiDispatchProtocol = {
>
> + PCH_SMI_DISPATCH_REVISION, // Revision
>
> + PchSmiUnRegister, // Unregister
>
> + PchSmiSerialIrqRegister, // SerialIrq
>
> + PchSmiMcSmiRegister, // McSmi
>
> + PchSmiSmbusRegister, // SmBus
>
> + PchSmiSpiAsyncRegister // SpiAsync
>
> +};
>
> +
>
> +/**
>
> + Install protocols of PCH specifics SMI types, including
>
> + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC
> SMI types.
>
> +
>
> + @retval the result of protocol installation
>
> +**/
>
> +EFI_STATUS
>
> +InstallPchSmiDispatchProtocols (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_HANDLE Handle;
>
> + EFI_STATUS Status;
>
> +
>
> + Handle = NULL;
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &Handle,
>
> + &gPchTcoSmiDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPchTcoSmiDispatchProtocol
>
> + );
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &Handle,
>
> + &gPchPcieSmiDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPchPcieSmiDispatchProtocol
>
> + );
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &Handle,
>
> + &gPchAcpiSmiDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPchAcpiSmiDispatchProtocol
>
> + );
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &Handle,
>
> + &gPchSmiDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPchSmiDispatchProtocol
>
> + );
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + The function to dispatch all callback function of PCH SMI types.
>
> +
>
> + @retval EFI_SUCCESS Function successfully completed
>
> + @retval EFI_UNSUPPORTED no
>
> +**/
>
> +EFI_STATUS
>
> +PchSmiTypeCallbackDispatcher (
>
> + IN DATABASE_RECORD *Record
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + PCH_SMI_TYPES PchSmiType;
>
> + UINTN RpIndex;
>
> + PCH_PCIE_SMI_RP_CONTEXT RpContext;
>
> +
>
> + PchSmiType = Record->PchSmiType;
>
> + Status = EFI_SUCCESS;
>
> +
>
> + switch (PchSmiType) {
>
> + case PchTcoSmiMchType:
>
> + case PchTcoSmiTcoTimeoutType:
>
> + case PchTcoSmiOsTcoType:
>
> + case PchTcoSmiNmiType:
>
> + case PchTcoSmiIntruderDetectType:
>
> + case PchTcoSmiSpiBiosWpType:
>
> + case PchTcoSmiLpcBiosWpType:
>
> + case PchTcoSmiNewCenturyType:
>
> + ((PCH_TCO_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback))
> ((EFI_HANDLE)&Record->Link);
>
> + break;
>
> + case PchPcieSmiRpHotplugType:
>
> + case PchPcieSmiRpLinkActiveType:
>
> + case PchPcieSmiRpLinkEqType:
>
> + RpContext.BusNum = DEFAULT_PCI_BUS_NUMBER_PCH;
>
> + RpContext.DevNum = (UINT8) Record-
> >SrcDesc.En[0].Reg.Data.pcie.Fields.Dev;
>
> + RpContext.FuncNum = (UINT8) Record-
> >SrcDesc.En[0].Reg.Data.pcie.Fields.Fnc;
>
> + GetPcieRpNumber (RpContext.DevNum, RpContext.FuncNum,
> &RpIndex);
>
> + RpContext.RpIndex = (UINT8) RpIndex;
>
> + ((PCH_PCIE_SMI_RP_DISPATCH_CALLBACK) (Record->PchSmiCallback))
> ((EFI_HANDLE)&Record->Link, &RpContext);
>
> + break;
>
> + case PchAcpiSmiPmeType:
>
> + case PchAcpiSmiPmeB0Type:
>
> + case PchAcpiSmiRtcAlarmType:
>
> + case PchAcpiSmiTmrOverflowType:
>
> + ((PCH_ACPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback))
> ((EFI_HANDLE)&Record->Link);
>
> + break;
>
> + case PchEspiSmiEspiSlaveType:
>
> + ((PCH_ESPI_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback))
> ((EFI_HANDLE)&Record->Link);
>
> + break;
>
> + case PchSmiSerialIrqType:
>
> + case PchSmiMcSmiType:
>
> + case PchSmiSmBusType:
>
> + case PchSmiSpiAsyncType:
>
> + case PchIoTrapSmiType: ///< internal type for IoTrap
>
> + ((PCH_SMI_DISPATCH_CALLBACK) (Record->PchSmiCallback))
> ((EFI_HANDLE)&Record->Link);
>
> + break;
>
> + default:
>
> + Status = EFI_UNSUPPORTED;
>
> + break;
>
> + }
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescIoTrap[4] = {
>
> + //
>
> + // PCH I/O Trap register 0 monitor
>
> + //
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG0) }
>
> + },
>
> + 4,
>
> + 0
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
>
> + },
>
> + 1,
>
> + 0
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MONITOR
>
> + }
>
> + },
>
> + //
>
> + // PCH I/O Trap register 1 monitor
>
> + //
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG1) }
>
> + },
>
> + 4,
>
> + 0
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
>
> + },
>
> + 1,
>
> + 1
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MONITOR
>
> + }
>
> + },
>
> + //
>
> + // PCH I/O Trap register 2 monitor
>
> + //
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG2) }
>
> + },
>
> + 4,
>
> + 0
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
>
> + },
>
> + 1,
>
> + 2
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MONITOR
>
> + }
>
> + },
>
> + //
>
> + // PCH I/O Trap register 3 monitor,
>
> + //
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPREG3) }
>
> + },
>
> + 4,
>
> + 0
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_PSTH, R_PSTH_PCR_TRPST) }
>
> + },
>
> + 1,
>
> + 3
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_MONITOR
>
> + }
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of IoTrap event.
>
> + This is internal function and only used by Iotrap module.
>
> +
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] IoTrapIndex Index number of IOTRAP register
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalIoTrapSmiRegister (
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + IN UINTN IoTrapIndex,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescIoTrap[IoTrapIndex],
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchIoTrapSmiType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescIoTrap[IoTrapIndex]);
>
> + PchSmmEnableSource (&mSrcDescIoTrap[IoTrapIndex]);
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalIoTrapSmiUnRegister (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + return PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tcher.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tcher.inf
> new file mode 100644
> index 0000000000..97ad2f457e
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiDispa
> tcher.inf
> @@ -0,0 +1,116 @@
> +## @file
>
> +# Component description file for the Pch SMI Dispatch Handlers module
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = PchSmiDispatcher
>
> +FILE_GUID = B0D6ED53-B844-43f5-BD2F-61095264E77E
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = DXE_SMM_DRIVER
>
> +PI_SPECIFICATION_VERSION = 1.10
>
> +ENTRY_POINT = InitializePchSmmDispatcher
>
> +
>
> +
>
> +[LibraryClasses]
>
> +UefiBootServicesTableLib
>
> +UefiDriverEntryPoint
>
> +IoLib
>
> +DebugLib
>
> +PcdLib
>
> +BaseLib
>
> +BaseMemoryLib
>
> +HobLib
>
> +DevicePathLib
>
> +PchCycleDecodingLib
>
> +PchPcieRpLib
>
> +PchPcrLib
>
> +SmmServicesTableLib
>
> +ReportStatusCodeLib
>
> +PerformanceLib
>
> +DxeServicesTableLib
>
> +GpioLib
>
> +GpioPrivateLib
>
> +EspiLib
>
> +S3BootScriptLib
>
> +ConfigBlockLib
>
> +PmcPrivateLib
>
> +PmcLib
>
> +SmiHandlerProfileLib
>
> +CpuPcieRpLib
>
> +PchPciBdfLib
>
> +PmcPrivateLibWithS3
>
> +CpuPcieInfoFruLib
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +
>
> +[Pcd]
>
> +# Progress Code for S3 Suspend start.
>
> +# PROGRESS_CODE_S3_SUSPEND_START = (EFI_SOFTWARE_SMM_DRIVER
> | (EFI_OEM_SPECIFIC | 0x00000000)) = 0x03078000
>
> +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendStart
>
> +# Progress Code for S3 Suspend end.
>
> +# PROGRESS_CODE_S3_SUSPEND_END = (EFI_SOFTWARE_SMM_DRIVER
> | (EFI_OEM_SPECIFIC | 0x00000001)) = 0x03078001
>
> +gSiPkgTokenSpaceGuid.PcdProgressCodeS3SuspendEnd
>
> +gSiPkgTokenSpaceGuid.PcdEfiGcdAllocateType
>
> +
>
> +
>
> +[Sources]
>
> +PchSmm.h
>
> +PchSmmCore.c
>
> +PchSmmHelpers.h
>
> +PchSmmHelpers.c
>
> +PchxSmmHelpers.h
>
> +PchxSmmHelpers.c
>
> +PchSmmUsb.c
>
> +PchSmmGpi.c
>
> +PchSmmPowerButton.c
>
> +PchSmmSw.c
>
> +PchSmmSx.c
>
> +PchSmmPeriodicTimer.c
>
> +IoTrap.c
>
> +PchSmiDispatch.c
>
> +PchSmmEspi.c
>
> +PchSmiHelperClient.c
>
> +
>
> +
>
> +[Protocols]
>
> +gEfiPciRootBridgeIoProtocolGuid ## CONSUMES
>
> +gEfiSmmGpiDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmSxDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmSwDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmUsbDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmPowerButtonDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmPeriodicTimerDispatch2ProtocolGuid ## PRODUCES
>
> +gEfiSmmBase2ProtocolGuid ## CONSUMES
>
> +gEfiSmmCpuProtocolGuid ## CONSUMES
>
> +gEfiSmmReadyToLockProtocolGuid ## CONSUMES
>
> +gEfiSmmIoTrapDispatch2ProtocolGuid ## PRODUCES
>
> +gPchSmmIoTrapControlGuid ## PRODUCES
>
> +gPchTcoSmiDispatchProtocolGuid ## PRODUCES
>
> +gPchPcieSmiDispatchProtocolGuid ## PRODUCES
>
> +gPchAcpiSmiDispatchProtocolGuid ## PRODUCES
>
> +gPchSmiDispatchProtocolGuid ## PRODUCES
>
> +gPchEspiSmiDispatchProtocolGuid ## PRODUCES
>
> +gPchSmmPeriodicTimerControlGuid ## PRODUCES
>
> +gIoTrapExDispatchProtocolGuid ## PRODUCES
>
> +gPchNvsAreaProtocolGuid ## CONSUMES
>
> +
>
> +
>
> +[Guids]
>
> +
>
> +
>
> +[Depex]
>
> +gEfiPciRootBridgeIoProtocolGuid AND
>
> +gEfiPciHostBridgeResourceAllocationProtocolGuid AND ## This is to ensure
> that PCI MMIO resource has been prepared and available for this driver to
> allocate.
>
> +gEfiSmmCpuProtocolGuid AND
>
> +gEfiSmmBase2ProtocolGuid AND ## This is for SmmServicesTableLib
>
> +gPchNvsAreaProtocolGuid
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> er.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> er.h
> new file mode 100644
> index 0000000000..189197f4a2
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> er.h
> @@ -0,0 +1,40 @@
> +/** @file
>
> + eSPI SMI Dispatch header
PCH SMI Helper Header
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#ifndef _PCH_SMI_HELPER_H_
>
> +#define _PCH_SMI_HELPER_H_
>
> +#include <Uefi/UefiBaseType.h>
>
> +
>
> +/**
>
> + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and
> Function Number
>
> +
>
> + @param[in] RpDev Root port device number.
>
> + @param[in] RpFun Root port function number.
>
> + @param[out] RpNumber Return corresponding physical Root Port
> index (0-based)
>
> +**/
>
> +VOID
>
> +GetPcieRpNumber (
>
> + IN UINTN RpDev,
>
> + IN UINTN RpFun,
>
> + OUT UINTN *RpNumber
>
> + );
>
> +
>
> +/**
>
> + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port
> physical Number
>
> +
>
> + @param[in] RpNumber Root port physical number. (0-based)
>
> + @param[out] RpDev Return corresponding root port device
> number.
>
> + @param[out] RpFun Return corresponding root port function
> number.
>
> +**/
>
> +VOID
>
> +GetPcieRpDevFun (
>
> + IN UINTN RpIndex,
>
> + OUT UINTN *RpDev,
>
> + OUT UINTN *RpFun
>
> + );
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> erClient.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> erClient.c
> new file mode 100644
> index 0000000000..7693e76683
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmiHelp
> erClient.c
> @@ -0,0 +1,57 @@
> +/** @file
>
> + This file provides function to handle client-server differences.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Register/PmcRegs.h>
>
> +#include <Register/PchPcieRpRegs.h>
>
> +#include <Register/CpuPcieRegs.h>
>
> +#include <Library/CpuPcieInfoFruLib.h>
>
> +#include <Library/CpuPcieRpLib.h>
>
> +#include <CpuPcieInfo.h>
>
> +#include <Library/PchPcieRpLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +
>
> +/**
>
> + Get Root Port physical Number by CPU or PCH Pcie Root Port Device and
> Function Number
>
> +
>
> + @param[in] RpDev Root port device number.
>
> + @param[in] RpFun Root port function number.
>
> + @param[out] RpNumber Return corresponding physical Root Port
> index (0-based)
>
> +**/
>
> +VOID
>
> +GetPcieRpNumber (
>
> + IN UINTN RpDev,
>
> + IN UINTN RpFun,
>
> + OUT UINTN *RpNumber
>
> + )
>
> +{
>
> + UINT64 RpBase;
>
> + RpBase = PCI_SEGMENT_LIB_ADDRESS (SA_SEG_NUM, SA_MC_BUS,
> RpDev, RpFun, 0);
>
> + GetPchPcieRpNumber (RpDev, RpFun, RpNumber);
>
> +}
>
> +
>
> +/**
>
> + Get CPU or PCH Pcie Root Port Device and Function Number by Root Port
> physical Number
>
> +
>
> + @param[in] RpNumber Root port physical number. (0-based)
>
> + @param[out] RpDev Return corresponding root port device
> number.
>
> + @param[out] RpFun Return corresponding root port function
> number.
>
> +**/
>
> +VOID
>
> +GetPcieRpDevFun (
>
> + IN UINTN RpIndex,
>
> + OUT UINTN *RpDev,
>
> + OUT UINTN *RpFun
>
> + )
>
> +{
>
> + if (RpIndex >= CpuRpIndex0 && RpIndex <= CpuRpIndex3) {
>
> + GetCpuPcieRpDevFun ((RpIndex - CpuRpIndex0), RpDev, RpFun);
>
> + } else {
>
> + *RpDev = PchPcieRpDevNumber (RpIndex);
>
> + *RpFun = PchPcieRpFuncNumber (RpIndex);
>
> + }
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
> new file mode 100644
> index 0000000000..6a23de2bc9
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmm.h
> @@ -0,0 +1,1043 @@
> +/** @file
>
> + Prototypes and defines for the PCH SMM Dispatcher.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _PCH_SMM_H_
>
> +#define _PCH_SMM_H_
>
> +
>
> +#include <Uefi.h>
>
> +#include <Protocol/PciRootBridgeIo.h>
>
> +#include <Protocol/LoadedImage.h>
>
> +#include <Protocol/SmmControl2.h>
>
> +#include <Protocol/SmmUsbDispatch2.h>
>
> +#include <Protocol/SmmSxDispatch2.h>
>
> +#include <Protocol/SmmSwDispatch2.h>
>
> +#include <Protocol/SmmGpiDispatch2.h>
>
> +#include <Protocol/SmmPowerButtonDispatch2.h>
>
> +#include <Protocol/SmmPeriodicTimerDispatch2.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/DxeServicesTableLib.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/IoLib.h>
>
> +#include <Library/BaseLib.h>
>
> +#include <Library/BaseMemoryLib.h>
>
> +#include <Library/DevicePathLib.h>
>
> +#include <Library/SmmServicesTableLib.h>
>
> +#include <Library/ReportStatusCodeLib.h>
>
> +#include <Library/PerformanceLib.h>
>
> +#include <Protocol/SmmReadyToLock.h>
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Library/PchCycleDecodingLib.h>
>
> +#include <Library/PchPcieRpLib.h>
>
> +#include <Library/PchPcrLib.h>
>
> +#include <Library/PciSegmentLib.h>
>
> +#include <Library/GpioLib.h>
>
> +#include <Library/PchInfoLib.h>
>
> +#include <Library/EspiLib.h>
>
> +#include <Library/GpioPrivateLib.h>
>
> +#include <Protocol/PchTcoSmiDispatch.h>
>
> +#include <Protocol/PchPcieSmiDispatch.h>
>
> +#include <Protocol/PchAcpiSmiDispatch.h>
>
> +#include <Protocol/PchSmiDispatch.h>
>
> +#include <Protocol/PchEspiSmiDispatch.h>
>
> +#include <Protocol/IoTrapExDispatch.h>
>
> +#include <Library/PmcLib.h>
>
> +#include "IoTrap.h"
>
> +
>
> +#define EFI_BAD_POINTER 0xAFAFAFAFAFAFAFAFULL
>
> +
>
> +extern BOOLEAN mReadyToLock;
>
> +
>
> +///
>
> +/// Define an enumeration for all the supported protocols
>
> +///
>
> +#define PCH_SMM_PROTOCOL_TYPE_MAX 6
>
> +
>
> +typedef enum {
>
> + UsbType,
>
> + SxType,
>
> + SwType,
>
> + GpiType,
>
> + PowerButtonType,
>
> + PeriodicTimerType,
>
> + PchSmiDispatchType,
>
> + PchSmmProtocolTypeMax
>
> +} PCH_SMM_PROTOCOL_TYPE;
>
> +
>
> +///
>
> +/// Define all the supported types of PCH SMI
>
> +///
>
> +typedef enum {
>
> + PchTcoSmiMchType,
>
> + PchTcoSmiTcoTimeoutType,
>
> + PchTcoSmiOsTcoType,
>
> + PchTcoSmiNmiType,
>
> + PchTcoSmiIntruderDetectType,
>
> + PchTcoSmiSpiBiosWpType,
>
> + PchTcoSmiLpcBiosWpType,
>
> + PchTcoSmiNewCenturyType,
>
> + PchPcieSmiRpHotplugType,
>
> + PchPcieSmiRpLinkActiveType,
>
> + PchPcieSmiRpLinkEqType,
>
> + PchAcpiSmiPmeType,
>
> + PchAcpiSmiPmeB0Type,
>
> + PchAcpiSmiRtcAlarmType,
>
> + PchAcpiSmiTmrOverflowType,
>
> + PchEspiSmiEspiSlaveType,
>
> + PchSmiSerialIrqType,
>
> + PchSmiMcSmiType,
>
> + PchSmiSmBusType,
>
> + PchSmiSpiAsyncType,
>
> + PchIoTrapSmiType ///< internal SMI type
>
> +} PCH_SMI_TYPES;
>
> +
>
> +///
>
> +/// Generic funciton pointer to cover all Pch SMI function pointer types
>
> +///
>
> +typedef
>
> +VOID
>
> +(EFIAPI *PCH_SMI_CALLBACK_FUNCTIONS) (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + ...
>
> + );
>
> +
>
> +
>
> +///
>
> +/// SPECIFYING A REGISTER
>
> +/// We want a general way of referring to addresses. For this case, we'll
> only
>
> +/// need addresses in the ACPI table (and the TCO entries within the ACPI
> table).
>
> +/// However, it's interesting to consider what it would take to support other
> types
>
> +/// of addresses. To address Will's concern, I think it prudent to
> accommodate it
>
> +/// early on in the design.
>
> +///
>
> +/// Addresses we need to consider:
>
> +///
>
> +/// Type: Required:
>
> +/// I/O Yes
>
> +/// ACPI (special case of I/O) Only if we want to
>
> +/// TCO (special case of I/O) Only if we want to
>
> +/// GPIO (special case of MMIO) Only if we want to
>
> +/// Memory (or Memory Mapped I/O) Only if we want to
>
> +/// PCIE Yes, for BiosWp
>
> +///
>
> +typedef enum {
>
> + ///
>
> + /// IO_ADDR_TYPE, /// unimplemented
>
> + ///
>
> + ACPI_ADDR_TYPE,
>
> + TCO_ADDR_TYPE,
>
> + ///
>
> + /// MEMORY_ADDR_TYPE, /// unimplemented
>
> + ///
>
> + GPIO_ADDR_TYPE,
>
> + MEMORY_MAPPED_IO_ADDRESS_TYPE,
>
> + PCIE_ADDR_TYPE,
>
> + PCR_ADDR_TYPE,
>
> + NUM_ADDR_TYPES, ///< count of items in this enum
>
> + PCH_SMM_ADDR_TYPE_NULL = -1 ///< sentinel to indicate NULL or to
> signal end of arrays
>
> +} ADDR_TYPE;
>
> +
>
> +//
>
> +// Assumption: 32-bits -- enum's evaluate to integer
>
> +// Assumption: This code will only run on IA-32. Justification: IA-64 doesn't
> have SMIs.
>
> +// We don't have to worry about 64-bit addresses.
>
> +// Typedef the size of addresses in case the numbers I'm using are wrong or
> in case
>
> +// this changes. This is a good idea because PCI_ADDR will change, for
> example, when
>
> +// we add support for PciExpress.
>
> +//
>
> +typedef UINT16 IO_ADDR;
>
> +typedef IO_ADDR ACPI_ADDR; ///< can omit
>
> +typedef IO_ADDR TCO_ADDR; ///< can omit
>
> +typedef UINTN MEM_ADDR;
>
> +typedef MEM_ADDR *MEMORY_MAPPED_IO_ADDRESS;
>
> +typedef MEM_ADDR *GPIO_ADDR;
>
> +typedef union {
>
> + UINT32 Raw;
>
> + struct {
>
> + UINT32 Reg: 16;
>
> + UINT32 Fnc: 3;
>
> + UINT32 Dev: 5;
>
> + UINT32 Bus: 8;
>
> + } Fields;
>
> +} PCIE_ADDR;
>
> +
>
> +typedef union {
>
> + UINT32 Raw;
>
> + struct {
>
> + UINT16 Offset;
>
> + UINT8 Pid;
>
> + UINT8 Base;
>
> + } Fields;
>
> +} PCR_ADDR;
>
> +
>
> +typedef struct {
>
> + ADDR_TYPE Type;
>
> + union {
>
> + ///
>
> + /// used to initialize during declaration/definition
>
> + ///
>
> + UINT32 raw;
>
> +
>
> + ///
>
> + /// used to access useful data
>
> + ///
>
> + IO_ADDR io;
>
> + ACPI_ADDR acpi;
>
> + TCO_ADDR tco;
>
> + GPIO_ADDR gpio;
>
> + MEM_ADDR mem;
>
> + MEMORY_MAPPED_IO_ADDRESS Mmio;
>
> + PCIE_ADDR pcie;
>
> + PCR_ADDR Pcr;
>
> +
>
> + } Data;
>
> +
>
> +} PCH_SMM_ADDRESS;
>
> +
>
> +///
>
> +/// SPECIFYING BITS WITHIN A REGISTER
>
> +/// Here's a struct that helps us specify a source or enable bit.
>
> +///
>
> +typedef struct {
>
> + PCH_SMM_ADDRESS Reg;
>
> + UINT8 SizeInBytes; ///< of the register
>
> + UINT8 Bit;
>
> +} PCH_SMM_BIT_DESC;
>
> +
>
> +//
>
> +// Sometimes, we'll have bit descriptions that are unused. It'd be great to
> have a
>
> +// way to easily identify them:
>
> +//
>
> +#define IS_BIT_DESC_NULL(BitDesc) ((BitDesc).Reg.Type ==
> PCH_SMM_ADDR_TYPE_NULL) ///< "returns" true when BitDesc is NULL
>
> +#define NULL_THIS_BIT_DESC(BitDesc) ((BitDesc).Reg.Type =
> PCH_SMM_ADDR_TYPE_NULL) ///< will "return" an integer w/ value of 0
>
> +#define NULL_BIT_DESC_INITIALIZER \
>
> + { \
>
> + { \
>
> + PCH_SMM_ADDR_TYPE_NULL, \
>
> + { \
>
> + 0 \
>
> + } \
>
> + }, \
>
> + 0, 0 \
>
> + }
>
> +//
>
> +// I'd like a type to specify the callback's Sts & En bits because they'll
>
> +// be commonly used together:
>
> +//
>
> +#define NUM_EN_BITS 2
>
> +#define NUM_STS_BITS 1
>
> +
>
> +//
>
> +// Flags
>
> +//
>
> +typedef UINT8 PCH_SMM_SOURCE_FLAGS;
>
> +
>
> +//
>
> +// Flags required to describe the event source
>
> +//
>
> +#define PCH_SMM_NO_FLAGS 0
>
> +#define PCH_SMM_SCI_EN_DEPENDENT 1
>
> +
>
> +typedef struct {
>
> + PCH_SMM_SOURCE_FLAGS Flags;
>
> + PCH_SMM_BIT_DESC En[NUM_EN_BITS]; ///< Describes the enable
> bit(s) for the SMI event
>
> + PCH_SMM_BIT_DESC Sts[NUM_STS_BITS]; ///< Describes the
> secondary status bit for the SMI event. Might be the same as TopLevelSmi
>
> + PCH_SMM_BIT_DESC PmcSmiSts; ///< Refereing to the top level
> status bit in PMC SMI_STS, i.e. R_PCH_SMI_STS
>
> +} PCH_SMM_SOURCE_DESC;
>
> +
>
> +///
>
> +/// Used to initialize null source descriptor
>
> +///
>
> +#define NULL_SOURCE_DESC_INITIALIZER \
>
> + { \
>
> + PCH_SMM_NO_FLAGS, \
>
> + { \
>
> + NULL_BIT_DESC_INITIALIZER, NULL_BIT_DESC_INITIALIZER \
>
> + }, \
>
> + { \
>
> + NULL_BIT_DESC_INITIALIZER \
>
> + }, \
>
> + NULL_BIT_DESC_INITIALIZER \
>
> + }
>
> +
>
> +///
>
> +/// Define a PCIE RP event context for SmiProfileHandlerInfo tool
>
> +///
>
> +typedef struct {
>
> + PCH_SMI_TYPES PchSmiType;
>
> + UINTN RpIndex;
>
> +} PCH_SMM_PCIE_REGISTER_CONTEXT;
>
> +
>
> +///
>
> +/// CHILD CONTEXTS
>
> +/// To keep consistent w/ the architecture, we'll need to provide the
> context
>
> +/// to the child when we call its callback function. After talking with Will,
>
> +/// we agreed that we'll need functions to "dig" the context out of the
> hardware
>
> +/// in many cases (Sx, Trap, Gpi, etc), and we'll need a function to compare
> those
>
> +/// contexts to prevent unnecessary dispatches. I'd like a general type for
> these
>
> +/// "GetContext" functions, so I'll need a union of all the protocol contexts
> for
>
> +/// our internal use:
>
> +///
>
> +typedef union {
>
> + //
>
> + // (in no particular order)
>
> + //
>
> + EFI_SMM_SX_REGISTER_CONTEXT Sx;
>
> + EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT PeriodicTimer;
>
> + EFI_SMM_SW_REGISTER_CONTEXT Sw;
>
> + EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT PowerButton;
>
> + EFI_SMM_USB_REGISTER_CONTEXT Usb;
>
> + EFI_SMM_GPI_REGISTER_CONTEXT Gpi;
>
> + PCH_SMM_PCIE_REGISTER_CONTEXT Pcie;
>
> +} PCH_SMM_CONTEXT;
>
> +
>
> +///
>
> +/// Misc data for PchDispatcher usage.
>
> +/// For PeriodicTimer, since the ElapsedTime is removed from
> EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT of EDKII,
>
> +/// and PchDispatcher needs it for every record. Thus move it here to
> support ElapsedTime.
>
> +///
>
> +typedef struct {
>
> + UINTN ElapsedTime;
>
> + ///
>
> + /// A switch to control periodic timer SMI enabling
>
> + ///
>
> + BOOLEAN TimerSmiEnabled;
>
> +} PCH_SMM_MISC_DATA;
>
> +
>
> +//
>
> +// Assumption: PeriodicTimer largest at 3x64-bits or 24 bytes
>
> +//
>
> +typedef struct _DATABASE_RECORD DATABASE_RECORD;
>
> +
>
> +///
>
> +/// Assumption: the GET_CONTEXT function will be as small and simple as
> possible.
>
> +/// Assumption: We don't need to pass in an enumeration for the protocol
> because each
>
> +/// GET_CONTEXT function is written for only one protocol.
>
> +/// We also need a function to compare contexts to see if the child should
> be dispatched
>
> +/// In addition, we need a function to acquire CommBuffer and
> CommBufferSize for
>
> +/// dispatch callback function of EDKII native support.
>
> +///
>
> +typedef
>
> +VOID
>
> +(EFIAPI *GET_CONTEXT) (
>
> + IN DATABASE_RECORD * Record,
>
> + OUT PCH_SMM_CONTEXT * Context
>
> + );
>
> +
>
> +typedef
>
> +BOOLEAN
>
> +(EFIAPI *CMP_CONTEXT) (
>
> + IN PCH_SMM_CONTEXT * Context1,
>
> + IN PCH_SMM_CONTEXT * Context2
>
> + );
>
> +
>
> +typedef
>
> +VOID
>
> +(EFIAPI *GET_COMMBUFFER) (
>
> + IN DATABASE_RECORD * Record,
>
> + OUT VOID **CommBuffer,
>
> + OUT UINTN * CommBufferSize
>
> + );
>
> +
>
> +///
>
> +/// Finally, every protocol will require a "Get Context" and "Compare
> Context" call, so
>
> +/// we may as well wrap that up in a table, too.
>
> +///
>
> +typedef struct {
>
> + GET_CONTEXT GetContext;
>
> + CMP_CONTEXT CmpContext;
>
> + GET_COMMBUFFER GetCommBuffer;
>
> +} CONTEXT_FUNCTIONS;
>
> +
>
> +extern CONTEXT_FUNCTIONS
> ContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX];
>
> +
>
> +///
>
> +/// MAPPING CONTEXT TO BIT DESCRIPTIONS
>
> +/// I'd like to have a general approach to mapping contexts to bit
> descriptions.
>
> +/// Sometimes, we'll find that we can use table lookups or constant
> assignments;
>
> +/// other times, we'll find that we'll need to use a function to perform the
> mapping.
>
> +/// If we define a macro to mask that process, we'll never have to change
> the code.
>
> +/// I don't know if this is desirable or not -- if it isn't, then we can get rid
>
> +/// of the macros and just use function calls or variable assignments.
> Doesn't matter
>
> +/// to me.
>
> +/// Mapping complex contexts requires a function
>
> +///
>
> +
>
> +/**
>
> + Maps a USB context to a source description.
>
> +
>
> + @param[in] Context The context we need to map. Type must be
> USB.
>
> + @param[out] SrcDesc The source description that corresponds to
> the given context.
>
> +
>
> +**/
>
> +VOID
>
> +MapUsbToSrcDesc (
>
> + IN PCH_SMM_CONTEXT *Context,
>
> + OUT PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Figure out which timer the child is requesting and
>
> + send back the source description
>
> +
>
> + @param[in] DispatchContext The pointer to the Dispatch Context
> instances
>
> + @param[out] SrcDesc The pointer to the source description
>
> +
>
> +**/
>
> +VOID
>
> +MapPeriodicTimerToSrcDesc (
>
> + IN PCH_SMM_CONTEXT *DispatchContext,
>
> + OUT PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +//
>
> +// Mapping simple contexts can be done by assignment or lookup table
>
> +//
>
> +extern CONST PCH_SMM_SOURCE_DESC mSxSourceDesc;
>
> +extern CONST PCH_SMM_SOURCE_DESC mPowerButtonSourceDesc;
>
> +extern CONST PCH_SMM_SOURCE_DESC mSrcDescNewCentury;
>
> +extern CONST PCH_SMM_SOURCE_DESC mGpiSourceDescTemplate;
>
> +
>
> +///
>
> +/// For PCHx, APMC is UINT8 port, so the MAX SWI Value is 0xFF.
>
> +///
>
> +#define MAXIMUM_SWI_VALUE 0xFF
>
> +///
>
> +/// Open: Need to make sure this kind of type cast will actually work.
>
> +/// May need an intermediate form w/ two VOID* arguments. I'll figure
>
> +/// that out when I start compiling.
>
> +///
>
> +typedef
>
> +VOID
>
> +(EFIAPI *PCH_SMM_CLEAR_SOURCE) (
>
> + CONST PCH_SMM_SOURCE_DESC * SrcDesc
>
> + );
>
> +
>
> +///
>
> +/// "DATABASE" RECORD
>
> +/// Linked list data structures
>
> +///
>
> +#define DATABASE_RECORD_SIGNATURE SIGNATURE_32 ('D', 'B', 'R', 'C')
>
> +
>
> +struct _DATABASE_RECORD {
>
> + UINT32 Signature;
>
> + LIST_ENTRY Link;
>
> + BOOLEAN Processed;
>
> + ///
>
> + /// Status and Enable bit description
>
> + ///
>
> + PCH_SMM_SOURCE_DESC SrcDesc;
>
> +
>
> + ///
>
> + /// Callback function
>
> + ///
>
> + EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
>
> + PCH_SMM_CONTEXT ChildContext;
>
> + UINTN ContextSize;
>
> +
>
> + ///
>
> + /// Special handling hooks -- init them to NULL if unused/unneeded
>
> + ///
>
> + PCH_SMM_CLEAR_SOURCE ClearSource;
>
> +
>
> + ///
>
> + /// Functions required to make callback code general
>
> + ///
>
> + CONTEXT_FUNCTIONS ContextFunctions;
>
> +
>
> + ///
>
> + /// The protocol that this record dispatches
>
> + ///
>
> + PCH_SMM_PROTOCOL_TYPE ProtocolType;
>
> +
>
> + ///
>
> + /// Misc data for private usage
>
> + ///
>
> + PCH_SMM_MISC_DATA MiscData;
>
> +
>
> + ///
>
> + /// PCH SMI callback function
>
> + ///
>
> + PCH_SMI_CALLBACK_FUNCTIONS PchSmiCallback;
>
> + ///
>
> + /// Indicate the PCH SMI types.
>
> + ///
>
> + PCH_SMI_TYPES PchSmiType;
>
> +};
>
> +
>
> +#define DATABASE_RECORD_FROM_LINK(_record) CR (_record,
> DATABASE_RECORD, Link, DATABASE_RECORD_SIGNATURE)
>
> +#define DATABASE_RECORD_FROM_CHILDCONTEXT(_record) CR (_record,
> DATABASE_RECORD, ChildContext, DATABASE_RECORD_SIGNATURE)
>
> +
>
> +///
>
> +/// HOOKING INTO THE ARCHITECTURE
>
> +///
>
> +typedef
>
> +EFI_STATUS
>
> +(EFIAPI *PCH_SMM_GENERIC_REGISTER) (
>
> + IN VOID **This,
>
> + IN VOID *DispatchFunction,
>
> + IN VOID *DispatchContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +typedef
>
> +EFI_STATUS
>
> +(EFIAPI *PCH_SMM_GENERIC_UNREGISTER) (
>
> + IN VOID **This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +///
>
> +/// Define a memory "stamp" equivalent in size and function to most of the
> protocols
>
> +///
>
> +typedef struct {
>
> + PCH_SMM_GENERIC_REGISTER Register;
>
> + PCH_SMM_GENERIC_UNREGISTER Unregister;
>
> + UINTN Extra1;
>
> + UINTN Extra2; ///< may not need this one
>
> +} PCH_SMM_GENERIC_PROTOCOL;
>
> +
>
> +/**
>
> + Register a child SMI dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL
> instance.
>
> + @param[in] DispatchFunction Pointer to dispatch function to be invoked
> for this SMI source.
>
> + @param[in] DispatchContext Pointer to the dispatch function's context.
>
> + @param[out] DispatchHandle Handle of dispatch function, for when
> interfacing
>
> + with the parent SMM driver, will be the address of linked
>
> + list link in the call back record.
>
> +
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create
> database record
>
> + @retval EFI_INVALID_PARAMETER The input parameter is invalid
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPiSmmCoreRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN PCH_SMM_CONTEXT *DispatchContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPiSmmCoreUnRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL
> instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmCoreUnRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +typedef union {
>
> + PCH_SMM_GENERIC_PROTOCOL Generic;
>
> + EFI_SMM_USB_DISPATCH2_PROTOCOL Usb;
>
> + EFI_SMM_SX_DISPATCH2_PROTOCOL Sx;
>
> + EFI_SMM_SW_DISPATCH2_PROTOCOL Sw;
>
> + EFI_SMM_GPI_DISPATCH2_PROTOCOL Gpi;
>
> + EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL PowerButton;
>
> + EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL PeriodicTimer;
>
> +} PCH_SMM_PROTOCOL;
>
> +
>
> +///
>
> +/// Define a structure to help us identify the generic protocol
>
> +///
>
> +#define PROTOCOL_SIGNATURE SIGNATURE_32 ('P', 'R', 'O', 'T')
>
> +
>
> +typedef struct {
>
> + UINTN Signature;
>
> +
>
> + PCH_SMM_PROTOCOL_TYPE Type;
>
> + EFI_GUID *Guid;
>
> + PCH_SMM_PROTOCOL Protocols;
>
> +} PCH_SMM_QUALIFIED_PROTOCOL;
>
> +
>
> +#define QUALIFIED_PROTOCOL_FROM_GENERIC(_generic) \
>
> + CR ( \
>
> + _generic, \
>
> + PCH_SMM_QUALIFIED_PROTOCOL, \
>
> + Protocols, \
>
> + PROTOCOL_SIGNATURE \
>
> + )
>
> +
>
> +///
>
> +/// Create private data for the protocols that we'll publish
>
> +///
>
> +typedef struct {
>
> + LIST_ENTRY CallbackDataBase;
>
> + EFI_HANDLE SmiHandle;
>
> + EFI_HANDLE InstallMultProtHandle;
>
> + PCH_SMM_QUALIFIED_PROTOCOL
> Protocols[PCH_SMM_PROTOCOL_TYPE_MAX];
>
> +} PRIVATE_DATA;
>
> +
>
> +extern PRIVATE_DATA mPrivateData;
>
> +extern UINT16 mAcpiBaseAddr;
>
> +extern UINT16 mTcoBaseAddr;
>
> +
>
> +/**
>
> + The internal function used to create and insert a database record
>
> +
>
> + @param[in] InsertRecord Record to insert to database.
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +SmmCoreInsertRecord (
>
> + IN DATABASE_RECORD *NewRecord,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Get the Sleep type
>
> +
>
> + @param[in] Record No use
>
> + @param[out] Context The context that includes SLP_TYP bits to be
> filled
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +SxGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *Context
>
> + );
>
> +
>
> +/**
>
> + Register a child SMI source dispatch function for the specified software
> SMI.
>
> +
>
> + This service registers a function (DispatchFunction) which will be called
> when the software
>
> + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On
> return,
>
> + DispatchHandle contains a unique handle which may be used later to
> unregister the function
>
> + using UnRegister().
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Function to register for handler when the
> specified software
>
> + SMI is generated.
>
> + @param[in, out] RegisterContext Pointer to the dispatch function's
> context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function which Software SMI input value the
>
> + dispatch function should be invoked for.
>
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
>
> + function instance.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the
> SMI source.
>
> + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI
> input value
>
> + is not within a valid range or is already in use.
>
> + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system
> or SMM) to manage this
>
> + child.
>
> + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not
> be assigned
>
> + for this dispatch.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSwSmiRegister (
>
> + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function for the specified software
> SMI.
>
> +
>
> + This service removes the handler associated with DispatchHandle so that it
> will no longer be
>
> + called in response to a software SMI.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
> unregistered.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSwSmiUnRegister (
>
> + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Init required protocol for Pch Sw Dispatch protocol.
>
> +**/
>
> +VOID
>
> +PchSwDispatchInit (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Check whether sleep type of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes sleep type 1
>
> + @param[in] Context2 Context 2 that includes sleep type 2
>
> +
>
> + @retval FALSE Sleep types match
>
> + @retval TRUE Sleep types don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +SxCmpContext (
>
> + IN PCH_SMM_CONTEXT *Context1,
>
> + IN PCH_SMM_CONTEXT *Context2
>
> + );
>
> +
>
> +/**
>
> + Update the elapsed time from the Interval data of DATABASE_RECORD
>
> +
>
> + @param[in] Record The pointer to the DATABASE_RECORD.
>
> + @param[out] HwContext The Context to be updated.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PeriodicTimerGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *Context
>
> + );
>
> +
>
> +/**
>
> + Check whether Periodic Timer of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes Periodic Timer 1
>
> + @param[in] Context2 Context 2 that includes Periodic Timer 2
>
> +
>
> + @retval FALSE Periodic Timer match
>
> + @retval TRUE Periodic Timer don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +PeriodicTimerCmpContext (
>
> + IN PCH_SMM_CONTEXT *Context1,
>
> + IN PCH_SMM_CONTEXT *Context2
>
> + );
>
> +
>
> +/**
>
> + Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
>
> +
>
> + @param[in] Record No use
>
> + @param[out] CommBuffer Point to the CommBuffer structure
>
> + @param[out] CommBufferSize Point to the Size of CommBuffer
> structure
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PeriodicTimerGetCommBuffer (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT VOID **CommBuffer,
>
> + OUT UINTN *CommBufferSize
>
> + );
>
> +
>
> +/**
>
> + Get the power button status.
>
> +
>
> + @param[in] Record The pointer to the DATABASE_RECORD.
>
> + @param[out] Context Calling context from the hardware, will be
> updated with the current power button status.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PowerButtonGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *Context
>
> + );
>
> +
>
> +/**
>
> + Check whether Power Button status of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes Power Button status 1
>
> + @param[in] Context2 Context 2 that includes Power Button status 2
>
> +
>
> + @retval FALSE Power Button status match
>
> + @retval TRUE Power Button status don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +PowerButtonCmpContext (
>
> + IN PCH_SMM_CONTEXT *Context1,
>
> + IN PCH_SMM_CONTEXT *Context2
>
> + );
>
> +
>
> +/**
>
> + This function is responsible for calculating and enabling any timers that are
> required
>
> + to dispatch messages to children. The SrcDesc argument isn't acutally used.
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC
> instance.
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchSmmPeriodicTimerClearSource (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + This services returns the next SMI tick period that is supported by the
> chipset.
>
> + The order returned is from longest to shortest interval period.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
>
> + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI
> interval period that is supported by the child.
>
> +
>
> + @retval EFI_SUCCESS The service returned successfully.
>
> + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is
> invalid.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmPeriodicTimerDispatchGetNextShorterInterval (
>
> + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
>
> + IN OUT UINT64 **SmiTickInterval
>
> + );
>
> +
>
> +/**
>
> + Install PCH SMM periodic timer control protocol
>
> +
>
> + @param[in] Handle handle for this driver
>
> +
>
> + @retval EFI_SUCCESS Driver initialization completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchSmmPeriodicTimerControlProtocol (
>
> + IN EFI_HANDLE Handle
>
> + );
>
> +
>
> +/**
>
> + When we get an SMI that indicates that we are transitioning to a sleep
> state,
>
> + we need to actually transition to that state. We do this by disabling the
>
> + "SMI on sleep enable" feature, which generates an SMI when the
> operating system
>
> + tries to put the system to sleep, and then physically putting the system to
> sleep.
>
> +**/
>
> +VOID
>
> +PchSmmSxGoToSleep (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Install protocols of PCH specifics SMI types, including
>
> + PCH TCO SMI types, PCH PCIE SMI types, PCH ACPI SMI types, PCH MISC
> SMI types.
>
> +
>
> + @retval the result of protocol installation
>
> +**/
>
> +EFI_STATUS
>
> +InstallPchSmiDispatchProtocols (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + The function to dispatch all callback function of PCH SMI types.
>
> +
>
> + @retval EFI_SUCCESS Function successfully completed
>
> + @retval EFI_UNSUPPORTED no
>
> +**/
>
> +EFI_STATUS
>
> +PchSmiTypeCallbackDispatcher (
>
> + IN DATABASE_RECORD *Record
>
> + );
>
> +
>
> +/**
>
> + The register function used to register SMI handler of IoTrap event.
>
> + This is internal function and only used by Iotrap module.
>
> +
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] IoTrapIndex Index number of IOTRAP register
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalIoTrapSmiRegister (
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + IN UINTN IoTrapIndex,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalIoTrapSmiUnRegister (
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Register an eSPI SMI handler based on the type
>
> +
>
> + @param[in] DispatchFunction Callback in an event of eSPI SMI
>
> + @param[in] PchSmiTypes The eSPI type published by
> PchSmiDispatch
>
> + @param[out] DispatchHandle The callback handle
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS Registration is successful.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalEspiSmiRegister (
>
> + IN PCH_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + IN PCH_SMI_TYPES PchSmiTypes,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister an eSPI SMI handler
>
> +
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +PchInternalEspiSmiUnRegister (
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + The internal function used to create and insert a database record
>
> + for SMI record of Pch Smi types.
>
> +
>
> + @param[in] SrcDesc The pointer to the SMI source description
>
> + @param[in] DispatchFunction Pointer to dispatch function to be
> invoked for this SMI source
>
> + @param[in] PchSmiType Specific SMI type of PCH SMI
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmiRecordInsert (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc,
>
> + IN PCH_SMI_CALLBACK_FUNCTIONS DispatchFunction,
>
> + IN PCH_SMI_TYPES PchSmiType,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +extern CONST PCH_SMM_SOURCE_DESC mSrcDescSerialIrq;
>
> +extern CONST PCH_SMM_SOURCE_DESC mSrcDescLpcBiosWp;
>
> +
>
> +/**
>
> + Clear the TCO SMI status bit and block after the SMI handling is done
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchTcoSmiClearSourceAndBlock (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Clear the TCO SMI status bit after the SMI handling is done
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchTcoSmiClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Initialize Source descriptor structure
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description
> table
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +NullInitSourceDesc (
>
> + PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + The register function used to register SMI handler of GPI SMI event.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Function to register for handler when the
> specified GPI causes an SMI.
>
> + @param[in] RegisterContext Pointer to the dispatch function's context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function the GPI(s) for which the dispatch function
>
> + should be invoked.
>
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
>
> + function instance.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_ACCESS_DENIED Register is not allowed
>
> + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI
> input value
>
> + is not within valid range.
>
> + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system
> or SMM) to manage this child.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchGpiSmiRegister (
>
> + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + Unregister a GPI SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchGpiSmiUnRegister (
>
> + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor
> e.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor
> e.c
> new file mode 100644
> index 0000000000..b2e76a8b72
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmCor
> e.c
> @@ -0,0 +1,926 @@
> +/** @file
>
> + This driver is responsible for the registration of child drivers
>
> + and the abstraction of the PCH SMI sources.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmm.h"
>
> +#include "PchSmmHelpers.h"
>
> +#include "PchSmmEspi.h"
>
> +#include <Library/SmiHandlerProfileLib.h>
>
> +#include <Register/GpioRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +#include <Register/RtcRegs.h>
>
> +
>
> +#define PROGRESS_CODE_S3_SUSPEND_START PcdGet32
> (PcdProgressCodeS3SuspendStart)
>
> +//
>
> +// MODULE / GLOBAL DATA
>
> +//
>
> +// Module variables used by the both the main dispatcher and the source
> dispatchers
>
> +// Declared in PchSmm.h
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mAcpiBaseAddr;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mTcoBaseAddr;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mReadyToLock;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED BOOLEAN mS3SusStart;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED PRIVATE_DATA mPrivateData =
> {
>
> + {
>
> + NULL,
>
> + NULL
>
> + }, // CallbackDataBase linked list head
>
> + NULL, // EFI handle returned when calling
> InstallMultipleProtocolInterfaces
>
> + NULL, //
>
> + { // protocol arrays
>
> + //
>
> + // elements within the array
>
> + //
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + UsbType,
>
> + &gEfiSmmUsbDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
>
> + }}
>
> + },
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + SxType,
>
> + &gEfiSmmSxDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
>
> + }}
>
> + },
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + SwType,
>
> + &gEfiSmmSwDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchSwSmiRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchSwSmiUnRegister,
>
> + (UINTN) MAXIMUM_SWI_VALUE
>
> + }}
>
> + },
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + GpiType,
>
> + &gEfiSmmGpiDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchGpiSmiRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchGpiSmiUnRegister,
>
> + (UINTN) PCH_GPIO_NUM_SUPPORTED_GPIS
>
> + }}
>
> + },
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + PowerButtonType,
>
> + &gEfiSmmPowerButtonDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister
>
> + }}
>
> + },
>
> + {
>
> + PROTOCOL_SIGNATURE,
>
> + PeriodicTimerType,
>
> + &gEfiSmmPeriodicTimerDispatch2ProtocolGuid,
>
> + {{
>
> + (PCH_SMM_GENERIC_REGISTER) PchPiSmmCoreRegister,
>
> + (PCH_SMM_GENERIC_UNREGISTER) PchPiSmmCoreUnRegister,
>
> + (UINTN) PchSmmPeriodicTimerDispatchGetNextShorterInterval
>
> + }}
>
> + },
>
> + }
>
> +};
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONTEXT_FUNCTIONS
> mContextFunctions[PCH_SMM_PROTOCOL_TYPE_MAX] = {
>
> + {
>
> + NULL,
>
> + NULL,
>
> + NULL
>
> + },
>
> + {
>
> + SxGetContext,
>
> + SxCmpContext,
>
> + NULL
>
> + },
>
> + {
>
> + NULL,
>
> + NULL,
>
> + NULL
>
> + },
>
> + {
>
> + NULL,
>
> + NULL,
>
> + NULL
>
> + },
>
> + {
>
> + PowerButtonGetContext,
>
> + PowerButtonCmpContext,
>
> + NULL
>
> + },
>
> + {
>
> + PeriodicTimerGetContext,
>
> + PeriodicTimerCmpContext,
>
> + PeriodicTimerGetCommBuffer
>
> + },
>
> +};
>
> +
>
> +//
>
> +// PROTOTYPES
>
> +//
>
> +// Functions use only in this file
>
> +//
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmCoreDispatcher (
>
> + IN EFI_HANDLE SmmImageHandle,
>
> + IN CONST VOID *PchSmmCore, OPTIONAL
>
> + IN OUT VOID *CommunicationBuffer,
>
> + IN OUT UINTN *SourceSize
>
> + );
>
> +
>
> +//
>
> +// FUNCTIONS
>
> +//
>
> +/**
>
> + SMM ready to lock notification event handler.
>
> +
>
> + @param Protocol Points to the protocol's unique identifier
>
> + @param Interface Points to the interface instance
>
> + @param Handle The handle on which the interface was installed
>
> +
>
> + @retval EFI_SUCCESS SmmReadyToLockCallback runs successfully
>
> +
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmReadyToLockCallback (
>
> + IN CONST EFI_GUID *Protocol,
>
> + IN VOID *Interface,
>
> + IN EFI_HANDLE Handle
>
> + )
>
> +{
>
> + mReadyToLock = TRUE;
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + <b>PchSmiDispatcher SMM Module Entry Point</b>\n
>
> + - <b>Introduction</b>\n
>
> + The PchSmiDispatcher module is an SMM driver which provides SMI
> handler registration
>
> + services for PCH generated SMIs.
>
> +
>
> + - <b>Details</b>\n
>
> + This module provides SMI handler registration servicies for PCH SMIs.
>
> + NOTE: All the register/unregister functions will be locked after SMM
> ready to boot signal event.
>
> + Please make sure no handler is installed after that.
>
> +
>
> + - @pre
>
> + - EFI_SMM_BASE2_PROTOCOL
>
> + - Documented in the System Management Mode Core Interface
> Specification
>
> + - EFI_PCI_ROOT_BRIDGE_IO_PROTOCOL
>
> + - Documented in the UEFI 2.0 Specification and above
>
> + - EFI_PCI_HOST_BRIDGE_RESOURCE_ALLOCATION_PROTOCOL
>
> + - This is to ensure that PCI MMIO and IO resource has been prepared
> and available for this driver to allocate.
>
> + - EFI_SMM_CPU_PROTOCOL
>
> +
>
> + - @result
>
> + The PchSmiDispatcher driver produces:
>
> + - EFI_SMM_USB_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_SX_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_SW_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_GPI_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_IO_TRAP_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_POWER_BUTTON_DISPATCH2_PROTOCOL
>
> + - EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL
>
> + - @link _PCH_SMM_IO_TRAP_CONTROL_PROTOCOL
> PCH_SMM_IO_TRAP_CONTROL_PROTOCOL @endlink
>
> + - @link _PCH_PCIE_SMI_DISPATCH_PROTOCOL
> PCH_PCIE_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_TCO_SMI_DISPATCH_PROTOCOL
> PCH_TCO_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_ACPI_SMI_DISPATCH_PROTOCOL
> PCH_ACPI_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_SMI_DISPATCH_PROTOCOL
> PCH_SMI_DISPATCH_PROTOCOL @endlink
>
> + - @link _PCH_ESPI_SMI_DISPATCH_PROTOCOL
> PCH_ESPI_SMI_DISPATCH_PROTOCOL @endlink
>
> +
>
> + @param[in] ImageHandle Pointer to the loaded image protocol for
> this driver
>
> + @param[in] SystemTable Pointer to the EFI System Table
>
> +
>
> + @retval EFI_SUCCESS PchSmmDispatcher Initialization completed.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InitializePchSmmDispatcher (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + VOID *SmmReadyToLockRegistration;
>
> +
>
> + mS3SusStart = FALSE;
>
> + //
>
> + // Access ACPI Base Addresses Register
>
> + //
>
> +
>
> + mAcpiBaseAddr = PmcGetAcpiBase ();
>
> + ASSERT (mAcpiBaseAddr != 0);
>
> +
>
> + //
>
> + // Access TCO Base Addresses Register
>
> + //
>
> + PchTcoBaseGet (&mTcoBaseAddr);
>
> + ASSERT (mTcoBaseAddr != 0);
>
> +
>
> + //
>
> + // Register a callback function to handle subsequent SMIs. This callback
>
> + // will be called by SmmCoreDispatcher.
>
> + //
>
> + Status = gSmst->SmiHandlerRegister (PchSmmCoreDispatcher, NULL,
> &mPrivateData.SmiHandle);
>
> + ASSERT_EFI_ERROR (Status);
>
> + //
>
> + // Initialize Callback DataBase
>
> + //
>
> + InitializeListHead (&mPrivateData.CallbackDataBase);
>
> +
>
> + //
>
> + // Enable SMIs on the PCH now that we have a callback
>
> + //
>
> + PchSmmInitHardware ();
>
> +
>
> + //
>
> + // Install and initialize all the needed protocols
>
> + //
>
> + PchSwDispatchInit ();
>
> + PchSmmPublishDispatchProtocols ();
>
> + InstallPchSmiDispatchProtocols ();
>
> + InstallIoTrap (ImageHandle);
>
> + InstallEspiSmi (ImageHandle);
>
> + InstallPchSmmPeriodicTimerControlProtocol
> (mPrivateData.InstallMultProtHandle);
>
> +
>
> + //
>
> + // Register EFI_SMM_READY_TO_LOCK_PROTOCOL_GUID notify function.
>
> + //
>
> + Status = gSmst->SmmRegisterProtocolNotify (
>
> + &gEfiSmmReadyToLockProtocolGuid,
>
> + SmmReadyToLockCallback,
>
> + &SmmReadyToLockRegistration
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + The internal function used to create and insert a database record
>
> +
>
> + @param[in] InsertRecord Record to insert to database.
>
> + @param[out] DispatchHandle Handle of dispatch function to register.
>
> +
>
> + @retval EFI_INVALID_PARAMETER Error with NULL SMI source
> description
>
> + @retval EFI_OUT_OF_RESOURCES Fail to allocate pool for database
> record
>
> + @retval EFI_SUCCESS The database record is created successfully.
>
> +**/
>
> +EFI_STATUS
>
> +SmmCoreInsertRecord (
>
> + IN DATABASE_RECORD *NewRecord,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + if ((NewRecord == NULL) ||
>
> + (NewRecord->Signature != DATABASE_RECORD_SIGNATURE))
>
> + {
>
> + ASSERT (FALSE);
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof
> (DATABASE_RECORD), (VOID **) &Record);
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT (FALSE);
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + CopyMem (Record, NewRecord, sizeof (DATABASE_RECORD));
>
> +
>
> + //
>
> + // After ensuring the source of event is not null, we will insert the record
> into the database
>
> + //
>
> + InsertTailList (&mPrivateData.CallbackDataBase, &Record->Link);
>
> +
>
> + //
>
> + // Child's handle will be the address linked list link in the record
>
> + //
>
> + *DispatchHandle = (EFI_HANDLE) (&Record->Link);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Protocol instance pointer.
>
> + @param[in] DispatchHandle Handle of dispatch function to
> deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPiSmmCoreUnRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordToDelete;
>
> + EFI_STATUS Status;
>
> + PCH_SMM_QUALIFIED_PROTOCOL *Qualified;
>
> +
>
> + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + Status = PchSmmCoreUnRegister (NULL, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler (
>
> + Qualified->Guid,
>
> + RecordToDelete->Callback,
>
> + &RecordToDelete->ChildContext,
>
> + RecordToDelete->ContextSize
>
> + );
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Register a child SMI dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL
> instance.
>
> + @param[in] DispatchFunction Pointer to dispatch function to be invoked
> for this SMI source.
>
> + @param[in] DispatchContext Pointer to the dispatch function's context.
>
> + @param[out] DispatchHandle Handle of dispatch function, for when
> interfacing
>
> + with the parent SMM driver, will be the address of linked
>
> + list link in the call back record.
>
> +
>
> + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create
> database record
>
> + @retval EFI_INVALID_PARAMETER The input parameter is invalid
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchPiSmmCoreRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN PCH_SMM_CONTEXT *DispatchContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD Record;
>
> + PCH_SMM_QUALIFIED_PROTOCOL *Qualified;
>
> + PCH_SMM_SOURCE_DESC NullSourceDesc;
>
> +
>
> + //
>
> + // Initialize NullSourceDesc
>
> + //
>
> + NullInitSourceDesc (&NullSourceDesc);
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event
> has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + ZeroMem (&Record, sizeof (DATABASE_RECORD));
>
> +
>
> + //
>
> + // Gather information about the registration request
>
> + //
>
> + Record.Callback = DispatchFunction;
>
> +
>
> + Qualified = QUALIFIED_PROTOCOL_FROM_GENERIC (This);
>
> +
>
> + Record.ProtocolType = Qualified->Type;
>
> +
>
> + Record.ContextFunctions = mContextFunctions[Qualified->Type];
>
> + //
>
> + // Perform linked list housekeeping
>
> + //
>
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
>
> +
>
> + switch (Qualified->Type) {
>
> + //
>
> + // By the end of this switch statement, we'll know the
>
> + // source description the child is registering for
>
> + //
>
> + case UsbType:
>
> + Record.ContextSize = sizeof (EFI_SMM_USB_REGISTER_CONTEXT);
>
> + CopyMem (&Record.ChildContext, DispatchContext,
> Record.ContextSize);
>
> + //
>
> + // Check the validity of Context Type
>
> + //
>
> + if ((Record.ChildContext.Usb.Type < UsbLegacy) ||
> (Record.ChildContext.Usb.Type > UsbWake)) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + MapUsbToSrcDesc (DispatchContext, &Record.SrcDesc);
>
> + Record.ClearSource = NULL;
>
> + //
>
> + // use default clear source function
>
> + //
>
> + break;
>
> +
>
> + case SxType:
>
> + Record.ContextSize = sizeof (EFI_SMM_SX_REGISTER_CONTEXT);
>
> + CopyMem (&Record.ChildContext, DispatchContext,
> Record.ContextSize);
>
> + //
>
> + // Check the validity of Context Type and Phase
>
> + //
>
> + if ((Record.ChildContext.Sx.Type < SxS0) ||
>
> + (Record.ChildContext.Sx.Type >= EfiMaximumSleepType) ||
>
> + (Record.ChildContext.Sx.Phase < SxEntry) ||
>
> + (Record.ChildContext.Sx.Phase >= EfiMaximumPhase)
>
> + ) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + CopyMem (&Record.SrcDesc, &mSxSourceDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
>
> + Record.ClearSource = NULL;
>
> + //
>
> + // use default clear source function
>
> + //
>
> + break;
>
> +
>
> + case PowerButtonType:
>
> + Record.ContextSize = sizeof
> (EFI_SMM_POWER_BUTTON_REGISTER_CONTEXT);
>
> + CopyMem (&Record.ChildContext, DispatchContext,
> Record.ContextSize);
>
> + //
>
> + // Check the validity of Context Phase
>
> + //
>
> + if ((Record.ChildContext.PowerButton.Phase < EfiPowerButtonEntry) ||
>
> + (Record.ChildContext.PowerButton.Phase > EfiPowerButtonExit))
>
> + {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + CopyMem (&Record.SrcDesc, &mPowerButtonSourceDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
>
> + Record.ClearSource = NULL;
>
> + //
>
> + // use default clear source function
>
> + //
>
> + break;
>
> +
>
> + case PeriodicTimerType:
>
> + Record.ContextSize = sizeof
> (EFI_SMM_PERIODIC_TIMER_REGISTER_CONTEXT);
>
> + CopyMem (&Record.ChildContext, DispatchContext,
> Record.ContextSize);
>
> + //
>
> + // Check the validity of timer value
>
> + //
>
> + if (DispatchContext->PeriodicTimer.SmiTickInterval <= 0) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + MapPeriodicTimerToSrcDesc (DispatchContext, &Record.SrcDesc);
>
> + Record.MiscData.TimerSmiEnabled = TRUE;
>
> + Record.ClearSource = PchSmmPeriodicTimerClearSource;
>
> + break;
>
> +
>
> + default:
>
> + return EFI_INVALID_PARAMETER;
>
> + break;
>
> + }
>
> +
>
> + if (CompareSources (&Record.SrcDesc, &NullSourceDesc)) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // After ensuring the source of event is not null, we will insert the record
> into the database
>
> + // Child's handle will be the address linked list link in the record
>
> + //
>
> + Status = SmmCoreInsertRecord (
>
> + &Record,
>
> + DispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + if (Record.ClearSource == NULL) {
>
> + //
>
> + // Clear the SMI associated w/ the source using the default function
>
> + //
>
> + PchSmmClearSource (&Record.SrcDesc);
>
> + } else {
>
> + //
>
> + // This source requires special handling to clear
>
> + //
>
> + Record.ClearSource (&Record.SrcDesc);
>
> + }
>
> +
>
> + PchSmmEnableSource (&Record.SrcDesc);
>
> + SmiHandlerProfileRegisterHandler (
>
> + Qualified->Guid,
>
> + DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + DispatchContext,
>
> + Record.ContextSize
>
> + );
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function with a parent SMM driver.
>
> +
>
> + @param[in] This Pointer to the PCH_SMM_GENERIC_PROTOCOL
> instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmCoreUnRegister (
>
> + IN PCH_SMM_GENERIC_PROTOCOL *This,
>
> + IN EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + BOOLEAN NeedClearEnable;
>
> + UINTN DescIndex;
>
> + DATABASE_RECORD *RecordToDelete;
>
> + DATABASE_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> +
>
> + if (DispatchHandle == NULL) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> +
>
> + //
>
> + // Take the entry out of the linked list
>
> + //
>
> + if (RecordToDelete->Link.ForwardLink == (LIST_ENTRY *)
> EFI_BAD_POINTER) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + RemoveEntryList (&RecordToDelete->Link);
>
> +
>
> + //
>
> + // Loop through all the souces in record linked list to see if any source
> enable is equal.
>
> + // If any source enable is equal, we do not want to disable it.
>
> + //
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
>
> + if (IS_BIT_DESC_NULL (RecordToDelete->SrcDesc.En[DescIndex])) {
>
> + continue;
>
> + }
>
> + NeedClearEnable = TRUE;
>
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
>
> + if (IsBitEqualToAnySourceEn (&RecordToDelete-
> >SrcDesc.En[DescIndex], &RecordInDb->SrcDesc)) {
>
> + NeedClearEnable = FALSE;
>
> + break;
>
> + }
>
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
>
> + }
>
> + if (NeedClearEnable == FALSE) {
>
> + continue;
>
> + }
>
> + WriteBitDesc (&RecordToDelete->SrcDesc.En[DescIndex], 0, FALSE);
>
> + }
>
> + Status = gSmst->SmmFreePool (RecordToDelete);
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT (FALSE);
>
> + return Status;
>
> + }
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + This function clears the pending SMI status before set EOS.
>
> + NOTE: This only clears the pending SMI with known reason.
>
> + Please do not clear unknown pending SMI status since that will hide
> potential issues.
>
> +
>
> + @param[in] SmiStsValue SMI status
>
> + @param[in] SciEn Sci Enable status
>
> +**/
>
> +STATIC
>
> +VOID
>
> +ClearPendingSmiStatus (
>
> + UINT32 SmiStsValue,
>
> + BOOLEAN SciEn
>
> + )
>
> +{
>
> + //
>
> + // Clear NewCentury status if it's not handled.
>
> + //
>
> + if (SmiStsValue & B_ACPI_IO_SMI_STS_TCO) {
>
> + if (IoRead16 (mTcoBaseAddr + R_TCO_IO_TCO1_STS) &
> B_TCO_IO_TCO1_STS_NEWCENTURY) {
>
> + PchTcoSmiClearSourceAndBlock (&mSrcDescNewCentury);
>
> + }
>
> + }
>
> + // Clear PWRBTNOR_STS if it's not handled.
>
> + //
>
> + if (IoRead16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS) &
> B_ACPI_IO_PM1_STS_PRBTNOR) {
>
> + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS,
> B_ACPI_IO_PM1_STS_PRBTNOR);
>
> + }
>
> + //
>
> + // Clear WADT_STS if this is triggered by WADT timer.
>
> + //
>
> + if (!SciEn) {
>
> + if (IoRead32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96) &
> B_ACPI_IO_GPE0_STS_127_96_WADT) {
>
> + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96,
> B_ACPI_IO_GPE0_STS_127_96_WADT);
>
> + }
>
> + }
>
> + //
>
> + // Clear GPIO_UNLOCK_SMI_STS in case it is set as GPIO Unlock SMI is not
> supported
>
> + //
>
> + if (SmiStsValue & B_ACPI_IO_SMI_STS_GPIO_UNLOCK) {
>
> + IoWrite32 (mAcpiBaseAddr + R_ACPI_IO_SMI_STS,
> B_ACPI_IO_SMI_STS_GPIO_UNLOCK);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + The callback function to handle subsequent SMIs. This callback will be
> called by SmmCoreDispatcher.
>
> +
>
> + @param[in] SmmImageHandle Not used
>
> + @param[in] PchSmmCore Not used
>
> + @param[in, out] CommunicationBuffer Not used
>
> + @param[in, out] SourceSize Not used
>
> +
>
> + @retval EFI_SUCCESS Function successfully completed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmCoreDispatcher (
>
> + IN EFI_HANDLE SmmImageHandle,
>
> + IN CONST VOID *PchSmmCore,
>
> + IN OUT VOID *CommunicationBuffer,
>
> + IN OUT UINTN *SourceSize
>
> + )
>
> +{
>
> + //
>
> + // Used to prevent infinite loops
>
> + //
>
> + UINTN EscapeCount;
>
> +
>
> + BOOLEAN ContextsMatch;
>
> + BOOLEAN EosSet;
>
> + BOOLEAN SxChildWasDispatched;
>
> +
>
> + DATABASE_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> + DATABASE_RECORD *RecordToExhaust;
>
> + LIST_ENTRY *LinkToExhaust;
>
> +
>
> + PCH_SMM_CONTEXT Context;
>
> + VOID *CommBuffer;
>
> + UINTN CommBufferSize;
>
> +
>
> + EFI_STATUS Status;
>
> + BOOLEAN SciEn;
>
> + UINT32 SmiEnValue;
>
> + UINT32 SmiStsValue;
>
> + UINT8 Port74Save;
>
> + UINT8 Port76Save;
>
> +
>
> + PCH_SMM_SOURCE_DESC ActiveSource;
>
> +
>
> + //
>
> + // Initialize ActiveSource
>
> + //
>
> + NullInitSourceDesc (&ActiveSource);
>
> +
>
> + EscapeCount = 3;
>
> + ContextsMatch = FALSE;
>
> + EosSet = FALSE;
>
> + SxChildWasDispatched = FALSE;
>
> + Status = EFI_SUCCESS;
>
> +
>
> + //
>
> + // Save IO index registers
>
> + // @note: Save/Restore port 70h directly might break NMI_EN# setting,
>
> + // then save/restore 74h/76h instead.
>
> + // @note: CF8 is not saved. Prefer method is to use MMIO instead of CF8
>
> + //
>
> + Port76Save = IoRead8 (R_RTC_IO_EXT_INDEX_ALT);
>
> + Port74Save = IoRead8 (R_RTC_IO_INDEX_ALT);
>
> +
>
> + if (!IsListEmpty (&mPrivateData.CallbackDataBase)) {
>
> + //
>
> + // We have children registered w/ us -- continue
>
> + //
>
> + while ((!EosSet) && (EscapeCount > 0)) {
>
> + EscapeCount--;
>
> +
>
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
>
> +
>
> + //
>
> + // Cache SciEn, SmiEnValue and SmiStsValue to determine if source is
> active
>
> + //
>
> + SciEn = PchSmmGetSciEn ();
>
> + SmiEnValue = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_SMI_EN));
>
> + SmiStsValue = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_SMI_STS));
>
> +
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
>
> +
>
> + //
>
> + // look for the first active source
>
> + //
>
> + if (!SourceIsActive (&RecordInDb->SrcDesc, SciEn, SmiEnValue,
> SmiStsValue)) {
>
> + //
>
> + // Didn't find the source yet, keep looking
>
> + //
>
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
>
> +
>
> + //
>
> + // if it's the last one, try to clear EOS
>
> + //
>
> + if (IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + //
>
> + // Clear pending SMI status before EOS
>
> + //
>
> + ClearPendingSmiStatus (SmiStsValue, SciEn);
>
> + EosSet = PchSmmSetAndCheckEos ();
>
> + }
>
> + } else {
>
> + //
>
> + // We found a source. If this is a sleep type, we have to go to
>
> + // appropriate sleep state anyway.No matter there is sleep child or not
>
> + //
>
> + if (RecordInDb->ProtocolType == SxType) {
>
> + SxChildWasDispatched = TRUE;
>
> + }
>
> + //
>
> + // "cache" the source description and don't query I/O anymore
>
> + //
>
> + CopyMem ((VOID *) &ActiveSource, (VOID *) &(RecordInDb-
> >SrcDesc), sizeof (PCH_SMM_SOURCE_DESC));
>
> + LinkToExhaust = LinkInDb;
>
> +
>
> + //
>
> + // exhaust the rest of the queue looking for the same source
>
> + //
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkToExhaust)) {
>
> + RecordToExhaust = DATABASE_RECORD_FROM_LINK
> (LinkToExhaust);
>
> + //
>
> + // RecordToExhaust->Link might be removed (unregistered) by
> Callback function, and then the
>
> + // system will hang in ASSERT() while calling GetNextNode().
>
> + // To prevent the issue, we need to get next record in DB here
> (before Callback function).
>
> + //
>
> + LinkToExhaust = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordToExhaust->Link);
>
> +
>
> + if (CompareSources (&RecordToExhaust->SrcDesc, &ActiveSource)) {
>
> + //
>
> + // These source descriptions are equal, so this callback should be
>
> + // dispatched.
>
> + //
>
> + if (RecordToExhaust->ContextFunctions.GetContext != NULL) {
>
> + //
>
> + // This child requires that we get a calling context from
>
> + // hardware and compare that context to the one supplied
>
> + // by the child.
>
> + //
>
> + ASSERT (RecordToExhaust->ContextFunctions.CmpContext !=
> NULL);
>
> +
>
> + //
>
> + // Make sure contexts match before dispatching event to child
>
> + //
>
> + RecordToExhaust->ContextFunctions.GetContext
> (RecordToExhaust, &Context);
>
> + ContextsMatch = RecordToExhaust-
> >ContextFunctions.CmpContext (&Context, &RecordToExhaust-
> >ChildContext);
>
> +
>
> + } else {
>
> + //
>
> + // This child doesn't require any more calling context beyond what
>
> + // it supplied in registration. Simply pass back what it gave us.
>
> + //
>
> + Context = RecordToExhaust->ChildContext;
>
> + ContextsMatch = TRUE;
>
> + }
>
> +
>
> + if (ContextsMatch) {
>
> + if (RecordToExhaust->ProtocolType == PchSmiDispatchType) {
>
> + //
>
> + // For PCH SMI dispatch protocols
>
> + //
>
> + PchSmiTypeCallbackDispatcher (RecordToExhaust);
>
> + } else {
>
> + if ((RecordToExhaust->ProtocolType == SxType) &&
> (Context.Sx.Type == SxS3) && (Context.Sx.Phase == SxEntry) &&
> !mS3SusStart) {
>
> + REPORT_STATUS_CODE (EFI_PROGRESS_CODE,
> PROGRESS_CODE_S3_SUSPEND_START);
>
> + mS3SusStart = TRUE;
>
> + }
>
> + //
>
> + // For EFI standard SMI dispatch protocols
>
> + //
>
> + if (RecordToExhaust->Callback != NULL) {
>
> + if (RecordToExhaust->ContextFunctions.GetCommBuffer !=
> NULL) {
>
> + //
>
> + // This callback function needs CommBuffer and
> CommBufferSize.
>
> + // Get those from child and then pass to callback function.
>
> + //
>
> + RecordToExhaust->ContextFunctions.GetCommBuffer
> (RecordToExhaust, &CommBuffer, &CommBufferSize);
>
> + } else {
>
> + //
>
> + // Child doesn't support the CommBuffer and CommBufferSize.
>
> + // Just pass NULL value to callback function.
>
> + //
>
> + CommBuffer = NULL;
>
> + CommBufferSize = 0;
>
> + }
>
> +
>
> + PERF_START_EX (NULL, "SmmFunction", NULL, AsmReadTsc (),
> RecordToExhaust->ProtocolType);
>
> + RecordToExhaust->Callback ((EFI_HANDLE) & RecordToExhaust-
> >Link, &Context, CommBuffer, &CommBufferSize);
>
> + PERF_END_EX (NULL, "SmmFunction", NULL, AsmReadTsc (),
> RecordToExhaust->ProtocolType);
>
> + if (RecordToExhaust->ProtocolType == SxType) {
>
> + SxChildWasDispatched = TRUE;
>
> + }
>
> + } else {
>
> + ASSERT (FALSE);
>
> + }
>
> + }
>
> + }
>
> + }
>
> + }
>
> +
>
> + if (RecordInDb->ClearSource == NULL) {
>
> + //
>
> + // Clear the SMI associated w/ the source using the default function
>
> + //
>
> + PchSmmClearSource (&ActiveSource);
>
> + } else {
>
> + //
>
> + // This source requires special handling to clear
>
> + //
>
> + RecordInDb->ClearSource (&ActiveSource);
>
> + }
>
> + //
>
> + // Clear pending SMI status before EOS
>
> + //
>
> + ClearPendingSmiStatus (SmiStsValue, SciEn);
>
> + //
>
> + // Also, try to clear EOS
>
> + //
>
> + EosSet = PchSmmSetAndCheckEos ();
>
> + //
>
> + // Queue is empty, reset the search
>
> + //
>
> + break;
>
> + }
>
> + }
>
> + }
>
> + }
>
> + //
>
> + // If you arrive here, there are two possible reasons:
>
> + // (1) you've got problems with clearing the SMI status bits in the
>
> + // ACPI table. If you don't properly clear the SMI bits, then you won't be
> able to set the
>
> + // EOS bit. If this happens too many times, the loop exits.
>
> + // (2) there was a SMM communicate for callback messages that was
> received prior
>
> + // to this driver.
>
> + // If there is an asynchronous SMI that occurs while processing the
> Callback, let
>
> + // all of the drivers (including this one) have an opportunity to scan for the
> SMI
>
> + // and handle it.
>
> + // If not, we don't want to exit and have the foreground app. clear EOS
> without letting
>
> + // these other sources get serviced.
>
> + //
>
> + // This assert is not valid with CSM legacy solution because it generates
> software SMI
>
> + // to test for legacy USB support presence.
>
> + // This may not be illegal, so we cannot assert at this time.
>
> + //
>
> + // ASSERT (EscapeCount > 0);
>
> + //
>
> + if (SxChildWasDispatched) {
>
> + //
>
> + // A child of the SmmSxDispatch protocol was dispatched during this call;
>
> + // put the system to sleep.
>
> + //
>
> + PchSmmSxGoToSleep ();
>
> + }
>
> + //
>
> + // Restore IO index registers
>
> + // @note: Save/Restore port 70h directly might break NMI_EN# setting,
>
> + // then save/restore 74h/76h instead.
>
> + //
>
> + IoWrite8 (R_RTC_IO_EXT_INDEX_ALT, Port76Save);
>
> + IoWrite8 (R_RTC_IO_INDEX_ALT, Port74Save);
>
> +
>
> + return Status;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .c
> new file mode 100644
> index 0000000000..9ce4072e37
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .c
> @@ -0,0 +1,1588 @@
> +/** @file
>
> + eSPI SMI implementation
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#include "PchSmmEspi.h"
>
> +#include <Library/PmcPrivateLib.h>
>
> +#include <Library/EspiLib.h>
>
> +#include <Library/SmiHandlerProfileLib.h>
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PchPcrRegs.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <PchBdfAssignment.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED ESPI_SMI_INSTANCE
> mEspiSmiInstance = {
>
> + //
>
> + // Signature
>
> + //
>
> + ESPI_SMI_INSTANCE_SIGNATURE,
>
> + //
>
> + // Handle
>
> + //
>
> + NULL,
>
> + //
>
> + // PchEspiSmiDispatchProtocol
>
> + //
>
> + {
>
> + PCH_ESPI_SMI_DISPATCH_REVISION,
>
> + EspiSmiUnRegister,
>
> + BiosWrProtectRegister,
>
> + BiosWrReportRegister,
>
> + PcNonFatalErrRegister,
>
> + PcFatalErrRegister,
>
> + VwNonFatalErrRegister,
>
> + VwFatalErrRegister,
>
> + FlashNonFatalErrRegister,
>
> + FlashFatalErrRegister,
>
> + LnkType1ErrRegister,
>
> + EspiSlaveSmiRegister
>
> + },
>
> + //
>
> + // PchSmiEspiHandle[EspiTopLevelTypeMax]
>
> + //
>
> + {
>
> + NULL, NULL, NULL
>
> + },
>
> + //
>
> + // CallbackDataBase[EspiSmiTypeMax]
>
> + //
>
> + {
>
> + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL},
>
> + {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}, {NULL, NULL}
>
> + },
>
> + //
>
> + // EspiSmiEventCounter[EspiSmiTypeMax]
>
> + //
>
> + {
>
> + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
>
> + },
>
> + //
>
> + // Barrier[EspiTopLevelTypeMax]
>
> + //
>
> + {
>
> + {
>
> + BiosWrProtect,
>
> + BiosWrProtect
>
> + },
>
> + {
>
> + BiosWrReport,
>
> + LnkType1Err
>
> + },
>
> + {
>
> + EspiSlaveSmi,
>
> + EspiSlaveSmi
>
> + }
>
> + }
>
> +};
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST ESPI_DESCRIPTOR
> mEspiDescriptor[EspiSmiTypeMax] = {
>
> + //
>
> + // BiosWrProtect
>
> + //
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
>
> + R_ESPI_CFG_PCBC
>
> + ) }
>
> + },
>
> + //
>
> + // SourceIsActiveAndMask and SourceIsActiveValue
>
> + //
>
> + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
>
> + B_ESPI_CFG_PCBC_BWPDS | B_ESPI_CFG_PCBC_LE,
>
> + //
>
> + // ClearStatusAndMask and ClearStatusOrMask
>
> + //
>
> + (UINT32) ~B_ESPI_CFG_PCBC_BWRS,
>
> + B_ESPI_CFG_PCBC_BWPDS
>
> + },
>
> + //
>
> + // BiosWrReport
>
> + //
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
>
> + R_ESPI_CFG_PCBC
>
> + ) }
>
> + },
>
> + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
>
> + B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWRE,
>
> + (UINT32) ~B_ESPI_CFG_PCBC_BWPDS,
>
> + B_ESPI_CFG_PCBC_BWRS
>
> + },
>
> + //
>
> + // PcNonFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
>
> + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI <<
> N_ESPI_PCR_XERR_XNFEE)),
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XNFES
>
> + },
>
> + //
>
> + // PcFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_PCERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
>
> + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI <<
> N_ESPI_PCR_XERR_XFEE)),
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XNFES),
>
> + B_ESPI_PCR_XERR_XFES
>
> + },
>
> + //
>
> + // VwNonFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
>
> + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI <<
> N_ESPI_PCR_XERR_XNFEE)),
>
> + (UINT32) ~B_ESPI_PCR_XERR_XFES,
>
> + B_ESPI_PCR_XERR_XNFES
>
> + },
>
> + //
>
> + // VwFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_VWERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
>
> + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI <<
> N_ESPI_PCR_XERR_XFEE)),
>
> + (UINT32) ~B_ESPI_PCR_XERR_XNFES,
>
> + B_ESPI_PCR_XERR_XFES
>
> + },
>
> + //
>
> + // FlashNonFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XNFEE),
>
> + (B_ESPI_PCR_XERR_XNFES | (V_ESPI_PCR_XERR_XNFEE_SMI <<
> N_ESPI_PCR_XERR_XNFEE)),
>
> + (UINT32) ~B_ESPI_PCR_XERR_XFES,
>
> + B_ESPI_PCR_XERR_XNFES
>
> + },
>
> + //
>
> + // FlashFatalErr
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_FCERR_SLV0) }
>
> + },
>
> + (B_ESPI_PCR_XERR_XFES | B_ESPI_PCR_XERR_XFEE),
>
> + (B_ESPI_PCR_XERR_XFES | (V_ESPI_PCR_XERR_XFEE_SMI <<
> N_ESPI_PCR_XERR_XFEE)),
>
> + (UINT32) ~B_ESPI_PCR_XERR_XNFES,
>
> + B_ESPI_PCR_XERR_XFES
>
> + },
>
> + //
>
> + // LnkType1Err
>
> + //
>
> + {
>
> + {
>
> + PCR_ADDR_TYPE,
>
> + {PCH_PCR_ADDRESS (PID_ESPISPI, R_ESPI_PCR_LNKERR_SLV0) }
>
> + },
>
> + B_ESPI_PCR_LNKERR_SLV0_LFET1S | B_ESPI_PCR_LNKERR_SLV0_LFET1E,
>
> + B_ESPI_PCR_LNKERR_SLV0_LFET1S |
> (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI <<
> N_ESPI_PCR_LNKERR_SLV0_LFET1E),
>
> + (UINT32) ~B_ESPI_PCR_LNKERR_SLV0_SLCRR,
>
> + B_ESPI_PCR_LNKERR_SLV0_LFET1S
>
> + },
>
> +};
>
> +
>
> +/**
>
> + Enable eSPI SMI source
>
> +
>
> + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE
>
> +**/
>
> +STATIC
>
> +VOID
>
> +EspiSmiEnableSource (
>
> + IN CONST ESPI_SMI_TYPE EspiSmiType
>
> + )
>
> +{
>
> + UINT64 PciBaseAddress;
>
> +
>
> + switch (EspiSmiType) {
>
> + case BiosWrProtect:
>
> + //
>
> + // It doesn't enable the BIOSLOCK here. Enable it by policy in DXE.
>
> + //
>
> + break;
>
> + case BiosWrReport:
>
> + PciBaseAddress = EspiPciCfgBase ();
>
> + PciSegmentAndThenOr32 (
>
> + PciBaseAddress + R_ESPI_CFG_PCBC,
>
> + (UINT32) ~(B_ESPI_CFG_PCBC_BWRS | B_ESPI_CFG_PCBC_BWPDS),
>
> + B_ESPI_CFG_PCBC_BWRE
>
> + );
>
> + break;
>
> + case PcNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_PCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XNFEE
>
> + );
>
> + break;
>
> +
>
> + case PcFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_PCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XFEE
>
> + );
>
> + break;
>
> +
>
> + case VwNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_VWERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XNFEE
>
> + );
>
> + break;
>
> +
>
> + case VwFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_VWERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XFEE
>
> + );
>
> + break;
>
> +
>
> + case FlashNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_FCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XNFEE
>
> + );
>
> + break;
>
> +
>
> + case FlashFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_FCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES),
>
> + B_ESPI_PCR_XERR_XFEE
>
> + );
>
> + break;
>
> +
>
> + case LnkType1Err:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_LNKERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR |
> B_ESPI_PCR_LNKERR_SLV0_LFET1S),
>
> + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI <<
> N_ESPI_PCR_LNKERR_SLV0_LFET1E)
>
> + );
>
> +
>
> + if (IsEspiSecondSlaveSupported ()) {
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_LNKERR_SLV1,
>
> + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR |
> B_ESPI_PCR_LNKERR_SLV0_LFET1S),
>
> + (UINT32) (V_ESPI_PCR_LNKERR_SLV0_LFET1E_SMI <<
> N_ESPI_PCR_LNKERR_SLV0_LFET1E)
>
> + );
>
> + }
>
> + break;
>
> +
>
> + default:
>
> + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> +
>
> +
>
> +/**
>
> + Disable eSPI SMI source
>
> +
>
> + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE
>
> +**/
>
> +STATIC
>
> +VOID
>
> +EspiSmiDisableSource (
>
> + IN CONST ESPI_SMI_TYPE EspiSmiType
>
> + )
>
> +{
>
> +
>
> + switch (EspiSmiType) {
>
> + case BiosWrProtect:
>
> + case BiosWrReport:
>
> + DEBUG ((DEBUG_ERROR, "Bit is write lock, thus BWRE/BWPDS source
> cannot be disabled \n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + case PcNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_PCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XNFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case PcFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_PCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_PCERR_SLV0_PCURD |
> B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case VwNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_VWERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XNFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case VwFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_VWERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case FlashNonFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_FCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XNFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case FlashFatalErr:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_FCERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES |
> B_ESPI_PCR_XERR_XFEE),
>
> + 0
>
> + );
>
> + break;
>
> +
>
> + case LnkType1Err:
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_LNKERR_SLV0,
>
> + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR |
> B_ESPI_PCR_LNKERR_SLV0_LFET1S),
>
> + 0
>
> + );
>
> +
>
> + if (IsEspiSecondSlaveSupported ()) {
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) R_ESPI_PCR_LNKERR_SLV1,
>
> + (UINT32) ~(B_ESPI_PCR_LNKERR_SLV0_SLCRR |
> B_ESPI_PCR_LNKERR_SLV0_LFET1S),
>
> + 0
>
> + );
>
> + }
>
> + break;
>
> +
>
> + default:
>
> + DEBUG ((DEBUG_ERROR, "Unsupported EspiSmiType \n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Clear a status for the SMI event
>
> +
>
> + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE
>
> +**/
>
> +STATIC
>
> +VOID
>
> +EspiSmiClearStatus (
>
> + IN CONST ESPI_SMI_TYPE EspiSmiType
>
> + )
>
> +{
>
> + UINT32 PciBus;
>
> + UINT32 PciDev;
>
> + UINT32 PciFun;
>
> + UINT32 PciReg;
>
> + UINT64 PciBaseAddress;
>
> + CONST ESPI_DESCRIPTOR *Desc;
>
> +
>
> + Desc = &mEspiDescriptor[EspiSmiType];
>
> +
>
> + switch (Desc->Address.Type) {
>
> + case PCIE_ADDR_TYPE:
>
> + PciBus = Desc->Address.Data.pcie.Fields.Bus;
>
> + PciDev = Desc->Address.Data.pcie.Fields.Dev;
>
> + PciFun = Desc->Address.Data.pcie.Fields.Fnc;
>
> + PciReg = Desc->Address.Data.pcie.Fields.Reg;
>
> + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
>
> + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, Desc-
> >ClearStatusAndMask, Desc->ClearStatusOrMask);
>
> + break;
>
> + case PCR_ADDR_TYPE:
>
> + PchPcrAndThenOr32 (
>
> + Desc->Address.Data.Pcr.Fields.Pid,
>
> + Desc->Address.Data.Pcr.Fields.Offset,
>
> + Desc->ClearStatusAndMask,
>
> + Desc->ClearStatusOrMask
>
> + );
>
> + break;
>
> + default:
>
> + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Checks if a source is active by looking at the enable and status bits
>
> +
>
> + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE
>
> +**/
>
> +STATIC
>
> +BOOLEAN
>
> +EspiSmiSourceIsActive (
>
> + IN CONST ESPI_SMI_TYPE EspiSmiType
>
> + )
>
> +{
>
> + BOOLEAN Active;
>
> + UINT32 PciBus;
>
> + UINT32 PciDev;
>
> + UINT32 PciFun;
>
> + UINT32 PciReg;
>
> + UINT64 PciBaseAddress;
>
> + UINT32 Data32;
>
> + CONST ESPI_DESCRIPTOR *Desc;
>
> +
>
> + Desc = &mEspiDescriptor[EspiSmiType];
>
> +
>
> + Active = FALSE;
>
> + switch (Desc->Address.Type) {
>
> + case PCIE_ADDR_TYPE:
>
> + PciBus = Desc->Address.Data.pcie.Fields.Bus;
>
> + PciDev = Desc->Address.Data.pcie.Fields.Dev;
>
> + PciFun = Desc->Address.Data.pcie.Fields.Fnc;
>
> + PciReg = Desc->Address.Data.pcie.Fields.Reg;
>
> + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
>
> + Data32 = PciSegmentRead32 (PciBaseAddress + PciReg);
>
> + break;
>
> +
>
> + case PCR_ADDR_TYPE:
>
> + Data32 = PchPcrRead32 (
>
> + Desc->Address.Data.Pcr.Fields.Pid,
>
> + Desc->Address.Data.Pcr.Fields.Offset
>
> + );
>
> + break;
>
> +
>
> + default:
>
> + Data32 = 0;
>
> + DEBUG ((DEBUG_ERROR, "Address type for eSPI SMI is invalid \n"));
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + if ((Data32 & Desc->SourceIsActiveAndMask) == Desc-
> >SourceIsActiveValue) {
>
> + Active = TRUE;
>
> + }
>
> +
>
> + return Active;
>
> +}
>
> +
>
> +/**
>
> + Insert a handler into the corresponding linked list based on EspiSmiType
>
> +
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[in] EspiSmiType Type based on ESPI_SMI_TYPE to
> determine which linked list to use
>
> + @param[out] DispatchHandle The link to the record in the database
>
> +
>
> + @retval EFI_SUCCESS Record was successfully inserted into master
> database
>
> + @retval EFI_OUT_OF_RESOURCES Cannot allocate pool to insert record
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +InsertEspiRecord (
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + IN ESPI_SMI_TYPE EspiSmiType,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + ESPI_SMI_RECORD *Record;
>
> +
>
> + Status = gSmst->SmmAllocatePool (EfiRuntimeServicesData, sizeof
> (ESPI_SMI_RECORD), (VOID **) &Record);
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT (FALSE);
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + SetMem (Record, sizeof (ESPI_SMI_RECORD), 0);
>
> +
>
> + Record->Callback = DispatchFunction;
>
> + Record->Signature = ESPI_SMI_RECORD_SIGNATURE;
>
> +
>
> + InsertTailList (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> &Record->Link);
>
> + EspiSmiClearStatus (EspiSmiType);
>
> + EspiSmiEnableSource (EspiSmiType);
>
> +
>
> + ++mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType];
>
> +
>
> + *DispatchHandle = (EFI_HANDLE) (&Record->Link);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + This callback is registered to PchSmiDispatch
>
> +
>
> + @param[in] DispatchHandle Used to determine which source have been
> triggered
>
> +**/
>
> +VOID
>
> +EspiSmiCallback (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *PchSmiRecord;
>
> + ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
>
> + ESPI_SMI_TYPE EspiSmiType;
>
> + ESPI_SMI_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> +
>
> + PchSmiRecord = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> +
>
> + if (PchSmiRecord->PchSmiType == PchTcoSmiLpcBiosWpType) {
>
> + EspiTopLevelType = EspiBiosWrProtect;
>
> + } else if (PchSmiRecord->PchSmiType == PchSmiSerialIrqType) {
>
> + EspiTopLevelType = EspiSerialIrq;
>
> + } else {
>
> + DEBUG ((DEBUG_ERROR, "EspiSmiCallback was dispatched with a wrong
> DispatchHandle"));
>
> + ASSERT (FALSE);
>
> + return;
>
> + }
>
> +
>
> + for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start;
> EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End;
> ++EspiSmiType) {
>
> + if (!EspiSmiSourceIsActive (EspiSmiType)) {
>
> + continue;
>
> + }
>
> + //
>
> + // The source is active, so walk the callback database and dispatch
>
> + //
>
> + if (!IsListEmpty (&mEspiSmiInstance.CallbackDataBase[EspiSmiType])) {
>
> + //
>
> + // We have children registered w/ us -- continue
>
> + //
>
> + LinkInDb = GetFirstNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
>
> +
>
> + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> LinkInDb)) {
>
> + RecordInDb = ESPI_RECORD_FROM_LINK (LinkInDb);
>
> +
>
> + //
>
> + // RecordInDb->Link might be removed (unregistered) by Callback
> function, and then the
>
> + // system will hang in ASSERT() while calling GetNextNode().
>
> + // To prevent the issue, we need to get next record in DB here (before
> Callback function).
>
> + //
>
> + LinkInDb = GetNextNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], &RecordInDb->Link);
>
> +
>
> + //
>
> + // Callback
>
> + //
>
> + if (RecordInDb->Callback != NULL) {
>
> + RecordInDb->Callback ((EFI_HANDLE) &RecordInDb->Link);
>
> + } else {
>
> + ASSERT (FALSE);
>
> + }
>
> + }
>
> + } else if (EspiSmiType == LnkType1Err) {
>
> + //
>
> + // If no proper handler registered for Link Type 1 Error
>
> + // Call default SMI handler recover otherwise
>
> + //
>
> + EspiDefaultFatalErrorHandler ();
>
> + }
>
> +
>
> + //
>
> + // Finish walking the linked list for the EspiSmiType, so clear status
>
> + //
>
> + EspiSmiClearStatus (EspiSmiType);
>
> + }
>
> +}
>
> +
>
> +//
>
> +// EspiBiosWp srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescEspiBiosWp = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_TCO
>
> + },
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
>
> + R_ESPI_CFG_PCBC
>
> + ) }
>
> + },
>
> + S_ESPI_CFG_PCBC,
>
> + N_ESPI_CFG_PCBC_LE
>
> + }
>
> + },
>
> + {
>
> + {
>
> + {
>
> + PCIE_ADDR_TYPE,
>
> + { (
>
> + (DEFAULT_PCI_BUS_NUMBER_PCH << 24) |
>
> + (PCI_DEVICE_NUMBER_PCH_LPC << 19) |
>
> + (PCI_FUNCTION_NUMBER_PCH_LPC << 16) |
>
> + R_ESPI_CFG_PCBC
>
> + ) }
>
> + },
>
> + S_ESPI_CFG_PCBC,
>
> + N_ESPI_CFG_PCBC_BWPDS
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_TCO
>
> + }
>
> +};
>
> +
>
> +/**
>
> + This function will register EspiSmiCallback with mSrcDescEspiBiosWp source
> decriptor
>
> + This function make sure there is only one BIOS WP SMI handler is
> registered.
>
> + While any ESPI sub BIOS WP SMI type is registered, all the BIOS WP SMI
>
> + will go to callback function EspiSmiCallback first, and then dispatchs the
> callbacks
>
> + recorded in mEspiSmiInstance.
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval others Registration failed
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +RegisterBiosWrProtectIfNull (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *Record;
>
> +
>
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect] == NULL) {
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescEspiBiosWp,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
>
> + PchTcoSmiLpcBiosWpType,
>
> + &mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Fail to register BIOS WP SMI handler \n"));
>
> + return Status;
>
> + }
>
> + Record = DATABASE_RECORD_FROM_LINK
> (mEspiSmiInstance.PchSmiEspiHandle[EspiBiosWrProtect]);
>
> + Record->ClearSource = PchTcoSmiClearSource;
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + This function will register EspiSmiCallback with mSrcDescSerialIrq source
> decriptor
>
> + This function make sure there is only one Serial IRQ SMI handler is
> registered.
>
> + While any ESPI sub Serial IRQ SMI type is registered, all the Serial IRQ SMI
>
> + will go to callback function EspiSmiCallback first, and then dispatchs the
> callbacks
>
> + recorded in mEspiSmiInstance.
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval others Registration failed
>
> +**/
>
> +STATIC
>
> +EFI_STATUS
>
> +RegisterSerialIrqIfNull (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq] == NULL) {
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescSerialIrq,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) EspiSmiCallback,
>
> + PchSmiSerialIrqType,
>
> + &mEspiSmiInstance.PchSmiEspiHandle[EspiSerialIrq]
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Fail to register Serial IRQ SMI handler \n"));
>
> + return Status;
>
> + }
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Installs and initialize this protocol
>
> +
>
> + @param[in] ImageHandle Not used
>
> +
>
> + @retval EFI_SUCCESS Installation succeed
>
> + @retval others Installation failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallEspiSmi (
>
> + IN EFI_HANDLE ImageHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + ESPI_SMI_TYPE EspiSmiType;
>
> +
>
> + DEBUG ((DEBUG_INFO, "[InstallEspiSmi] Enter\n"));
>
> +
>
> + //
>
> + // InitializeListHead for
> mEspiSmiInstance.CallBackDataBase[EspiTopLevelTypeMax]
>
> + //
>
> + for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
>
> + InitializeListHead (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
>
> + }
>
> +
>
> + //
>
> + // Install EfiEspiSmiDispatchProtocol
>
> + //
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &mEspiSmiInstance.Handle,
>
> + &gPchEspiSmiDispatchProtocolGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mEspiSmiInstance.PchEspiSmiDispatchProtocol
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Failed to install eSPI SMI Dispatch
> Protocol\n"));
>
> + ASSERT (FALSE);
>
> + return Status;
>
> + }
>
> +
>
> + // Register eSPI SMM callback to enable Fatal Error handling by default
> handler
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> +
>
> + // Enable LnkType1Err SMI generation for default handler
>
> + EspiSmiClearStatus (LnkType1Err);
>
> + EspiSmiEnableSource (LnkType1Err);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +BiosWrProtectRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterBiosWrProtectIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, BiosWrProtect,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +BiosWrReportRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, BiosWrReport,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non
> Fatal Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PcNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, PcNonFatalErr,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PcFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, PcFatalErr, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VwNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, VwNonFatalErr,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Error
> event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VwFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, VwFatalErr, DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FlashNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, FlashNonFatalErr,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Error
> event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FlashFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, FlashFatalErr,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Link Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +LnkType1ErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = RegisterSerialIrqIfNull ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> + //
>
> + // Insert a record
>
> + //
>
> + Status = InsertEspiRecord (DispatchFunction, LnkType1Err,
> DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> + return Status;
>
> +}
>
> +
>
> +//
>
> +// EspiSlave srcdesc
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSrcDescEspiSlave = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_ESPI
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_ESPI
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_ESPI
>
> + }
>
> +};
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI
>
> + This routine will also lock down ESPI_SMI_LOCK bit after registration and
> prevent
>
> + this handler from unregistration.
>
> + On platform that supports more than 1 device through another chip select
> (SPT-H),
>
> + the SMI handler itself needs to inspect both the eSPI devices' interrupt
> status registers
>
> + (implementation specific for each Slave) in order to identify and service
> the cause.
>
> + After servicing it, it has to clear the Slaves' internal SMI# status registers
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and register
> is blocked.
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +EspiSlaveSmiRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + //
>
> + // If ESPI_SMI_LOCK is set, the register is blocked.
>
> + //
>
> + if (PmcIsEspiSmiLockSet ()) {
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + //
>
> + // @note: This service doesn't utilize the data base of mEspiSmiInstance.
>
> + // While SMI is triggered it directly goes to the registing
> DispatchFunction
>
> + // instead of EspiSmiCallback.
>
> + //
>
> + Status = PchSmiRecordInsert (
>
> + &mSrcDescEspiSlave,
>
> + (PCH_SMI_CALLBACK_FUNCTIONS) DispatchFunction,
>
> + PchEspiSmiEspiSlaveType,
>
> + DispatchHandle
>
> + );
>
> + PchSmmClearSource (&mSrcDescEspiSlave);
>
> + PchSmmEnableSource (&mSrcDescEspiSlave);
>
> +
>
> + //
>
> + // Lock down the ESPI_SMI_LOCK after ESPI SMI is enabled.
>
> + //
>
> + PmcLockEspiSmiWithS3BootScript ();
>
> + //
>
> + // Keep the DispatchHandle which will be used for unregister function.
>
> + //
>
> + mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] = *DispatchHandle;
>
> +
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileRegisterHandler (&gPchEspiSmiDispatchProtocolGuid,
> (EFI_SMM_HANDLER_ENTRY_POINT2)DispatchFunction,
> (UINTN)RETURN_ADDRESS (0), NULL, 0);
>
> + }
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to unregister a callback based on
> handle
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchHandle Handle acquired during registration
>
> +
>
> + @retval EFI_SUCCESS Unregister successful
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle is null
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has
> bad pointer
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in
> database
>
> + @retval EFI_ACCESS_DENIED Unregistration is done after end of DXE
>
> + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to
> unregistered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +EspiSmiUnRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + ESPI_TOP_LEVEL_TYPE EspiTopLevelType;
>
> + ESPI_SMI_TYPE EspiSmiType;
>
> + BOOLEAN SafeToDisable;
>
> + LIST_ENTRY *LinkInDb;
>
> + ESPI_SMI_RECORD *RecordPointer;
>
> + DATABASE_RECORD *RecordToDelete;
>
> +
>
> + if (DispatchHandle == NULL) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + if (((LIST_ENTRY *) DispatchHandle)->ForwardLink == (LIST_ENTRY *)
> EFI_BAD_POINTER) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // For DispatchHandle belongs to Espi Slave SMI, refuses the request of
> unregistration.
>
> + //
>
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiPmc] == DispatchHandle) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed for ESPI Slave SMI
> handle! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + //
>
> + // Iterate through all the database to find the record
>
> + //
>
> + for (EspiSmiType = 0; EspiSmiType < EspiSmiTypeMax; ++EspiSmiType) {
>
> + LinkInDb = GetFirstNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType]);
>
> +
>
> + while (!IsNull (&mEspiSmiInstance.CallbackDataBase[EspiSmiType],
> LinkInDb)) {
>
> + if (LinkInDb != (LIST_ENTRY *) DispatchHandle) {
>
> + LinkInDb = GetNextNode
> (&mEspiSmiInstance.CallbackDataBase[EspiSmiType], LinkInDb);
>
> +
>
> + } else {
>
> + //
>
> + // Found the source to be from this list
>
> + //
>
> + RemoveEntryList (LinkInDb);
>
> + RecordPointer = (ESPI_RECORD_FROM_LINK (LinkInDb));
>
> +
>
> + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
>
> + if (--mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] == 0) {
>
> + EspiSmiDisableSource (EspiSmiType);
>
> + }
>
> + }
>
> +
>
> + Status = gSmst->SmmFreePool (RecordPointer);
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT (FALSE);
>
> + }
>
> +
>
> + goto EspiSmiUnRegisterEnd;
>
> + }
>
> + }
>
> + }
>
> + //
>
> + // If the code reach here, the handle passed in cannot be found
>
> + //
>
> + DEBUG ((DEBUG_ERROR, "eSPI SMI handle is not in record database \n"));
>
> + ASSERT (FALSE);
>
> + return EFI_INVALID_PARAMETER;
>
> +
>
> +EspiSmiUnRegisterEnd:
>
> +
>
> + //
>
> + // Unregister and clear the handle from PchSmiDispatch
>
> + //
>
> + for (EspiTopLevelType = 0; EspiTopLevelType < EspiTopLevelTypeMax;
> ++EspiTopLevelType) {
>
> + SafeToDisable = TRUE;
>
> + //
>
> + // Checks all the child events that belongs to a top level status in PMC
>
> + //
>
> + for (EspiSmiType = mEspiSmiInstance.Barrier[EspiTopLevelType].Start;
> EspiSmiType <= mEspiSmiInstance.Barrier[EspiTopLevelType].End;
> ++EspiSmiType) {
>
> + if (mEspiSmiInstance.EspiSmiEventCounter[EspiSmiType] != 0) {
>
> + SafeToDisable = FALSE;
>
> + }
>
> + }
>
> + //
>
> + // Finally, disable the top level event in PMC
>
> + //
>
> + if (SafeToDisable) {
>
> + if (mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] != NULL) {
>
> + Status = PchSmmCoreUnRegister (NULL,
> mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType]);
>
> + ASSERT_EFI_ERROR (Status);
>
> + mEspiSmiInstance.PchSmiEspiHandle[EspiTopLevelType] = NULL;
>
> + }
>
> + }
>
> + }
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + if (!EFI_ERROR (Status)) {
>
> + SmiHandlerProfileUnregisterHandler
> (&gPchEspiSmiDispatchProtocolGuid, RecordToDelete->Callback, NULL, 0);
>
> + }
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Returns AND maks for clearing eSPI channel registers errors statuses
>
> + In addition to common status bit we add channel specific erro bits to avoid
> clearing them
>
> +
>
> + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW, 2
> for OOB, 3 for FA)
>
> +
>
> + @retval UINT32 AND mask with all the status bit masked to not
> clear them by mistake
>
> +**/
>
> +UINT32
>
> +GetEspiChannelStatusClearMask (
>
> + UINT8 ChannelNumber
>
> + )
>
> +{
>
> + UINT32 Data32;
>
> +
>
> + // Common error status bits for all channel registers
>
> + Data32 = B_ESPI_PCR_XERR_XNFES | B_ESPI_PCR_XERR_XFES;
>
> +
>
> + // Check channels for channel specific status bits
>
> + switch(ChannelNumber) {
>
> + case 0: // Peripheral Channel specific status bits
>
> + Data32 |= B_ESPI_PCR_PCERR_PCURD;
>
> + break;
>
> + case 3: // Flash Access Channel specific status bits
>
> + Data32 |= B_ESPI_PCR_FCERR_SAFBLK;
>
> + break;
>
> + }
>
> +
>
> + // Return the expected AND mask
>
> + return (UINT32)~(Data32);
>
> +}
>
> +
>
> +/**
>
> + Checks if channel error register data has Fatal Error bit set
>
> + If yes then reset the channel on slave
>
> +
>
> + @param[in] ChannelBaseAddress Base address
>
> + @param[in] ChannelNumber Channel number (0 for PC, 1 for VW, 2
> for OOB, 3 for FA)
>
> + @param[in] SlaveId Slave ID of which channel is to be reset
>
> +**/
>
> +VOID
>
> +CheckSlaveChannelErrorAndReset (
>
> + UINT16 ChannelBaseAddress,
>
> + UINT8 ChannelNumber,
>
> + UINT8 SlaveId
>
> + )
>
> +{
>
> + UINT32 Data32;
>
> + UINT16 ChannelAddress;
>
> + EFI_STATUS Status;
>
> +
>
> + if (ChannelNumber == 2) {
>
> + DEBUG ((DEBUG_INFO, "Channel %d is not supported by this function
> due to lack of error register\n", ChannelNumber));
>
> + return;
>
> + }
>
> +
>
> + if (!IsEspiSlaveChannelSupported (SlaveId, ChannelNumber)) {
>
> + DEBUG ((DEBUG_WARN, "Channel %d is not supported by slave
> device\n", ChannelNumber));
>
> + return;
>
> + }
>
> +
>
> + // Calculate channel address based on slave id
>
> + ChannelAddress = (UINT16) (ChannelBaseAddress + (SlaveId *
> S_ESPI_PCR_XERR));
>
> +
>
> + // Reading channel error register data
>
> + Data32 = PchPcrRead32 (PID_ESPISPI, ChannelAddress);
>
> +
>
> + DEBUG ((DEBUG_INFO, "eSPI channel error register (0x%4X) has value
> 0x%8X\n", ChannelAddress, Data32));
>
> +
>
> + // Check Fatal Error status bit in channel error register data
>
> + if ((Data32 & B_ESPI_PCR_XERR_XFES) != 0) {
>
> + Status = PchEspiSlaveChannelReset (SlaveId, ChannelNumber);
>
> +
>
> + if (EFI_ERROR (Status)) {
>
> + switch (Status) {
>
> + case EFI_UNSUPPORTED:
>
> + DEBUG ((DEBUG_ERROR, "Slave doesn't support channel %d\n",
> ChannelNumber));
>
> + break;
>
> + case EFI_TIMEOUT:
>
> + DEBUG ((DEBUG_ERROR, "Timeout occured during channel %d reset
> on slave %d\n", ChannelNumber, SlaveId));
>
> + break;
>
> + default:
>
> + DEBUG ((DEBUG_ERROR, "Error occured during channel %d reset\n",
> ChannelNumber));
>
> + break;
>
> + }
>
> + } else {
>
> + DEBUG ((DEBUG_INFO, "eSPI Slave %d channel %d reset ended
> successfully\n", SlaveId, ChannelNumber));
>
> + // If channel reset was successfull clear the fatal error flag by writing one
>
> + // we should be aware not to clear other status bits by mistake and mask
> them
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + ChannelAddress,
>
> + GetEspiChannelStatusClearMask (ChannelNumber),
>
> + B_ESPI_PCR_XERR_XFES
>
> + );
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + eSPI SMI handler for Fatal Error recovery flow
>
> +**/
>
> +VOID
>
> +EspiDefaultFatalErrorHandler (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 Data32;
>
> + UINT8 SlaveId;
>
> + UINT8 MaxSlavesCount;
>
> +
>
> + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Enter\n"));
>
> +
>
> + MaxSlavesCount = IsEspiSecondSlaveSupported () ? 2 : 1;
>
> +
>
> + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] MaxSlavesCount
> %d\n", MaxSlavesCount));
>
> +
>
> + for (SlaveId = 0; SlaveId < MaxSlavesCount; ++SlaveId) {
>
> + //
>
> + // Check if slave has SLCRR bit set. If it does it means it needs recovery.
>
> + //
>
> + Data32 = PchPcrRead32 (PID_ESPISPI, (UINT16)
> (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)));
>
> +
>
> + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Slave %d LNKERR
> reg 0x%8X\n", SlaveId, Data32));
>
> + //
>
> + // If SLCRR[31] bit is set we need to recover that slave
>
> + //
>
> + if ((Data32 & B_ESPI_PCR_LNKERR_SLV0_SLCRR) != 0) {
>
> + // 1. Perform in-band reset
>
> + PchEspiSlaveInBandReset (SlaveId);
>
> +
>
> + // 2. Channels reset
>
> + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 0,
> SlaveId); // Peripheral channel reset
>
> + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_VWERR_SLV0, 1,
> SlaveId); // Virtual Wire channel reset
>
> +
>
> + // Flash Access channel is not supported for CS1#
>
> + if (SlaveId == 0) {
>
> + CheckSlaveChannelErrorAndReset (R_ESPI_PCR_PCERR_SLV0, 3,
> SlaveId); // Flash Access channel reset
>
> + }
>
> +
>
> + // Clear SLCRR bit of slave after all channels recovery was done
>
> + PchPcrAndThenOr32 (
>
> + PID_ESPISPI,
>
> + (UINT16) (R_ESPI_PCR_LNKERR_SLV0 + (SlaveId * S_ESPI_PCR_XERR)),
>
> + (UINT32)~(B_ESPI_PCR_LNKERR_SLV0_LFET1S),
>
> + (UINT32) (B_ESPI_PCR_LNKERR_SLV0_SLCRR)
>
> + );
>
> + }
>
> + }
>
> +
>
> + DEBUG ((DEBUG_INFO, "[EspiRecoverFromFatalError] Exit\n"));
>
> +}
>
> +
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .h
> new file mode 100644
> index 0000000000..4903464fae
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmEspi
> .h
> @@ -0,0 +1,341 @@
> +/** @file
>
> + eSPI SMI Dispatch header
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +
>
> +#ifndef _PCH_SMM_ESPI_H_
>
> +#define _PCH_SMM_ESPI_H_
>
> +
>
> +#include "PchSmmHelpers.h"
>
> +
>
> +#define ESPI_SMI_INSTANCE_SIGNATURE SIGNATURE_32 ('E', 'S', 'P', 'I')
>
> +#define ESPI_SMI_RECORD_SIGNATURE SIGNATURE_32 ('E', 'S', 'R', 'C')
>
> +
>
> +#define ESPI_INSTANCE_FROM_THIS(_this) CR (_this,
> ESPI_SMI_INSTANCE, EfiEspiSmiDispatchProtocol,
> ESPI_SMI_INSTANCE_SIGNATURE)
>
> +#define ESPI_RECORD_FROM_LINK(_link) CR (_link, ESPI_SMI_RECORD,
> Link, ESPI_SMI_RECORD_SIGNATURE)
>
> +
>
> +typedef enum {
>
> + EspiBiosWrProtect, ///< BIOS Write Protect
>
> + EspiSerialIrq, ///< eSPI Master Asserted SMI
>
> + EspiPmc, ///< eSPI PMC SMI
>
> + EspiTopLevelTypeMax
>
> +} ESPI_TOP_LEVEL_TYPE;
>
> +
>
> +typedef enum {
>
> + BiosWrProtect, ///< BIOS Write Protect
>
> + BiosWrReport, ///< Peripheral Channel BIOS Write Protect
>
> + PcNonFatalErr, ///< Peripheral Channel Non Fatal Error
>
> + PcFatalErr, ///< Peripheral Channel Fatal Error
>
> + VwNonFatalErr, ///< Virtual Wire Non Fatal Error
>
> + VwFatalErr, ///< Virtual Wire Fatal Error
>
> + FlashNonFatalErr, ///< Flash Channel Non Fatal Error
>
> + FlashFatalErr, ///< Flash Channel Fatal Error
>
> + LnkType1Err, ///< Link Error
>
> + EspiSlaveSmi, ///< Espi Slave SMI
>
> + EspiSmiTypeMax
>
> +} ESPI_SMI_TYPE;
>
> +
>
> +///
>
> +/// This is used to classify ESPI_SMI_TYPE to ESPI_TOP_LEVEL_TYPE.
>
> +/// Used during dispatching and unregistering
>
> +///
>
> +typedef struct {
>
> + ESPI_SMI_TYPE Start;
>
> + ESPI_SMI_TYPE End;
>
> +} ESPI_SMI_TYPE_BARRIER;
>
> +
>
> +typedef struct _ESPI_SMI_INSTANCE {
>
> + ///
>
> + /// Signature associated with this instance
>
> + ///
>
> + UINT32 Signature;
>
> + ///
>
> + /// EFI_HANDLE acquired when installing PchEspiSmiDispatchProtocol
>
> + ///
>
> + EFI_HANDLE Handle;
>
> + ///
>
> + /// The protocol to register or unregister eSPI SMI callbacks
>
> + ///
>
> + PCH_ESPI_SMI_DISPATCH_PROTOCOL PchEspiSmiDispatchProtocol;
>
> + ///
>
> + /// The handle acquired when registering eSPI SMI callback to
> PchSmiDispatch
>
> + ///
>
> + EFI_HANDLE PchSmiEspiHandle[EspiTopLevelTypeMax];
>
> + ///
>
> + /// The linked list for record database.
>
> + ///
>
> + LIST_ENTRY CallbackDataBase[EspiSmiTypeMax];
>
> + ///
>
> + /// This is an internal counter to track the number of eSPI master events
> have been registered.
>
> + /// When unregistering, we can disable the SMI if the counter is zero
>
> + ///
>
> + UINTN EspiSmiEventCounter[EspiSmiTypeMax];
>
> + ///
>
> + /// Instance of barrier
>
> + ///
>
> + CONST ESPI_SMI_TYPE_BARRIER Barrier[EspiTopLevelTypeMax];
>
> +} ESPI_SMI_INSTANCE;
>
> +
>
> +typedef struct _ESPI_DESCRIPTOR {
>
> + PCH_SMM_ADDRESS Address;
>
> + UINT32 SourceIsActiveAndMask;
>
> + UINT32 SourceIsActiveValue;
>
> + UINT32 ClearStatusAndMask;
>
> + UINT32 ClearStatusOrMask;
>
> +} ESPI_DESCRIPTOR;
>
> +
>
> +///
>
> +/// A simple record to store the callbacks associated with an eSPI SMI
> source
>
> +///
>
> +typedef struct _ESPI_SMI_RECORD {
>
> + UINT32 Signature;
>
> + LIST_ENTRY Link;
>
> + PCH_ESPI_SMI_DISPATCH_CALLBACK Callback;
>
> +} ESPI_SMI_RECORD;
>
> +
>
> +/**
>
> + Installs and initialize this protocol
>
> +
>
> + @param[in] ImageHandle Not used
>
> +
>
> + @retval EFI_SUCCESS Installation succeed
>
> + @retval others Installation failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallEspiSmi (
>
> + IN EFI_HANDLE ImageHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a BIOS Write Protect event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +BiosWrProtectRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a BIOS Write Report event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +BiosWrReportRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Non
> Fatal Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PcNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Peripheral Channel Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PcFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Non Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VwNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Virtual Wire Fatal Error
> event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +VwFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Flash Channel Non Fatal
> Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FlashNonFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Flash Channel Fatal Error
> event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +FlashFatalErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a Link Error event
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +LnkType1ErrRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to register a eSPI slave SMI
>
> + NOTE: The register function is not available when the ESPI_SMI_LOCK bit is
> set.
>
> + This runtine will also lock donw ESPI_SMI_LOCK bit after registration
> and
>
> + prevent this handler from unregistration.
>
> + On platform that supports more than 1 device through another chip select
> (SPT-H),
>
> + the SMI handler itself needs to inspect both the eSPI devices' interrupt
> status registers
>
> + (implementation specific for each Slave) in order to identify and service
> the cause.
>
> + After servicing it, it has to clear the Slaves' internal SMI# status registers
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchFunction The callback to execute
>
> + @param[out] DispatchHandle The handle for this callback registration
>
> +
>
> + @retval EFI_SUCCESS Registration succeed
>
> + @retval EFI_ACCESS_DENIED Return access denied if the
> SmmReadyToLock event has been triggered
>
> + @retval EFI_ACCESS_DENIED The ESPI_SMI_LOCK is set and register
> is blocked.
>
> + @retval others Registration failed
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +EspiSlaveSmiRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN PCH_ESPI_SMI_DISPATCH_CALLBACK DispatchFunction,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI Dispatch Protocol instance to unregister a callback based on
> handle
>
> +
>
> + @param[in] This Not used
>
> + @param[in] DispatchHandle Handle acquired during registration
>
> +
>
> + @retval EFI_SUCCESS Unregister successful
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle is null
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle's forward link has
> bad pointer
>
> + @retval EFI_INVALID_PARAMETER DispatchHandle does not exist in
> database
>
> + @retval EFI_ACCESS_DENIED Unregistration is done after end of DXE
>
> + @retval EFI_ACCESS_DENIED DispatchHandle is not allowed to
> unregistered
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +EspiSmiUnRegister (
>
> + IN PCH_ESPI_SMI_DISPATCH_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + );
>
> +
>
> +/**
>
> + eSPI SMI handler for Fatal Error recovery flow
>
> +
>
> + @param[in] DispatchHandle Handle acquired during registration
>
> +**/
>
> +VOID
>
> +EspiDefaultFatalErrorHandler (
>
> + VOID
>
> + );
>
> +
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi.
> c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi
> .c
> new file mode 100644
> index 0000000000..61f925c860
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmGpi
> .c
> @@ -0,0 +1,263 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Smm Gpi dispatch
> protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmm.h"
>
> +#include "PchSmmHelpers.h"
>
> +#include <Library/SmiHandlerProfileLib.h>
>
> +#include <Register/GpioRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +
>
> +//
>
> +// Structure for GPI SMI is a template which needs to have
>
> +// GPI Smi bit offset and Smi Status & Enable registers updated (accordingly
>
> +// to choosen group and pad number) after adding it to SMM Callback
> database
>
> +//
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mPchGpiSourceDescTemplate = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + NULL_BIT_DESC_INITIALIZER,
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + GPIO_ADDR_TYPE, {0x0}
>
> + },
>
> + S_GPIO_PCR_GP_SMI_STS, 0x0,
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_GPIO_SMI
>
> + }
>
> +};
>
> +
>
> +/**
>
> + The register function used to register SMI handler of GPI SMI event.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Function to register for handler when the
> specified GPI causes an SMI.
>
> + @param[in] RegisterContext Pointer to the dispatch function's context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function the GPI(s) for which the dispatch function
>
> + should be invoked.
>
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
>
> + function instance.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_ACCESS_DENIED Register is not allowed
>
> + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The GPI
> input value
>
> + is not within valid range.
>
> + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system
> or SMM) to manage this child.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchGpiSmiRegister (
>
> + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN EFI_SMM_GPI_REGISTER_CONTEXT *RegisterContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD Record;
>
> + GPIO_PAD GpioPad;
>
> + UINT8 GpiSmiBitOffset;
>
> + UINT32 GpiHostSwOwnRegAddress;
>
> + UINT32 GpiSmiStsRegAddress;
>
> + UINT32 Data32Or;
>
> + UINT32 Data32And;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the EndOfDxe event
> has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + Status = GpioGetPadAndSmiRegs (
>
> + (UINT32) RegisterContext->GpiNum,
>
> + &GpioPad,
>
> + &GpiSmiBitOffset,
>
> + &GpiHostSwOwnRegAddress,
>
> + &GpiSmiStsRegAddress
>
> + );
>
> +
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> +
>
> + ZeroMem (&Record, sizeof (DATABASE_RECORD));
>
> +
>
> + //
>
> + // Gather information about the registration request
>
> + //
>
> + Record.Callback = DispatchFunction;
>
> + Record.ChildContext.Gpi = *RegisterContext;
>
> + Record.ProtocolType = GpiType;
>
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
>
> +
>
> + CopyMem (&Record.SrcDesc, &mPchGpiSourceDescTemplate, sizeof
> (PCH_SMM_SOURCE_DESC) );
>
> +
>
> + Record.SrcDesc.Sts[0].Reg.Data.raw = GpiSmiStsRegAddress; // GPI SMI
> Status register
>
> + Record.SrcDesc.Sts[0].Bit = GpiSmiBitOffset; // Bit position for
> selected pad
>
> +
>
> + //
>
> + // Insert GpiSmi handler to PchSmmCore database
>
> + //
>
> + *DispatchHandle = NULL;
>
> +
>
> + Status = SmmCoreInsertRecord (
>
> + &Record,
>
> + DispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + SmiHandlerProfileRegisterHandler (
>
> + &gEfiSmmGpiDispatch2ProtocolGuid,
>
> + (EFI_SMM_HANDLER_ENTRY_POINT2) DispatchFunction,
>
> + (UINTN)RETURN_ADDRESS (0),
>
> + RegisterContext,
>
> + sizeof(*RegisterContext)
>
> + );
>
> +
>
> + //
>
> + // Enable GPI SMI
>
> + // HOSTSW_OWN with respect to generating GPI SMI has negative logic:
>
> + // - 0 (ACPI mode) - GPIO pad will be capable of generating SMI/NMI/SCI
>
> + // - 1 (GPIO mode) - GPIO pad will not generate SMI/NMI/SCI
>
> + //
>
> + Data32And = (UINT32)~(1u << GpiSmiBitOffset);
>
> + MmioAnd32 (GpiHostSwOwnRegAddress, Data32And);
>
> +
>
> + //
>
> + // Add HOSTSW_OWN programming into S3 boot script
>
> + //
>
> + Data32Or = 0;
>
> + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32,
> GpiHostSwOwnRegAddress, &Data32Or, &Data32And);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Unregister a GPI SMI source dispatch function with a parent SMM driver
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_GPI_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + unregistered and the SMI source has been disabled
>
> + if there are no other registered child dispatch
>
> + functions for this SMI source.
>
> + @retval EFI_INVALID_PARAMETER Handle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchGpiSmiUnRegister (
>
> + IN CONST EFI_SMM_GPI_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + DATABASE_RECORD *RecordToDelete;
>
> + DATABASE_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> + GPIO_PAD GpioPad;
>
> + UINT8 GpiSmiBitOffset;
>
> + UINT32 GpiHostSwOwnRegAddress;
>
> + UINT32 GpiSmiStsRegAddress;
>
> + UINT32 Data32Or;
>
> + UINT32 Data32And;
>
> + BOOLEAN DisableGpiSmiSource;
>
> +
>
> +
>
> + if (DispatchHandle == NULL) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + RecordToDelete = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + if ((RecordToDelete->Signature != DATABASE_RECORD_SIGNATURE) ||
>
> + (RecordToDelete->ProtocolType != GpiType)) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + DisableGpiSmiSource = TRUE;
>
> + //
>
> + // Loop through all sources in record linked list to see if any other GPI SMI
>
> + // is installed on the same pin. If no then disable GPI SMI capability on this
> pad
>
> + //
>
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
>
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
>
> + //
>
> + // If this is the record to delete skip it
>
> + //
>
> + if (RecordInDb == RecordToDelete) {
>
> + continue;
>
> + }
>
> + //
>
> + // Check if record is GPI SMI type
>
> + //
>
> + if (RecordInDb->ProtocolType == GpiType) {
>
> + //
>
> + // Check if same GPIO pad is the source of this SMI
>
> + //
>
> + if (RecordInDb->ChildContext.Gpi.GpiNum == RecordToDelete-
> >ChildContext.Gpi.GpiNum) {
>
> + DisableGpiSmiSource = FALSE;
>
> + break;
>
> + }
>
> + }
>
> + }
>
> +
>
> + if (DisableGpiSmiSource) {
>
> + GpioGetPadAndSmiRegs (
>
> + (UINT32) RecordToDelete->ChildContext.Gpi.GpiNum,
>
> + &GpioPad,
>
> + &GpiSmiBitOffset,
>
> + &GpiHostSwOwnRegAddress,
>
> + &GpiSmiStsRegAddress
>
> + );
>
> +
>
> + Data32Or = 1u << GpiSmiBitOffset;
>
> + Data32And = 0xFFFFFFFF;
>
> + MmioOr32 (GpiHostSwOwnRegAddress, Data32Or);
>
> + S3BootScriptSaveMemReadWrite (S3BootScriptWidthUint32,
> GpiHostSwOwnRegAddress, &Data32Or, &Data32And);
>
> + }
>
> +
>
> +
>
> + RemoveEntryList (&RecordToDelete->Link);
>
> + ZeroMem (RecordToDelete, sizeof (DATABASE_RECORD));
>
> + Status = gSmst->SmmFreePool (RecordToDelete);
>
> +
>
> + if (EFI_ERROR (Status)) {
>
> + ASSERT (FALSE);
>
> + return Status;
>
> + }
>
> + SmiHandlerProfileUnregisterHandler (
>
> + &gEfiSmmGpiDispatch2ProtocolGuid,
>
> + RecordToDelete->Callback,
>
> + &RecordToDelete->ChildContext,
>
> + RecordToDelete->ContextSize
>
> + );
>
> + return EFI_SUCCESS;
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.c
> new file mode 100644
> index 0000000000..6bbf9ea8e8
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.c
> @@ -0,0 +1,332 @@
> +/** @file
>
> + Helper functions for PCH SMM dispatcher.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Register/PmcRegs.h>
>
> +
>
> +///
>
> +/// #define BIT_ZERO 0x00000001
>
> +///
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST UINT32 BIT_ZERO =
> 0x00000001;
>
> +
>
> +///
>
> +/// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
>
> +///
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors' enable settings.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The enable settings of the 2 SMM source
> descriptors are identical.
>
> + @retval FALSE The enable settings of the 2 SMM source
> descriptors are not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareEnables (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + )
>
> +{
>
> + BOOLEAN IsEqual;
>
> + UINTN DescIndex;
>
> +
>
> + IsEqual = TRUE;
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
>
> + ///
>
> + /// It's okay to compare a NULL bit description to a non-NULL bit
> description.
>
> + /// They are unequal and these tests will generate the correct result.
>
> + ///
>
> + if (Src1->En[DescIndex].Bit != Src2->En[DescIndex].Bit ||
>
> + Src1->En[DescIndex].Reg.Type != Src2->En[DescIndex].Reg.Type ||
>
> + Src1->En[DescIndex].Reg.Data.raw != Src2-
> >En[DescIndex].Reg.Data.raw
>
> + ) {
>
> + IsEqual = FALSE;
>
> + break;
>
> + ///
>
> + /// out of for loop
>
> + ///
>
> + }
>
> + }
>
> +
>
> + return IsEqual;
>
> +}
>
> +
>
> +/**
>
> + Compare a bit descriptor to the enables of source descriptor. Includes null
> address type.
>
> +
>
> + @param[in] BitDesc Pointer to the PCH SMI bit descriptor
>
> + @param[in] Src Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The bit desc is equal to any of the enables in source
> descriptor
>
> + @retval FALSE The bid desc is not equal to all of the enables in
> source descriptor
>
> +**/
>
> +BOOLEAN
>
> +IsBitEqualToAnySourceEn (
>
> + CONST IN PCH_SMM_BIT_DESC *BitDesc,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src
>
> + )
>
> +{
>
> + BOOLEAN IsEqual;
>
> + UINTN DescIndex;
>
> +
>
> + IsEqual = FALSE;
>
> +
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; ++DescIndex) {
>
> + if ((BitDesc->Reg.Type == Src->En[DescIndex].Reg.Type) &&
>
> + (BitDesc->Reg.Data.raw == Src->En[DescIndex].Reg.Data.raw) &&
>
> + (BitDesc->Bit == Src->En[DescIndex].Bit)) {
>
> + IsEqual = TRUE;
>
> + break;
>
> + }
>
> + }
>
> + return IsEqual;
>
> +}
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors' statuses.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The statuses of the 2 SMM source descriptors are
> identical.
>
> + @retval FALSE The statuses of the 2 SMM source descriptors are
> not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareStatuses (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + )
>
> +{
>
> + BOOLEAN IsEqual;
>
> + UINTN DescIndex;
>
> +
>
> + IsEqual = TRUE;
>
> +
>
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
>
> + ///
>
> + /// It's okay to compare a NULL bit description to a non-NULL bit
> description.
>
> + /// They are unequal and these tests will generate the correct result.
>
> + ///
>
> + if (Src1->Sts[DescIndex].Bit != Src2->Sts[DescIndex].Bit ||
>
> + Src1->Sts[DescIndex].Reg.Type != Src2->Sts[DescIndex].Reg.Type ||
>
> + Src1->Sts[DescIndex].Reg.Data.raw != Src2-
> >Sts[DescIndex].Reg.Data.raw
>
> + ) {
>
> + IsEqual = FALSE;
>
> + break;
>
> + ///
>
> + /// out of for loop
>
> + ///
>
> + }
>
> + }
>
> +
>
> + return IsEqual;
>
> +}
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors, based on Enable settings and Status
> settings of them.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The 2 SMM source descriptors are identical.
>
> + @retval FALSE The 2 SMM source descriptors are not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareSources (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + )
>
> +{
>
> + return (BOOLEAN) (CompareEnables (Src1, Src2) && CompareStatuses
> (Src1, Src2));
>
> +}
>
> +
>
> +/**
>
> + Check if an SMM source is active.
>
> +
>
> + @param[in] Src Pointer to the PCH SMI source description table
>
> + @param[in] SciEn Indicate if SCI is enabled or not
>
> + @param[in] SmiEnValue Value from R_ACPI_IO_SMI_EN
>
> + @param[in] SmiStsValue Value from R_ACPI_IO_SMI_STS
>
> +
>
> + @retval TRUE It is active.
>
> + @retval FALSE It is inactive.
>
> +**/
>
> +BOOLEAN
>
> +SourceIsActive (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src,
>
> + CONST IN BOOLEAN SciEn,
>
> + CONST IN UINT32 SmiEnValue,
>
> + CONST IN UINT32 SmiStsValue
>
> + )
>
> +{
>
> + UINTN DescIndex;
>
> +
>
> + ///
>
> + /// This source is dependent on SciEn, and SciEn == 1. An ACPI OS is
> present,
>
> + /// so we shouldn't do anything w/ this source until SciEn == 0.
>
> + ///
>
> + if ((Src->Flags == PCH_SMM_SCI_EN_DEPENDENT) && (SciEn)) {
>
> + return FALSE;
>
> + }
>
> +
>
> + ///
>
> + /// Checking top level SMI status. If the status is not active, return false
> immediately
>
> + ///
>
> + if (!IS_BIT_DESC_NULL (Src->PmcSmiSts)) {
>
> + if ((Src->PmcSmiSts.Reg.Type == ACPI_ADDR_TYPE) &&
>
> + (Src->PmcSmiSts.Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
>
> + ((SmiStsValue & (1u << Src->PmcSmiSts.Bit)) == 0)) {
>
> + return FALSE;
>
> + }
>
> + }
>
> +
>
> + ///
>
> + /// Read each bit desc from hardware and make sure it's a one
>
> + ///
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (Src->En[DescIndex])) {
>
> + if ((Src->En[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
>
> + (Src->En[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_EN) &&
>
> + ((SmiEnValue & (1u << Src->En[DescIndex].Bit)) == 0)) {
>
> + return FALSE;
>
> + } else if (ReadBitDesc (&Src->En[DescIndex]) == 0) {
>
> + return FALSE;
>
> + }
>
> + }
>
> + }
>
> +
>
> + ///
>
> + /// Read each bit desc from hardware and make sure it's a one
>
> + ///
>
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (Src->Sts[DescIndex])) {
>
> + if ((Src->Sts[DescIndex].Reg.Type == ACPI_ADDR_TYPE) &&
>
> + (Src->Sts[DescIndex].Reg.Data.acpi == R_ACPI_IO_SMI_STS) &&
>
> + ((SmiStsValue & (1u << Src->Sts[DescIndex].Bit)) == 0)) {
>
> + return FALSE;
>
> + } else if (ReadBitDesc (&Src->Sts[DescIndex]) == 0) {
>
> + return FALSE;
>
> + }
>
> + }
>
> + }
>
> +
>
> + return TRUE;
>
> +}
>
> +
>
> +/**
>
> + Enable the SMI source event by set the SMI enable bit, this function would
> also clear SMI
>
> + status bit to make initial state is correct
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmEnableSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINTN DescIndex;
>
> +
>
> + ///
>
> + /// Set enables to 1 by writing a 1
>
> + ///
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
>
> + WriteBitDesc (&SrcDesc->En[DescIndex], 1, FALSE);
>
> + }
>
> + }
>
> + ///
>
> + /// Clear statuses to 0 by writing a 1
>
> + ///
>
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
>
> + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Disable the SMI source event by clear the SMI enable bit
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmDisableSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINTN DescIndex;
>
> +
>
> + for (DescIndex = 0; DescIndex < NUM_EN_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (SrcDesc->En[DescIndex])) {
>
> + WriteBitDesc (&SrcDesc->En[DescIndex], 0, FALSE);
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Clear the SMI status bit by set the source bit of SMI status register
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINTN DescIndex;
>
> +
>
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
>
> + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
>
> + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
>
> + }
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Sets the source to a 1 and then waits for it to clear.
>
> + Be very careful when calling this function -- it will not
>
> + ASSERT. An acceptable case to call the function is when
>
> + waiting for the NEWCENTURY_STS bit to clear (which takes
>
> + 3 RTCCLKs).
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmClearSourceAndBlock (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + UINTN DescIndex;
>
> + BOOLEAN IsSet;
>
> +
>
> + for (DescIndex = 0; DescIndex < NUM_STS_BITS; DescIndex++) {
>
> +
>
> + if (!IS_BIT_DESC_NULL (SrcDesc->Sts[DescIndex])) {
>
> + ///
>
> + /// Write the bit
>
> + ///
>
> + WriteBitDesc (&SrcDesc->Sts[DescIndex], 1, TRUE);
>
> +
>
> + ///
>
> + /// Don't return until the bit actually clears.
>
> + ///
>
> + IsSet = TRUE;
>
> + while (IsSet) {
>
> + IsSet = ReadBitDesc (&SrcDesc->Sts[DescIndex]);
>
> + ///
>
> + /// IsSet will eventually clear -- or else we'll have
>
> + /// an infinite loop.
>
> + ///
>
> + }
>
> + }
>
> + }
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.h
> new file mode 100644
> index 0000000000..db7713fa02
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmHel
> pers.h
> @@ -0,0 +1,155 @@
> +/** @file
>
> + Helper functions for PCH SMM
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef PCH_SMM_HELPERS_H
>
> +#define PCH_SMM_HELPERS_H
>
> +
>
> +#include "PchSmm.h"
>
> +#include "PchxSmmHelpers.h"
>
> +//
>
> +//
> //////////////////////////////////////////////////////////////////////////////
> /////////////////////////////////////
>
> +// SUPPORT / HELPER FUNCTIONS (PCH version-independent)
>
> +//
>
> +
>
> +/**
>
> + Publish SMI Dispatch protocols.
>
> +
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmPublishDispatchProtocols (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors' enable settings.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The enable settings of the 2 SMM source
> descriptors are identical.
>
> + @retval FALSE The enable settings of the 2 SMM source
> descriptors are not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareEnables (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + );
>
> +
>
> +/**
>
> + Compare a bit descriptor to the enables of source descriptor. Includes null
> address type.
>
> +
>
> + @param[in] BitDesc Pointer to the PCH SMI bit descriptor
>
> + @param[in] Src Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The bit desc is equal to any of the enables in source
> descriptor
>
> + @retval FALSE The bid desc is not equal to all of the enables in
> source descriptor
>
> +**/
>
> +BOOLEAN
>
> +IsBitEqualToAnySourceEn (
>
> + CONST IN PCH_SMM_BIT_DESC *BitDesc,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src
>
> + );
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors' statuses.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The statuses of the 2 SMM source descriptors are
> identical.
>
> + @retval FALSE The statuses of the 2 SMM source descriptors are
> not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareStatuses (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + );
>
> +
>
> +/**
>
> + Compare 2 SMM source descriptors, based on Enable settings and Status
> settings of them.
>
> +
>
> + @param[in] Src1 Pointer to the PCH SMI source description table 1
>
> + @param[in] Src2 Pointer to the PCH SMI source description table 2
>
> +
>
> + @retval TRUE The 2 SMM source descriptors are identical.
>
> + @retval FALSE The 2 SMM source descriptors are not identical.
>
> +**/
>
> +BOOLEAN
>
> +CompareSources (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src1,
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src2
>
> + );
>
> +
>
> +/**
>
> + Check if an SMM source is active.
>
> +
>
> + @param[in] Src Pointer to the PCH SMI source description table
>
> + @param[in] SciEn Indicate if SCI is enabled or not
>
> + @param[in] SmiEnValue Value from R_PCH_SMI_EN
>
> + @param[in] SmiStsValue Value from R_PCH_SMI_STS
>
> +
>
> + @retval TRUE It is active.
>
> + @retval FALSE It is inactive.
>
> +**/
>
> +BOOLEAN
>
> +SourceIsActive (
>
> + CONST IN PCH_SMM_SOURCE_DESC *Src,
>
> + CONST IN BOOLEAN SciEn,
>
> + CONST IN UINT32 SmiEnValue,
>
> + CONST IN UINT32 SmiStsValue
>
> + );
>
> +
>
> +/**
>
> + Enable the SMI source event by set the SMI enable bit, this function would
> also clear SMI
>
> + status bit to make initial state is correct
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmEnableSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Disable the SMI source event by clear the SMI enable bit
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmDisableSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Clear the SMI status bit by set the source bit of SMI status register
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmClearSource (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Sets the source to a 1 and then waits for it to clear.
>
> + Be very careful when calling this function -- it will not
>
> + ASSERT. An acceptable case to call the function is when
>
> + waiting for the NEWCENTURY_STS bit to clear (which takes
>
> + 3 RTCCLKs).
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH SMI source description table
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmClearSourceAndBlock (
>
> + CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri
> odicTimer.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri
> odicTimer.c
> new file mode 100644
> index 0000000000..3c3e638cbf
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPeri
> odicTimer.c
> @@ -0,0 +1,667 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Periodical Timer
> dispatch protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Protocol/PchSmmPeriodicTimerControl.h>
>
> +#include <Library/PmcPrivateLib.h>
>
> +
>
> +//
>
> +// There is only one instance for PeriodicTimerCommBuffer.
>
> +// It's safe in SMM since there is no re-entry for the function.
>
> +//
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> EFI_SMM_PERIODIC_TIMER_CONTEXT mPchPeriodicTimerCommBuffer;
>
> +
>
> +typedef enum {
>
> + PERIODIC_TIMER= 0,
>
> + SWSMI_TIMER,
>
> + NUM_TIMERS
>
> +} SUPPORTED_TIMER;
>
> +
>
> +typedef struct _TIMER_INTERVAL {
>
> + UINT64 Interval;
>
> + UINT8 AssociatedTimer;
>
> +} TIMER_INTERVAL;
>
> +
>
> +#define NUM_INTERVALS 8
>
> +
>
> +//
>
> +// Time constants, in 100 nano-second units
>
> +//
>
> +#define TIME_64s 640000000 ///< 64 s
>
> +#define TIME_32s 320000000 ///< 32 s
>
> +#define TIME_16s 160000000 ///< 16 s
>
> +#define TIME_8s 80000000 ///< 8 s
>
> +#define TIME_64ms 640000 ///< 64 ms
>
> +#define TIME_32ms 320000 ///< 32 ms
>
> +#define TIME_16ms 160000 ///< 16 ms
>
> +#define TIME_1_5ms 15000 ///< 1.5 ms
>
> +
>
> +typedef enum {
>
> + INDEX_TIME_64s = 0,
>
> + INDEX_TIME_32s,
>
> + INDEX_TIME_16s,
>
> + INDEX_TIME_8s,
>
> + INDEX_TIME_64ms,
>
> + INDEX_TIME_32ms,
>
> + INDEX_TIME_16ms,
>
> + INDEX_TIME_1_5ms,
>
> + INDEX_TIME_MAX
>
> +} TIMER_INTERVAL_INDEX;
>
> +
>
> +static TIMER_INTERVAL mSmmPeriodicTimerIntervals[NUM_INTERVALS] = {
>
> + {
>
> + TIME_64s,
>
> + PERIODIC_TIMER
>
> + },
>
> + {
>
> + TIME_32s,
>
> + PERIODIC_TIMER
>
> + },
>
> + {
>
> + TIME_16s,
>
> + PERIODIC_TIMER
>
> + },
>
> + {
>
> + TIME_8s,
>
> + PERIODIC_TIMER
>
> + },
>
> + {
>
> + TIME_64ms,
>
> + SWSMI_TIMER
>
> + },
>
> + {
>
> + TIME_32ms,
>
> + SWSMI_TIMER
>
> + },
>
> + {
>
> + TIME_16ms,
>
> + SWSMI_TIMER
>
> + },
>
> + {
>
> + TIME_1_5ms,
>
> + SWSMI_TIMER
>
> + },
>
> +};
>
> +
>
> +typedef struct _TIMER_INFO {
>
> + UINTN NumChildren; ///< number of children using this timer
>
> + UINT64 MinReqInterval; ///< minimum interval required by children
>
> + UINTN CurrentSetting; ///< interval this timer is set at right now (index
> into interval table)
>
> +} TIMER_INFO;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED TIMER_INFO
> mTimers[NUM_TIMERS];
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mTimerSourceDesc[NUM_TIMERS] = {
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_PERIODIC
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PERIODIC
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PERIODIC
>
> + }
>
> + },
>
> + {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_SWSMI_TMR
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SWSMI_TMR
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_SWSMI_TMR
>
> + }
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Program Smm Periodic Timer
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC
> instance.
>
> +**/
>
> +VOID
>
> +PchSmmPeriodicTimerProgramTimers (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + );
>
> +
>
> +/**
>
> + Convert the dispatch context to the timer interval, this function will assert
> if then either:
>
> + (1) The context contains an invalid interval
>
> + (2) The timer interval table is corrupt
>
> +
>
> + @param[in] DispatchContext The pointer to the Dispatch Context
>
> +
>
> + @retval TIMER_INTERVAL The timer interval of input dispatch context
>
> +**/
>
> +TIMER_INTERVAL *
>
> +ContextToTimerInterval (
>
> + IN PCH_SMM_CONTEXT *DispatchContext
>
> + )
>
> +{
>
> + UINTN loopvar;
>
> +
>
> + ///
>
> + /// Determine which timer this child is using
>
> + ///
>
> + for (loopvar = 0; loopvar < NUM_INTERVALS; loopvar++) {
>
> + if (((DispatchContext->PeriodicTimer.SmiTickInterval == 0) &&
>
> + (DispatchContext->PeriodicTimer.Period >=
> mSmmPeriodicTimerIntervals[loopvar].Interval)) ||
>
> + (DispatchContext->PeriodicTimer.SmiTickInterval ==
> mSmmPeriodicTimerIntervals[loopvar].Interval)) {
>
> + return &mSmmPeriodicTimerIntervals[loopvar];
>
> + }
>
> + }
>
> + ///
>
> + /// If this assertion fires, then either:
>
> + /// (1) the context contains an invalid interval
>
> + /// (2) the timer interval table is corrupt
>
> + ///
>
> + ASSERT (FALSE);
>
> +
>
> + return NULL;
>
> +}
>
> +
>
> +/**
>
> + Figure out which timer the child is requesting and
>
> + send back the source description
>
> +
>
> + @param[in] DispatchContext The pointer to the Dispatch Context
> instances
>
> + @param[out] SrcDesc The pointer to the source description
>
> +
>
> +**/
>
> +VOID
>
> +MapPeriodicTimerToSrcDesc (
>
> + IN PCH_SMM_CONTEXT *DispatchContext,
>
> + OUT PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + TIMER_INTERVAL *TimerInterval;
>
> +
>
> + ///
>
> + /// Figure out which timer the child is requesting and
>
> + /// send back the source description
>
> + ///
>
> + TimerInterval = ContextToTimerInterval (DispatchContext);
>
> + if (TimerInterval == NULL) {
>
> + return;
>
> + }
>
> +
>
> + CopyMem (
>
> + (VOID *) SrcDesc,
>
> + (VOID *) (&mTimerSourceDesc[TimerInterval->AssociatedTimer]),
>
> + sizeof (PCH_SMM_SOURCE_DESC)
>
> + );
>
> +
>
> + ///
>
> + /// Program the value of the interval into hardware
>
> + ///
>
> + PchSmmPeriodicTimerProgramTimers (SrcDesc);
>
> +}
>
> +
>
> +/**
>
> + Update the elapsed time from the Interval data of DATABASE_RECORD
>
> +
>
> + @param[in] Record The pointer to the DATABASE_RECORD.
>
> + @param[out] HwContext The Context to be updated.
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PeriodicTimerGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *HwContext
>
> + )
>
> +{
>
> + TIMER_INTERVAL *TimerInterval;
>
> +
>
> + ASSERT (Record->ProtocolType == PeriodicTimerType);
>
> +
>
> + TimerInterval = ContextToTimerInterval (&Record->ChildContext);
>
> + if (TimerInterval == NULL) {
>
> + return;
>
> + }
>
> + ///
>
> + /// Ignore the hardware context. It's not required for this protocol.
>
> + /// Instead, just increment the child's context.
>
> + /// Update the elapsed time w/ the data from our tables
>
> + ///
>
> + Record->MiscData.ElapsedTime += mTimers[TimerInterval-
> >AssociatedTimer].MinReqInterval;
>
> + *HwContext = Record->ChildContext;
>
> +}
>
> +
>
> +/**
>
> + Check whether Periodic Timer of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes Periodic Timer 1
>
> + @param[in] Context2 Context 2 that includes Periodic Timer 2
>
> +
>
> + @retval FALSE Periodic Timer match
>
> + @retval TRUE Periodic Timer don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +PeriodicTimerCmpContext (
>
> + IN PCH_SMM_CONTEXT *HwContext,
>
> + IN PCH_SMM_CONTEXT *ChildContext
>
> + )
>
> +{
>
> + DATABASE_RECORD *Record;
>
> + Record = DATABASE_RECORD_FROM_CHILDCONTEXT (ChildContext);
>
> +
>
> + if (!Record->MiscData.TimerSmiEnabled) {
>
> + return FALSE;
>
> + }
>
> + if (Record->MiscData.ElapsedTime >= ChildContext->PeriodicTimer.Period)
> {
>
> + ///
>
> + /// For EDKII, the ElapsedTime is reset when
> PeriodicTimerGetCommBuffer
>
> + ///
>
> + return TRUE;
>
> + } else {
>
> + return FALSE;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Gather the CommBuffer information of SmmPeriodicTimerDispatch2.
>
> +
>
> + @param[in] Record No use
>
> + @param[out] CommBuffer Point to the CommBuffer structure
>
> + @param[out] CommBufferSize Point to the Size of CommBuffer
> structure
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PeriodicTimerGetCommBuffer (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT VOID **CommBuffer,
>
> + OUT UINTN *CommBufferSize
>
> + )
>
> +{
>
> + ASSERT (Record->ProtocolType == PeriodicTimerType);
>
> +
>
> + mPchPeriodicTimerCommBuffer.ElapsedTime = Record-
> >MiscData.ElapsedTime;
>
> +
>
> + ///
>
> + /// For EDKII, the ElapsedTime is reset here
>
> + ///
>
> + Record->MiscData.ElapsedTime = 0;
>
> +
>
> + ///
>
> + /// Return the CommBuffer
>
> + ///
>
> + *CommBuffer = (VOID *) &mPchPeriodicTimerCommBuffer;
>
> + *CommBufferSize = sizeof (EFI_SMM_PERIODIC_TIMER_CONTEXT);
>
> +}
>
> +
>
> +/**
>
> + Program Smm Periodic Timer
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC
> instance.
>
> +**/
>
> +VOID
>
> +PchSmmPeriodicTimerProgramTimers (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + SUPPORTED_TIMER Timer;
>
> + DATABASE_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> + TIMER_INTERVAL *TimerInterval;
>
> +
>
> + ///
>
> + /// Find the minimum required interval for each timer
>
> + ///
>
> + for (Timer = 0; Timer < NUM_TIMERS; Timer++) {
>
> + mTimers[Timer].MinReqInterval = ~ (UINT64) 0x0;
>
> + mTimers[Timer].NumChildren = 0;
>
> + }
>
> +
>
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
>
> + if (RecordInDb->ProtocolType == PeriodicTimerType) {
>
> + if (RecordInDb->MiscData.TimerSmiEnabled) {
>
> + ///
>
> + /// This child is registerd with the PeriodicTimer protocol
>
> + ///
>
> + TimerInterval = ContextToTimerInterval (&RecordInDb->ChildContext);
>
> + if (TimerInterval == NULL) {
>
> + return;
>
> + }
>
> +
>
> + Timer = TimerInterval->AssociatedTimer;
>
> + if (Timer < 0 || Timer >= NUM_TIMERS) {
>
> + ASSERT (FALSE);
>
> + CpuDeadLoop ();
>
> + return;
>
> + }
>
> + if (mTimers[Timer].MinReqInterval > RecordInDb-
> >ChildContext.PeriodicTimer.SmiTickInterval) {
>
> + mTimers[Timer].MinReqInterval = RecordInDb-
> >ChildContext.PeriodicTimer.SmiTickInterval;
>
> + }
>
> + mTimers[Timer].NumChildren++;
>
> + }
>
> + }
>
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase,
> &RecordInDb->Link);
>
> + }
>
> + ///
>
> + /// Program the hardware
>
> + ///
>
> + if (mTimers[PERIODIC_TIMER].NumChildren > 0) {
>
> + switch (mTimers[PERIODIC_TIMER].MinReqInterval) {
>
> + case TIME_64s:
>
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate64s);
>
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_64s;
>
> + break;
>
> +
>
> + case TIME_32s:
>
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate32s);
>
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_32s;
>
> + break;
>
> +
>
> + case TIME_16s:
>
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate16s);
>
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_16s;
>
> + break;
>
> +
>
> + case TIME_8s:
>
> + PmcSetPeriodicSmiRate (PmcPeriodicSmiRate8s);
>
> + mTimers[PERIODIC_TIMER].CurrentSetting = INDEX_TIME_8s;
>
> + break;
>
> +
>
> + default:
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + ///
>
> + /// Restart the timer here, just need to clear the SMI
>
> + ///
>
> + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_PERIODIC) {
>
> + PchSmmClearSource (&mTimerSourceDesc[PERIODIC_TIMER]);
>
> + }
>
> + } else {
>
> + PchSmmDisableSource (&mTimerSourceDesc[PERIODIC_TIMER]);
>
> + }
>
> +
>
> + if (mTimers[SWSMI_TIMER].NumChildren > 0) {
>
> + switch (mTimers[SWSMI_TIMER].MinReqInterval) {
>
> + case TIME_64ms:
>
> + PmcSetSwSmiRate (PmcSwSmiRate64ms);
>
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_64ms;
>
> + break;
>
> +
>
> + case TIME_32ms:
>
> + PmcSetSwSmiRate (PmcSwSmiRate32ms);
>
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_32ms;
>
> + break;
>
> +
>
> + case TIME_16ms:
>
> + PmcSetSwSmiRate (PmcSwSmiRate16ms);
>
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_16ms;
>
> + break;
>
> +
>
> + case TIME_1_5ms:
>
> + PmcSetSwSmiRate (PmcSwSmiRate1p5ms);
>
> + mTimers[SWSMI_TIMER].CurrentSetting = INDEX_TIME_1_5ms;
>
> + break;
>
> +
>
> + default:
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + ///
>
> + /// Restart the timer here, need to disable, clear, then enable to restart
> this timer
>
> + ///
>
> + if (SrcDesc->Sts[0].Bit == N_ACPI_IO_SMI_STS_SWSMI_TMR) {
>
> + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);
>
> + PchSmmClearSource (&mTimerSourceDesc[SWSMI_TIMER]);
>
> + PchSmmEnableSource (&mTimerSourceDesc[SWSMI_TIMER]);
>
> + }
>
> + } else {
>
> + PchSmmDisableSource (&mTimerSourceDesc[SWSMI_TIMER]);
>
> + }
>
> +}
>
> +
>
> +/**
>
> + This services returns the next SMI tick period that is supported by the
> chipset.
>
> + The order returned is from longest to shortest interval period.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL instance.
>
> + @param[in, out] SmiTickInterval Pointer to pointer of the next shorter SMI
> interval period that is supported by the child.
>
> +
>
> + @retval EFI_SUCCESS The service returned successfully.
>
> + @retval EFI_INVALID_PARAMETER The parameter SmiTickInterval is
> invalid.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmPeriodicTimerDispatchGetNextShorterInterval (
>
> + IN CONST EFI_SMM_PERIODIC_TIMER_DISPATCH2_PROTOCOL *This,
>
> + IN OUT UINT64 **SmiTickInterval
>
> + )
>
> +{
>
> + TIMER_INTERVAL *IntervalPointer;
>
> +
>
> + ASSERT (SmiTickInterval != NULL);
>
> +
>
> + IntervalPointer = (TIMER_INTERVAL *) *SmiTickInterval;
>
> +
>
> + if (IntervalPointer == NULL) {
>
> + ///
>
> + /// The first time child requesting an interval
>
> + ///
>
> + IntervalPointer = &mSmmPeriodicTimerIntervals[0];
>
> + } else if (IntervalPointer ==
> &mSmmPeriodicTimerIntervals[NUM_INTERVALS - 1]) {
>
> + ///
>
> + /// At end of the list
>
> + ///
>
> + IntervalPointer = NULL;
>
> + } else {
>
> + if ((IntervalPointer >= &mSmmPeriodicTimerIntervals[0]) &&
>
> + (IntervalPointer < &mSmmPeriodicTimerIntervals[NUM_INTERVALS -
> 1])
>
> + ) {
>
> + ///
>
> + /// Get the next interval in the list
>
> + ///
>
> + IntervalPointer++;
>
> + } else {
>
> + ///
>
> + /// Input is out of range
>
> + ///
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + }
>
> +
>
> + if (IntervalPointer != NULL) {
>
> + *SmiTickInterval = &IntervalPointer->Interval;
>
> + } else {
>
> + *SmiTickInterval = NULL;
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + This function is responsible for calculating and enabling any timers that are
> required
>
> + to dispatch messages to children. The SrcDesc argument isn't acutally used.
>
> +
>
> + @param[in] SrcDesc Pointer to the PCH_SMM_SOURCE_DESC
> instance.
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PchSmmPeriodicTimerClearSource (
>
> + IN CONST PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + PchSmmPeriodicTimerProgramTimers (SrcDesc);
>
> +}
>
> +
>
> +
>
> +/**
>
> + Check if the handle is in type of PeriodicTimer
>
> +
>
> + @retval TRUE The handle is in type of PeriodicTimer.
>
> + @retval FALSE The handle is not in type of PeriodicTimer.
>
> +**/
>
> +BOOLEAN
>
> +IsSmmPeriodicTimerHandle (
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordInDb;
>
> + LIST_ENTRY *LinkInDb;
>
> +
>
> + LinkInDb = GetFirstNode (&mPrivateData.CallbackDataBase);
>
> + while (!IsNull (&mPrivateData.CallbackDataBase, LinkInDb)) {
>
> + if (DispatchHandle == (EFI_HANDLE) LinkInDb) {
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (LinkInDb);
>
> + if (RecordInDb->ProtocolType == PeriodicTimerType) {
>
> + return TRUE;
>
> + }
>
> + }
>
> + LinkInDb = GetNextNode (&mPrivateData.CallbackDataBase, LinkInDb);
>
> + }
>
> + return FALSE;
>
> +}
>
> +
>
> +/**
>
> + Pause SMM periodic timer callback function.
>
> +
>
> + This function disable the SMI enable of SMI timer according to the
> DispatchHandle,
>
> + which is returned by SMM periodic timer callback registration.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmPeriodicTimerControlPause (
>
> + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordInDb;
>
> +
>
> + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + RecordInDb->MiscData.TimerSmiEnabled = FALSE;
>
> + //
>
> + // reset the timer interval per SMI trigger due to stop a periodic timer SMI
>
> + //
>
> + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Resume SMM periodic timer callback function.
>
> +
>
> + This function enable the SMI enable of SMI timer according to the
> DispatchHandle,
>
> + which is returned by SMM periodic timer callback registration.
>
> +
>
> + @retval EFI_SUCCESS This operation is complete.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle is invalid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSmmPeriodicTimerControlResume (
>
> + IN PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + DATABASE_RECORD *RecordInDb;
>
> +
>
> + if (IsSmmPeriodicTimerHandle (DispatchHandle) == FALSE) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + RecordInDb = DATABASE_RECORD_FROM_LINK (DispatchHandle);
>
> + RecordInDb->MiscData.TimerSmiEnabled = TRUE;
>
> + //
>
> + // reset the timer interval per SMI trigger due to resume a periodic timer
> SMI
>
> + //
>
> + PchSmmPeriodicTimerProgramTimers (&RecordInDb->SrcDesc);
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED
> PCH_SMM_PERIODIC_TIMER_CONTROL_PROTOCOL
> mPchSmmPeriodicTimerControlProtocol = {
>
> + PchSmmPeriodicTimerControlPause,
>
> + PchSmmPeriodicTimerControlResume
>
> +};
>
> +
>
> +/**
>
> + Install PCH SMM periodic timer control protocol
>
> +
>
> + @param[in] Handle handle for this driver
>
> +
>
> + @retval EFI_SUCCESS Driver initialization completed successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +InstallPchSmmPeriodicTimerControlProtocol (
>
> + IN EFI_HANDLE Handle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Install protocol interface
>
> + //
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &Handle,
>
> + &gPchSmmPeriodicTimerControlGuid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPchSmmPeriodicTimerControlProtocol
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo
> werButton.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo
> werButton.c
> new file mode 100644
> index 0000000000..bfed944848
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmPo
> werButton.c
> @@ -0,0 +1,81 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Smm Power Button
> dispatch protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <PchSmmHelpers.h>
>
> +#include <Library/PmcPrivateLib.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mPowerButtonSourceDesc = {
>
> + PCH_SMM_SCI_EN_DEPENDENT,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_EN}
>
> + },
>
> + S_ACPI_IO_PM1_EN,
>
> + N_ACPI_IO_PM1_EN_PWRBTN
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_PM1_STS}
>
> + },
>
> + S_ACPI_IO_PM1_STS,
>
> + N_ACPI_IO_PM1_STS_PWRBTN
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_PM1_STS_REG
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Get the power button status.
>
> +
>
> + @param[in] Record The pointer to the DATABASE_RECORD.
>
> + @param[out] Context Calling context from the hardware, will be
> updated with the current power button status.
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +PowerButtonGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *Context
>
> + )
>
> +{
>
> + if (PmcGetPwrBtnLevel ()) {
>
> + Context->PowerButton.Phase = EfiPowerButtonExit;
>
> + } else {
>
> + Context->PowerButton.Phase = EfiPowerButtonEntry;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Check whether Power Button status of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes Power Button status 1
>
> + @param[in] Context2 Context 2 that includes Power Button status 2
>
> +
>
> + @retval FALSE Power Button status match
>
> + @retval TRUE Power Button status don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +PowerButtonCmpContext (
>
> + IN PCH_SMM_CONTEXT *Context1,
>
> + IN PCH_SMM_CONTEXT *Context2
>
> + )
>
> +{
>
> + return (BOOLEAN) (Context1->PowerButton.Phase == Context2-
> >PowerButton.Phase);
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.
> c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.
> c
> new file mode 100644
> index 0000000000..9b13bf6308
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSw.
> c
> @@ -0,0 +1,381 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Smm Sw dispatch
> protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Protocol/SmmCpu.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/PmcRegs.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED EFI_SMM_CPU_PROTOCOL
> *mSmmCpuProtocol;
>
> +
>
> +STATIC LIST_ENTRY mSwSmiCallbackDataBase;
>
> +
>
> +//
>
> +// "SWSMI" RECORD
>
> +// Linked list data structures
>
> +//
>
> +#define SW_SMI_RECORD_SIGNATURE SIGNATURE_32 ('S', 'W', 'S', 'M')
>
> +
>
> +#define SW_SMI_RECORD_FROM_LINK(_record) CR (_record,
> SW_SMI_RECORD, Link, SW_SMI_RECORD_SIGNATURE)
>
> +
>
> +typedef struct {
>
> + UINT32 Signature;
>
> + LIST_ENTRY Link;
>
> + EFI_SMM_SW_REGISTER_CONTEXT Context;
>
> + EFI_SMM_HANDLER_ENTRY_POINT2 Callback;
>
> +} SW_SMI_RECORD;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSwSourceDesc = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_APMC
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_APM
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_APM
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Check the SwSmiInputValue to see if there is a duplicated one in the
> database
>
> +
>
> + @param[in] SwSmiInputValue SwSmiInputValue
>
> +
>
> + @retval EFI_SUCCESS There is no duplicated SwSmiInputValue
>
> + @retval EFI_INVALID_PARAMETER There is a duplicated
> SwSmiInputValue
>
> +**/
>
> +EFI_STATUS
>
> +SmiInputValueDuplicateCheck (
>
> + IN UINTN SwSmiInputValue
>
> + )
>
> +{
>
> + SW_SMI_RECORD *SwSmiRecord;
>
> + LIST_ENTRY *LinkInDb;
>
> +
>
> + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase);
>
> + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
>
> + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
>
> + if (SwSmiRecord->Context.SwSmiInputValue == SwSmiInputValue) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord-
> >Link);
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Register a child SMI source dispatch function for the specified software
> SMI.
>
> +
>
> + This service registers a function (DispatchFunction) which will be called
> when the software
>
> + SMI source specified by RegisterContext->SwSmiCpuIndex is detected. On
> return,
>
> + DispatchHandle contains a unique handle which may be used later to
> unregister the function
>
> + using UnRegister().
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchFunction Function to register for handler when the
> specified software
>
> + SMI is generated.
>
> + @param[in, out] RegisterContext Pointer to the dispatch function's
> context.
>
> + The caller fills this context in before calling
>
> + the register function to indicate to the register
>
> + function which Software SMI input value the
>
> + dispatch function should be invoked for.
>
> + @param[out] DispatchHandle Handle generated by the dispatcher to
> track the
>
> + function instance.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
>
> + registered and the SMI source has been enabled.
>
> + @retval EFI_DEVICE_ERROR The SW driver was unable to enable the
> SMI source.
>
> + @retval EFI_INVALID_PARAMETER RegisterContext is invalid. The SW SMI
> input value
>
> + is not within a valid range or is already in use.
>
> + @retval EFI_OUT_OF_RESOURCES There is not enough memory (system
> or SMM) to manage this
>
> + child.
>
> + @retval EFI_OUT_OF_RESOURCES A unique software SMI value could not
> be assigned
>
> + for this dispatch.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSwSmiRegister (
>
> + IN EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_SMM_HANDLER_ENTRY_POINT2 DispatchFunction,
>
> + IN EFI_SMM_SW_REGISTER_CONTEXT *DispatchContext,
>
> + OUT EFI_HANDLE *DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + SW_SMI_RECORD *SwSmiRecord;
>
> + UINTN Index;
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "Register is not allowed if the SmmReadyToLock
> event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + //
>
> + // Find available SW SMI value if the input is -1
>
> + //
>
> + if (DispatchContext->SwSmiInputValue == (UINTN) -1) {
>
> + for (Index = 1; Index < MAXIMUM_SWI_VALUE; Index++) {
>
> + if (!EFI_ERROR (SmiInputValueDuplicateCheck (Index))) {
>
> + DispatchContext->SwSmiInputValue = Index;
>
> + break;
>
> + }
>
> + }
>
> + if (DispatchContext->SwSmiInputValue == (UINTN) -1) {
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + }
>
> + //
>
> + // Check if it's a valid SW SMI value.
>
> + // The value must not bigger than 0xFF.
>
> + // And the value must not be 0xFF sincie it's used for SmmControll
> protocol.
>
> + //
>
> + if (DispatchContext->SwSmiInputValue >= MAXIMUM_SWI_VALUE) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + if (EFI_ERROR (SmiInputValueDuplicateCheck (DispatchContext-
> >SwSmiInputValue))) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Create database record and add to database
>
> + //
>
> + Status = gSmst->SmmAllocatePool (
>
> + EfiRuntimeServicesData,
>
> + sizeof (SW_SMI_RECORD),
>
> + (VOID **) &SwSmiRecord
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + DEBUG ((DEBUG_ERROR, "Failed to allocate memory for SwSmiRecord!
> \n"));
>
> + return EFI_OUT_OF_RESOURCES;
>
> + }
>
> + //
>
> + // Gather information about the registration request
>
> + //
>
> + SwSmiRecord->Signature = SW_SMI_RECORD_SIGNATURE;
>
> + SwSmiRecord->Context.SwSmiInputValue = DispatchContext-
> >SwSmiInputValue;
>
> + SwSmiRecord->Callback = DispatchFunction;
>
> + //
>
> + // Publish the S/W SMI numbers in Serial logs used for Debug build.
>
> + //
>
> + DEBUG ((DEBUG_INFO, "SW SMI NUM %x Sw Record at Address 0x%X\n",
> SwSmiRecord->Context.SwSmiInputValue, SwSmiRecord));
>
> +
>
> + InsertTailList (&mSwSmiCallbackDataBase, &SwSmiRecord->Link);
>
> +
>
> + //
>
> + // Child's handle will be the address linked list link in the record
>
> + //
>
> + *DispatchHandle = (EFI_HANDLE) (&SwSmiRecord->Link);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Unregister a child SMI source dispatch function for the specified software
> SMI.
>
> +
>
> + This service removes the handler associated with DispatchHandle so that it
> will no longer be
>
> + called in response to a software SMI.
>
> +
>
> + @param[in] This Pointer to the
> EFI_SMM_SW_DISPATCH2_PROTOCOL instance.
>
> + @param[in] DispatchHandle Handle of dispatch function to deregister.
>
> +
>
> + @retval EFI_SUCCESS The dispatch function has been successfully
> unregistered.
>
> + @retval EFI_INVALID_PARAMETER The DispatchHandle was not valid.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSwSmiUnRegister (
>
> + IN CONST EFI_SMM_SW_DISPATCH2_PROTOCOL *This,
>
> + IN EFI_HANDLE DispatchHandle
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + SW_SMI_RECORD *RecordToDelete;
>
> +
>
> + if (DispatchHandle == 0) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + //
>
> + // Return access denied if the SmmReadyToLock event has been triggered
>
> + //
>
> + if (mReadyToLock == TRUE) {
>
> + DEBUG ((DEBUG_ERROR, "UnRegister is not allowed if the
> SmmReadyToLock event has been triggered! \n"));
>
> + return EFI_ACCESS_DENIED;
>
> + }
>
> +
>
> + RecordToDelete = SW_SMI_RECORD_FROM_LINK (DispatchHandle);
>
> + //
>
> + // Take the entry out of the linked list
>
> + //
>
> + if (RecordToDelete->Signature != SW_SMI_RECORD_SIGNATURE) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + RemoveEntryList (&RecordToDelete->Link);
>
> + ZeroMem (RecordToDelete, sizeof (SW_SMI_RECORD));
>
> + Status = gSmst->SmmFreePool (RecordToDelete);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Main entry point for an SMM handler dispatch or communicate-based
> callback.
>
> +
>
> + @param[in] DispatchHandle The unique handle assigned to this handler
> by SmiHandlerRegister().
>
> + @param[in] Context Points to an optional handler context which was
> specified when the
>
> + handler was registered.
>
> + @param[in,out] CommBuffer A pointer to a collection of data in
> memory that will
>
> + be conveyed from a non-SMM environment into an SMM
> environment.
>
> + @param[in,out] CommBufferSize The size of the CommBuffer.
>
> +
>
> + @retval EFI_SUCCESS The interrupt was handled and quiesced.
> No other handlers
>
> + should still be called.
>
> + @retval EFI_WARN_INTERRUPT_SOURCE_QUIESCED The interrupt has
> been quiesced but other handlers should
>
> + still be called.
>
> + @retval EFI_WARN_INTERRUPT_SOURCE_PENDING The interrupt is still
> pending and other handlers should still
>
> + be called.
>
> + @retval EFI_INTERRUPT_PENDING The interrupt could not be
> quiesced.
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +PchSwSmiDispatcher (
>
> + IN EFI_HANDLE DispatchHandle,
>
> + IN CONST VOID *Context,
>
> + IN OUT VOID *CommBuffer,
>
> + IN OUT UINTN *CommBufferSize
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_SMM_SAVE_STATE_IO_INFO SmiIoInfo;
>
> + UINTN CpuIndex;
>
> + SW_SMI_RECORD *SwSmiRecord;
>
> + LIST_ENTRY *LinkInDb;
>
> + EFI_SMM_SW_CONTEXT SwSmiCommBuffer;
>
> + UINTN SwSmiCommBufferSize;
>
> +
>
> + SwSmiCommBufferSize = sizeof (EFI_SMM_SW_CONTEXT);
>
> + //
>
> + // The value in DataPort might not be accurate in multiple thread
> environment.
>
> + // There might be racing condition for R_PCH_IO_APM_STS port.
>
> + // Therefor, this is just for reference.
>
> + //
>
> + SwSmiCommBuffer.DataPort = IoRead8 (R_PCH_IO_APM_STS);
>
> +
>
> + for (CpuIndex = 0; CpuIndex < gSmst->NumberOfCpus; CpuIndex++) {
>
> + Status = mSmmCpuProtocol->ReadSaveState (
>
> + mSmmCpuProtocol,
>
> + sizeof (EFI_SMM_SAVE_STATE_IO_INFO),
>
> + EFI_SMM_SAVE_STATE_REGISTER_IO,
>
> + CpuIndex,
>
> + &SmiIoInfo
>
> + );
>
> + //
>
> + // If this is not the SMI source, skip it.
>
> + //
>
> + if (EFI_ERROR (Status)) {
>
> + continue;
>
> + }
>
> + //
>
> + // If the IO address is not "BYTE" "WRITE" to "R_PCH_IO_APM_CNT
> (0xB2)", skip it.
>
> + //
>
> + if ((SmiIoInfo.IoPort != R_PCH_IO_APM_CNT) ||
>
> + (SmiIoInfo.IoType != EFI_SMM_SAVE_STATE_IO_TYPE_OUTPUT) ||
>
> + (SmiIoInfo.IoWidth != EFI_SMM_SAVE_STATE_IO_WIDTH_UINT8))
>
> + {
>
> + continue;
>
> + }
>
> + //
>
> + // If the IO data is used for SmmControl protocol, skip it.
>
> + //
>
> + if (SmiIoInfo.IoData == 0xFF) {
>
> + continue;
>
> + }
>
> +
>
> + SwSmiCommBuffer.SwSmiCpuIndex = CpuIndex;
>
> + SwSmiCommBuffer.CommandPort = (UINT8) SmiIoInfo.IoData;
>
> +
>
> + LinkInDb = GetFirstNode (&mSwSmiCallbackDataBase);
>
> + while (!IsNull (&mSwSmiCallbackDataBase, LinkInDb)) {
>
> + SwSmiRecord = SW_SMI_RECORD_FROM_LINK (LinkInDb);
>
> + if (SwSmiRecord->Context.SwSmiInputValue == SmiIoInfo.IoData) {
>
> + SwSmiRecord->Callback ((EFI_HANDLE) &SwSmiRecord->Link,
> &SwSmiRecord->Context, &SwSmiCommBuffer, &SwSmiCommBufferSize);
>
> + }
>
> + LinkInDb = GetNextNode (&mSwSmiCallbackDataBase, &SwSmiRecord-
> >Link);
>
> + }
>
> + }
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Init required protocol for Pch Sw Dispatch protocol.
>
> +**/
>
> +VOID
>
> +PchSwDispatchInit (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_HANDLE DispatchHandle;
>
> + DATABASE_RECORD Record;
>
> +
>
> + //
>
> + // Locate PI SMM CPU protocol
>
> + //
>
> + Status = gSmst->SmmLocateProtocol (&gEfiSmmCpuProtocolGuid, NULL,
> (VOID **)&mSmmCpuProtocol);
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Initialize SW SMI Callback DataBase
>
> + //
>
> + InitializeListHead (&mSwSmiCallbackDataBase);
>
> +
>
> + //
>
> + // Insert SwSmi handler to PchSmmCore database
>
> + // There will always be one SwType record in PchSmmCore database
>
> + //
>
> + ZeroMem (&Record, sizeof (DATABASE_RECORD));
>
> + Record.Signature = DATABASE_RECORD_SIGNATURE;
>
> + Record.Callback = PchSwSmiDispatcher;
>
> + Record.ProtocolType = SwType;
>
> +
>
> + CopyMem (&Record.SrcDesc, &mSwSourceDesc, sizeof
> (PCH_SMM_SOURCE_DESC));
>
> +
>
> + DispatchHandle = NULL;
>
> + Status = SmmCoreInsertRecord (
>
> + &Record,
>
> + &DispatchHandle
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
> new file mode 100644
> index 0000000000..7d79f21dbd
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmSx.c
> @@ -0,0 +1,224 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Smm Sx dispatch
> protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Register/PmcRegs.h>
>
> +#include <Register/PchPcieRpRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include "PchSmiHelper.h"
>
> +
>
> +extern BOOLEAN mS3SusStart;
>
> +#define PROGRESS_CODE_S3_SUSPEND_END PcdGet32
> (PcdProgressCodeS3SuspendEnd)
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mSxSourceDesc = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_ON_SLP_EN
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_ON_SLP_EN
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_ON_SLP_EN
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Get the Sleep type
>
> +
>
> + @param[in] Record No use
>
> + @param[out] Context The context that includes SLP_TYP bits to be
> filled
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +SxGetContext (
>
> + IN DATABASE_RECORD *Record,
>
> + OUT PCH_SMM_CONTEXT *Context
>
> + )
>
> +{
>
> + UINT32 Pm1Cnt;
>
> +
>
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
>
> +
>
> + ///
>
> + /// By design, the context phase will always be ENTRY
>
> + ///
>
> + Context->Sx.Phase = SxEntry;
>
> +
>
> + ///
>
> + /// Map the PM1_CNT register's SLP_TYP bits to the context type
>
> + ///
>
> + switch (Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) {
>
> + case V_ACPI_IO_PM1_CNT_S0:
>
> + Context->Sx.Type = SxS0;
>
> + break;
>
> +
>
> + case V_ACPI_IO_PM1_CNT_S1:
>
> + Context->Sx.Type = SxS1;
>
> + break;
>
> +
>
> + case V_ACPI_IO_PM1_CNT_S3:
>
> + Context->Sx.Type = SxS3;
>
> + break;
>
> +
>
> + case V_ACPI_IO_PM1_CNT_S4:
>
> + Context->Sx.Type = SxS4;
>
> + break;
>
> +
>
> + case V_ACPI_IO_PM1_CNT_S5:
>
> + Context->Sx.Type = SxS5;
>
> + break;
>
> +
>
> + default:
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Check whether sleep type of two contexts match
>
> +
>
> + @param[in] Context1 Context 1 that includes sleep type 1
>
> + @param[in] Context2 Context 2 that includes sleep type 2
>
> +
>
> + @retval FALSE Sleep types match
>
> + @retval TRUE Sleep types don't match
>
> +**/
>
> +BOOLEAN
>
> +EFIAPI
>
> +SxCmpContext (
>
> + IN PCH_SMM_CONTEXT *Context1,
>
> + IN PCH_SMM_CONTEXT *Context2
>
> + )
>
> +{
>
> + return (BOOLEAN) (Context1->Sx.Type == Context2->Sx.Type);
>
> +}
>
> +
>
> +/**
>
> + For each PCIE RP clear PME SCI status and disable SCI, then
> PCIEXP_WAKE_STS from PMC.
>
> + This prevents platform from waking more than one time due to a single
> PCIE wake event.
>
> + Normally it's up to OS to clear SCI statuses. But in a scenario where
> platform wakes
>
> + and goes to S5 instead of booting to OS, the SCI status would remain set
> and would trigger another wake.
>
> +**/
>
> +VOID
>
> +ClearPcieSci (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 MaxPorts;
>
> + UINT32 RpIndex;
>
> + UINT64 RpBase;
>
> +
>
> + MaxPorts = GetPchMaxPciePortNum ();
>
> + for (RpIndex = 0; RpIndex < MaxPorts; RpIndex++) {
>
> + RpBase = PchPcieRpPciCfgBase (RpIndex);
>
> + if (PciSegmentRead16 (RpBase + PCI_VENDOR_ID_OFFSET) != 0xFFFF) {
>
> + PciSegmentAnd8 ((RpBase + R_PCH_PCIE_CFG_MPC + 3),
> (UINT8)~((UINT8)(B_PCH_PCIE_CFG_MPC_PMCE >> 24)));
>
> + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_SMSCS,
> B_PCH_PCIE_CFG_SMSCS_PMCS);
>
> + }
>
> + }
>
> + IoWrite16 (mAcpiBaseAddr + R_ACPI_IO_PM1_STS,
> B_ACPI_IO_PM1_STS_PCIEXP_WAKE_STS);
>
> +}
>
> +
>
> +
>
> +/**
>
> + When we get an SMI that indicates that we are transitioning to a sleep
> state,
>
> + we need to actually transition to that state. We do this by disabling the
>
> + "SMI on sleep enable" feature, which generates an SMI when the
> operating system
>
> + tries to put the system to sleep, and then physically putting the system to
> sleep.
>
> +
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmSxGoToSleep (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 Pm1Cnt;
>
> +
>
> + ClearPcieSci ();
>
> +
>
> + ///
>
> + /// Disable SMIs
>
> + ///
>
> + PchSmmClearSource (&mSxSourceDesc);
>
> + PchSmmDisableSource (&mSxSourceDesc);
>
> +
>
> + ///
>
> + /// Get Power Management 1 Control Register Value
>
> + ///
>
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
>
> +
>
> + ///
>
> + /// Record S3 suspend performance data
>
> + ///
>
> + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) ==
> V_ACPI_IO_PM1_CNT_S3) {
>
> + ///
>
> + /// Report status code before goto S3 sleep
>
> + ///
>
> + REPORT_STATUS_CODE (EFI_PROGRESS_CODE,
> PROGRESS_CODE_S3_SUSPEND_END);
>
> + mS3SusStart = FALSE;
>
> + ///
>
> + /// Write back cache into memory and invalidate cache before going to
> sleep.
>
> + ///
>
> + AsmWbinvd ();
>
> + }
>
> +
>
> + ///
>
> + /// Now that SMIs are disabled, write to the SLP_EN bit again to trigger the
> sleep
>
> + ///
>
> + Pm1Cnt |= B_ACPI_IO_PM1_CNT_SLP_EN;
>
> +
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);
>
> +
>
> + ///
>
> + /// Should only proceed if wake event is generated.
>
> + ///
>
> + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SLP_TYP) ==
> V_ACPI_IO_PM1_CNT_S1) {
>
> + while (((IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS))) &
> B_ACPI_IO_PM1_STS_WAK) == 0x0);
>
> + } else {
>
> + CpuDeadLoop ();
>
> + }
>
> + ///
>
> + /// The system just went to sleep. If the sleep state was S1, then code
> execution will resume
>
> + /// here when the system wakes up.
>
> + ///
>
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
>
> +
>
> + if ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) == 0) {
>
> + ///
>
> + /// An ACPI OS isn't present, clear the sleep information
>
> + ///
>
> + Pm1Cnt &= ~B_ACPI_IO_PM1_CNT_SLP_TYP;
>
> + Pm1Cnt |= V_ACPI_IO_PM1_CNT_S0;
>
> +
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT), Pm1Cnt);
>
> + }
>
> +
>
> + PchSmmClearSource (&mSxSourceDesc);
>
> + PchSmmEnableSource (&mSxSourceDesc);
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb
> .c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb
> .c
> new file mode 100644
> index 0000000000..a0c67bd959
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchSmmUsb
> .c
> @@ -0,0 +1,230 @@
> +/** @file
>
> + File to contain all the hardware specific stuff for the Smm USB dispatch
> protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Register/UsbRegs.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/PmcRegs.h>
>
> +#include <Library/PchPciBdfLib.h>
>
> +#include <PchBdfAssignment.h>
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mUsb1Legacy = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_LEGACY_USB
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_LEGACY_USB
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_LEGACY_USB
>
> + }
>
> +};
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED CONST PCH_SMM_SOURCE_DESC
> mUsb3Legacy = {
>
> + PCH_SMM_NO_FLAGS,
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_EN}
>
> + },
>
> + S_ACPI_IO_SMI_EN,
>
> + N_ACPI_IO_SMI_EN_LEGACY_USB3
>
> + },
>
> + NULL_BIT_DESC_INITIALIZER
>
> + },
>
> + {
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_LEGACY_USB3
>
> + }
>
> + },
>
> + {
>
> + {
>
> + ACPI_ADDR_TYPE,
>
> + {R_ACPI_IO_SMI_STS}
>
> + },
>
> + S_ACPI_IO_SMI_STS,
>
> + N_ACPI_IO_SMI_STS_LEGACY_USB3
>
> + }
>
> +};
>
> +
>
> +typedef enum {
>
> + PchUsbControllerLpc0 = 0,
>
> + PchUsbControllerXhci,
>
> + PchUsbControllerTypeMax
>
> +} PCH_USB_CONTROLLER_TYPE;
>
> +
>
> +typedef struct {
>
> + UINT8 Function;
>
> + UINT8 Device;
>
> + PCH_USB_CONTROLLER_TYPE UsbConType;
>
> +} USB_CONTROLLER;
>
> +
>
> +GLOBAL_REMOVE_IF_UNREFERENCED USB_CONTROLLER
> mUsbControllersMap[] = {
>
> + {
>
> + PCI_FUNCTION_NUMBER_PCH_LPC,
>
> + PCI_DEVICE_NUMBER_PCH_LPC,
>
> + PchUsbControllerLpc0
>
> + },
>
> + {
>
> + PCI_FUNCTION_NUMBER_PCH_XHCI,
>
> + PCI_DEVICE_NUMBER_PCH_XHCI,
>
> + PchUsbControllerXhci
>
> + }
>
> +};
>
> +
>
> +/**
>
> + Find the handle that best matches the input Device Path and return the
> USB controller type
>
> +
>
> + @param[in] DevicePath Pointer to the device Path table
>
> + @param[out] Controller Returned with the USB controller type of the
> input device path
>
> +
>
> + @retval EFI_SUCCESS Find the handle that best matches the input
> Device Path
>
> + @exception EFI_UNSUPPORTED Invalid device Path table or can't find
> any match USB device path
>
> + PCH_USB_CONTROLLER_TYPE The USB controller type of
> the input
>
> + device path
>
> +**/
>
> +EFI_STATUS
>
> +DevicePathToSupportedController (
>
> + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
>
> + OUT PCH_USB_CONTROLLER_TYPE *Controller
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_HANDLE DeviceHandle;
>
> + ACPI_HID_DEVICE_PATH *AcpiNode;
>
> + PCI_DEVICE_PATH *PciNode;
>
> + EFI_DEVICE_PATH_PROTOCOL *RemaingDevicePath;
>
> + UINT8 UsbIndex;
>
> + ///
>
> + /// Find the handle that best matches the Device Path. If it is only a
>
> + /// partial match the remaining part of the device path is returned in
>
> + /// RemainingDevicePath.
>
> + ///
>
> + RemaingDevicePath = DevicePath;
>
> + Status = gBS->LocateDevicePath (
>
> + &gEfiPciRootBridgeIoProtocolGuid,
>
> + &DevicePath,
>
> + &DeviceHandle
>
> + );
>
> + if (EFI_ERROR (Status)) {
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +
>
> + DevicePath = RemaingDevicePath;
>
> +
>
> + ///
>
> + /// Get first node: Acpi Node
>
> + ///
>
> + AcpiNode = (ACPI_HID_DEVICE_PATH *) RemaingDevicePath;
>
> +
>
> + if (AcpiNode->Header.Type != ACPI_DEVICE_PATH ||
>
> + AcpiNode->Header.SubType != ACPI_DP ||
>
> + DevicePathNodeLength (&AcpiNode->Header) != sizeof
> (ACPI_HID_DEVICE_PATH) ||
>
> + AcpiNode->HID != EISA_PNP_ID (0x0A03) ||
>
> + AcpiNode->UID != 0
>
> + ) {
>
> + return EFI_UNSUPPORTED;
>
> + } else {
>
> + ///
>
> + /// Get the next node: Pci Node
>
> + ///
>
> + RemaingDevicePath = NextDevicePathNode (RemaingDevicePath);
>
> + PciNode = (PCI_DEVICE_PATH *) RemaingDevicePath;
>
> + if (PciNode->Header.Type != HARDWARE_DEVICE_PATH ||
>
> + PciNode->Header.SubType != HW_PCI_DP ||
>
> + DevicePathNodeLength (&PciNode->Header) != sizeof
> (PCI_DEVICE_PATH)
>
> + ) {
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +
>
> + for (UsbIndex = 0; UsbIndex < sizeof (mUsbControllersMap) / sizeof
> (USB_CONTROLLER); UsbIndex++) {
>
> + if ((PciNode->Device == mUsbControllersMap[UsbIndex].Device) &&
>
> + (PciNode->Function == mUsbControllersMap[UsbIndex].Function)) {
>
> + *Controller = mUsbControllersMap[UsbIndex].UsbConType;
>
> + return EFI_SUCCESS;
>
> + }
>
> + }
>
> +
>
> + return EFI_UNSUPPORTED;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Maps a USB context to a source description.
>
> +
>
> + @param[in] Context The context we need to map. Type must be
> USB.
>
> + @param[in] SrcDesc The source description that corresponds to the
> given context.
>
> +
>
> +**/
>
> +VOID
>
> +MapUsbToSrcDesc (
>
> + IN PCH_SMM_CONTEXT *Context,
>
> + OUT PCH_SMM_SOURCE_DESC *SrcDesc
>
> + )
>
> +{
>
> + PCH_USB_CONTROLLER_TYPE Controller;
>
> + EFI_STATUS Status;
>
> +
>
> + Status = DevicePathToSupportedController (Context->Usb.Device,
> &Controller);
>
> + ///
>
> + /// Either the device path passed in by the child is incorrect or
>
> + /// the ones stored here internally are incorrect.
>
> + ///
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + switch (Context->Usb.Type) {
>
> + case UsbLegacy:
>
> + switch (Controller) {
>
> + case PchUsbControllerLpc0:
>
> + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb1Legacy), sizeof
> (PCH_SMM_SOURCE_DESC));
>
> + break;
>
> +
>
> + case PchUsbControllerXhci:
>
> + CopyMem ((VOID *) SrcDesc, (VOID *) (&mUsb3Legacy), sizeof
> (PCH_SMM_SOURCE_DESC));
>
> + break;
>
> +
>
> + default:
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + break;
>
> +
>
> + case UsbWake:
>
> + ASSERT (FALSE);
>
> + break;
>
> +
>
> + default:
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.c
> new file mode 100644
> index 0000000000..a0b7e37d46
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.c
> @@ -0,0 +1,778 @@
> +/** @file
>
> + This driver is responsible for the registration of child drivers
>
> + and the abstraction of the PCH SMI sources.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include "PchSmmHelpers.h"
>
> +#include <Register/PchRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +
>
> +//
>
> +// Help handle porting bit shifts to IA-64.
>
> +//
>
> +#define BIT_ZERO 0x00000001
>
> +
>
> +/**
>
> + Publish SMI Dispatch protocols.
>
> +
>
> +
>
> +**/
>
> +VOID
>
> +PchSmmPublishDispatchProtocols (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status = EFI_SUCCESS;
>
> + UINTN Index;
>
> + //
>
> + // Install protocol interfaces.
>
> + //
>
> + for (Index = 0; Index < PCH_SMM_PROTOCOL_TYPE_MAX; Index++) {
>
> + Status = gSmst->SmmInstallProtocolInterface (
>
> + &mPrivateData.InstallMultProtHandle,
>
> + mPrivateData.Protocols[Index].Guid,
>
> + EFI_NATIVE_INTERFACE,
>
> + &mPrivateData.Protocols[Index].Protocols.Generic
>
> + );
>
> + }
>
> + ASSERT_EFI_ERROR (Status);
>
> +}
>
> +
>
> +/**
>
> + Initialize bits that aren't necessarily related to an SMI source.
>
> +
>
> +
>
> + @retval EFI_SUCCESS SMI source initialization completed.
>
> + @retval Asserts Global Smi Bit is not enabled successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmInitHardware (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> +
>
> + //
>
> + // Clear all SMIs
>
> + //
>
> + PchSmmClearSmi ();
>
> +
>
> + Status = PchSmmEnableGlobalSmiBit ();
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + //
>
> + // Be *really* sure to clear all SMIs
>
> + //
>
> + PchSmmClearSmi ();
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Enables the PCH to generate SMIs. Note that no SMIs will be generated
>
> + if no SMI sources are enabled. Conversely, no enabled SMI source will
>
> + generate SMIs if SMIs are not globally enabled. This is the main
>
> + switchbox for SMI generation.
>
> +
>
> +
>
> + @retval EFI_SUCCESS Enable Global Smi Bit completed
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmEnableGlobalSmiBit (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 SmiEn;
>
> +
>
> + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
>
> +
>
> + //
>
> + // Set the "global smi enable" bit
>
> + //
>
> + SmiEn |= B_ACPI_IO_SMI_EN_GBL_SMI;
>
> +
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Clears the SMI after all SMI source have been processed.
>
> + Note that this function will not work correctly (as it is
>
> + written) unless all SMI sources have been processed.
>
> + A revision of this function could manually clear all SMI
>
> + status bits to guarantee success.
>
> +
>
> +
>
> + @retval EFI_SUCCESS Clears the SMIs completed
>
> + @retval Asserts EOS was not set to a 1
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmClearSmi (
>
> + VOID
>
> + )
>
> +{
>
> + BOOLEAN EosSet;
>
> + BOOLEAN SciEn;
>
> + UINT32 Pm1Cnt;
>
> + UINT16 Pm1Sts;
>
> + UINT32 Gpe0Sts;
>
> + UINT32 SmiSts;
>
> + UINT16 DevActSts;
>
> + UINT16 Tco1Sts;
>
> +
>
> + Gpe0Sts = 0;
>
> + //
>
> + // Determine whether an ACPI OS is present (via the SCI_EN bit)
>
> + //
>
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
>
> + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) ==
> B_ACPI_IO_PM1_CNT_SCI_EN);
>
> + if (!SciEn) {
>
> + //
>
> + // Clear any SMIs that double as SCIs (when SCI_EN==0)
>
> + //
>
> + Pm1Sts = IoRead16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS));
>
> + Gpe0Sts = IoRead32 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_GPE0_STS_127_96));
>
> +
>
> + Pm1Sts |=
>
> + (
>
> + B_ACPI_IO_PM1_STS_WAK |
>
> + B_ACPI_IO_PM1_STS_PRBTNOR |
>
> + B_ACPI_IO_PM1_STS_RTC |
>
> + B_ACPI_IO_PM1_STS_PWRBTN |
>
> + B_ACPI_IO_PM1_STS_GBL |
>
> + B_ACPI_IO_PM1_STS_TMROF
>
> + );
>
> +
>
> + Gpe0Sts |=
>
> + (
>
> + B_ACPI_IO_GPE0_STS_127_96_WADT |
>
> + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |
>
> + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |
>
> + B_ACPI_IO_GPE0_STS_127_96_PME_B0 |
>
> + B_ACPI_IO_GPE0_STS_127_96_PME |
>
> + B_ACPI_IO_GPE0_STS_127_96_BATLOW |
>
> + B_ACPI_IO_GPE0_STS_127_96_RI |
>
> + B_ACPI_IO_GPE0_STS_127_96_SWGPE
>
> + );
>
> +
>
> + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_STS), (UINT16)
> Pm1Sts);
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_GPE0_STS_127_96),
> (UINT32) Gpe0Sts);
>
> + }
>
> + //
>
> + // Clear all SMIs that are unaffected by SCI_EN
>
> + //
>
> + SmiSts = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS));
>
> + DevActSts = IoRead16 ((UINTN) (mAcpiBaseAddr +
> R_ACPI_IO_DEVACT_STS));
>
> + Tco1Sts = IoRead16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS));
>
> +
>
> + SmiSts |=
>
> + (
>
> + B_ACPI_IO_SMI_STS_SMBUS |
>
> + B_ACPI_IO_SMI_STS_PERIODIC |
>
> + B_ACPI_IO_SMI_STS_TCO |
>
> + B_ACPI_IO_SMI_STS_MCSMI |
>
> + B_ACPI_IO_SMI_STS_SWSMI_TMR |
>
> + B_ACPI_IO_SMI_STS_APM |
>
> + B_ACPI_IO_SMI_STS_ON_SLP_EN |
>
> + B_ACPI_IO_SMI_STS_BIOS
>
> + );
>
> + DevActSts |=
>
> + (
>
> + B_ACPI_IO_DEVACT_STS_KBC |
>
> + B_ACPI_IO_DEVACT_STS_PIRQDH |
>
> + B_ACPI_IO_DEVACT_STS_PIRQCG |
>
> + B_ACPI_IO_DEVACT_STS_PIRQBF |
>
> + B_ACPI_IO_DEVACT_STS_PIRQAE
>
> + );
>
> + Tco1Sts |=
>
> + (
>
> + B_TCO_IO_TCO1_STS_DMISERR |
>
> + B_TCO_IO_TCO1_STS_DMISMI |
>
> + B_TCO_IO_TCO1_STS_DMISCI |
>
> + B_TCO_IO_TCO1_STS_BIOSWR |
>
> + B_TCO_IO_TCO1_STS_NEWCENTURY |
>
> + B_TCO_IO_TCO1_STS_TIMEOUT |
>
> + B_TCO_IO_TCO1_STS_TCO_INT |
>
> + B_TCO_IO_TCO1_STS_SW_TCO_SMI
>
> + );
>
> +
>
> + GpioClearAllGpiSmiSts ();
>
> +
>
> + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO1_STS), Tco1Sts);
>
> +
>
> + //
>
> + // We do not want to write 1 to clear INTRD_DET bit.
>
> + //
>
> + IoWrite16 ((UINTN) (mTcoBaseAddr + R_TCO_IO_TCO2_STS), (UINT16)
> ~B_TCO_IO_TCO2_STS_INTRD_DET);
>
> +
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_STS), SmiSts);
>
> +
>
> + IoWrite16 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_DEVACT_STS),
> DevActSts);
>
> +
>
> + //
>
> + // Try to clear the EOS bit. ASSERT on an error
>
> + //
>
> + EosSet = PchSmmSetAndCheckEos ();
>
> + ASSERT (EosSet);
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Set the SMI EOS bit after all SMI source have been processed.
>
> +
>
> +
>
> + @retval FALSE EOS was not set to a 1; this is an error
>
> + @retval TRUE EOS was correctly set to a 1
>
> +**/
>
> +BOOLEAN
>
> +PchSmmSetAndCheckEos (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 SmiEn;
>
> +
>
> + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
>
> +
>
> + //
>
> + // Reset the PCH to generate subsequent SMIs
>
> + //
>
> + SmiEn |= B_ACPI_IO_SMI_EN_EOS;
>
> +
>
> + IoWrite32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN), SmiEn);
>
> +
>
> + //
>
> + // Double check that the assert worked
>
> + //
>
> + SmiEn = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_SMI_EN));
>
> +
>
> + //
>
> + // Return TRUE if EOS is set correctly
>
> + //
>
> + if ((SmiEn & B_ACPI_IO_SMI_EN_EOS) == 0) {
>
> + //
>
> + // EOS was not set to a 1; this is an error
>
> + //
>
> + return FALSE;
>
> + } else {
>
> + //
>
> + // EOS was correctly set to a 1
>
> + //
>
> + return TRUE;
>
> + }
>
> +}
>
> +
>
> +/**
>
> + Determine whether an ACPI OS is present (via the SCI_EN bit)
>
> +
>
> +
>
> + @retval TRUE ACPI OS is present
>
> + @retval FALSE ACPI OS is not present
>
> +**/
>
> +BOOLEAN
>
> +PchSmmGetSciEn (
>
> + VOID
>
> + )
>
> +{
>
> + BOOLEAN SciEn;
>
> + UINT32 Pm1Cnt;
>
> +
>
> + //
>
> + // Determine whether an ACPI OS is present (via the SCI_EN bit)
>
> + //
>
> + Pm1Cnt = IoRead32 ((UINTN) (mAcpiBaseAddr + R_ACPI_IO_PM1_CNT));
>
> + SciEn = (BOOLEAN) ((Pm1Cnt & B_ACPI_IO_PM1_CNT_SCI_EN) ==
> B_ACPI_IO_PM1_CNT_SCI_EN);
>
> +
>
> + return SciEn;
>
> +}
>
> +
>
> +/**
>
> + Read a specifying bit with the register
>
> + These may or may not need to change w/ the PCH version; they're highly
> IA-32 dependent, though.
>
> +
>
> + @param[in] BitDesc The struct that includes register address, size in
> byte and bit number
>
> +
>
> + @retval TRUE The bit is enabled
>
> + @retval FALSE The bit is disabled
>
> +**/
>
> +BOOLEAN
>
> +ReadBitDesc (
>
> + CONST PCH_SMM_BIT_DESC *BitDesc
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT64 Register;
>
> + UINT32 PciBus;
>
> + UINT32 PciDev;
>
> + UINT32 PciFun;
>
> + UINT32 PciReg;
>
> + UINTN RegSize;
>
> + BOOLEAN BitWasOne;
>
> + UINTN ShiftCount;
>
> + UINTN RegisterOffset;
>
> + UINT32 BaseAddr;
>
> + UINT64 PciBaseAddress;
>
> +
>
> + ASSERT (BitDesc != NULL);
>
> + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
>
> +
>
> + RegSize = 0;
>
> + Register = 0;
>
> + ShiftCount = 0;
>
> + BitWasOne = FALSE;
>
> +
>
> + switch (BitDesc->Reg.Type) {
>
> +
>
> + case ACPI_ADDR_TYPE:
>
> + case TCO_ADDR_TYPE:
>
> + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
>
> + RegisterOffset = BitDesc->Reg.Data.acpi;
>
> + BaseAddr = mAcpiBaseAddr;
>
> + } else {
>
> + RegisterOffset = BitDesc->Reg.Data.tco;
>
> + BaseAddr = mTcoBaseAddr;
>
> + }
>
> + switch (BitDesc->SizeInBytes) {
>
> +
>
> + case 0:
>
> + //
>
> + // Chances are that this field didn't get initialized.
>
> + // Check your assignments to bit descriptions.
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> +
>
> + case 1:
>
> + RegSize = SMM_IO_UINT8;
>
> + break;
>
> +
>
> + case 2:
>
> + RegSize = SMM_IO_UINT16;
>
> + break;
>
> +
>
> + case 4:
>
> + RegSize = SMM_IO_UINT32;
>
> + break;
>
> +
>
> + case 8:
>
> + RegSize = SMM_IO_UINT64;
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + //
>
> + // Double check that we correctly read in the acpi base address
>
> + //
>
> + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1));
>
> +
>
> + ShiftCount = BitDesc->Bit;
>
> + //
>
> + // As current CPU Smm Io can only support at most
>
> + // 32-bit read/write,if Operation is 64 bit,
>
> + // we do a 32 bit operation according to BitDesc->Bit
>
> + //
>
> + if (RegSize == SMM_IO_UINT64) {
>
> + RegSize = SMM_IO_UINT32;
>
> + //
>
> + // If the operation is for high 32 bits
>
> + //
>
> + if (BitDesc->Bit >= 32) {
>
> + RegisterOffset += 4;
>
> + ShiftCount -= 32;
>
> + }
>
> + }
>
> +
>
> + Status = gSmst->SmmIo.Io.Read (
>
> + &gSmst->SmmIo,
>
> + RegSize,
>
> + BaseAddr + RegisterOffset,
>
> + 1,
>
> + &Register
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + if ((Register & (LShiftU64 (BIT_ZERO, ShiftCount))) != 0) {
>
> + BitWasOne = TRUE;
>
> + } else {
>
> + BitWasOne = FALSE;
>
> + }
>
> + break;
>
> +
>
> + case GPIO_ADDR_TYPE:
>
> + case MEMORY_MAPPED_IO_ADDRESS_TYPE:
>
> + //
>
> + // Read the register, and it with the bit to read
>
> + //
>
> + switch (BitDesc->SizeInBytes) {
>
> + case 1:
>
> + Register = (UINT64) MmioRead8 ((UINTN) BitDesc->Reg.Data.Mmio);
>
> + break;
>
> +
>
> + case 2:
>
> + Register = (UINT64) MmioRead16 ((UINTN) BitDesc->Reg.Data.Mmio);
>
> + break;
>
> +
>
> + case 4:
>
> + Register = (UINT64) MmioRead32 ((UINTN) BitDesc->Reg.Data.Mmio);
>
> + break;
>
> +
>
> + case 8:
>
> + Register = (UINT64) MmioRead32 ((UINTN) BitDesc-
> >Reg.Data.Mmio);
>
> + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc-
> >Reg.Data.Mmio + 4);
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
>
> + if (Register) {
>
> + BitWasOne = TRUE;
>
> + } else {
>
> + BitWasOne = FALSE;
>
> + }
>
> + break;
>
> +
>
> + case PCIE_ADDR_TYPE:
>
> + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus;
>
> + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev;
>
> + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc;
>
> + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg;
>
> + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
>
> + switch (BitDesc->SizeInBytes) {
>
> +
>
> + case 0:
>
> + //
>
> + // Chances are that this field didn't get initialized.
>
> + // Check your assignments to bit descriptions.
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> +
>
> + case 1:
>
> + Register = (UINT64) PciSegmentRead8 (PciBaseAddress + PciReg);
>
> + break;
>
> +
>
> + case 2:
>
> + Register = (UINT64) PciSegmentRead16 (PciBaseAddress + PciReg);
>
> + break;
>
> +
>
> + case 4:
>
> + Register = (UINT64) PciSegmentRead32 (PciBaseAddress + PciReg);
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + if ((Register & (LShiftU64 (BIT_ZERO, BitDesc->Bit))) != 0) {
>
> + BitWasOne = TRUE;
>
> + } else {
>
> + BitWasOne = FALSE;
>
> + }
>
> + break;
>
> +
>
> + case PCR_ADDR_TYPE:
>
> + //
>
> + // Read the register, and it with the bit to read
>
> + //
>
> + switch (BitDesc->SizeInBytes) {
>
> + case 1:
>
> + Register = PchPcrRead8 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc-
> >Reg.Data.Pcr.Fields.Offset);
>
> + break;
>
> +
>
> + case 2:
>
> + Register = PchPcrRead16 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc-
> >Reg.Data.Pcr.Fields.Offset);
>
> + break;
>
> +
>
> + case 4:
>
> + Register = PchPcrRead32 (BitDesc->Reg.Data.Pcr.Fields.Pid, BitDesc-
> >Reg.Data.Pcr.Fields.Offset);
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + Register = Register & (LShiftU64 (BIT0, BitDesc->Bit));
>
> + if (Register) {
>
> + BitWasOne = TRUE;
>
> + } else {
>
> + BitWasOne = FALSE;
>
> + }
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // This address type is not yet implemented
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +
>
> + return BitWasOne;
>
> +}
>
> +
>
> +/**
>
> + Write a specifying bit with the register
>
> +
>
> + @param[in] BitDesc The struct that includes register address, size in
> byte and bit number
>
> + @param[in] ValueToWrite The value to be wrote
>
> + @param[in] WriteClear If the rest bits of the register is write clear
>
> +
>
> +**/
>
> +VOID
>
> +WriteBitDesc (
>
> + CONST PCH_SMM_BIT_DESC *BitDesc,
>
> + CONST BOOLEAN ValueToWrite,
>
> + CONST BOOLEAN WriteClear
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT64 Register;
>
> + UINT64 AndVal;
>
> + UINT64 OrVal;
>
> + UINT32 RegSize;
>
> + UINT32 PciBus;
>
> + UINT32 PciDev;
>
> + UINT32 PciFun;
>
> + UINT32 PciReg;
>
> + UINTN RegisterOffset;
>
> + UINT32 BaseAddr;
>
> + UINT64 PciBaseAddress;
>
> +
>
> + ASSERT (BitDesc != NULL);
>
> + ASSERT (!IS_BIT_DESC_NULL (*BitDesc));
>
> +
>
> + RegSize = 0;
>
> + Register = 0;
>
> +
>
> + if (WriteClear) {
>
> + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit);
>
> + } else {
>
> + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit));
>
> + }
>
> +
>
> + OrVal = (LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit));
>
> +
>
> + switch (BitDesc->Reg.Type) {
>
> +
>
> + case ACPI_ADDR_TYPE:
>
> + case TCO_ADDR_TYPE:
>
> + if (BitDesc->Reg.Type == ACPI_ADDR_TYPE) {
>
> + RegisterOffset = BitDesc->Reg.Data.acpi;
>
> + BaseAddr = mAcpiBaseAddr;
>
> + } else {
>
> + RegisterOffset = BitDesc->Reg.Data.tco;
>
> + BaseAddr = mTcoBaseAddr;
>
> + }
>
> +
>
> + switch (BitDesc->SizeInBytes) {
>
> +
>
> + case 0:
>
> + //
>
> + // Chances are that this field didn't get initialized.
>
> + // Check your assignments to bit descriptions.
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> +
>
> + case 1:
>
> + RegSize = SMM_IO_UINT8;
>
> + break;
>
> +
>
> + case 2:
>
> + RegSize = SMM_IO_UINT16;
>
> + break;
>
> +
>
> + case 4:
>
> + RegSize = SMM_IO_UINT32;
>
> + break;
>
> +
>
> + case 8:
>
> + RegSize = SMM_IO_UINT64;
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + //
>
> + // Double check that we correctly read in the acpi base address
>
> + //
>
> + ASSERT ((BaseAddr != 0x0) && ((BaseAddr & 0x1) != 0x1));
>
> +
>
> + //
>
> + // As current CPU Smm Io can only support at most
>
> + // 32-bit read/write,if Operation is 64 bit,
>
> + // we do a 32 bit operation according to BitDesc->Bit
>
> + //
>
> + if (RegSize == SMM_IO_UINT64) {
>
> + RegSize = SMM_IO_UINT32;
>
> + //
>
> + // If the operation is for high 32 bits
>
> + //
>
> + if (BitDesc->Bit >= 32) {
>
> + RegisterOffset += 4;
>
> +
>
> + if (WriteClear) {
>
> + AndVal = LShiftU64 (BIT_ZERO, BitDesc->Bit - 32);
>
> + } else {
>
> + AndVal = ~(LShiftU64 (BIT_ZERO, BitDesc->Bit - 32));
>
> + }
>
> +
>
> + OrVal = LShiftU64 ((UINT32) ValueToWrite, BitDesc->Bit - 32);
>
> + }
>
> + }
>
> +
>
> + Status = gSmst->SmmIo.Io.Read (
>
> + &gSmst->SmmIo,
>
> + RegSize,
>
> + BaseAddr + RegisterOffset,
>
> + 1,
>
> + &Register
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> +
>
> + Register &= AndVal;
>
> + Register |= OrVal;
>
> +
>
> + Status = gSmst->SmmIo.Io.Write (
>
> + &gSmst->SmmIo,
>
> + RegSize,
>
> + BaseAddr + RegisterOffset,
>
> + 1,
>
> + &Register
>
> + );
>
> + ASSERT_EFI_ERROR (Status);
>
> + break;
>
> +
>
> + case GPIO_ADDR_TYPE:
>
> + case MEMORY_MAPPED_IO_ADDRESS_TYPE:
>
> + //
>
> + // Read the register, or it with the bit to set, then write it back.
>
> + //
>
> + switch (BitDesc->SizeInBytes) {
>
> + case 1:
>
> + MmioAndThenOr8 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT8)
> AndVal, (UINT8) OrVal);
>
> + break;
>
> +
>
> + case 2:
>
> + MmioAndThenOr16 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT16)
> AndVal, (UINT16) OrVal);
>
> + break;
>
> +
>
> + case 4:
>
> + MmioAndThenOr32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32)
> AndVal, (UINT32) OrVal);
>
> + break;
>
> +
>
> + case 8:
>
> + Register = (UINT64) MmioRead32 ((UINTN) BitDesc-
> >Reg.Data.Mmio);
>
> + *((UINT32 *) (&Register) + 1) = MmioRead32 ((UINTN) BitDesc-
> >Reg.Data.Mmio + 4);
>
> + Register &= AndVal;
>
> + Register |= OrVal;
>
> + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio, (UINT32) Register);
>
> + MmioWrite32 ((UINTN) BitDesc->Reg.Data.Mmio + 4, *((UINT32 *)
> (&Register) + 1));
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + break;
>
> +
>
> + case PCIE_ADDR_TYPE:
>
> + PciBus = BitDesc->Reg.Data.pcie.Fields.Bus;
>
> + PciDev = BitDesc->Reg.Data.pcie.Fields.Dev;
>
> + PciFun = BitDesc->Reg.Data.pcie.Fields.Fnc;
>
> + PciReg = BitDesc->Reg.Data.pcie.Fields.Reg;
>
> + PciBaseAddress = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH, PciBus, PciDev, PciFun, 0);
>
> + switch (BitDesc->SizeInBytes) {
>
> +
>
> + case 0:
>
> + //
>
> + // Chances are that this field didn't get initialized -- check your
> assignments
>
> + // to bit descriptions.
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> +
>
> + case 1:
>
> + PciSegmentAndThenOr8 (PciBaseAddress + PciReg, (UINT8) AndVal,
> (UINT8) OrVal);
>
> + break;
>
> +
>
> + case 2:
>
> + PciSegmentAndThenOr16 (PciBaseAddress + PciReg, (UINT16) AndVal,
> (UINT16) OrVal);
>
> + break;
>
> +
>
> + case 4:
>
> + PciSegmentAndThenOr32 (PciBaseAddress + PciReg, (UINT32) AndVal,
> (UINT32) OrVal);
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + break;
>
> +
>
> + case PCR_ADDR_TYPE:
>
> + //
>
> + // Read the register, or it with the bit to set, then write it back.
>
> + //
>
> + switch (BitDesc->SizeInBytes) {
>
> + case 1:
>
> + PchPcrAndThenOr8 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid,
> (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT8) AndVal, (UINT8)
> OrVal);
>
> + break;
>
> +
>
> + case 2:
>
> + PchPcrAndThenOr16 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid,
> (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT16) AndVal, (UINT16)
> OrVal);
>
> + break;
>
> +
>
> + case 4:
>
> + PchPcrAndThenOr32 ((PCH_SBI_PID) BitDesc->Reg.Data.Pcr.Fields.Pid,
> (UINT16) BitDesc->Reg.Data.Pcr.Fields.Offset, (UINT32) AndVal, (UINT32)
> OrVal);
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // Unsupported or invalid register size
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> + break;
>
> +
>
> + default:
>
> + //
>
> + // This address type is not yet implemented
>
> + //
>
> + ASSERT (FALSE);
>
> + break;
>
> + }
>
> +}
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.h
> new file mode 100644
> index 0000000000..6dd6f2027d
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/PchSmiDispatcher/Smm/PchxSmmHe
> lpers.h
> @@ -0,0 +1,107 @@
> +/** @file
>
> + This driver is responsible for the registration of child drivers
>
> + and the abstraction of the PCH SMI sources.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _PCHX_SMM_HELPERS_H_
>
> +#define _PCHX_SMM_HELPERS_H_
>
> +
>
> +#include "PchSmm.h"
>
> +
>
> +/**
>
> + Initialize bits that aren't necessarily related to an SMI source.
>
> +
>
> +
>
> + @retval EFI_SUCCESS SMI source initialization completed.
>
> + @retval Asserts Global Smi Bit is not enabled successfully.
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmInitHardware (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Enables the PCH to generate SMIs. Note that no SMIs will be generated
>
> + if no SMI sources are enabled. Conversely, no enabled SMI source will
>
> + generate SMIs if SMIs are not globally enabled. This is the main
>
> + switchbox for SMI generation.
>
> +
>
> +
>
> + @retval EFI_SUCCESS Enable Global Smi Bit completed
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmEnableGlobalSmiBit (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Clears the SMI after all SMI source have been processed.
>
> + Note that this function will not work correctly (as it is
>
> + written) unless all SMI sources have been processed.
>
> + A revision of this function could manually clear all SMI
>
> + status bits to guarantee success.
>
> +
>
> +
>
> + @retval EFI_SUCCESS Clears the SMIs completed
>
> + @retval Asserts EOS was not set to a 1
>
> +**/
>
> +EFI_STATUS
>
> +PchSmmClearSmi (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Set the SMI EOS bit after all SMI source have been processed.
>
> +
>
> +
>
> + @retval FALSE EOS was not set to a 1; this is an error
>
> + @retval TRUE EOS was correctly set to a 1
>
> +**/
>
> +BOOLEAN
>
> +PchSmmSetAndCheckEos (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Determine whether an ACPI OS is present (via the SCI_EN bit)
>
> +
>
> +
>
> + @retval TRUE ACPI OS is present
>
> + @retval FALSE ACPI OS is not present
>
> +**/
>
> +BOOLEAN
>
> +PchSmmGetSciEn (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Read a specifying bit with the register
>
> +
>
> + @param[in] BitDesc The struct that includes register address, size in
> byte and bit number
>
> +
>
> + @retval TRUE The bit is enabled
>
> + @retval FALSE The bit is disabled
>
> +**/
>
> +BOOLEAN
>
> +ReadBitDesc (
>
> + CONST PCH_SMM_BIT_DESC *BitDesc
>
> + );
>
> +
>
> +/**
>
> + Write a specifying bit with the register
>
> +
>
> + @param[in] BitDesc The struct that includes register address, size in
> byte and bit number
>
> + @param[in] ValueToWrite The value to be wrote
>
> + @param[in] WriteClear If the rest bits of the register is write clear
>
> +
>
> +**/
>
> +VOID
>
> +WriteBitDesc (
>
> + CONST PCH_SMM_BIT_DESC *BitDesc,
>
> + CONST BOOLEAN ValueToWrite,
>
> + CONST BOOLEAN WriteClear
>
> + );
>
> +
>
> +#endif
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> ol.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> ol.inf
> new file mode 100644
> index 0000000000..a142cfa95a
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> ol.inf
> @@ -0,0 +1,54 @@
> +## @file
>
> +# Component description file for SmmControl module
>
> +#
>
> +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +#
>
> +##
>
> +
>
> +
>
> +[Defines]
>
> +INF_VERSION = 0x00010017
>
> +BASE_NAME = SmmControl
>
> +FILE_GUID = A0BAD9F7-AB78-491b-B583-C52B7F84B9E0
>
> +VERSION_STRING = 1.0
>
> +MODULE_TYPE = DXE_RUNTIME_DRIVER
>
> +ENTRY_POINT = SmmControlDriverEntryInit
>
> +#
>
> +# The following information is for reference only and not required by the
> build tools.
>
> +#
>
> +# VALID_ARCHITECTURES = IA32 X64
>
> +#
>
> +
>
> +
>
> +
>
> +[LibraryClasses]
>
> +IoLib
>
> +UefiDriverEntryPoint
>
> +DebugLib
>
> +UefiBootServicesTableLib
>
> +UefiRuntimeServicesTableLib
>
> +PmcLib
>
> +GpioLib
>
> +
>
> +
>
> +[Packages]
>
> +MdePkg/MdePkg.dec
>
> +TigerlakeSiliconPkg/SiPkg.dec
>
> +
>
> +
>
> +[Sources]
>
> +SmmControlDriver.h
>
> +SmmControlDriver.c
>
> +
>
> +
>
> +[Protocols]
>
> +gEfiSmmControl2ProtocolGuid ## PRODUCES
>
> +
>
> +
>
> +[Guids]
>
> +gEfiEventVirtualAddressChangeGuid
>
> +
>
> +
>
> +[Depex]
>
> +TRUE
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.c
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.c
> new file mode 100644
> index 0000000000..5822f42165
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.c
> @@ -0,0 +1,394 @@
> +/** @file
>
> + This is the driver that publishes the SMM Control Protocol.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#include <Library/IoLib.h>
>
> +#include <Library/DebugLib.h>
>
> +#include <Library/UefiDriverEntryPoint.h>
>
> +#include <Library/UefiBootServicesTableLib.h>
>
> +#include <Library/UefiRuntimeServicesTableLib.h>
>
> +#include <Guid/EventGroup.h>
>
> +#include <Library/PmcLib.h>
>
> +#include <Library/GpioLib.h>
>
> +#include <IndustryStandard/Pci30.h>
>
> +#include <Register/PchRegsLpc.h>
>
> +#include <Register/SpiRegs.h>
>
> +#include <Register/PmcRegs.h>
>
> +#include "SmmControlDriver.h"
>
> +
>
> +STATIC SMM_CONTROL_PRIVATE_DATA mSmmControl;
>
> +GLOBAL_REMOVE_IF_UNREFERENCED UINT16 mABase;
>
> +
>
> +VOID
>
> +EFIAPI
>
> +DisablePendingSmis (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + Fixup internal data pointers so that the services can be called in virtual
> mode.
>
> +
>
> + @param[in] Event The event registered.
>
> + @param[in] Context Event context.
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +SmmControlVirtualAddressChangeEvent (
>
> + IN EFI_EVENT Event,
>
> + IN VOID *Context
>
> + )
>
> +{
>
> + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Trigger));
>
> + gRT->ConvertPointer (0, (VOID *) &(mSmmControl.SmmControl.Clear));
>
> +}
>
> +
>
> +/**
>
> + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n
>
> + - <b>Introduction</b>\n
>
> + The SmmControl module is a DXE RUNTIME driver that provides a
> standard way
>
> + for other drivers to trigger software SMIs.
>
> +
>
> + - @pre
>
> + - PCH Power Management I/O space base address has already been
> programmed.
>
> + If SmmControl Runtime DXE driver is run before Status Code Runtime
> Protocol
>
> + is installed and there is the need to use Status code in the driver, it will
>
> + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to
> the dependency file.
>
> + - EFI_SMM_BASE2_PROTOCOL
>
> + - Documented in the System Management Mode Core Interface
> Specification.
>
> +
>
> + - @result
>
> + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL
> documented in
>
> + System Management Mode Core Interface Specification.
>
> +
>
> + @param[in] ImageHandle Handle for the image of this driver
>
> + @param[in] SystemTable Pointer to the EFI System Table
>
> +
>
> + @retval EFI_STATUS Results of the installation of the SMM Control
> Protocol
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmControlDriverEntryInit (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + EFI_EVENT Event;
>
> +
>
> + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() Start\n"));
>
> +
>
> + //
>
> + // Get the Power Management I/O space base address. We assume that
>
> + // this base address has already been programmed if this driver is
>
> + // being run.
>
> + //
>
> + mABase = PmcGetAcpiBase ();
>
> +
>
> + Status = EFI_SUCCESS;
>
> + if (mABase != 0) {
>
> + //
>
> + // Install the instance of the protocol
>
> + //
>
> + mSmmControl.Signature =
> SMM_CONTROL_PRIVATE_DATA_SIGNATURE;
>
> + mSmmControl.Handle = ImageHandle;
>
> +
>
> + mSmmControl.SmmControl.Trigger = Activate;
>
> + mSmmControl.SmmControl.Clear = Deactivate;
>
> + mSmmControl.SmmControl.MinimumTriggerPeriod = 0;
>
> +
>
> + //
>
> + // Install our protocol interfaces on the device's handle
>
> + //
>
> + Status = gBS->InstallMultipleProtocolInterfaces (
>
> + &mSmmControl.Handle,
>
> + &gEfiSmmControl2ProtocolGuid,
>
> + &mSmmControl.SmmControl,
>
> + NULL
>
> + );
>
> + } else {
>
> + Status = EFI_DEVICE_ERROR;
>
> + return Status;
>
> + }
>
> +
>
> + Status = gBS->CreateEventEx (
>
> + EVT_NOTIFY_SIGNAL,
>
> + TPL_NOTIFY,
>
> + SmmControlVirtualAddressChangeEvent,
>
> + NULL,
>
> + &gEfiEventVirtualAddressChangeGuid,
>
> + &Event
>
> + );
>
> + //
>
> + // Disable any PCH SMIs that, for whatever reason, are asserted after the
> boot.
>
> + //
>
> + DisablePendingSmis ();
>
> +
>
> + DEBUG ((DEBUG_INFO, "SmmControlDriverEntryInit() End\n"));
>
> +
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + Trigger the software SMI
>
> +
>
> + @param[in] Data The value to be set on the software SMI data
> port
>
> +
>
> + @retval EFI_SUCCESS Function completes successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmTrigger (
>
> + IN UINT8 Data
>
> + )
>
> +{
>
> + UINT32 OutputData;
>
> + UINT32 OutputPort;
>
> +
>
> + //
>
> + // Enable the APMC SMI
>
> + //
>
> + OutputPort = mABase + R_ACPI_IO_SMI_EN;
>
> + OutputData = IoRead32 ((UINTN) OutputPort);
>
> + OutputData |= (B_ACPI_IO_SMI_EN_APMC |
> B_ACPI_IO_SMI_EN_GBL_SMI);
>
> + DEBUG (
>
> + (DEBUG_VERBOSE,
>
> + "The SMI Control Port at address %x will be written to %x.\n",
>
> + OutputPort,
>
> + OutputData)
>
> + );
>
> + IoWrite32 (
>
> + (UINTN) OutputPort,
>
> + (UINT32) (OutputData)
>
> + );
>
> +
>
> + OutputPort = R_PCH_IO_APM_CNT;
>
> + OutputData = Data;
>
> +
>
> + //
>
> + // Generate the APMC SMI
>
> + //
>
> + IoWrite8 (
>
> + (UINTN) OutputPort,
>
> + (UINT8) (OutputData)
>
> + );
>
> +
>
> + return EFI_SUCCESS;
>
> +}
>
> +
>
> +/**
>
> + Clear the SMI status
>
> +
>
> +
>
> + @retval EFI_SUCCESS The function completes successfully
>
> + @retval EFI_DEVICE_ERROR Something error occurred
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmClear (
>
> + VOID
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT32 OutputData;
>
> + UINT32 OutputPort;
>
> +
>
> + Status = EFI_SUCCESS;
>
> +
>
> + //
>
> + // Clear the Power Button Override Status Bit, it gates EOS from being set.
>
> + //
>
> + OutputPort = mABase + R_ACPI_IO_PM1_STS;
>
> + OutputData = B_ACPI_IO_PM1_STS_PRBTNOR;
>
> + DEBUG (
>
> + (DEBUG_VERBOSE,
>
> + "The PM1 Status Port at address %x will be written to %x.\n",
>
> + OutputPort,
>
> + OutputData)
>
> + );
>
> + IoWrite16 (
>
> + (UINTN) OutputPort,
>
> + (UINT16) (OutputData)
>
> + );
>
> +
>
> + //
>
> + // Clear the APM SMI Status Bit
>
> + //
>
> + OutputPort = mABase + R_ACPI_IO_SMI_STS;
>
> + OutputData = B_ACPI_IO_SMI_STS_APM;
>
> + DEBUG (
>
> + (DEBUG_VERBOSE,
>
> + "The SMI Status Port at address %x will be written to %x.\n",
>
> + OutputPort,
>
> + OutputData)
>
> + );
>
> + IoWrite32 (
>
> + (UINTN) OutputPort,
>
> + (UINT32) (OutputData)
>
> + );
>
> +
>
> + //
>
> + // Set the EOS Bit
>
> + //
>
> + OutputPort = mABase + R_ACPI_IO_SMI_EN;
>
> + OutputData = IoRead32 ((UINTN) OutputPort);
>
> + OutputData |= B_ACPI_IO_SMI_EN_EOS;
>
> + DEBUG (
>
> + (DEBUG_VERBOSE,
>
> + "The SMI Control Port at address %x will be written to %x.\n",
>
> + OutputPort,
>
> + OutputData)
>
> + );
>
> + IoWrite32 (
>
> + (UINTN) OutputPort,
>
> + (UINT32) (OutputData)
>
> + );
>
> +
>
> + //
>
> + // There is no need to read EOS back and check if it is set.
>
> + // This can lead to a reading of zero if an SMI occurs right after the SMI_EN
> port read
>
> + // but before the data is returned to the CPU.
>
> + // SMM Dispatcher should make sure that EOS is set after all SMI sources
> are processed.
>
> + //
>
> + return Status;
>
> +}
>
> +
>
> +/**
>
> + This routine generates an SMI
>
> +
>
> + @param[in] This The EFI SMM Control protocol instance
>
> + @param[in, out] CommandPort The buffer contains data to the
> command port
>
> + @param[in, out] DataPort The buffer contains data to the data port
>
> + @param[in] Periodic Periodic or not
>
> + @param[in] ActivationInterval Interval of periodic SMI
>
> +
>
> + @retval EFI Status Describing the result of the operation
>
> + @retval EFI_INVALID_PARAMETER Some parameter value passed is
> not supported
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +Activate (
>
> + IN CONST EFI_SMM_CONTROL2_PROTOCOL * This,
>
> + IN OUT UINT8 *CommandPort OPTIONAL,
>
> + IN OUT UINT8 *DataPort OPTIONAL,
>
> + IN BOOLEAN Periodic OPTIONAL,
>
> + IN UINTN ActivationInterval OPTIONAL
>
> + )
>
> +{
>
> + EFI_STATUS Status;
>
> + UINT8 Data;
>
> +
>
> + if (Periodic) {
>
> + DEBUG ((DEBUG_WARN, "Invalid parameter\n"));
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + if (CommandPort == NULL) {
>
> + Data = 0xFF;
>
> + } else {
>
> + Data = *CommandPort;
>
> + }
>
> + //
>
> + // Clear any pending the APM SMI
>
> + //
>
> + Status = SmmClear ();
>
> + if (EFI_ERROR (Status)) {
>
> + return Status;
>
> + }
>
> +
>
> + return SmmTrigger (Data);
>
> +}
>
> +
>
> +/**
>
> + This routine clears an SMI
>
> +
>
> + @param[in] This The EFI SMM Control protocol instance
>
> + @param[in] Periodic Periodic or not
>
> +
>
> + @retval EFI Status Describing the result of the operation
>
> + @retval EFI_INVALID_PARAMETER Some parameter value passed is not
> supported
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +Deactivate (
>
> + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
>
> + IN BOOLEAN Periodic OPTIONAL
>
> + )
>
> +{
>
> + if (Periodic) {
>
> + return EFI_INVALID_PARAMETER;
>
> + }
>
> +
>
> + return SmmClear ();
>
> +}
>
> +/**
>
> + Disable all pending SMIs
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +DisablePendingSmis (
>
> + VOID
>
> + )
>
> +{
>
> + UINT32 Data;
>
> + BOOLEAN SciEn;
>
> +
>
> + //
>
> + // Determine whether an ACPI OS is present (via the SCI_EN bit)
>
> + //
>
> + Data = IoRead16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT);
>
> + SciEn = (BOOLEAN) ((Data & B_ACPI_IO_PM1_CNT_SCI_EN) ==
> B_ACPI_IO_PM1_CNT_SCI_EN);
>
> +
>
> + if (!SciEn) {
>
> + //
>
> + // Clear any SMIs that double as SCIs (when SCI_EN==0)
>
> + //
>
> + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_STS, 0xFFFF);
>
> + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_EN, 0);
>
> + IoWrite16 ((UINTN) mABase + R_ACPI_IO_PM1_CNT, 0);
>
> + IoWrite32 (
>
> + (UINTN) mABase + R_ACPI_IO_GPE0_STS_127_96,
>
> + (UINT32)( B_ACPI_IO_GPE0_STS_127_96_WADT |
>
> + B_ACPI_IO_GPE0_STS_127_96_USB_CON_DSX_STS |
>
> + B_ACPI_IO_GPE0_STS_127_96_LAN_WAKE |
>
> + B_ACPI_IO_GPE0_STS_127_96_PME_B0 |
>
> + B_ACPI_IO_GPE0_STS_127_96_PME |
>
> + B_ACPI_IO_GPE0_STS_127_96_BATLOW |
>
> + B_ACPI_IO_GPE0_STS_127_96_RI |
>
> + B_ACPI_IO_GPE0_STS_127_96_SWGPE)
>
> + );
>
> + IoWrite32 ((UINTN) mABase + R_ACPI_IO_GPE0_EN_127_96, (UINT32)
> B_ACPI_IO_GPE0_EN_127_96_WADT);
>
> + }
>
> + //
>
> + // Clear and disable all SMIs that are unaffected by SCI_EN
>
> + //
>
> + GpioDisableAllGpiSmi ();
>
> +
>
> + GpioClearAllGpiSmiSts ();
>
> +
>
> + IoWrite32 ((UINTN) mABase + R_ACPI_IO_DEVACT_STS, 0x0000FFFF);
>
> +
>
> + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_STS, ~0u);
>
> +
>
> + //
>
> + // (Make sure to write this register last -- EOS re-enables SMIs for the PCH)
>
> + //
>
> + Data = IoRead32 ((UINTN) mABase + R_ACPI_IO_SMI_EN);
>
> + //
>
> + // clear all bits except those tied to SCI_EN
>
> + //
>
> + Data &= B_ACPI_IO_SMI_EN_BIOS_RLS;
>
> + //
>
> + // enable SMIs and specifically enable writes to APM_CNT.
>
> + //
>
> + Data |= B_ACPI_IO_SMI_EN_GBL_SMI | B_ACPI_IO_SMI_EN_APMC;
>
> + //
>
> + // NOTE: Default value of EOS is set in PCH, it will be automatically cleared
> Once the PCH asserts SMI# low,
>
> + // we don't need to do anything to clear it
>
> + //
>
> + IoWrite32 ((UINTN) mABase + R_ACPI_IO_SMI_EN, Data);
>
> +}
>
> +
>
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.h
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.h
> new file mode 100644
> index 0000000000..af368e6945
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/Pch/SmmControl/RuntimeDxe/SmmContr
> olDriver.h
> @@ -0,0 +1,130 @@
> +/** @file
>
> + Header file for SMM Control Driver.
>
> +
>
> + Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
>
> + SPDX-License-Identifier: BSD-2-Clause-Patent
>
> +**/
>
> +#ifndef _SMM_CONTROL_DRIVER_H_
>
> +#define _SMM_CONTROL_DRIVER_H_
>
> +
>
> +#include <Protocol/SmmControl2.h>
>
> +
>
> +
>
> +#define SMM_CONTROL_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('i',
> '4', 's', 'c')
>
> +
>
> +typedef struct {
>
> + UINTN Signature;
>
> + EFI_HANDLE Handle;
>
> + EFI_SMM_CONTROL2_PROTOCOL SmmControl;
>
> +} SMM_CONTROL_PRIVATE_DATA;
>
> +
>
> +#define SMM_CONTROL_PRIVATE_DATA_FROM_THIS(a) CR (a,
> SMM_CONTROL_PRIVATE_DATA, SmmControl,
> SMM_CONTROL_DEV_SIGNATURE)
>
> +
>
> +//
>
> +// Prototypes
>
> +//
>
> +
>
> +/**
>
> + <b>SmmControl DXE RUNTIME Module Entry Point</b>\n
>
> + - <b>Introduction</b>\n
>
> + The SmmControl module is a DXE RUNTIME driver that provides a
> standard way
>
> + for other drivers to trigger software SMIs.
>
> +
>
> + - @pre
>
> + - PCH Power Management I/O space base address has already been
> programmed.
>
> + If SmmControl Runtime DXE driver is run before Status Code Runtime
> Protocol
>
> + is installed and there is the need to use Status code in the driver, it will
>
> + be necessary to add EFI_STATUS_CODE_RUNTIME_PROTOCOL_GUID to
> the dependency file.
>
> + - EFI_SMM_BASE2_PROTOCOL
>
> + - Documented in the System Management Mode Core Interface
> Specification.
>
> +
>
> + - @result
>
> + The SmmControl driver produces the EFI_SMM_CONTROL_PROTOCOL
> documented in
>
> + System Management Mode Core Interface Specification.
>
> +
>
> + @param[in] ImageHandle Handle for the image of this driver
>
> + @param[in] SystemTable Pointer to the EFI System Table
>
> +
>
> + @retval EFI_STATUS Results of the installation of the SMM Control
> Protocol
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmControlDriverEntryInit (
>
> + IN EFI_HANDLE ImageHandle,
>
> + IN EFI_SYSTEM_TABLE *SystemTable
>
> + );
>
> +
>
> +/**
>
> + Trigger the software SMI
>
> +
>
> + @param[in] Data The value to be set on the software SMI data
> port
>
> +
>
> + @retval EFI_SUCCESS Function completes successfully
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmTrigger (
>
> + UINT8 Data
>
> + );
>
> +
>
> +/**
>
> + Clear the SMI status
>
> +
>
> +
>
> + @retval EFI_SUCCESS The function completes successfully
>
> + @retval EFI_DEVICE_ERROR Something error occurred
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +SmmClear (
>
> + VOID
>
> + );
>
> +
>
> +/**
>
> + This routine generates an SMI
>
> +
>
> + @param[in] This The EFI SMM Control protocol instance
>
> + @param[in, out] ArgumentBuffer The buffer of argument
>
> + @param[in, out] ArgumentBufferSize The size of the argument buffer
>
> + @param[in] Periodic Periodic or not
>
> + @param[in] ActivationInterval Interval of periodic SMI
>
> +
>
> + @retval EFI Status Describing the result of the operation
>
> + @retval EFI_INVALID_PARAMETER Some parameter value passed is
> not supported
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +Activate (
>
> + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
>
> + IN OUT UINT8 *ArgumentBuffer OPTIONAL,
>
> + IN OUT UINT8 *ArgumentBufferSize OPTIONAL,
>
> + IN BOOLEAN Periodic OPTIONAL,
>
> + IN UINTN ActivationInterval OPTIONAL
>
> + );
>
> +
>
> +/**
>
> + This routine clears an SMI
>
> +
>
> + @param[in] This The EFI SMM Control protocol instance
>
> + @param[in] Periodic Periodic or not
>
> +
>
> + @retval EFI Status Describing the result of the operation
>
> + @retval EFI_INVALID_PARAMETER Some parameter value passed is not
> supported
>
> +**/
>
> +EFI_STATUS
>
> +EFIAPI
>
> +Deactivate (
>
> + IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
>
> + IN BOOLEAN Periodic OPTIONAL
>
> + );
>
> +/**
>
> + Disable all pending SMIs
>
> +
>
> +**/
>
> +VOID
>
> +EFIAPI
>
> +DisablePendingSmis (
>
> + VOID
>
> + );
>
> +
>
> +#endif
>
> --
> 2.24.0.windows.2
next prev parent reply other threads:[~2021-02-04 3:56 UTC|newest]
Thread overview: 81+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-01 1:36 [PATCH 01/40] TigerlakeSiliconPkg: Add package and Include/ConfigBlock headers Heng Luo
2021-02-01 1:36 ` [PATCH 02/40] TigerlakeSiliconPkg/Include: Add Library, PPI and Protocol include headers Heng Luo
2021-02-04 3:51 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 03/40] TigerlakeSiliconPkg/Include: Add Pins, Register and other " Heng Luo
2021-02-04 3:52 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 04/40] TigerlakeSiliconPkg/Cpu: Add Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 05/40] TigerlakeSiliconPkg/Pch: Add include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 06/40] TigerlakeSiliconPkg/Pch: Add IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 07/40] TigerlakeSiliconPkg/SystemAgent: Add include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 08/40] TigerlakeSiliconPkg/SystemAgent: Add IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 09/40] TigerlakeSiliconPkg/Fru: Add TglCpu/Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 10/40] TigerlakeSiliconPkg/Fru: Add TglCpu/IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 11/40] TigerlakeSiliconPkg/Fru: Add TglPch/Include headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 12/40] TigerlakeSiliconPkg/Fru: Add TglPch/IncludePrivate headers Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 13/40] TigerlakeSiliconPkg/IpBlock: Add Cnvi component Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 14/40] TigerlakeSiliconPkg/IpBlock: Add CpuPcieRp component Heng Luo
2021-02-04 3:53 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 15/40] TigerlakeSiliconPkg/IpBlock: Add Espi component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 16/40] TigerlakeSiliconPkg/IpBlock: Add Gbe component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 17/40] TigerlakeSiliconPkg/IpBlock: Add Gpio component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 18/40] TigerlakeSiliconPkg/IpBlock: Add Graphics component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 19/40] TigerlakeSiliconPkg/IpBlock: Add Hda component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 20/40] TigerlakeSiliconPkg/IpBlock: Add HostBridge component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 21/40] TigerlakeSiliconPkg/IpBlock: Add P2sb component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 22/40] TigerlakeSiliconPkg/IpBlock: Add PchDmi component Heng Luo
2021-02-04 3:54 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component Heng Luo
2021-02-04 3:55 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 24/40] TigerlakeSiliconPkg/IpBlock: Add Pmc component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 25/40] TigerlakeSiliconPkg/IpBlock: Add Psf component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 26/40] TigerlakeSiliconPkg/IpBlock: Add Sata component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 27/40] TigerlakeSiliconPkg/IpBlock: Add SerialIo component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 28/40] TigerlakeSiliconPkg/IpBlock: Add Smbus component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 29/40] TigerlakeSiliconPkg/IpBlock: Add Spi component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 30/40] TigerlakeSiliconPkg/IpBlock: Add Vtd component Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 31/40] TigerlakeSiliconPkg/Library: Add package common library instances Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 32/40] TigerlakeSiliconPkg/Pch: Add Pch " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 33/40] TigerlakeSiliconPkg/Pch: Add Pch private " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 34/40] TigerlakeSiliconPkg/SystemAgent: Add Acpi Tables and " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 35/40] TigerlakeSiliconPkg/Fru/TglCpu: Add CpuPcieRp and Vtd " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Heng Luo
2021-02-04 3:56 ` Nate DeSimone [this message]
2021-02-01 1:36 ` [PATCH 37/40] TigerlakeSiliconPkg/SystemAgent: Add SystemAgent modules Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 38/40] TigerlakeSiliconPkg/Fru: Add Fru DSC files Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 39/40] TigerlakeSiliconPkg: Add package " Heng Luo
2021-02-04 3:56 ` Nate DeSimone
2021-02-01 1:36 ` [PATCH 40/40] Maintainers.txt: Add TigerlakeSiliconPkg maintainers Heng Luo
2021-02-04 3:51 ` Nate DeSimone
2021-02-04 8:24 ` Heng Luo
2021-02-04 3:51 ` [PATCH 01/40] TigerlakeSiliconPkg: Add package and Include/ConfigBlock headers Nate DeSimone
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-list from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=BN6PR1101MB2147EEDA2BA37FD01047EB45CDB39@BN6PR1101MB2147.namprd11.prod.outlook.com \
--to=devel@edk2.groups.io \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox