public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
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


  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