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 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component
Date: Thu, 4 Feb 2021 03:55:01 +0000	[thread overview]
Message-ID: <BN6PR1101MB214775A7976A423C4442B4E0CDB39@BN6PR1101MB2147.namprd11.prod.outlook.com> (raw)
In-Reply-To: <20210201013657.1833-23-heng.luo@intel.com>

Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>

> -----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 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component
> 
> REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3171
> 
> Adds the following files:
>   * IpBlock/PcieRp/IncludePrivate
>   * IpBlock/PcieRp/Library
>   * IpBlock/PcieRp/LibraryPrivate
> 
> 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/IpBlock/PcieRp/IncludePrivate/Library/DxeP
> chPcieRpPolicyLib.h                            |   55 ++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PciEx
> pressHelpersLib.h                             |  173
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PcieR
> pLib.h                                        |  109
> ++++++++++++++++++++++++++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/Pci
> eSipRegs.h                                     |   45 ++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib/B
> asePcieHelperLib.c                             |  315
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> +++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib/B
> asePcieHelperLib.inf                           |   37 +++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcie
> RpLib/PchPcieRpLib.c                              |   69
> ++++++++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcie
> RpLib/PchPcieRpLibInternal.h                      |   20 +++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcie
> RpLib/PchPcieRpLibVer2.c                          |  128
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcie
> RpLib/PeiDxeSmmPchPcieRpLibVer2.inf               |   39 +++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieR
> pPolicyLib/DxePchPcieRpPolicyLib.c              |  179
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieR
> pPolicyLib/DxePchPcieRpPolicyLib.inf            |   30 ++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHel
> persLibrary/PciExpressHelpersLibrary.c        | 1997
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHel
> persLibrary/PciExpressHelpersLibrary.h        |   40 ++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHel
> persLibrary/PeiDxeSmmPciExpressHelpersLib.inf |   49
> ++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpL
> ib/PcieClientRpLib.c                          |  247
> ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> ++++++++++++++++++++++++++++++++++++++++++++++++++
> 
> Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpL
> ib/PcieClientRpLib.inf                        |   43 +++++++++++++++++++
>  17 files changed, 3575 insertions(+)
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Dx
> ePchPcieRpPolicyLib.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Dx
> ePchPcieRpPolicyLib.h
> new file mode 100644
> index 0000000000..1dea61388e
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Dx
> ePchPcieRpPolicyLib.h
> @@ -0,0 +1,55 @@
> +/** @file
> 
> +  DXE PcieRp policy library.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#ifndef _DXE_PCH_PCIERP_POLICY_LIB_H_
> 
> +#define _DXE_PCH_PCIERP_POLICY_LIB_H_
> 
> +
> 
> +#include <Protocol/PchPolicy.h>
> 
> +
> 
> +/**
> 
> +  Load DXE Config block default for Pch PCIE RP
> 
> +
> 
> +  @param[in] ConfigBlockPointer         Pointer to config block
> 
> +**/
> 
> +VOID
> 
> +LoadPchPcieRpDxeConfigDefault (
> 
> +  IN VOID          *ConfigBlockPointer
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Print PCIE_RP_DXE_CONFIG.
> 
> +
> 
> +  @param[in] PchPolicy            Pointer to a PCH_POLICY_PROTOCOL
> 
> +**/
> 
> +VOID
> 
> +PchPcieRpDxePrintConfig (
> 
> +  IN PCH_POLICY_PROTOCOL    *PchPolicy
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Get PchPcieRp config block table size.
> 
> +
> 
> +  @retval      Size of config block
> 
> +**/
> 
> +UINT16
> 
> +PchPcieRpDxeGetConfigBlockTotalSize (
> 
> +  VOID
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Add PchPcieRp ConfigBlock.
> 
> +
> 
> +  @param[in] ConfigBlockTableAddress    The pointer to config block table
> 
> +
> 
> +  @retval EFI_SUCCESS                   The policy default is initialized.
> 
> +  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create
> buffer
> 
> +**/
> 
> +EFI_STATUS
> 
> +PchPcieRpDxeAddConfigBlock (
> 
> +  IN VOID           *ConfigBlockTableAddress
> 
> +  );
> 
> +
> 
> +#endif
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> ExpressHelpersLib.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> ExpressHelpersLib.h
> new file mode 100644
> index 0000000000..d7ca34dc38
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> ExpressHelpersLib.h
> @@ -0,0 +1,173 @@
> +/** @file
> 
> +  Header file for PCI Express helpers library
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#ifndef _PCI_EXPRESS_HELPERS_LIB_H_
> 
> +#define _PCI_EXPRESS_HELPERS_LIB_H_
> 
> +
> 
> +#include <PchPolicyCommon.h>
> 
> +#include <Library/PcieRpLib.h>
> 
> +
> 
> +typedef enum {
> 
> +  TpoScale2us,
> 
> +  TpoScale10us,
> 
> +  TpoScale100us,
> 
> +  TpoScaleMax
> 
> +} T_PO_SCALE;
> 
> +//
> 
> +// This structure keeps segment:bus:device:function coordinates of a PCIe
> device
> 
> +// in a single variable. PcieCap is offset to PCI Express capabilities.
> 
> +//
> 
> +typedef struct {
> 
> +  UINT32 Seg : 8;
> 
> +  UINT32 Bus : 8;
> 
> +  UINT32 Dev : 5;
> 
> +  UINT32 Func : 3;
> 
> +  UINT32 PcieCap : 8;
> 
> +} SBDF;
> 
> +
> 
> +/*
> 
> +  Converts Tpower_on from value:scale notation to microseconds
> 
> +
> 
> +  @param[in] TpoScale   T power on scale
> 
> +  @param[in] TpoValue   T power on value
> 
> +
> 
> +  @retval    number of microseconds
> 
> +*/
> 
> +UINT32
> 
> +TpoToUs (
> 
> +  UINT32 TpoScale,
> 
> +  UINT32 TpoValue
> 
> +  );
> 
> +
> 
> +/**
> 
> +PCIe controller Sku.
> 
> +**/
> 
> +
> 
> +typedef enum {
> 
> +  EnumPchPcie = 0,
> 
> +  EnumiTbtPcie = 1,
> 
> +  EnumCpuPcie = 2,
> 
> +  EnumPciSkuMax = 3
> 
> +} PCI_SKU;
> 
> +
> 
> +/*
> 
> +  Initializes the following features in rootport and devices behind it:
> 
> +  Maximum Payload Size (generic)
> 
> +  Rootport packet split (proprietary)
> 
> +  EonOfInterrupt forwarding (proprietary)
> 
> +  Common Clock Configuration (generic)
> 
> +
> 
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> 
> +  Proprietary: code uses registers and features that are specific to Intel
> silicon
> 
> +  and probably only this Reference Code knows how to handle that.
> 
> +
> 
> +  If OEM implemented generic feature enabling in his platform code or
> trusts Operating System
> 
> +  to do it, then those features can be deleted from here.
> 
> +
> 
> +  CCC requires link retrain, which takes a while. CCC must happen before
> L0s/L1 programming.
> 
> +  If there was guarantee no code would access PCI while links retrain, it
> would be possible to skip this waiting
> 
> +
> 
> +  @param[in] RpSegment  address of rootport on PCIe
> 
> +  @param[in] RpBus      address of rootport on PCIe
> 
> +  @param[in] RpDevice   address of rootport on PCIe
> 
> +  @param[in] RpFunction address of rootport on PCIe
> 
> +  @param[in] BusMin     minimum Bus number that can be assigned below
> this rootport
> 
> +  @param[in] BusMax     maximum Bus number that can be assigned below
> this rootport
> 
> +*/
> 
> +VOID
> 
> +RootportDownstreamConfiguration (
> 
> +  UINT8                     RpSegment,
> 
> +  UINT8                     RpBus,
> 
> +  UINT8                     RpDevice,
> 
> +  UINT8                     RpFunction,
> 
> +  UINT8                     BusMin,
> 
> +  UINT8                     BusMax,
> 
> +  PCI_SKU                   PciSku
> 
> +  );
> 
> +
> 
> +/*
> 
> +  Configures the following power-management related features in rootport
> and devices behind it:
> 
> +  LTR limit (generic)
> 
> +  LTR override (proprietary)
> 
> +  Clock Power Management (generic)
> 
> +  L1 substates (generic except for the override table)
> 
> +  L1.LOW substate (proprietary)
> 
> +  L0s and L1 (generic)
> 
> +
> 
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> 
> +  Proprietary: code uses registers and features that are specific to Intel
> silicon
> 
> +  and probably only this Reference Code knows how to handle that.
> 
> +
> 
> +  If OEM implemented generic feature enabling in his platform code or
> trusts Operating System
> 
> +  to do it, then those features can be deleted from here.
> 
> +
> 
> +  @param[in] RpSegment                address of rootport on PCIe
> 
> +  @param[in] RpBus                    address of rootport on PCIe
> 
> +  @param[in] RpDevice                 address of rootport on PCIe
> 
> +  @param[in] RpFunction               address of rootport on PCIe
> 
> +  @param[in] BusMin                   minimal Bus number that can be assigned
> below this rootport
> 
> +  @param[in] BusMax                   maximum Bus number that can be assigned
> below this rootport
> 
> +  @param[in] PcieRpCommonConfig       a pointer to Pcie Root Port Common
> Config
> 
> +  @param[in] AspmOverrideTableSize    size of override array
> 
> +  @param[in] AspmOverrideTable        array of device that need exceptions
> in configuration
> 
> +*/
> 
> +VOID
> 
> +RootportDownstreamPmConfiguration (
> 
> +  UINT8                               RpSegment,
> 
> +  UINT8                               RpBus,
> 
> +  UINT8                               RpDevice,
> 
> +  UINT8                               RpFunction,
> 
> +  UINT8                               BusMin,
> 
> +  UINT8                               BusMax,
> 
> +  PCIE_ROOT_PORT_COMMON_CONFIG        *PcieRpCommonConfig,
> 
> +  UINT32                              AspmOverrideTableSize,
> 
> +  PCH_PCIE_DEVICE_OVERRIDE            *AspmOverrideTable
> 
> +  );
> 
> +
> 
> +typedef struct {
> 
> +  UINT32 MaxSnoopLatencyValue         : 10;
> 
> +  UINT32 MaxSnoopLatencyScale         : 3;
> 
> +  UINT32 MaxNoSnoopLatencyValue       : 10;
> 
> +  UINT32 MaxNoSnoopLatencyScale       : 3;
> 
> +  UINT32 Reserved                     : 6;
> 
> +} LTR_LIMIT;
> 
> +
> 
> +/**
> 
> +  Checks if given PCI device is capable of Latency Tolerance Reporting
> 
> +
> 
> +  @param[in] Sbdf            device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval TRUE if yes
> 
> +**/
> 
> +BOOLEAN
> 
> +IsLtrCapable (
> 
> +  SBDF Sbdf
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Returns combination of two LTR override values
> 
> +  The resulting LTR override separately chooses stricter limits for snoop and
> nosnoop
> 
> +
> 
> +  @param[in] LtrA      LTR override values to be combined
> 
> +  @param[in] LtrB      LTR override values to be combined
> 
> +
> 
> +  @retval LTR override value
> 
> +**/
> 
> +LTR_OVERRIDE
> 
> +CombineLtr (
> 
> +  LTR_OVERRIDE LtrA,
> 
> +  LTR_OVERRIDE LtrB
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Extended Virtual Channel Configuration
> 
> +**/
> 
> +typedef struct {
> 
> +  UINT16 CapOffset;
> 
> +  UINT8  ExtVcCount;
> 
> +} MULTI_VC_SUPPORT;
> 
> +
> 
> +#endif // _PCI_EXPRESS_HELPERS_LIB_H_
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> eRpLib.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> eRpLib.h
> new file mode 100644
> index 0000000000..ed75e438c7
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pci
> eRpLib.h
> @@ -0,0 +1,109 @@
> +/** @file
> 
> +  Header file for PCH PCI Express helpers library
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#ifndef _PCIE_RP_LIB_
> 
> +#define _PCIE_RP_LIB_
> 
> +
> 
> +#include <PchPolicyCommon.h>
> 
> +
> 
> +typedef struct {
> 
> +  UINT32 MaxSnoopLatencyValue         : 10;
> 
> +  UINT32 MaxSnoopLatencyScale         : 3;
> 
> +  UINT32 MaxSnoopLatencyRequirement   : 1;
> 
> +  UINT32 MaxNoSnoopLatencyValue       : 10;
> 
> +  UINT32 MaxNoSnoopLatencyScale       : 3;
> 
> +  UINT32 MaxNoSnoopLatencyRequirement : 1;
> 
> +  UINT32 ForceOverride                : 1;
> 
> +} LTR_OVERRIDE;
> 
> +
> 
> +/**
> 
> +  Get PCIe port number for enabled Root Port.
> 
> +
> 
> +  @param[in] RpBase    Root Port pci segment base address
> 
> +
> 
> +  @retval Root Port number (1 based)
> 
> +**/
> 
> +UINT32
> 
> +PciePortNum (
> 
> +  IN     UINT64  RpBase
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Get PCIe root port index
> 
> +  @param[in] RpBase    Root Port pci segment base address
> 
> +  @return Root Port index (0 based)
> 
> +**/
> 
> +UINT32
> 
> +PciePortIndex (
> 
> +  IN     UINT64  RpBase
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This function checks whether PHY lane power gating is enabled on the
> port.
> 
> +
> 
> +  @param[in] RpBase                 Root Port base address
> 
> +
> 
> +  @retval TRUE                      PHY power gating is enabled
> 
> +  @retval FALSE                     PHY power gating disabled
> 
> +**/
> 
> +BOOLEAN
> 
> +PcieIsPhyLanePgEnabled (
> 
> +  IN     UINT64  RpBase
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Configures Root Port packet split.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] Mps                            maximum packet size
> 
> +**/
> 
> +VOID
> 
> +ConfigureRpPacketSplit (
> 
> +  UINT64 RpBase,
> 
> +  UINT8  Mps
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Configures LTR override in Root Port's proprietary registers.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] LtrConfig                      Root Port LTR configuration
> 
> +  @param[in] AspmOverride                   combination of LTR override values
> from all devices under this Root Port
> 
> +**/
> 
> +VOID
> 
> +ConfigureRpLtrOverride (
> 
> +  UINT64           RpBase,
> 
> +  UINT32           DevNum,
> 
> +  LTR_OVERRIDE     *TreeLtr,
> 
> +  PCIE_LTR_CONFIG  *LtrConfig
> 
> +  );
> 
> +
> 
> +/**
> 
> +  This function configures EOI message forwarding for PCIe port.
> 
> +  If there's an IoAPIC behind this port, forwarding will be enabled
> 
> +  Otherwise it will be disabled to minimize bus traffic
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] IoApicPresent  TRUE if there's IoAPIC behind this Root Port
> 
> +**/
> 
> +VOID
> 
> +ConfigureEoiForwarding (
> 
> +  UINT64   RpBase,
> 
> +  BOOLEAN  IoApicPresent
> 
> +  );
> 
> +
> 
> +/**
> 
> +  Configures proprietary parts of L1 substates configuration in Root Port
> 
> +
> 
> +  @param[in] RpSbdf       segment:bus:device:function coordinates of Root
> Port
> 
> +  @param[in] LtrCapable   TRUE if Root Port is LTR capable
> 
> +**/
> 
> +VOID
> 
> +L1ssProprietaryConfiguration (
> 
> +  UINT64  RpBase,
> 
> +  BOOLEAN LtrCapable
> 
> +  );
> 
> +#endif
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/P
> cieSipRegs.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/P
> cieSipRegs.h
> new file mode 100644
> index 0000000000..1fc470b8ba
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/P
> cieSipRegs.h
> @@ -0,0 +1,45 @@
> +/** @file
> 
> +  Register names for PCIe SIP specific registers
> 
> +
> 
> +  Conventions:
> 
> +
> 
> +  - Register definition format:
> 
> +
> Prefix_[GenerationName]_[ComponentName]_SubsystemName_RegisterS
> pace_RegisterName
> 
> +  - Prefix:
> 
> +  Definitions beginning with "R_" are registers
> 
> +  Definitions beginning with "B_" are bits within registers
> 
> +  Definitions beginning with "V_" are meaningful values within the bits
> 
> +  Definitions beginning with "S_" are register size
> 
> +  Definitions beginning with "N_" are the bit position
> 
> +  - [GenerationName]:
> 
> +  Three letter acronym of the generation is used (e.g. SKL,KBL,CNL etc.).
> 
> +  Register name without GenerationName applies to all generations.
> 
> +  - [ComponentName]:
> 
> +  This field indicates the component name that the register belongs to (e.g.
> PCH, SA etc.)
> 
> +  Register name without ComponentName applies to all components.
> 
> +  Register that is specific to -LP denoted by "_PCH_LP_" in component
> name.
> 
> +  - SubsystemName:
> 
> +  This field indicates the subsystem name of the component that the
> register belongs to
> 
> +    (e.g. PCIE, USB, SATA, GPIO, PMC etc.).
> 
> +  - RegisterSpace:
> 
> +  MEM - MMIO space register of subsystem.
> 
> +  IO  - IO space register of subsystem.
> 
> +  PCR - Private configuration register of subsystem.
> 
> +  CFG - PCI configuration space register of subsystem.
> 
> +  - RegisterName:
> 
> +  Full register name.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +
> 
> +#ifndef _PCIE_SIP_RP_REGS_H_
> 
> +#define _PCIE_SIP_RP_REGS_H_
> 
> +
> 
> +#include <PcieRegs.h>
> 
> +
> 
> +#define R_PCIE_CFG_CCFG                               0xD0
> 
> +#define B_PCIE_CFG_CCFG_UNRS                          (BIT6 | BIT5 | BIT4)
> 
> +#define N_PCIE_CFG_CCFG_UNRS                          4
> 
> +
> 
> +#endif
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.c
> new file mode 100644
> index 0000000000..1b3e629431
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.c
> @@ -0,0 +1,315 @@
> +/** @file
> 
> +  This file contains routines that support PCI Express initialization
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#include <Library/PcieHelperLib.h>
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <PcieRegs.h>
> 
> +
> 
> +#define ASPM_L1_NO_LIMIT 0xFF
> 
> +#define LINK_RETRAIN_WAIT_TIME 1000 // microseconds
> 
> +
> 
> +/**
> 
> +  Finds the Offset to a given Capabilities ID
> 
> +  Each capability has an ID and a pointer to next Capability, so they form a
> linked list.
> 
> +  This function walks the list of Capabilities present in device's pci cfg. If
> requested capability
> 
> +  can be found, its offset is returned.
> 
> +  If the capability can't be found or if device doesn't exist, function returns 0
> 
> +  CAPID list:
> 
> +    0x01 = PCI Power Management Interface
> 
> +    0x04 = Slot Identification
> 
> +    0x05 = MSI Capability
> 
> +    0x10 = PCI Express Capability
> 
> +
> 
> +  @param[in] DeviceBase           device's base address
> 
> +  @param[in] CapId                CAPID to search for
> 
> +
> 
> +  @retval 0                       CAPID not found (this includes situation where device
> doesn't exit)
> 
> +  @retval Other                   CAPID found, Offset of desired CAPID
> 
> +**/
> 
> +UINT8
> 
> +PcieBaseFindCapId (
> 
> +  IN UINT64  DeviceBase,
> 
> +  IN UINT8   CapId
> 
> +  )
> 
> +{
> 
> +  UINT8  CapHeaderOffset;
> 
> +  UINT8  CapHeaderId;
> 
> +  UINT16 Data16;
> 
> +  //
> 
> +  // We do not explicitly check if device exists to save time and avoid
> unnecessary PCI access
> 
> +  // If the device doesn't exist, check for CapHeaderId != 0xFF will fail and
> function will return offset 0
> 
> +  //
> 
> +  if ((PciSegmentRead8 (DeviceBase + PCI_PRIMARY_STATUS_OFFSET) &
> EFI_PCI_STATUS_CAPABILITY) == 0x00) {
> 
> +    ///
> 
> +    /// Function has no capability pointer
> 
> +    ///
> 
> +    return 0;
> 
> +  } else {
> 
> +    ///
> 
> +    /// Check the header layout to determine the Offset of Capabilities
> Pointer Register
> 
> +    ///
> 
> +    if ((PciSegmentRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) &
> HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE)) {
> 
> +      ///
> 
> +      /// If CardBus bridge, start at Offset 0x14
> 
> +      ///
> 
> +      CapHeaderOffset = EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR;
> 
> +    } else {
> 
> +      ///
> 
> +      /// Otherwise, start at Offset 0x34
> 
> +      ///
> 
> +      CapHeaderOffset = PCI_CAPBILITY_POINTER_OFFSET;
> 
> +    }
> 
> +    ///
> 
> +    /// Get Capability Header, A pointer value of 00h is used to indicate the
> last capability in the list.
> 
> +    ///
> 
> +    CapHeaderId     = 0;
> 
> +    CapHeaderOffset = PciSegmentRead8 (DeviceBase + CapHeaderOffset) &
> ((UINT8) ~(BIT0 | BIT1));
> 
> +    while (CapHeaderOffset != 0 && CapHeaderId != 0xFF) {
> 
> +      Data16 = PciSegmentRead16 (DeviceBase + CapHeaderOffset);
> 
> +      CapHeaderId = (UINT8)(Data16 & 0xFF);
> 
> +      if (CapHeaderId == CapId) {
> 
> +        if (CapHeaderOffset > PCI_MAXLAT_OFFSET) {
> 
> +          ///
> 
> +          /// Return valid capability offset
> 
> +          ///
> 
> +          return CapHeaderOffset;
> 
> +        } else {
> 
> +          ASSERT ((FALSE));
> 
> +          return 0;
> 
> +        }
> 
> +      }
> 
> +      ///
> 
> +      /// Each capability must be DWORD aligned.
> 
> +      /// The bottom two bits of all pointers (including the initial pointer at
> 34h) are reserved
> 
> +      /// and must be implemented as 00b although software must mask them
> to allow for future uses of these bits.
> 
> +      ///
> 
> +      CapHeaderOffset = (UINT8)(Data16 >> 8);
> 
> +    }
> 
> +    return 0;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Find the Offset to a given Capabilities ID
> 
> +  CAPID list:
> 
> +    0x01 = PCI Power Management Interface
> 
> +    0x04 = Slot Identification
> 
> +    0x05 = MSI Capability
> 
> +    0x10 = PCI Express Capability
> 
> +
> 
> +  @param[in] Segment              Pci Segment Number
> 
> +  @param[in] Bus                  Pci Bus Number
> 
> +  @param[in] Device               Pci Device Number
> 
> +  @param[in] Function             Pci Function Number
> 
> +  @param[in] CapId                CAPID to search for
> 
> +
> 
> +  @retval 0                       CAPID not found
> 
> +  @retval Other                   CAPID found, Offset of desired CAPID
> 
> +**/
> 
> +UINT8
> 
> +PcieFindCapId (
> 
> +  IN UINT8   Segment,
> 
> +  IN UINT8   Bus,
> 
> +  IN UINT8   Device,
> 
> +  IN UINT8   Function,
> 
> +  IN UINT8   CapId
> 
> +  )
> 
> +{
> 
> +  UINT64 DeviceBase;
> 
> +
> 
> +  DeviceBase = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device,
> Function, 0);
> 
> +  return PcieBaseFindCapId (DeviceBase, CapId);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Search and return the offset of desired Pci Express Capability ID
> 
> +  CAPID list:
> 
> +    0x0001 = Advanced Error Reporting Capability
> 
> +    0x0002 = Virtual Channel Capability
> 
> +    0x0003 = Device Serial Number Capability
> 
> +    0x0004 = Power Budgeting Capability
> 
> +
> 
> +  @param[in] DeviceBase           device base address
> 
> +  @param[in] CapId                Extended CAPID to search for
> 
> +
> 
> +  @retval 0                       CAPID not found, this includes situation where device
> doesn't exist
> 
> +  @retval Other                   CAPID found, Offset of desired CAPID
> 
> +**/
> 
> +UINT16
> 
> +PcieBaseFindExtendedCapId (
> 
> +  IN UINT64  DeviceBase,
> 
> +  IN UINT16  CapId
> 
> +  )
> 
> +{
> 
> +  UINT16  CapHeaderOffset;
> 
> +  UINT16  CapHeaderId;
> 
> +  ///
> 
> +  /// Start to search at Offset 0x100
> 
> +  /// Get Capability Header, A pointer value of 00h is used to indicate the last
> capability in the list.
> 
> +  ///
> 
> +  CapHeaderId     = 0;
> 
> +  CapHeaderOffset = R_PCIE_CFG_EXCAP_OFFSET;
> 
> +  while (CapHeaderOffset != 0 && CapHeaderId != MAX_UINT16) {
> 
> +    CapHeaderId = PciSegmentRead16 (DeviceBase + CapHeaderOffset);
> 
> +    if (CapHeaderId == CapId) {
> 
> +      return CapHeaderOffset;
> 
> +    }
> 
> +    ///
> 
> +    /// Each capability must be DWORD aligned.
> 
> +    /// The bottom two bits of all pointers are reserved and must be
> implemented as 00b
> 
> +    /// although software must mask them to allow for future uses of these
> bits.
> 
> +    ///
> 
> +    CapHeaderOffset = (PciSegmentRead16 (DeviceBase + CapHeaderOffset
> + 2) >> 4) & ((UINT16) ~(BIT0 | BIT1));
> 
> +  }
> 
> +
> 
> +  return 0;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Search and return the offset of desired Pci Express Capability ID
> 
> +  CAPID list:
> 
> +    0x0001 = Advanced Error Reporting Capability
> 
> +    0x0002 = Virtual Channel Capability
> 
> +    0x0003 = Device Serial Number Capability
> 
> +    0x0004 = Power Budgeting Capability
> 
> +
> 
> +  @param[in] Segment              Pci Segment Number
> 
> +  @param[in] Bus                  Pci Bus Number
> 
> +  @param[in] Device               Pci Device Number
> 
> +  @param[in] Function             Pci Function Number
> 
> +  @param[in] CapId                Extended CAPID to search for
> 
> +
> 
> +  @retval 0                       CAPID not found, this includes situation where device
> doesn't exist
> 
> +  @retval Other                   CAPID found, Offset of desired CAPID
> 
> +**/
> 
> +UINT16
> 
> +PcieFindExtendedCapId (
> 
> +  IN UINT8   Segment,
> 
> +  IN UINT8   Bus,
> 
> +  IN UINT8   Device,
> 
> +  IN UINT8   Function,
> 
> +  IN UINT16  CapId
> 
> +  )
> 
> +{
> 
> +  UINT64  DeviceBase;
> 
> +
> 
> +  DeviceBase = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device,
> Function, 0);
> 
> +  return PcieBaseFindExtendedCapId (DeviceBase, CapId);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if PCI device at given address exists
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +
> 
> +  @retval TRUE if exists
> 
> +**/
> 
> +BOOLEAN
> 
> +IsDevicePresent (
> 
> +  UINT64 Base
> 
> +  )
> 
> +{
> 
> +  if (PciSegmentRead16 (Base) == 0xFFFF) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  return TRUE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if device is a multifunction device
> 
> +  Besides comparing Multifunction bit (BIT7) it checks if contents of
> HEADER_TYPE register
> 
> +  make sense (header != 0xFF) to prevent false positives when called on
> devices which do not exist
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +
> 
> +  @retval TRUE if multifunction; FALSE otherwise
> 
> +**/
> 
> +BOOLEAN
> 
> +IsMultifunctionDevice (
> 
> +  UINT64 Base
> 
> +  )
> 
> +{
> 
> +  UINT8 HeaderType;
> 
> +  HeaderType = PciSegmentRead8(Base + PCI_HEADER_TYPE_OFFSET);
> 
> +  if ((HeaderType == 0xFF) || ((HeaderType &
> HEADER_TYPE_MULTI_FUNCTION) == 0)) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  return TRUE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks device's Slot Clock Configuration
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +  @param[in] PcieCapOffset   devices Pci express capability list register
> offset
> 
> +
> 
> +  @retval TRUE when device uses slot clock, FALSE otherwise
> 
> +**/
> 
> +BOOLEAN
> 
> +GetScc (
> 
> +  UINT64    Base,
> 
> +  UINT8     PcieCapOffset
> 
> +  )
> 
> +{
> 
> +  return !!(PciSegmentRead16 (Base + PcieCapOffset +
> R_PCIE_LSTS_OFFSET) & B_PCIE_LSTS_SCC);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Common Clock Configuration bit for given device.
> 
> +
> 
> +  @param[in] PcieCapOffset   devices Pci express capability list register
> offset
> 
> +  @param[in] Base            device's base address
> 
> +**/
> 
> +VOID
> 
> +EnableCcc (
> 
> +  UINT64    Base,
> 
> +  UINT8     PcieCapOffset
> 
> +  )
> 
> +{
> 
> +  PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET,
> B_PCIE_LCTL_CCC);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Retrains link behind given device.
> 
> +  It only makes sense to call it for downstream ports. If called for upstream
> port nothing will happen.
> 
> +  If WaitUntilDone is TRUE function will wait until link retrain had finished,
> otherwise it will return immediately.
> 
> +  Link must finish retrain before software can access the device on the other
> side. If it's not going to access it
> 
> +  then considerable time can be saved by not waiting here.
> 
> +
> 
> +  @param[in] Base             device's base address
> 
> +  @param[in] PcieCapOffset    devices Pci express capability list register
> offset
> 
> +  @param[in] WaitUntilDone    when TRUE, function waits until link has
> retrained
> 
> +**/
> 
> +VOID
> 
> +RetrainLink (
> 
> +  UINT64  Base,
> 
> +  UINT8   PcieCapOffset,
> 
> +  BOOLEAN WaitUntilDone
> 
> +  )
> 
> +{
> 
> +  UINT16 LinkTraining;
> 
> +  UINT32 TimeoutUs;
> 
> +
> 
> +  TimeoutUs = LINK_RETRAIN_WAIT_TIME;
> 
> +  //
> 
> +  // Before triggering link retrain make sure it's not already retraining.
> Otherwise
> 
> +  // settings recently entered in LCTL register might go unnoticed
> 
> +  //
> 
> +  do {
> 
> +    LinkTraining = (PciSegmentRead16 (Base + PcieCapOffset +
> R_PCIE_LSTS_OFFSET) & B_PCIE_LSTS_LT);
> 
> +    TimeoutUs--;
> 
> +  } while (LinkTraining && (TimeoutUs != 0));
> 
> +
> 
> +  PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET,
> B_PCIE_LCTL_RL);
> 
> +
> 
> +  TimeoutUs = LINK_RETRAIN_WAIT_TIME;
> 
> +  if (WaitUntilDone) {
> 
> +    do {
> 
> +      LinkTraining = (PciSegmentRead16 (Base + PcieCapOffset +
> R_PCIE_LSTS_OFFSET) & B_PCIE_LSTS_LT);
> 
> +      TimeoutUs--;
> 
> +    } while (LinkTraining && (TimeoutUs != 0));
> 
> +  }
> 
> +}
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.inf
> new file mode 100644
> index 0000000000..458a540859
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib
> /BasePcieHelperLib.inf
> @@ -0,0 +1,37 @@
> +## @file
> 
> +# Component description file for the BasePcieHelperLib
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +
> 
> +[Defines]
> 
> +INF_VERSION = 0x00010017
> 
> +BASE_NAME = BasePcieHelperLib
> 
> +FILE_GUID = 568F5812-A9A8-4A4A-AD4D-471DD5F0BC11
> 
> +VERSION_STRING = 1.0
> 
> +MODULE_TYPE = BASE
> 
> +LIBRARY_CLASS = BasePcieHelperLib
> 
> +#
> 
> +# The following information is for reference only and not required by the
> build tools.
> 
> +#
> 
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> 
> +#
> 
> +
> 
> +
> 
> +
> 
> +[LibraryClasses]
> 
> +DebugLib
> 
> +PciSegmentLib
> 
> +
> 
> +
> 
> +[Packages]
> 
> +MdePkg/MdePkg.dec
> 
> +TigerlakeSiliconPkg/SiPkg.dec
> 
> +
> 
> +
> 
> +[Sources]
> 
> +BasePcieHelperLib.c
> 
> +
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLib.c
> new file mode 100644
> index 0000000000..153c073093
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLib.c
> @@ -0,0 +1,69 @@
> +/** @file
> 
> +  PCIE root port library.
> 
> +  All function in this library is available for PEI, DXE, and SMM,
> 
> +  But do not support UEFI RUNTIME environment call.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +
> 
> +#include <Base.h>
> 
> +#include <Uefi/UefiBaseType.h>
> 
> +#include <Library/IoLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/PciSegmentLib.h>
> 
> +#include <Library/PchInfoLib.h>
> 
> +#include <Library/PchPcrLib.h>
> 
> +#include <Library/PchPcieRpLib.h>
> 
> +#include <PcieRegs.h>
> 
> +#include <Register/PchRegs.h>
> 
> +#include <PchPcieRpInfo.h>
> 
> +#include <Register/PchPcieRpRegs.h>
> 
> +#include <Register/PchPcrRegs.h>
> 
> +#include <Library/PchPciBdfLib.h>
> 
> +
> 
> +#include "PchPcieRpLibInternal.h"
> 
> +
> 
> +/**
> 
> +  Gets pci segment base address of PCIe root port.
> 
> +
> 
> +  @param RpIndex    Root Port Index (0 based)
> 
> +  @return PCIe port base address.
> 
> +**/
> 
> +UINT64
> 
> +PchPcieBase (
> 
> +  IN  UINT32   RpIndex
> 
> +  )
> 
> +{
> 
> +  return PchPcieRpPciCfgBase (RpIndex);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Determines whether L0s is supported on current stepping.
> 
> +
> 
> +  @return TRUE if L0s is supported, FALSE otherwise
> 
> +**/
> 
> +BOOLEAN
> 
> +PchIsPcieL0sSupported (
> 
> +  VOID
> 
> +  )
> 
> +{
> 
> +  return TRUE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Some early PCH steppings require Native ASPM to be disabled due to
> hardware issues:
> 
> +   - RxL0s exit causes recovery
> 
> +   - Disabling PCIe L0s capability disables L1
> 
> +  Use this function to determine affected steppings.
> 
> +
> 
> +  @return TRUE if Native ASPM is supported, FALSE otherwise
> 
> +**/
> 
> +BOOLEAN
> 
> +PchIsPcieNativeAspmSupported (
> 
> +  VOID
> 
> +  )
> 
> +{
> 
> +  return PchIsPcieL0sSupported ();
> 
> +}
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibInternal.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibInternal.h
> new file mode 100644
> index 0000000000..1766cff618
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibInternal.h
> @@ -0,0 +1,20 @@
> +/** @file
> 
> +  PCIE root port library.
> 
> +  All function in this library is available for PEI, DXE, and SMM,
> 
> +  But do not support UEFI RUNTIME environment call.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +
> 
> +#ifndef _PCH_PCIE_RP_LIB_INTERNAL_H_
> 
> +#define _PCH_PCIE_RP_LIB_INTERNAL_H_
> 
> +
> 
> +typedef struct {
> 
> +  UINT8 DevNum;
> 
> +  UINT8 Pid;
> 
> +  UINT8 RpNumBase;
> 
> +} PCH_PCIE_CONTROLLER_INFO;
> 
> +
> 
> +#endif
> 
> +
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibVer2.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibVer2.c
> new file mode 100644
> index 0000000000..df90a87df7
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PchPcieRpLibVer2.c
> @@ -0,0 +1,128 @@
> +/** @file
> 
> +  PCIE root port library.
> 
> +  All function in this library is available for PEI, DXE, and SMM,
> 
> +  But do not support UEFI RUNTIME environment call.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +
> 
> +#include <Base.h>
> 
> +#include <Uefi/UefiBaseType.h>
> 
> +#include <Library/IoLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/PciSegmentLib.h>
> 
> +#include <Library/PchInfoLib.h>
> 
> +#include <Library/PchPcrLib.h>
> 
> +#include <Library/PchPcieRpLib.h>
> 
> +#include <PcieRegs.h>
> 
> +#include <Register/PchRegs.h>
> 
> +#include <PchBdfAssignment.h>
> 
> +#include <PchPcieRpInfo.h>
> 
> +#include <Register/PchPcieRpRegs.h>
> 
> +#include <Register/PchPcrRegs.h>
> 
> +
> 
> +#include "PchPcieRpLibInternal.h"
> 
> +
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_CONTROLLER_INFO
> mPchPcieControllerInfo[] = {
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_1,  PID_SPA,  0 },
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_5,  PID_SPB,  4 },
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_9,  PID_SPC,  8 },
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_13, PID_SPD, 12 },
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_17, PID_SPE, 16 }, //
> PCH-H only
> 
> +  { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_21, PID_SPF, 20 }  // PCH-
> H only
> 
> +};
> 
> +
> 
> +/**
> 
> +  Get 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.
> 
> +
> 
> +  @retval     EFI_SUCCESS           Root port device and function is retrieved
> 
> +  @retval     EFI_INVALID_PARAMETER RpNumber is invalid
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +GetPchPcieRpDevFun (
> 
> +  IN  UINTN   RpNumber,
> 
> +  OUT UINTN   *RpDev,
> 
> +  OUT UINTN   *RpFun
> 
> +  )
> 
> +{
> 
> +  UINTN       Index;
> 
> +  UINTN       FuncIndex;
> 
> +  UINT32      PciePcd;
> 
> +
> 
> +  if (RpNumber >= GetPchMaxPciePortNum ()) {
> 
> +    DEBUG ((DEBUG_ERROR, "GetPchPcieRpDevFun invalid RpNumber %x",
> RpNumber));
> 
> +    ASSERT (FALSE);
> 
> +    return EFI_INVALID_PARAMETER;
> 
> +  }
> 
> +
> 
> +  Index = RpNumber / PCH_PCIE_CONTROLLER_PORTS;
> 
> +  FuncIndex = RpNumber - mPchPcieControllerInfo[Index].RpNumBase;
> 
> +  *RpDev = mPchPcieControllerInfo[Index].DevNum;
> 
> +  PciePcd = PchPcrRead32 (mPchPcieControllerInfo[Index].Pid,
> R_SPX_PCR_PCD);
> 
> +  *RpFun = (PciePcd >> (FuncIndex * S_SPX_PCR_PCD_RP_FIELD)) &
> B_SPX_PCR_PCD_RP1FN;
> 
> +
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get Root Port physical Number by 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)
> 
> +
> 
> +  @retval     EFI_SUCCESS           Physical root port is retrieved
> 
> +**/
> 
> +EFI_STATUS
> 
> +EFIAPI
> 
> +GetPchPcieRpNumber (
> 
> +  IN  UINTN   RpDev,
> 
> +  IN  UINTN   RpFun,
> 
> +  OUT UINTN   *RpNumber
> 
> +  )
> 
> +{
> 
> +  UINT64 RpBase;
> 
> +
> 
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS
> (DEFAULT_PCI_SEGMENT_NUMBER_PCH,
> DEFAULT_PCI_BUS_NUMBER_PCH, RpDev, RpFun, 0);
> 
> +  *RpNumber = (PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) >>
> N_PCH_PCIE_CFG_LCAP_PN) -1;
> 
> +  return EFI_SUCCESS;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This function returns PID according to PCIe controller index
> 
> +
> 
> +  @param[in] ControllerIndex     PCIe controller index
> 
> +
> 
> +  @retval PCH_SBI_PID    Returns PID for SBI Access
> 
> +**/
> 
> +PCH_SBI_PID
> 
> +PchGetPcieControllerSbiPid (
> 
> +  IN UINT32  ControllerIndex
> 
> +  )
> 
> +{
> 
> +  ASSERT (ControllerIndex < ARRAY_SIZE (mPchPcieControllerInfo));
> 
> +  return mPchPcieControllerInfo[ControllerIndex].Pid;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This function returns PID according to Root Port Number
> 
> +
> 
> +  @param[in] RpIndex     Root Port Index (0-based)
> 
> +
> 
> +  @retval PCH_SBI_PID    Returns PID for SBI Access
> 
> +**/
> 
> +PCH_SBI_PID
> 
> +GetRpSbiPid (
> 
> +  IN UINTN  RpIndex
> 
> +  )
> 
> +{
> 
> +  return PchGetPcieControllerSbiPid ((UINT32) (RpIndex /
> PCH_PCIE_CONTROLLER_PORTS));
> 
> +}
> 
> +
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PeiDxeSmmPchPcieRpLibVer2.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PeiDxeSmmPchPcieRpLibVer2.inf
> new file mode 100644
> index 0000000000..4fc217581b
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPci
> eRpLib/PeiDxeSmmPchPcieRpLibVer2.inf
> @@ -0,0 +1,39 @@
> +## @file
> 
> +# PCIE root port Library.
> 
> +#
> 
> +# All function in this library is available for PEI, DXE, and SMM,
> 
> +# But do not support UEFI RUNTIME environment call.
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +
> 
> +[Defines]
> 
> +INF_VERSION = 0x00010017
> 
> +BASE_NAME = PeiDxeSmmPchPcieRpLib
> 
> +FILE_GUID = B522981C-E0C5-4E04-A82A-C61D4F0B2C75
> 
> +VERSION_STRING = 1.0
> 
> +MODULE_TYPE = BASE
> 
> +LIBRARY_CLASS = PchPcieRpLib
> 
> +
> 
> +
> 
> +[LibraryClasses]
> 
> +BaseLib
> 
> +IoLib
> 
> +DebugLib
> 
> +PciSegmentLib
> 
> +PchInfoLib
> 
> +PchPcrLib
> 
> +
> 
> +
> 
> +[Packages]
> 
> +MdePkg/MdePkg.dec
> 
> +TigerlakeSiliconPkg/SiPkg.dec
> 
> +
> 
> +
> 
> +[Sources]
> 
> +PchPcieRpLib.c
> 
> +PchPcieRpLibVer2.c
> 
> +
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcie
> RpPolicyLib/DxePchPcieRpPolicyLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPci
> eRpPolicyLib/DxePchPcieRpPolicyLib.c
> new file mode 100644
> index 0000000000..577e436e32
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPci
> eRpPolicyLib/DxePchPcieRpPolicyLib.c
> @@ -0,0 +1,179 @@
> +/** @file
> 
> +  This file provides services for PcieRp policy function
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#include <Uefi.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <Library/SiConfigBlockLib.h>
> 
> +#include <Library/ConfigBlockLib.h>
> 
> +#include <Protocol/PchPolicy.h>
> 
> +#include <PchPcieRpConfig.h>
> 
> +
> 
> +#define PCI_CLASS_NETWORK             0x02
> 
> +#define PCI_CLASS_NETWORK_ETHERNET    0x00
> 
> +#define PCI_CLASS_NETWORK_OTHER       0x80
> 
> +
> 
> +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE
> mPcieDeviceTable[] = {
> 
> +  //
> 
> +  // Intel PRO/Wireless
> 
> +  //
> 
> +  { 0x8086, 0x422b, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x422c, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x4238, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x4239, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel WiMAX/WiFi Link
> 
> +  //
> 
> +  { 0x8086, 0x0082, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0085, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0083, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0084, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0086, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0087, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0088, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0089, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x008F, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0090, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, 0,
> 0, 0, 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Crane Peak WLAN NIC
> 
> +  //
> 
> +  { 0x8086, 0x08AE, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x08AF, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Crane Peak w/BT WLAN NIC
> 
> +  //
> 
> +  { 0x8086, 0x0896, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0897, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Kelsey Peak WiFi, WiMax
> 
> +  //
> 
> +  { 0x8086, 0x0885, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0886, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Centrino Wireless-N 105
> 
> +  //
> 
> +  { 0x8086, 0x0894, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0895, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Centrino Wireless-N 135
> 
> +  //
> 
> +  { 0x8086, 0x0892, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0893, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Centrino Wireless-N 2200
> 
> +  //
> 
> +  { 0x8086, 0x0890, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0891, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Centrino Wireless-N 2230
> 
> +  //
> 
> +  { 0x8086, 0x0887, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x0888, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Centrino Wireless-N 6235
> 
> +  //
> 
> +  { 0x8086, 0x088E, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x088F, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel CampPeak 2 Wifi
> 
> +  //
> 
> +  { 0x8086, 0x08B5, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x08B6, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel WilkinsPeak 1 Wifi
> 
> +  //
> 
> +  { 0x8086, 0x08B3, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1,
> PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x08B4, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1,
> PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Wilkins Peak 2 Wifi
> 
> +  //
> 
> +  { 0x8086, 0x08B1, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1,
> PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, 0, 0 },
> 
> +  { 0x8086, 0x08B2, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1,
> PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Intel Wilkins Peak PF Wifi
> 
> +  //
> 
> +  { 0x8086, 0x08B0, 0xff, PCI_CLASS_NETWORK,
> PCI_CLASS_NETWORK_OTHER, PchPcieAspmL1, PchPcieL1L2Override, 0, 0, 0,
> 0, 0, 0, 0 },
> 
> +  //
> 
> +  // Teton Glacier Endpoint
> 
> +  //
> 
> +  { 0x8086, 0x0975, 0xff, 0, 0, 0, PchPcieL1SubstatesOverride, 0, 0xff, 0x3C, 0,
> 5, 0, 0, 0, 0 },
> 
> +
> 
> +  //
> 
> +  // End of Table
> 
> +  //
> 
> +  { 0 }
> 
> +};
> 
> +
> 
> +/**
> 
> +  Print PCIE_RP_DXE_CONFIG.
> 
> +
> 
> +  @param[in] PchPolicy            Pointer to a PCH_POLICY_PROTOCOL
> 
> +**/
> 
> +VOID
> 
> +PchPcieRpDxePrintConfig (
> 
> +  IN PCH_POLICY_PROTOCOL    *PchPolicy
> 
> +  )
> 
> +{
> 
> +  EFI_STATUS            Status;
> 
> +  PCIE_RP_DXE_CONFIG    *PchPcieRpDxeConfig;
> 
> +
> 
> +  Status = GetConfigBlock ((VOID *) PchPolicy, &gPchPcieRpDxeConfigGuid,
> (VOID *) &PchPcieRpDxeConfig);
> 
> +  ASSERT_EFI_ERROR (Status);
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "------------------ PCH PCIE DXE CONFIG --------------
> ----\n"));
> 
> +  DEBUG ((DEBUG_INFO, " PcieDeviceOverrideTablePtr :
> 0x%x\n",PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Load DXE Config block default for Pch PCIE RP
> 
> +
> 
> +  @param[in] ConfigBlockPointer         Pointer to config block
> 
> +**/
> 
> +VOID
> 
> +LoadPchPcieRpDxeConfigDefault (
> 
> +  IN VOID          *ConfigBlockPointer
> 
> +  )
> 
> +{
> 
> +  PCIE_RP_DXE_CONFIG  *PchPcieRpDxeConfig;
> 
> +
> 
> +  PchPcieRpDxeConfig = ConfigBlockPointer;
> 
> +  PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr = mPcieDeviceTable;
> 
> +}
> 
> +
> 
> +STATIC COMPONENT_BLOCK_ENTRY  mPchPcieRpBlocks = {
> 
> +  &gPchPcieRpDxeConfigGuid,
> 
> +  sizeof (PCIE_RP_DXE_CONFIG),
> 
> +  PCIE_RP_DXE_CONFIG_REVISION,
> 
> +  LoadPchPcieRpDxeConfigDefault
> 
> +};
> 
> +
> 
> +/**
> 
> +  Get PchPcieRp config block table size.
> 
> +
> 
> +  @retval      Size of config block
> 
> +**/
> 
> +UINT16
> 
> +PchPcieRpDxeGetConfigBlockTotalSize (
> 
> +  VOID
> 
> +  )
> 
> +{
> 
> +  return mPchPcieRpBlocks.Size;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Add PchPcieRp ConfigBlock.
> 
> +
> 
> +  @param[in] ConfigBlockTableAddress    The pointer to config block table
> 
> +
> 
> +  @retval EFI_SUCCESS                   The policy default is initialized.
> 
> +  @retval EFI_OUT_OF_RESOURCES          Insufficient resources to create
> buffer
> 
> +**/
> 
> +EFI_STATUS
> 
> +PchPcieRpDxeAddConfigBlock (
> 
> +  IN VOID           *ConfigBlockTableAddress
> 
> +  )
> 
> +{
> 
> +  return AddComponentConfigBlocks (ConfigBlockTableAddress,
> &mPchPcieRpBlocks, 1);
> 
> +}
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcie
> RpPolicyLib/DxePchPcieRpPolicyLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPci
> eRpPolicyLib/DxePchPcieRpPolicyLib.inf
> new file mode 100644
> index 0000000000..6158e77a35
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPci
> eRpPolicyLib/DxePchPcieRpPolicyLib.inf
> @@ -0,0 +1,30 @@
> +## @file
> 
> +# Component description file for the PchPcieRp policy library
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +[Defines]
> 
> +INF_VERSION = 0x00010017
> 
> +BASE_NAME = DxePchPcieRpPolicyLib
> 
> +FILE_GUID = 328B0DE5-189A-4DB0-BFE1-557F4F89010B
> 
> +VERSION_STRING = 1.0
> 
> +MODULE_TYPE = BASE
> 
> +LIBRARY_CLASS = DxePchPcieRpPolicyLib
> 
> +
> 
> +[LibraryClasses]
> 
> +DebugLib
> 
> +ConfigBlockLib
> 
> +SiConfigBlockLib
> 
> +
> 
> +[Packages]
> 
> +MdePkg/MdePkg.dec
> 
> +TigerlakeSiliconPkg/SiPkg.dec
> 
> +
> 
> +[Sources]
> 
> +DxePchPcieRpPolicyLib.c
> 
> +
> 
> +[Guids]
> 
> +gPchPcieRpDxeConfigGuid  ## CONSUMES
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.c
> new file mode 100644
> index 0000000000..401a9fbe7b
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.c
> @@ -0,0 +1,1997 @@
> +/** @file
> 
> +  This file contains routines that support PCI Express initialization
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#include "PciExpressHelpersLibrary.h"
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <Library/PcieHelperLib.h>
> 
> +#include <Library/PchPciBdfLib.h>
> 
> +#include <Library/PcieRpLib.h>
> 
> +#include <PchPcieRpInfo.h>
> 
> +#include <CpuPcieInfo.h>
> 
> +#include <CpuPcieHob.h>
> 
> +#include <Library/HobLib.h>
> 
> +#include <Register/PchPcieRpRegs.h>
> 
> +
> 
> +#define ASPM_L1_NO_LIMIT 0xFF
> 
> +#define ASPM_L0s_NO_LIMIT 0x7
> 
> +#define LINK_RETRAIN_WAIT_TIME 1000 // microseconds
> 
> +
> 
> +typedef union {
> 
> +  struct {
> 
> +    UINT32  RequesterCapable       : 1;
> 
> +    UINT32  ResponderCapable       : 1;
> 
> +    UINT32  RootCapable            : 1;
> 
> +    UINT32  Reserved               : 5;
> 
> +    UINT32  LocalClockGranularity  : 8;
> 
> +    UINT32  Reserved2              : 16;
> 
> +  } Bits;
> 
> +  UINT32  Uint32;
> 
> +} PTM_CAPS;
> 
> +
> 
> +typedef union {
> 
> +  struct {
> 
> +    UINT32 Enable                 : 1;
> 
> +    UINT32 RootSelect             : 1;
> 
> +    UINT32 Reserved               : 6;
> 
> +    UINT32 EffectiveGranularity   : 8;
> 
> +    UINT32 Reserved2              : 16;
> 
> +  } Bits;
> 
> +  UINT32  Uint32;
> 
> +} PTM_CTRL;
> 
> +
> 
> +typedef struct {
> 
> +  UINT32                          Size;
> 
> +  const PCH_PCIE_DEVICE_OVERRIDE* Table;
> 
> +} OVERRIDE_TABLE;
> 
> +
> 
> +typedef enum {
> 
> +  DevTypePci,
> 
> +  DevTypePcieEndpoint,
> 
> +  DevTypePcieUpstream,
> 
> +  DevTypePcieDownstream,
> 
> +  DevTypeMax
> 
> +} PCI_DEV_TYPE;
> 
> +
> 
> +//
> 
> +// This structure keeps in one place all data relevant to enabling L0s and L1.
> 
> +// L0s latencies are encoded in the same way as in hardware registers. The
> only operation
> 
> +// that will be performed on them is comparison
> 
> +// L1 latencies are decoded to microseconds, because they will be used in
> subtractions and additions
> 
> +//
> 
> +typedef struct {
> 
> +  UINT32  L0sSupported          : 1;
> 
> +  UINT32  L1Supported           : 1;
> 
> +  UINT32  L0sAcceptableLatency  : 3; // encoded as in hardware register
> 
> +  UINT32  L1AcceptableLatencyUs : 8; // decoded to microseconds
> 
> +  UINT32  LinkL0sExitLatency    : 3; // encoded as in hardware register
> 
> +  UINT32  LinkL1ExitLatencyUs   : 8; // decoded to microseconds
> 
> +} ASPM_CAPS;
> 
> +
> 
> +typedef struct {
> 
> +  UINT32     AspmL11  : 1;
> 
> +  UINT32     AspmL12  : 1;
> 
> +  UINT32     PmL11    : 1;
> 
> +  UINT32     PmL12    : 1;
> 
> +  UINT32     Cmrt     : 8; // Common Mode Restore Time
> 
> +  UINT32     TpoScale : 2; // T power_on scale
> 
> +  UINT32     TpoValue : 6; // T power_on value
> 
> +} L1SS_CAPS;
> 
> +
> 
> +#define MAX_SBDF_TABLE_SIZE 50 //arbitrary table size; big enough to
> accomodate even full length TBT chain.
> 
> +
> 
> +typedef struct {
> 
> +  UINT32 Count;
> 
> +  SBDF   Entry [MAX_SBDF_TABLE_SIZE];
> 
> +} SBDF_TABLE;
> 
> +
> 
> +/**
> 
> +  Converts device's segment:bus:device:function coordinates to flat address
> 
> +
> 
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval    address of device's PCI cfg space
> 
> +**/
> 
> +STATIC
> 
> +UINT64
> 
> +SbdfToBase (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  return PCI_SEGMENT_LIB_ADDRESS (Sbdf.Seg, Sbdf.Bus, Sbdf.Dev,
> Sbdf.Func, 0);
> 
> +}
> 
> +
> 
> +/*
> 
> +  Converts Tpower_on from value:scale notation to microseconds
> 
> +
> 
> +  @param[in] TpoScale   T power on scale
> 
> +  @param[in] TpoValue   T power on value
> 
> +
> 
> +  @retval    number of microseconds
> 
> +*/
> 
> +UINT32
> 
> +TpoToUs (
> 
> +  UINT32 TpoScale,
> 
> +  UINT32 TpoValue
> 
> +  )
> 
> +{
> 
> +  static const UINT8 TpoScaleMultiplier[] = {2, 10, 100};
> 
> +
> 
> +  ASSERT (TpoScale < TpoScaleMax);
> 
> +  if (TpoScale >= TpoScaleMax) {
> 
> +    return 0;
> 
> +  }
> 
> +  return (TpoScaleMultiplier[TpoScale] * TpoValue);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get max payload size supported by device.
> 
> +
> 
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval    Max payload size, encoded in the same way as in register
> (0=128b, 1=256b, etc)
> 
> +**/
> 
> +STATIC
> 
> +UINT8
> 
> +GetMps (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  return (PciSegmentRead16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCAP_OFFSET) & B_PCIE_DCAP_MPS);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Maximum Payload Size to be used by device
> 
> +
> 
> +  @param[in] Sbdf   device's segment:bus:device:function coordinates
> 
> +  @param[in] Mps    Max payload size, encoded in the same way as in
> register (0=128b, 1=256b, etc)
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetMps (
> 
> +  SBDF  Sbdf,
> 
> +  UINT8  Mps
> 
> +  )
> 
> +{
> 
> +  PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCTL_OFFSET, (UINT16) ~B_PCIE_DCTL_MPS, Mps <<
> N_PCIE_DCTL_MPS);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Enables LTR feature in given device
> 
> +
> 
> +  @param[in] Sbdf            device's segment:bus:device:function coordinates
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +EnableLtr (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  if (Sbdf.PcieCap == 0) {
> 
> +    return;
> 
> +  }
> 
> +  PciSegmentOr32 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCTL2_OFFSET, B_PCIE_DCTL2_LTREN);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns information about type of device.
> 
> +
> 
> +  @param[out] Sbdf            device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval     one of: not a PCIe device (legacy PCI), PCIe endpoint, PCIe
> upstream port or PCIe downstream port (including rootport)
> 
> +**/
> 
> +STATIC
> 
> +PCI_DEV_TYPE
> 
> +GetDeviceType (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  UINT8 DeviceType;
> 
> +
> 
> +  if (Sbdf.PcieCap == 0) {
> 
> +    return DevTypePci;
> 
> +  }
> 
> +  DeviceType = (UINT8) ((PciSegmentRead16 (SbdfToBase (Sbdf) +
> Sbdf.PcieCap + R_PCIE_XCAP_OFFSET) & B_PCIE_XCAP_DT) >>
> N_PCIE_XCAP_DT);
> 
> +  if (DeviceType == PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT) {
> 
> +    return DevTypePcieUpstream;
> 
> +  } else if (DeviceType == PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT
> || DeviceType == PCIE_DEVICE_PORT_TYPE_ROOT_PORT) {
> 
> +    return DevTypePcieDownstream;
> 
> +  } else {
> 
> +    return DevTypePcieEndpoint;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Initializes Dev:Func numbers for use in FindNextPcieChild or
> FindNextLegalSbdf functions.
> 
> +
> 
> +  @param[out] Sbdf            device's segment:bus:device:function coordinates
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +InitChildFinder (
> 
> +  OUT SBDF *Sbdf
> 
> +  )
> 
> +{
> 
> +  //
> 
> +  // Initialize Dev/Func to maximum values, so that when FindNextLegalSbdf
> ()
> 
> +  // is called on those input parameters, it will return 1st legal address (Dev 0
> Func 0).
> 
> +  //
> 
> +  Sbdf->Dev = PCI_MAX_DEVICE;
> 
> +  Sbdf->Func = PCI_MAX_FUNC;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks the device is a bridge and has non-zero secondary bus number
> assigned.
> 
> +  If so, it returns TRUE and initializes ChildSbdf with such values that
> 
> +  allow searching for devices on the secondary bus.
> 
> +  ChildSbdf will be mangled even if this function returns FALSE.
> 
> +
> 
> +  Legal bus assignment is assumed. This function doesn't check subordinate
> bus numbers of
> 
> +  the the device it was called on or any bridges between it and root complex
> 
> +
> 
> +  @param[in]  Sbdf       device's segment:bus:device:function coordinates
> 
> +  @param[out] ChildSbdf  SBDF initialized in such way that calling
> FindNextPcieChild( ) on it will find all children devices
> 
> +
> 
> +  @retval TRUE if device is a bridge and has a bus behind it; FALSE otherwise
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +HasChildBus (
> 
> +  SBDF   Sbdf,
> 
> +  SBDF   *ChildSbdf
> 
> +  )
> 
> +{
> 
> +  UINT32 Data32;
> 
> +  UINT64 Base;
> 
> +  UINT8  SecondaryBus;
> 
> +
> 
> +  ChildSbdf->Seg = Sbdf.Seg;
> 
> +  InitChildFinder (ChildSbdf);
> 
> +
> 
> +  Base = SbdfToBase (Sbdf);
> 
> +
> 
> +  if (PciSegmentRead8 (Base + R_PCI_BCC_OFFSET) != PCI_CLASS_BRIDGE) {
> 
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02:%02:%02: no\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +    return FALSE;
> 
> +  }
> 
> +  Data32 = PciSegmentRead32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
> 
> +  SecondaryBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);
> 
> +  ChildSbdf->Bus = SecondaryBus;
> 
> +  if (SecondaryBus == 0) {
> 
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: no\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +    return FALSE;
> 
> +  } else {
> 
> +    DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: yes, %x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func, SecondaryBus));
> 
> +    return TRUE;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets LTR limit in a device.
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +  @param[in] Ltr             LTR limit
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetLtrLimit (
> 
> +  UINT64    Base,
> 
> +  LTR_LIMIT Ltr
> 
> +  )
> 
> +{
> 
> +  UINT16 LtrCapOffset;
> 
> +  UINT16 Data16;
> 
> +
> 
> +  LtrCapOffset = PcieBaseFindExtendedCapId (Base, R_PCIE_LTRECH_CID);
> 
> +  if (LtrCapOffset == 0) {
> 
> +    return;
> 
> +  }
> 
> +  Data16 = (UINT16)((Ltr.MaxSnoopLatencyValue <<
> N_PCIE_LTRECH_MSLR_VALUE) | (Ltr.MaxSnoopLatencyScale <<
> N_PCIE_LTRECH_MSLR_SCALE));
> 
> +  PciSegmentWrite16(Base + LtrCapOffset + R_PCIE_LTRECH_MSLR_OFFSET,
> Data16);
> 
> +
> 
> +  Data16 = (UINT16)((Ltr.MaxNoSnoopLatencyValue <<
> N_PCIE_LTRECH_MNSLR_VALUE) | (Ltr.MaxNoSnoopLatencyScale <<
> N_PCIE_LTRECH_MNSLR_SCALE));
> 
> +  PciSegmentWrite16(Base + LtrCapOffset +
> R_PCIE_LTRECH_MNSLR_OFFSET, Data16);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if device at given address exists and is a PCI Express device.
> 
> +  PCI express devices are distinguished from PCI by having Capability ID 0x10
> 
> +  If the device is PCI express then its SDBF structure gets updated with
> pointer to
> 
> +  the PCIe Capability. This is an optimization feature. It greatly decreases the
> number
> 
> +  of bus accesses, since most features configured by this library depend on
> registers
> 
> +  whose location is relative to PCIe capability.
> 
> +
> 
> +  @param[in,out] Sbdf   on entry, segment:bus:device:function coordinates
> 
> +                        on exit, PcieCap offset is updated
> 
> +
> 
> +  @retval               TRUE when PCIe device exists; FALSE if it's not PCIe or
> there's no device at all
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +IsPcieDevice (
> 
> +  SBDF *Sbdf
> 
> +  )
> 
> +{
> 
> +  UINT8 PcieCapOffset;
> 
> +  UINT64         Base;
> 
> +
> 
> +  Base = SbdfToBase(*Sbdf);
> 
> +
> 
> +  if (PciSegmentRead16 (Base) == 0xFFFF) {
> 
> +    return FALSE;
> 
> +  }
> 
> +
> 
> +
> 
> +  PcieCapOffset = PcieBaseFindCapId (Base,
> EFI_PCI_CAPABILITY_ID_PCIEXP);
> 
> +  if (PcieCapOffset == 0) {
> 
> +    DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - legacy\n", Sbdf-
> >Bus, Sbdf->Dev, Sbdf->Func));
> 
> +    return FALSE;
> 
> +  } else {
> 
> +    Sbdf->PcieCap = PcieCapOffset;
> 
> +    DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - yes\n", Sbdf-
> >Bus, Sbdf->Dev, Sbdf->Func));
> 
> +    return TRUE;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns TRUE and Dev:Func numbers where a PCIe device could legally be
> located, or FALSE if there
> 
> +  no such coordinates left.
> 
> +
> 
> +  Segment and Bus fields of SBDF structure are input only and determine
> which bus will be scanned.
> 
> +  This function should be called in a while() loop. It replaces the less efficient
> method of
> 
> +  using nested FOR loops that iterate over all device and function numbers.
> It is optimized for
> 
> +  the amount of bus access. If function0 doesn't exist or doesn't have
> Multifunction bit set,
> 
> +  then higher function numbers are skipped. If parent of this bus is a
> downstream port, then
> 
> +  Device numbers 1-31 get skipped too (there can be only Dev0 behind
> downstream ports)
> 
> +  If device/function number == 0x1F/0x7, this function returns first possible
> address, that is 0:0
> 
> +  Any other device number means Dev:Func contain address of last found
> child device
> 
> +  and this function should search for next one
> 
> +
> 
> +  @param[in]     ParentDevType  type of bridge who's partent of this bus
> 
> +  @param[in,out] Sbdf           On entry: location returned previously from this
> function
> 
> +                                          Dev:Func value of 1F:07 means search should start
> from the beginning
> 
> +                                On exit:  if legal Dev:Func combination was found, that
> Dev:Func is returned
> 
> +                                          otherwise, Dev:Func are initialized to 1F:07 for
> convenience
> 
> +
> 
> +  @retval TRUE when next legal Dev:Func address was found; FALSE
> otherwise
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +FindNextLegalSbdf (
> 
> +  IN     PCI_DEV_TYPE ParentDevType,
> 
> +  IN OUT SBDF         *Sbdf
> 
> +  )
> 
> +{
> 
> +  UINT8  MaxDev;
> 
> +  UINT64 Func0Base;
> 
> +
> 
> +  if (ParentDevType == DevTypePcieEndpoint) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  if (ParentDevType == DevTypePcieUpstream) {
> 
> +    MaxDev = PCI_MAX_DEVICE;
> 
> +  } else {
> 
> +    MaxDev = 0;
> 
> +  }
> 
> +  Func0Base = PCI_SEGMENT_LIB_ADDRESS (Sbdf->Seg, Sbdf->Bus, Sbdf-
> >Dev, 0, 0);
> 
> +  if ((Sbdf->Dev == PCI_MAX_DEVICE) && Sbdf->Func == PCI_MAX_FUNC) {
> 
> +    Sbdf->Dev = 0;
> 
> +    Sbdf->Func = 0;
> 
> +    return TRUE;
> 
> +  } else if ((Sbdf->Func == PCI_MAX_FUNC) || (Sbdf->Func == 0 &&
> !IsMultifunctionDevice (Func0Base))) {
> 
> +  //
> 
> +  // if it's the last function of a device, then return Func0 of new device or
> FALSE in case there are no more devices
> 
> +  //
> 
> +    if (Sbdf->Dev == MaxDev) {
> 
> +      InitChildFinder (Sbdf);
> 
> +      return FALSE;
> 
> +    }
> 
> +    (Sbdf->Dev)++;
> 
> +    Sbdf->Func = 0;
> 
> +    return TRUE;
> 
> +  } else {
> 
> +    (Sbdf->Func)++;
> 
> +    return TRUE;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Finds next PCIe (not legacy PCI) device behind given device
> 
> +  If device/function number == 0x1F/0x7, this function searches for children
> from scratch
> 
> +  Any other device number means Dev:Func contain address of last found
> child device
> 
> +  and this function should search for next one
> 
> +
> 
> +  @param[in]     ParentDevType  type of bridge who's partent of this bus
> 
> +  @param[in,out] Sbdf           On entry: location returned previously from this
> function
> 
> +                                          Dev:Func value of 0x1F:0x07 means search should start
> from the beginning
> 
> +                                On exit:  if PCIe device was found, its SBDF coordinates are
> returned
> 
> +                                          otherwise, Dev:Func are initialized to 0x1F:0x07 for
> convenience
> 
> +  @retval TRUE when next PCIe device was found; FALSE otherwise
> 
> +**/
> 
> +BOOLEAN
> 
> +FindNextPcieChild (
> 
> +  IN     PCI_DEV_TYPE ParentDevType,
> 
> +  IN OUT SBDF   *Sbdf
> 
> +  )
> 
> +{
> 
> +  while ( FindNextLegalSbdf (ParentDevType, Sbdf)) {
> 
> +    if (IsPcieDevice (Sbdf)) {
> 
> +      return TRUE;
> 
> +    }
> 
> +  }
> 
> +  return FALSE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if given device supports Clock Power Management
> 
> +
> 
> +  @param[in] Sbdf     segment:bus:device:function coordinates of a device
> 
> +
> 
> +  @retval TRUE when device supports it, FALSE otherwise
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +IsCpmSupported (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_LCAP_OFFSET) & B_PCIE_LCAP_CPM);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Enable Clock Power Management bit for given device
> 
> +
> 
> +  @param[in] Sbdf            segment:bus:device:function coordinates of a
> device
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +EnableCpm (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  PciSegmentOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_LCTL_OFFSET, B_PCIE_LCTL_ECPM);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if given device is an IoAPIC
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +
> 
> +  @retval TRUE if it's an IoAPIC
> 
> +**/
> 
> +BOOLEAN
> 
> +IsIoApicDevice (
> 
> +  UINT64 Base
> 
> +  )
> 
> +{
> 
> +  UINT8 BaseClassCode;
> 
> +  UINT8 SubClassCode;
> 
> +  UINT8 ProgInterface;
> 
> +
> 
> +  BaseClassCode = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 2);
> 
> +  SubClassCode  = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 1);
> 
> +  ProgInterface = PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET);
> 
> +  if ((BaseClassCode == PCI_CLASS_SYSTEM_PERIPHERAL) &&
> 
> +      (SubClassCode == PCI_SUBCLASS_PIC) &&
> 
> +      ((ProgInterface == PCI_IF_APIC_CONTROLLER) ||
> 
> +       (ProgInterface == PCI_IF_APIC_CONTROLLER2))) {
> 
> +    return TRUE;
> 
> +  }
> 
> +  return FALSE;
> 
> +}
> 
> +
> 
> +/**
> 
> +  There are some devices which support L1 substates, but due to silicon bugs
> the corresponding register
> 
> +  cannot be found by scanning PCIe capabilities. This function checks list of
> such devices and if one
> 
> +  is found, returns its L1ss capability register offset
> 
> +
> 
> +  @param[in] Base       base address of device
> 
> +  @param[in] Override   table of devices that need override
> 
> +
> 
> +  @retval               offset to L1ss capability register
> 
> +**/
> 
> +UINT16
> 
> +GetOverrideL1ssCapsOffset (
> 
> +  UINT64         Base,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  UINT16 DeviceId;
> 
> +  UINT16 VendorId;
> 
> +  UINT8  Revision;
> 
> +  UINT32 Index;
> 
> +
> 
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> 
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> 
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> 
> +
> 
> +  for (Index = 0; Index < Override->Size; Index++) {
> 
> +    if (((Override->Table[Index].OverrideConfig &
> PchPcieL1SubstatesOverride) == PchPcieL1SubstatesOverride) &&
> 
> +        (Override->Table[Index].VendorId == VendorId) &&
> 
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> 
> +        (Override->Table[Index].RevId == Revision || Override-
> >Table[Index].RevId == 0xFFFF)) {
> 
> +      return Override->Table[Index].L1SubstatesCapOffset;
> 
> +    }
> 
> +  }
> 
> +  return 0;
> 
> +}
> 
> +
> 
> +/**
> 
> +  There are some devices whose implementation of L1 substates is partially
> broken. This function checks
> 
> +  list of such devices and if one is found, overrides their L1ss-related
> capabilities
> 
> +
> 
> +  @param[in]     Base       base address of device
> 
> +  @param[in]     Override   table of devices that need override
> 
> +  @param[in,out] L1ss       on entry, capabilities read from register; on exit,
> capabilities modified according ot override table
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +OverrideL1ssCaps (
> 
> +  UINT64         Base,
> 
> +  OVERRIDE_TABLE *Override,
> 
> +  L1SS_CAPS      *L1ss
> 
> +  )
> 
> +{
> 
> +  UINT16 DeviceId;
> 
> +  UINT16 VendorId;
> 
> +  UINT8  Revision;
> 
> +  UINT32 Index;
> 
> +
> 
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> 
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> 
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> 
> +
> 
> +  for (Index = 0; Index < Override->Size; Index++) {
> 
> +    if (((Override->Table[Index].OverrideConfig &
> PchPcieL1SubstatesOverride) == PchPcieL1SubstatesOverride) &&
> 
> +        (Override->Table[Index].VendorId == VendorId) &&
> 
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> 
> +        (Override->Table[Index].RevId == Revision || Override-
> >Table[Index].RevId == 0xFF)) {
> 
> +
> 
> +      L1ss->PmL12   &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_PPL12S);
> 
> +      L1ss->PmL11   &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_PPL11S);
> 
> +      L1ss->AspmL12 &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_AL12S);
> 
> +      L1ss->AspmL11 &= !!(Override->Table[Index].L1SubstatesCapMask &
> B_PCIE_EX_L1SCAP_AL1SS);
> 
> +      if (Override->Table[Index].L1sTpowerOnValue != 0) {
> 
> +        L1ss->Cmrt = Override->Table[Index].L1sCommonModeRestoreTime;
> 
> +        L1ss->TpoScale = Override->Table[Index].L1sTpowerOnScale;
> 
> +        L1ss->TpoValue = Override->Table[Index].L1sTpowerOnValue;
> 
> +      }
> 
> +      return;
> 
> +    }
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns L1 sub states capabilities of a device
> 
> +
> 
> +  @param[in] Base   base address of a device
> 
> +
> 
> +  @retval L1SS_CAPS structure filled with device's capabilities
> 
> +**/
> 
> +STATIC
> 
> +L1SS_CAPS
> 
> +GetL1ssCaps (
> 
> +  UINT64         Base,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  L1SS_CAPS Capabilities = {0};
> 
> +  UINT16    PcieCapOffset;
> 
> +  UINT32    CapsRegister;
> 
> +
> 
> +  PcieCapOffset = GetOverrideL1ssCapsOffset (Base, Override);
> 
> +  if (PcieCapOffset == 0) {
> 
> +    PcieCapOffset = PcieBaseFindExtendedCapId (Base,
> V_PCIE_EX_L1S_CID);
> 
> +  }
> 
> +  if (PcieCapOffset == 0) {
> 
> +    return Capabilities;
> 
> +  }
> 
> +  CapsRegister = PciSegmentRead32 (Base + PcieCapOffset +
> R_PCIE_EX_L1SCAP_OFFSET);
> 
> +  if (CapsRegister & B_PCIE_EX_L1SCAP_L1PSS) {
> 
> +    //
> 
> +    // Skip L1.1 checking since some device only indecate L1.2 support.
> 
> +    // [1604452805]
> 
> +    //
> 
> +    Capabilities.PmL11 = !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL11S);
> 
> +    Capabilities.PmL12 = !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL12S);
> 
> +    Capabilities.AspmL12 = !!(CapsRegister & B_PCIE_EX_L1SCAP_AL12S);
> 
> +    Capabilities.AspmL11 = !!(CapsRegister & B_PCIE_EX_L1SCAP_AL1SS);
> 
> +    Capabilities.Cmrt = (CapsRegister & B_PCIE_EX_L1SCAP_CMRT) >>
> N_PCIE_EX_L1SCAP_CMRT;
> 
> +    Capabilities.TpoValue = (CapsRegister & B_PCIE_EX_L1SCAP_PTV) >>
> N_PCIE_EX_L1SCAP_PTV;
> 
> +    Capabilities.TpoScale = (CapsRegister & B_PCIE_EX_L1SCAP_PTPOS) >>
> N_PCIE_EX_L1SCAP_PTPOS;
> 
> +  }
> 
> +  OverrideL1ssCaps (Base, Override, &Capabilities);
> 
> +  return Capabilities;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns combination of two sets of L1 substate capabilities
> 
> +  Given feature is supported by the link only if both sides support it
> 
> +  Time parameters for link (Cmrt and Tpo) depend on the bigger value
> between two sides
> 
> +
> 
> +  @param[in] L1ssA      L1 substate capabilities of first device
> 
> +  @param[in] L1ssB      L1 substate capabilities of second device
> 
> +
> 
> +  @retval Link's L1 substate capabilities
> 
> +**/
> 
> +STATIC
> 
> +L1SS_CAPS
> 
> +CombineL1ss (
> 
> +  L1SS_CAPS L1ssA,
> 
> +  L1SS_CAPS L1ssB
> 
> +  )
> 
> +{
> 
> +  L1SS_CAPS Combined;
> 
> +
> 
> +  Combined.PmL12 = L1ssA.PmL12 && L1ssB.PmL12;
> 
> +  Combined.PmL11 = L1ssA.PmL11 && L1ssB.PmL11;
> 
> +  Combined.AspmL12 = L1ssA.AspmL12 && L1ssB.AspmL12;
> 
> +  Combined.AspmL11 = L1ssA.AspmL11 && L1ssB.AspmL11;
> 
> +  Combined.Cmrt = MAX (L1ssA.Cmrt, L1ssB.Cmrt);
> 
> +  if (TpoToUs (L1ssA.TpoScale, L1ssA.TpoValue) > TpoToUs (L1ssB.TpoScale,
> L1ssB.TpoValue)) {
> 
> +    Combined.TpoScale = L1ssA.TpoScale;
> 
> +    Combined.TpoValue = L1ssA.TpoValue;
> 
> +  } else {
> 
> +    Combined.TpoScale = L1ssB.TpoScale;
> 
> +    Combined.TpoValue = L1ssB.TpoValue;
> 
> +  }
> 
> +  return Combined;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures L1 substate feature in a device
> 
> +
> 
> +  @param[in] Sbdf     segment:bus:device:function coordinates of a device
> 
> +  @param[in] L1ss     configuration to be programmed
> 
> +  @param[in] Override table of devices that require special handling
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetL1ss (
> 
> +  SBDF           Sbdf,
> 
> +  L1SS_CAPS      L1ss,
> 
> +  OVERRIDE_TABLE *Override,
> 
> +  BOOLEAN   IsCpuPcie
> 
> +
> 
> +  )
> 
> +{
> 
> +  UINT16    PcieCapOffset;
> 
> +  UINT32    Ctrl1Register;
> 
> +  UINT32    Ctrl2Register;
> 
> +  UINT64    Base;
> 
> +
> 
> +  Base = SbdfToBase(Sbdf);
> 
> +  Ctrl1Register = 0;
> 
> +  Ctrl2Register = 0;
> 
> +
> 
> +  PcieCapOffset = GetOverrideL1ssCapsOffset (Base, Override);
> 
> +  if (PcieCapOffset == 0) {
> 
> +    PcieCapOffset = PcieBaseFindExtendedCapId (Base,
> V_PCIE_EX_L1S_CID);
> 
> +  }
> 
> +  if (PcieCapOffset == 0) {
> 
> +    return;
> 
> +  }
> 
> +
> 
> +  Ctrl1Register |= (L1ss.PmL12 ? B_PCIE_EX_L1SCAP_PPL12S : 0);
> 
> +  Ctrl1Register |= (L1ss.PmL11 ? B_PCIE_EX_L1SCAP_PPL11S : 0);
> 
> +  Ctrl1Register |= (L1ss.AspmL12 ? B_PCIE_EX_L1SCAP_AL12S : 0);
> 
> +  Ctrl1Register |= (L1ss.AspmL11 ? B_PCIE_EX_L1SCAP_AL1SS : 0);
> 
> +  if ((GetDeviceType (Sbdf) == DevTypePcieDownstream)) {
> 
> +    Ctrl1Register |= (L1ss.Cmrt << N_PCIE_EX_L1SCAP_CMRT);
> 
> +  }
> 
> +  ///
> 
> +  /// BWG 1.3 Section 5.5.7.6 LTR Threshold Latency
> 
> +  /// Set L1.2 LTR threshold using formula (TpoToUs (L1ss.TpoScale,
> L1ss.TpoValue) + L1ss.Cmrt + 10)
> 
> +  ///
> 
> +  Ctrl1Register |= ((TpoToUs (L1ss.TpoScale, L1ss.TpoValue) + L1ss.Cmrt +
> 10) << N_PCIE_EX_L1SCTL1_L12LTRTLV);
> 
> +  Ctrl1Register |= (2 << N_PCIE_EX_L1SCTL1_L12LTRTLSV);
> 
> +
> 
> +  Ctrl2Register |= (L1ss.TpoScale);
> 
> +  Ctrl2Register |= (L1ss.TpoValue << N_PCIE_EX_L1SCTL2_POWT);
> 
> +  //
> 
> +  // Set CLKREQ Acceleration Interrupt Enable
> 
> +  //
> 
> +  Ctrl1Register |= B_PCIE_EX_L1SCTL1_L1SSEIE;
> 
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
> 0);
> 
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL2_OFFSET,
> Ctrl2Register);
> 
> +  PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
> Ctrl1Register);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Converts L1 latency from enumerated register value to microseconds
> 
> +
> 
> +  @param[in] L1Latency     latency value retrieved from register; see PCIE
> specification for encoding
> 
> +
> 
> +  @retval    L1 latency converted to microseconds
> 
> +**/
> 
> +UINT32
> 
> +L1LatencyToUs (
> 
> +  UINT32 L1Latency
> 
> +  )
> 
> +{
> 
> +  if (L1Latency < 7) {
> 
> +    return 1 * (BIT0 << L1Latency);
> 
> +  } else {
> 
> +    return ASPM_L1_NO_LIMIT;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Modifies L1 latency by provided value
> 
> +
> 
> +  @param[in] Aspm     Structure that contains ASPM capabilities of a link,
> including L1 acceptable latency
> 
> +  @param[in] Value    Value, in microseconds, to be added to L1 acceptable
> latency. Can be negative.
> 
> +
> 
> +  @retval             Aspm structure with modified L1 acceptable latency
> 
> +**/
> 
> +STATIC
> 
> +ASPM_CAPS
> 
> +PatchL1AcceptableLatency (
> 
> +  ASPM_CAPS Aspm,
> 
> +  INT8      Value
> 
> +  )
> 
> +{
> 
> +  if (Aspm.L1AcceptableLatencyUs != ASPM_L1_NO_LIMIT) {
> 
> +    if (Value > 0) {
> 
> +      Aspm.L1AcceptableLatencyUs += Value;
> 
> +    } else {
> 
> +      if (Aspm.L1AcceptableLatencyUs > (UINT32)(-1*Value)) {
> 
> +        Aspm.L1AcceptableLatencyUs = Aspm.L1AcceptableLatencyUs + Value;
> 
> +      } else {
> 
> +        Aspm.L1AcceptableLatencyUs = 0;
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  return Aspm;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Reads ASPM capabilities of a device
> 
> +
> 
> +  @param[in] Sbdf segment:bus:device:function coordinates of a device
> 
> +
> 
> +  @retval           structure containing device's ASPM capabilities
> 
> +**/
> 
> +STATIC
> 
> +ASPM_CAPS
> 
> +GetAspmCaps (
> 
> +  SBDF   Sbdf
> 
> +  )
> 
> +{
> 
> +
> 
> +  UINT32    LinkCapRegister;
> 
> +  UINT32    DevCapRegister;
> 
> +  UINT64    Base;
> 
> +  ASPM_CAPS Aspm = {0};
> 
> +
> 
> +  Base = SbdfToBase (Sbdf);
> 
> +
> 
> +  LinkCapRegister = PciSegmentRead32 (Base + Sbdf.PcieCap +
> R_PCIE_LCAP_OFFSET);
> 
> +  DevCapRegister = PciSegmentRead32 (Base + Sbdf.PcieCap +
> R_PCIE_DCAP_OFFSET);
> 
> +
> 
> +  ///
> 
> +  /// Check endpoint for pre-1.1 devices based on the Role based Error
> Reporting Capability bit. Don't report L0s support for old devices
> 
> +  ///
> 
> +  if (DevCapRegister & B_PCIE_DCAP_RBER) {
> 
> +    Aspm.L0sSupported = !!(LinkCapRegister & B_PCIE_LCAP_APMS_L0S);
> 
> +  }
> 
> +  Aspm.L1Supported = !!(LinkCapRegister & B_PCIE_LCAP_APMS_L1);
> 
> +
> 
> +  Aspm.LinkL0sExitLatency = (LinkCapRegister & B_PCIE_LCAP_EL0) >>
> N_PCIE_LCAP_EL0;
> 
> +  Aspm.LinkL1ExitLatencyUs = L1LatencyToUs( (LinkCapRegister &
> B_PCIE_LCAP_EL1) >> N_PCIE_LCAP_EL1);
> 
> +
> 
> +  if (GetDeviceType (Sbdf) == DevTypePcieEndpoint) {
> 
> +    Aspm.L0sAcceptableLatency = (DevCapRegister & B_PCIE_DCAP_E0AL)
> >> N_PCIE_DCAP_E0AL;
> 
> +    Aspm.L1AcceptableLatencyUs = L1LatencyToUs( (DevCapRegister &
> B_PCIE_DCAP_E1AL) >> N_PCIE_DCAP_E1AL);
> 
> +    DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:%d
> L1%c %d:%d\n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,
> 
> +                                                                           Aspm.L0sSupported?'+':'-',
> Aspm.LinkL0sExitLatency, Aspm.L0sAcceptableLatency,
> 
> +                                                                           Aspm.L1Supported?'+':'-',
> Aspm.LinkL1ExitLatencyUs, Aspm.L1AcceptableLatencyUs));
> 
> +  } else {
> 
> +    Aspm.L0sAcceptableLatency = ASPM_L0s_NO_LIMIT;
> 
> +    Aspm.L1AcceptableLatencyUs = ASPM_L1_NO_LIMIT;
> 
> +    DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:x
> L1%c %d:x\n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,
> 
> +                                                                           Aspm.L0sSupported?'+':'-',
> Aspm.LinkL0sExitLatency,
> 
> +                                                                           Aspm.L1Supported?'+':'-',
> Aspm.LinkL1ExitLatencyUs));
> 
> +  }
> 
> +  return Aspm;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get ASPM L0s and L1 override of given device.
> 
> +
> 
> +  @param[in] Sbdf                Segment,Bus,Device,Function address of
> currently visited PCIe device
> 
> +  @param[in,out] MyAspm          Current device's ASPM capabilities structure
> 
> +  @param[in] Override            Pch Pcie devices OverrideTable
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +GetOverrideAspm (
> 
> +  SBDF           Sbdf,
> 
> +  ASPM_CAPS      *MyAspm,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  UINT16      DeviceId;
> 
> +  UINT16      VendorId;
> 
> +  UINT8       Revision;
> 
> +  UINT32      Index;
> 
> +  UINT64      Base;
> 
> +
> 
> +  Base = SbdfToBase (Sbdf);
> 
> +
> 
> +  VendorId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> 
> +  DeviceId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> 
> +  Revision = PciSegmentRead8  (Base + PCI_REVISION_ID_OFFSET);
> 
> +
> 
> +  for (Index = 0; Index < Override->Size; Index++) {
> 
> +    if (((Override->Table[Index].OverrideConfig & PchPcieL1L2Override) ==
> PchPcieL1L2Override) &&
> 
> +        (Override->Table[Index].VendorId == VendorId) &&
> 
> +        (Override->Table[Index].DeviceId == DeviceId) &&
> 
> +        (Override->Table[Index].RevId == Revision || Override-
> >Table[Index].RevId == 0xFF)) {
> 
> +      DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, original
> L0sSupported = 0x%x, L1Supported = 0x%x\n",
> 
> +              Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported, MyAspm-
> >L1Supported));
> 
> +      if (MyAspm->L0sSupported) {
> 
> +        //
> 
> +        // If L0s is supported in capability, apply platform override.
> 
> +        //
> 
> +        MyAspm->L0sSupported = Override->Table[Index].EndPointAspm &
> BIT0;
> 
> +      }
> 
> +      if (MyAspm->L1Supported) {
> 
> +        //
> 
> +        // If L1 is supported in capability, apply platform override.
> 
> +        //
> 
> +        MyAspm->L1Supported = (Override->Table[Index].EndPointAspm &
> BIT1) >> 1;
> 
> +      }
> 
> +      DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, override
> L0sSupported = 0x%x, L1Supported = 0x%x\n",
> 
> +              Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported, MyAspm-
> >L1Supported));
> 
> +    }
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Combines ASPM capabilities of two devices on both ends of a link to
> determine link's ASPM capabilities
> 
> +
> 
> +  @param[in] AspmA, AspmB  ASPM capabilities of two devices
> 
> +
> 
> +  @retval    ASPM_CAPS structure containing combined ASPM capabilities
> 
> +**/
> 
> +STATIC
> 
> +ASPM_CAPS
> 
> +CombineAspm (
> 
> +  ASPM_CAPS AspmA,
> 
> +  ASPM_CAPS AspmB,
> 
> +  BOOLEAN   DownstreamPort
> 
> +  )
> 
> +{
> 
> +  ASPM_CAPS Combined;
> 
> +
> 
> +  if (DownstreamPort) {
> 
> +    //
> 
> +    // When combining ASPM in downstream ports, combination must reflect
> state of link just below
> 
> +    // and consider all acceptable latencies of all endpoints anywhere down
> below that port
> 
> +    //
> 
> +    Combined.L0sSupported = AspmA.L0sSupported & AspmB.L0sSupported;
> 
> +    Combined.L1Supported = AspmA.L1Supported & AspmB.L1Supported;
> 
> +    Combined.LinkL0sExitLatency = MAX (AspmA.LinkL0sExitLatency,
> AspmB.LinkL0sExitLatency);
> 
> +    Combined.LinkL1ExitLatencyUs = MAX (AspmA.LinkL1ExitLatencyUs,
> AspmB.LinkL1ExitLatencyUs);
> 
> +    Combined.L0sAcceptableLatency = MIN (AspmA.L0sAcceptableLatency,
> AspmB.L0sAcceptableLatency);
> 
> +    Combined.L1AcceptableLatencyUs = MIN
> (AspmA.L1AcceptableLatencyUs, AspmB.L1AcceptableLatencyUs);
> 
> +  } else {
> 
> +    //
> 
> +    // When combining ASPM in switch upstream ports,
> 
> +    // Supported and ExitLatency must only reflect capabilities of upstream
> port itself
> 
> +    // But acceptable latencies must consider all endpoints anywhere below
> 
> +    //
> 
> +    Combined.L0sSupported = AspmA.L0sSupported;
> 
> +    Combined.L1Supported = AspmA.L1Supported;
> 
> +    Combined.LinkL0sExitLatency = AspmA.LinkL0sExitLatency;
> 
> +    Combined.LinkL1ExitLatencyUs = AspmA.LinkL1ExitLatencyUs;
> 
> +    Combined.L0sAcceptableLatency = MIN (AspmA.L0sAcceptableLatency,
> AspmB.L0sAcceptableLatency);
> 
> +    Combined.L1AcceptableLatencyUs = MIN
> (AspmA.L1AcceptableLatencyUs, AspmB.L1AcceptableLatencyUs);
> 
> +  }
> 
> +  DEBUG ((DEBUG_INFO, "CombineAspm %x:%x -> %x\n",
> AspmA.L1AcceptableLatencyUs, AspmB.L1AcceptableLatencyUs,
> Combined.L1AcceptableLatencyUs));
> 
> +  return Combined;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if L1 can be enabled on given link, according to ASPM parameters of
> that link
> 
> +
> 
> +  @param[in] Aspm            set of parameters describing this link and endpoint
> devices below it
> 
> +
> 
> +  @retval    TRUE if L1 can be enabled
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +IsL1Allowed (
> 
> +  ASPM_CAPS Aspm
> 
> +  )
> 
> +{
> 
> +  return (Aspm.L1Supported && (Aspm.L1AcceptableLatencyUs >=
> Aspm.LinkL1ExitLatencyUs));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if L0s can be enabled on given link, according to ASPM parameters
> of that link
> 
> +
> 
> +  @param[in] Aspm            set of parameters describing this link and endpoint
> devices below it
> 
> +
> 
> +  @retval    TRUE if L0s can be enabled
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +IsL0sAllowed (
> 
> +  ASPM_CAPS Aspm
> 
> +  )
> 
> +{
> 
> +  return (Aspm.L0sSupported && (Aspm.L0sAcceptableLatency >=
> Aspm.LinkL0sExitLatency));
> 
> +}
> 
> +
> 
> +/**
> 
> +  Enables L0s and L1 for given port, if possible.
> 
> +  L0s/L1 can be enabled if it's supported on both sides of a link and if link's
> latency doesn't exceed
> 
> +  acceptable latency of any endpoint below this link
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +  @param[in] Aspm            set of parameters describing this link and endpoint
> devices below it
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetAspm (
> 
> +  SBDF      Sbdf,
> 
> +  ASPM_CAPS Aspm
> 
> +  )
> 
> +{
> 
> +  UINT16 DataOr;
> 
> +
> 
> +  DataOr = 0;
> 
> +  if (IsL0sAllowed (Aspm)) {
> 
> +    DataOr |= V_PCIE_LCTL_ASPM_L0S;
> 
> +  }
> 
> +  if (IsL1Allowed (Aspm)) {
> 
> +    DataOr |= V_PCIE_LCTL_ASPM_L1;
> 
> +  }
> 
> +  DEBUG ((DEBUG_INFO, "SetAspm on %02x:%02x:%02x to %d\n",
> Sbdf.Bus,Sbdf.Dev,Sbdf.Func, DataOr));
> 
> +  PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_LCTL_OFFSET, (UINT16)~B_PCIE_LCTL_ASPM, DataOr);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Adds device entry to a list of devices.
> 
> +
> 
> +  @param[in,out] Table    array of devices
> 
> +  @param[in]     Sbdf     segment:bus:device:function coordinates of device
> to be added to table
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +AddToDeviceTable (
> 
> +  SBDF_TABLE *Table,
> 
> +  SBDF       Sbdf
> 
> +  )
> 
> +{
> 
> +  if (Table->Count < MAX_SBDF_TABLE_SIZE) {
> 
> +    Table->Entry[Table->Count++] = Sbdf;
> 
> +  } else {
> 
> +    ASSERT (FALSE);
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Remove device entry from a list and clear its bus assignment
> 
> +
> 
> +  @param[in,out] Table    array of devices
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +ClearBusFromTable (
> 
> +  SBDF_TABLE *Table
> 
> +  )
> 
> +{
> 
> +  while (Table->Count > 0) {
> 
> +    PciSegmentWrite32 (SbdfToBase (Table->Entry[Table->Count - 1]) +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
> 
> +    Table->Count--;
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Attempts to assign secondary and subordinate bus numbers to
> uninitialized bridges in PCIe tree
> 
> +  If the device is a bridge and already has bus numbers assigned, they won't
> be changed
> 
> +  Otherwise new bus number will be assigned below this bridge.
> 
> +  This function can be called from SMM, where BIOS must not modify bus
> numbers to prevent
> 
> +  conflict with OS enumerator. To prevent this, this function returns list of
> bridges whose
> 
> +  bus numbers were changed. All devices from that list must have buses
> cleared afterwards.
> 
> +
> 
> +  @param[in] Sbdf                segment:bus:device:function coordinates of
> device to be added to table
> 
> +  @param[in] MinBus              minimum Bus number that can be assigned
> below this port
> 
> +  @param[in] MaxBus              maximum Bus number that can be assigned
> below this port
> 
> +  @param[in] BridgeCleanupList   list of bridges where bus numbers were
> modified
> 
> +
> 
> +  @retval    maximum bus number assigned anywhere below this device
> 
> +**/
> 
> +STATIC
> 
> +UINT8
> 
> +RecursiveBusAssignment (
> 
> +  SBDF       Sbdf,
> 
> +  UINT8      MinBus,
> 
> +  UINT8      MaxBus,
> 
> +  SBDF_TABLE *BridgeCleanupList
> 
> +  )
> 
> +{
> 
> +  UINT64  Base;
> 
> +  SBDF    ChildSbdf;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +  UINT32  Data32;
> 
> +  UINT8   BelowBus;
> 
> +  UINT8   SecondaryBus;
> 
> +  UINT8   SubordinateBus;
> 
> +
> 
> +  ChildSbdf.Seg = Sbdf.Seg;
> 
> +  InitChildFinder (&ChildSbdf);
> 
> +  Base = SbdfToBase (Sbdf);
> 
> +
> 
> +  //
> 
> +  // On way down:
> 
> +  //   assign secondary bus, then increase it by one before stepping down;
> temporarily assign max subordinate bus
> 
> +  // On way up:
> 
> +  //   fix subordinate bus assignment to equal max bus number assigned
> anywhere below; return that number
> 
> +  //
> 
> +  DevType = GetDeviceType (Sbdf);
> 
> +  if ((Sbdf.Bus >= MaxBus) || (DevType == DevTypePcieEndpoint) ||
> (DevType == DevTypePci)) {
> 
> +    return (UINT8) Sbdf.Bus;
> 
> +  } else  {
> 
> +    Data32 = PciSegmentRead32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET);
> 
> +    SecondaryBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);
> 
> +    SubordinateBus = (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SBBN) >>
> 16);
> 
> +    if (SecondaryBus != 0) {
> 
> +      ChildSbdf.Bus = SecondaryBus;
> 
> +      MinBus = SecondaryBus + 1;
> 
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentP %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus,
> SubordinateBus));
> 
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +        BelowBus = RecursiveBusAssignment (ChildSbdf, MinBus,
> SubordinateBus, BridgeCleanupList);
> 
> +        MinBus = BelowBus + 1;
> 
> +      }
> 
> +      return SubordinateBus;
> 
> +    } else {
> 
> +      Data32 = Sbdf.Bus + (MinBus << 8) + (MaxBus << 16);
> 
> +      PciSegmentWrite32(Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Data32);
> 
> +      AddToDeviceTable (BridgeCleanupList, Sbdf);
> 
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentE %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus, MaxBus));
> 
> +      BelowBus = MinBus;
> 
> +      ChildSbdf.Bus = MinBus;
> 
> +      MinBus++;
> 
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +        BelowBus = RecursiveBusAssignment (ChildSbdf, MinBus, MaxBus,
> BridgeCleanupList);
> 
> +        MinBus = BelowBus + 1;
> 
> +      }
> 
> +      Data32  &= ~B_PCI_BRIDGE_BNUM_SBBN;
> 
> +      Data32 |= (BelowBus << 16);
> 
> +      PciSegmentWrite32 (Base +
> PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Data32);
> 
> +      DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentL %x:%x:%x ->
> %x,%x,%x \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus,
> (Data32&0xFF00)>>8, BelowBus));
> 
> +      return BelowBus;
> 
> +    }
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Enables L0s and/or L1 for PCIE links in the hierarchy below
> 
> +  L0s/L1 can be enabled when both sides of a link support it and link latency
> is smaller than acceptable latency
> 
> +  ASPM of a given link is independend from any other link (except 1ms L1
> adjustment, read below), so it's possible to
> 
> +  have a hierarchy when RP link has no ASPM but links below do.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] Depth                          How many links there are between this
> port and root complex
> 
> +  @param[in] Override                       Pch Pcie devices OverrideTable
> 
> +
> 
> +  @retval structure that describes acceptable latencies of all endpoints
> below plus ASPM parameters of last link
> 
> +**/
> 
> +STATIC
> 
> +ASPM_CAPS
> 
> +RecursiveAspmConfiguration (
> 
> +  SBDF           Sbdf,
> 
> +  UINT8          Depth,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  SBDF         ChildSbdf;
> 
> +  ASPM_CAPS    MyAspm;
> 
> +  ASPM_CAPS    ChildAspm;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveAspmConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  //
> 
> +  // On way down:
> 
> +  //   pass number of links traversed; increase it per upstream port visited
> (not endpoint)
> 
> +  // On way up:
> 
> +  //   EndPoint: read Acceptable Latencies; subtract Depth From
> L1AcceptableLat to account for "1us per switch additional delay"
> 
> +  //   Downstreamport: AND L0s/L1 caps; calculate LinkLatency; enable L0s/L1
> if supported and if acceptable latency is bigger than link latency;
> 
> +  //     if L1 not enabled, add back 1us to Acceptable Latency to cancel earlier
> Depth subtraction
> 
> +  //   UpstreamPort: calculate minimum of below Acceptable Latencies;
> return that, with upper link's Latency and L0s/L1 support
> 
> +  //
> 
> +  DevType = GetDeviceType(Sbdf);
> 
> +  if (DevType == DevTypePcieUpstream) {
> 
> +    Depth++;
> 
> +  }
> 
> +  MyAspm = GetAspmCaps (Sbdf);
> 
> +  //
> 
> +  // Get ASPM L0s and L1 override
> 
> +  //
> 
> +  if (Override != NULL) {
> 
> +    GetOverrideAspm (Sbdf, &MyAspm, Override);
> 
> +  }
> 
> +  if (DevType == DevTypePcieEndpoint) {
> 
> +    //
> 
> +    // Every switch between endpoint and CPU introduces 1us additional
> latency on L1 exit. This is reflected by
> 
> +    // subtracting 1us per switch from endpoint's acceptable L1 latency.
> 
> +    // In case L1 doesn't get enabled in one of switches, that 1us will be
> added back.
> 
> +    // This calculation is not precise. It ignores that some switches' added
> delay may be shadowed by
> 
> +    // other links' exit latency. But it guarantees that acceptable latency won't
> be exceeded and is simple
> 
> +    // enough to perform in a single iteration without backtracking.
> 
> +    //
> 
> +    return PatchL1AcceptableLatency (MyAspm, (-1 * Depth));
> 
> +  }
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      ChildAspm = RecursiveAspmConfiguration (ChildSbdf, Depth, Override);
> 
> +      MyAspm = CombineAspm (MyAspm, ChildAspm, (DevType ==
> DevTypePcieDownstream));
> 
> +    }
> 
> +    if (DevType == DevTypePcieDownstream) {
> 
> +      SetAspm (Sbdf, MyAspm);
> 
> +      //
> 
> +      // ASPM config must be consistent across all functions of a device. That's
> why there's while loop.
> 
> +      //
> 
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +        SetAspm (ChildSbdf, MyAspm);
> 
> +      }
> 
> +      if (!IsL1Allowed (MyAspm)) {
> 
> +        MyAspm = PatchL1AcceptableLatency (MyAspm, 1);
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  return MyAspm;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Enables L1 substates for PCIE links in the hierarchy below
> 
> +  L1.1 / L1.2 can be enabled if both sides of a link support it.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +
> 
> +  @retval  structure that describes L1ss capabilities of the device
> 
> +**/
> 
> +STATIC
> 
> +L1SS_CAPS
> 
> +RecursiveL1ssConfiguration (
> 
> +  SBDF           Sbdf,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  UINT64  Base;
> 
> +  SBDF    ChildSbdf;
> 
> +  L1SS_CAPS CombinedCaps;
> 
> +  L1SS_CAPS ChildCaps;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +  BOOLEAN   IsCpuPcie;
> 
> +  UINT32    DevNum;
> 
> +
> 
> +  IsCpuPcie = FALSE;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveL1ssConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  Base = SbdfToBase (Sbdf);
> 
> +  DevNum = Sbdf.Dev;
> 
> +  if (DevNum == SA_PEG0_DEV_NUM || DevNum == SA_PEG3_DEV_NUM)
> {
> 
> +    IsCpuPcie = TRUE;
> 
> +  }
> 
> +  //
> 
> +  // On way down:
> 
> +  //   do nothing
> 
> +  // On way up:
> 
> +  //   In downstream ports, combine L1ss capabilities of that port and device
> behind it, then enable L1.1 and/or L1.2 if possible
> 
> +  //   Return L1ss capabilities
> 
> +  //
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      ChildCaps = RecursiveL1ssConfiguration (ChildSbdf, Override);
> 
> +      if (DevType == DevTypePcieDownstream && ChildSbdf.Func == 0) {
> 
> +        CombinedCaps = CombineL1ss (GetL1ssCaps (Base, Override),
> ChildCaps);
> 
> +        SetL1ss (Sbdf, CombinedCaps, Override, IsCpuPcie);
> 
> +        SetL1ss (ChildSbdf, CombinedCaps, Override, IsCpuPcie);
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  return GetL1ssCaps (Base, Override);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if there is an IoAPIC device in the PCIe hierarchy.
> 
> +  If one is found, this function doesn't check for more and returns
> 
> +
> 
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +
> 
> +  @retval  TRUE if IoAPIC device was found
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +RecursiveIoApicCheck (
> 
> +  SBDF       Sbdf
> 
> +  )
> 
> +{
> 
> +  SBDF         ChildSbdf;
> 
> +  UINT8        IoApicPresent;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveIoApicCheck %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  IoApicPresent = FALSE;
> 
> +
> 
> +  if (IsIoApicDevice (SbdfToBase (Sbdf))) {
> 
> +    DEBUG ((DEBUG_INFO, "IoApicFound @%x:%x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +    return TRUE;
> 
> +  }
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      IoApicPresent = RecursiveIoApicCheck (ChildSbdf);
> 
> +      if (IoApicPresent) {
> 
> +        break;
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  DEBUG ((DEBUG_INFO, "IoApic status %d @%x:%x:%x:%x\n",
> IoApicPresent, Sbdf.Seg, Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +  return IoApicPresent;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Calculates Maximum Payload Size supported by PCIe hierarchy.
> 
> +  Starting from a device, it finds the minimum MPS supported by devices
> below it.
> 
> +  There are many valid strategies for setting MPS. This implementation
> chooses
> 
> +  one that is safest, but doesn't guarantee maximum performance:
> 
> +    Find minimum MPS under given rootport, then program that minimum
> value everywhere below that rootport
> 
> +
> 
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +
> 
> +  @retval  MPS supported by PCIe hierarchy, calculated as MIN(MPS of all
> devices below)
> 
> +**/
> 
> +STATIC
> 
> +UINT8
> 
> +RecursiveMpsCheck (
> 
> +  SBDF       Sbdf
> 
> +  )
> 
> +{
> 
> +  SBDF         ChildSbdf;
> 
> +  UINT8        MyMps;
> 
> +  UINT8        SubtreeMps;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveMpsCheck %x:%x:%x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  MyMps = GetMps (Sbdf);
> 
> +  if (MyMps == 0) {
> 
> +    return MyMps;
> 
> +  }
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      SubtreeMps = RecursiveMpsCheck (ChildSbdf);
> 
> +      MyMps = MIN(MyMps, SubtreeMps);
> 
> +    }
> 
> +  }
> 
> +  return MyMps;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Maximum Payload Size in PCIe hierarchy.
> 
> +  Starting from a device, it programs the same MPS value to it and all devices
> below it.
> 
> +  There are many valid strategies for setting MPS. This implementation
> chooses
> 
> +  one that is safest, but doesn't guarantee maximum performance:
> 
> +    Find minimum MPS under given rootport, then program that minimum
> value everywhere below that rootport
> 
> +
> 
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] Mps                            Maximum Payload Size to be programmed
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +RecursiveMpsConfiguration (
> 
> +  SBDF       Sbdf,
> 
> +  UINT8      Mps
> 
> +  )
> 
> +{
> 
> +  SBDF    ChildSbdf;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveMpsConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      RecursiveMpsConfiguration (ChildSbdf, Mps);
> 
> +    }
> 
> +  }
> 
> +  SetMps (Sbdf, Mps);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Enable Clock Power Management bit for devices that support it.
> 
> +  A device supports CPM only if all function of this device report CPM
> support.
> 
> +  Downstream ports never report CPM capability, so it's only relevant for
> upstream ports.
> 
> +  When this function executes on upstream component, it will check CPM &
> set ECPM of downstream component
> 
> +  When this function executes on downstream component, all devices
> below it are guaranteed to
> 
> +  return CPM=0 so it will do nothing
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +
> 
> +  @retval TRUE = this device supports CPM, FALSE = it doesn't
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +RecursiveCpmConfiguration (
> 
> +  SBDF       Sbdf
> 
> +  )
> 
> +{
> 
> +  SBDF         ChildSbdf;
> 
> +  BOOLEAN      ChildCpm;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveCpmConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  ChildCpm = FALSE;
> 
> +
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    ChildCpm = TRUE;
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      ChildCpm &= RecursiveCpmConfiguration (ChildSbdf);
> 
> +    }
> 
> +    if (ChildCpm) {
> 
> +      while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +        EnableCpm (ChildSbdf);
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  return IsCpmSupported (Sbdf);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Sets Common Clock Configuration bit for devices that share common clock
> across link
> 
> +  Devices on both sides of a PCIE link share common clock if both upstream
> component
> 
> +  and function 0 of downstream component report Slot Clock Configuration
> bit = 1.
> 
> +  When this function executes on upstream component, it checks SCC of
> both sides of the link
> 
> +  If they both support it, sets CCC for both sides (this means all functions of
> downstream component)
> 
> +  When this function executes on downstream component, it only returns
> SCC capability
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] WaitForRetrain                 decides if this function should busy-
> wait for link retrain
> 
> +
> 
> +  @retval TRUE = this device supports SCC, FALSE = it doesn't
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +RecursiveCccConfiguration (
> 
> +  SBDF       Sbdf,
> 
> +  BOOLEAN    WaitForRetrain
> 
> +  )
> 
> +{
> 
> +  UINT64       Base;
> 
> +  SBDF         ChildSbdf;
> 
> +  BOOLEAN      MyScc;
> 
> +  BOOLEAN      ChildScc;
> 
> +  BOOLEAN      LinkScc;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveCccConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  ChildScc = 0;
> 
> +  Base = SbdfToBase(Sbdf);
> 
> +  MyScc = GetScc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      ChildScc |= RecursiveCccConfiguration (ChildSbdf, WaitForRetrain);
> 
> +    }
> 
> +    if (DevType == DevTypePcieDownstream) {
> 
> +      LinkScc = MyScc & ChildScc;
> 
> +      if (LinkScc) {
> 
> +        EnableCcc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);
> 
> +        while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +          EnableCcc (SbdfToBase(ChildSbdf), (UINT8)ChildSbdf.PcieCap);
> 
> +        }
> 
> +        RetrainLink(Base, (UINT8)Sbdf.PcieCap, WaitForRetrain);
> 
> +      }
> 
> +    }
> 
> +  }
> 
> +  return MyScc;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures Latency Tolerance Reporting in given device and in PCIe tree
> below it.
> 
> +  This function configures Maximum LTR and enables LTR mechanism. It
> visits devices using depth-first search
> 
> +  and skips branches behind devices which do not support LTR.
> 
> +  Maximum LTR:
> 
> +    This function will set LTR's upper bound for every visited device. Max LTR
> value is provided as a parameter
> 
> +  Enable LTR:
> 
> +    LTR should be enabled top-to-bottom in every visited device that
> supports LTR. This function does not
> 
> +    iterate down behind devices with no LTR support. In effect, LTR will be
> enabled in given device if that device
> 
> +    and all devices above it on the way to RootComplex do support LTR.
> 
> +
> 
> +  This function expects that bridges have bus numbers already configured
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] LtrLimit                       Ltr to be programmed to every endpoint
> 
> +
> 
> +  @retval MaxLTR programmed in this device
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +RecursiveLtrConfiguration (
> 
> +  SBDF       Sbdf,
> 
> +  LTR_LIMIT  LtrLimit
> 
> +  )
> 
> +{
> 
> +  UINT64  Base;
> 
> +  SBDF    ChildSbdf;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveLtrConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  Base = SbdfToBase(Sbdf);
> 
> +
> 
> +  if (!IsLtrCapable (Sbdf)) {
> 
> +    DEBUG ((DEBUG_INFO, "Not LtrCapable %02x:%02x:%02x\n", Sbdf.Bus,
> Sbdf.Dev, Sbdf.Func));
> 
> +    return;
> 
> +  }
> 
> +  EnableLtr (Sbdf);
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      RecursiveLtrConfiguration (ChildSbdf, LtrLimit);
> 
> +    }
> 
> +  }
> 
> +  SetLtrLimit (Base, LtrLimit);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks to see device is PTM Capable
> 
> +
> 
> +  @param[in] Sbdf    device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval TRUE = PTM Capability found, FALSE = Not PTM capable
> 
> +**/
> 
> +STATIC
> 
> +BOOLEAN
> 
> +IsPtmCapable (
> 
> +  SBDF       Sbdf
> 
> +  )
> 
> +{
> 
> +  UINT16     CapHeaderOffset;
> 
> +
> 
> +  CapHeaderOffset = PcieFindExtendedCapId ((UINT8) Sbdf.Seg, (UINT8)
> Sbdf.Bus, (UINT8) Sbdf.Dev, (UINT8) Sbdf.Func, V_PCIE_EX_PTM_CID);
> 
> +
> 
> +  return (CapHeaderOffset != 0);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get PTM Capability register from PCIe Extended Capability Space.
> 
> +
> 
> +  @param[in] Sbdf                device's segment:bus:device:function
> coordinates
> 
> +  @param[in] PtmCapHeaderOffset  PTM Capability Header Offset
> 
> +
> 
> +  @retval LocalPtm       Returns PTM Capability.
> 
> +                         If Device is not PTM capable then PTM Capability is zeroed out.
> 
> +**/
> 
> +STATIC
> 
> +PTM_CAPS
> 
> +GetPtmCapability (
> 
> +  SBDF      Sbdf,
> 
> +  UINT16    PtmCapHeaderOffset
> 
> +  )
> 
> +{
> 
> +  PTM_CAPS PtmCaps;
> 
> +
> 
> +  PtmCaps.Uint32 = 0;
> 
> +
> 
> +  if (PtmCapHeaderOffset != 0) {
> 
> +    PtmCaps.Uint32 = PciSegmentRead32 (SbdfToBase (Sbdf) +
> PtmCapHeaderOffset + R_PCIE_EX_PTMCAP_OFFSET);
> 
> +  }
> 
> +
> 
> +  return PtmCaps;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get PTM Control register from PCIe Extended Capability Space.
> 
> +
> 
> +  @param[in] Sbdf                device's segment:bus:device:function
> coordinates
> 
> +  @param[in] PtmCapHeaderOffset  PTM Capability Header Offset
> 
> +
> 
> +  @retval LocalPtm       Returns PTM Control.
> 
> +                         If Device is not PTM capable then PTM Control is zeroed out.
> 
> +**/
> 
> +STATIC
> 
> +PTM_CTRL
> 
> +GetPtmControl (
> 
> +  SBDF      Sbdf,
> 
> +  UINT16    PtmCapHeaderOffset
> 
> +  )
> 
> +{
> 
> +  PTM_CTRL PtmCtrl;
> 
> +
> 
> +  PtmCtrl.Uint32 = 0;
> 
> +
> 
> +  if (PtmCapHeaderOffset != 0) {
> 
> +    PtmCtrl.Uint32 = PciSegmentRead32 (SbdfToBase (Sbdf) +
> PtmCapHeaderOffset + R_PCIE_EX_PTMCTL_OFFSET);
> 
> +  }
> 
> +
> 
> +  return PtmCtrl;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Set PTM Control register in the PCIe Extended Capability Space.
> 
> +
> 
> +  @param[in] Sbdf                device's segment:bus:device:function
> coordinates
> 
> +  @param[in] PtmCapHeaderOffset  PTM Capability Header Offset
> 
> +  @param[in] PtmCtrl             PTM Control Register
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetPtmControl (
> 
> +  SBDF      Sbdf,
> 
> +  UINT16    PtmCapHeaderOffset,
> 
> +  PTM_CTRL  PtmCtrl
> 
> +  )
> 
> +{
> 
> +  if (PtmCapHeaderOffset != 0) {
> 
> +    PciSegmentWrite32 (SbdfToBase (Sbdf) + PtmCapHeaderOffset +
> R_PCIE_EX_PTMCTL_OFFSET, PtmCtrl.Uint32);
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Enable PTM on device's control register. Set the Effective Clock
> Granularity.
> 
> +
> 
> +  @param[in]     Sbdf                 device's segment:bus:device:function
> coordinates
> 
> +  @param[in out] EffectiveGranularity Effective Clock Granularity of the PTM
> hierarchy
> 
> +  @param[in out] PtmHierarchy         Indicates if the current device is within a
> PTM hierarchy
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +SetPtm (
> 
> +  IN     SBDF       Sbdf,
> 
> +  IN OUT UINT8      *EffectiveGranularity,
> 
> +  IN OUT BOOLEAN    *PtmHierarchy
> 
> +  )
> 
> +{
> 
> +  PTM_CTRL CurrentPtmCtrl;
> 
> +  PTM_CAPS CurrentPtmCaps;
> 
> +  PTM_CTRL OrigPtmCtrl;
> 
> +  UINT16   PtmCapHeaderOffset;
> 
> +
> 
> +  PtmCapHeaderOffset = PcieFindExtendedCapId ((UINT8) Sbdf.Seg,
> (UINT8) Sbdf.Bus, (UINT8) Sbdf.Dev, (UINT8) Sbdf.Func,
> V_PCIE_EX_PTM_CID);
> 
> +  CurrentPtmCtrl = GetPtmControl (Sbdf, PtmCapHeaderOffset);
> 
> +  CurrentPtmCaps = GetPtmCapability (Sbdf, PtmCapHeaderOffset);
> 
> +
> 
> +  OrigPtmCtrl.Uint32 = CurrentPtmCtrl.Uint32;
> 
> +
> 
> +  if ( (*PtmHierarchy == FALSE) && CurrentPtmCaps.Bits.RootCapable) {
> 
> +    // Select device as PTM Root if PTM Root is not selected.
> 
> +    CurrentPtmCtrl.Bits.RootSelect = TRUE;
> 
> +    *EffectiveGranularity = (UINT8)
> CurrentPtmCaps.Bits.LocalClockGranularity;
> 
> +    *PtmHierarchy = TRUE;
> 
> +  }
> 
> +
> 
> +  if (*PtmHierarchy == TRUE) {
> 
> +    // Enable PTM if device is part of a ptm hierarchy
> 
> +    CurrentPtmCtrl.Bits.Enable = TRUE;
> 
> +
> 
> +    if (CurrentPtmCaps.Bits.RequesterCapable) {
> 
> +      // Set Effective Granularity if PTM device is Requester roles.
> 
> +      CurrentPtmCtrl.Bits.EffectiveGranularity = *EffectiveGranularity;
> 
> +    }
> 
> +  }
> 
> +
> 
> +  if (OrigPtmCtrl.Uint32 != CurrentPtmCtrl.Uint32) {
> 
> +    SetPtmControl (Sbdf, PtmCapHeaderOffset, CurrentPtmCtrl);
> 
> +  }
> 
> +
> 
> +  // Update EffectiveGranularity.
> 
> +  // Set to zero if 1 or more switches between the root and endpoint report
> local granularity = 0.
> 
> +  // Otherwise set to the max local granularity of the hierarchy.
> 
> +  if ( ((CurrentPtmCaps.Bits.LocalClockGranularity == 0) &&
> CurrentPtmCaps.Bits.RequesterCapable) ||
> 
> +       (*EffectiveGranularity  == 0) ) {
> 
> +    *EffectiveGranularity = 0;
> 
> +  } else {
> 
> +    *EffectiveGranularity = MAX (*EffectiveGranularity, (UINT8)
> CurrentPtmCaps.Bits.LocalClockGranularity);
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures PTM hierarchies by searching for Endpoints and Upstream
> Switches
> 
> +  that are PTM capable. Each PTM device role is identified and configured
> accordingly.
> 
> +  PTM root capable devices are selected as PTM root if the device is not
> already in a
> 
> +  PTM hierarchy.
> 
> +  PTM capable Root Ports must be configured before calling this function.
> 
> +  @note: This function has not been tested with switches.
> 
> +
> 
> +  @param[in] Sbdf                 Address of curretly visited Pcie device
> 
> +  @param[in] EffectiveGranularity The largest Clock Granularity from
> Upstream Devices
> 
> +  @param[in] PtmHierarchy         TRUE = Device in a PTM Hierarchy, FALSE =
> Not in PTM Hierarchy
> 
> +**/
> 
> +STATIC
> 
> +VOID
> 
> +RecursivePtmConfiguration (
> 
> +  SBDF          Sbdf,
> 
> +  UINT8         EffectiveGranularity,
> 
> +  BOOLEAN       PtmHierarchy
> 
> +  )
> 
> +{
> 
> +  SBDF         ChildSbdf;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursivePtmConfiguration %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  DevType = GetDeviceType (Sbdf);
> 
> +
> 
> +  if (IsPtmCapable (Sbdf)) {
> 
> +    //
> 
> +    // Enable PTM for PTM Capable devices (Endpoints, Upstream Switch, and
> Root Ports).
> 
> +    // @Note: Switches have not been tested.
> 
> +    //
> 
> +    SetPtm (Sbdf, &EffectiveGranularity, &PtmHierarchy);
> 
> +  } else if (!IsPtmCapable (Sbdf) && (DevType == DevTypePcieUpstream) ) {
> 
> +    //
> 
> +    // Non-PTM UpStream Switch Ports breaks the PTM Hierarchy.
> 
> +    // No other downstream PTM devices should be PTM enabled until a PTM
> Root capable device is selected.
> 
> +    //
> 
> +    PtmHierarchy = FALSE;
> 
> +    EffectiveGranularity = 0;
> 
> +  }
> 
> +
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      RecursivePtmConfiguration (ChildSbdf, EffectiveGranularity,
> PtmHierarchy);
> 
> +    }
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Initializes the following features in rootport and devices behind it:
> 
> +  Maximum Payload Size (generic)
> 
> +  Rootport packet split (proprietary)
> 
> +  EonOfInterrupt forwarding (proprietary)
> 
> +  Common Clock Configuration (generic)
> 
> +
> 
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> 
> +  Proprietary: code uses registers and features that are specific to Intel
> silicon
> 
> +  and probably only this Reference Code knows how to handle that.
> 
> +
> 
> +  If OEM implemented generic feature enabling in his platform code or
> trusts Operating System
> 
> +  to do it, then those features can be deleted from here.
> 
> +
> 
> +  CCC requires link retrain, which takes a while. CCC must happen before
> L0s/L1 programming.
> 
> +  If there was guarantee no code would access PCI while links retrain, it
> would be possible to skip this waiting
> 
> +
> 
> +  @param[in] RpSegment  address of rootport on PCIe
> 
> +  @param[in] RpBus      address of rootport on PCIe
> 
> +  @param[in] RpDevice   address of rootport on PCIe
> 
> +  @param[in] RpFunction address of rootport on PCIe
> 
> +  @param[in] BusMin     minimum Bus number that can be assigned below
> this rootport
> 
> +  @param[in] BusMax     maximum Bus number that can be assigned below
> this rootport
> 
> +**/
> 
> +VOID
> 
> +RootportDownstreamConfiguration (
> 
> +  UINT8                     RpSegment,
> 
> +  UINT8                     RpBus,
> 
> +  UINT8                     RpDevice,
> 
> +  UINT8                     RpFunction,
> 
> +  UINT8                     BusMin,
> 
> +  UINT8                     BusMax,
> 
> +  PCI_SKU                   PciSku
> 
> +  )
> 
> +{
> 
> +  UINT8           Mps;
> 
> +  BOOLEAN         IoApicPresent;
> 
> +  UINT64          RpBase;
> 
> +  SBDF            RpSbdf;
> 
> +  SBDF_TABLE      BridgeCleanupList;
> 
> +
> 
> +  IoApicPresent = FALSE;
> 
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice,
> RpFunction, 0);
> 
> +  if (!(IsDevicePresent (RpBase))) {
> 
> +    return;
> 
> +  }
> 
> +  RpSbdf.Seg = RpSegment;
> 
> +  RpSbdf.Bus = RpBus;
> 
> +  RpSbdf.Dev = RpDevice;
> 
> +  RpSbdf.Func = RpFunction;
> 
> +  RpSbdf.PcieCap = PcieBaseFindCapId (RpBase,
> EFI_PCI_CAPABILITY_ID_PCIEXP);
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RootportDownstreamConfiguration %x:%x\n",
> RpDevice, RpFunction));
> 
> +  BridgeCleanupList.Count = 0;
> 
> +  RecursiveBusAssignment (RpSbdf, BusMin, BusMax, &BridgeCleanupList);
> 
> +
> 
> +  Mps = RecursiveMpsCheck (RpSbdf);
> 
> +  RecursiveMpsConfiguration (RpSbdf, Mps);
> 
> +  if (PciSku == EnumPchPcie) {
> 
> +    RpBase = SbdfToBase (RpSbdf);
> 
> +    ConfigureRpPacketSplit(RpBase, Mps);
> 
> +    IoApicPresent = RecursiveIoApicCheck(RpSbdf);
> 
> +  }
> 
> +  if ((PciSku == EnumPchPcie) || (PciSku == EnumCpuPcie)) {
> 
> +    ConfigureEoiForwarding (RpBase, IoApicPresent);
> 
> +  }
> 
> +  RecursiveCccConfiguration (RpSbdf, TRUE);
> 
> +
> 
> +  if (IsPtmCapable (RpSbdf)) {
> 
> +    RecursivePtmConfiguration (RpSbdf, 0, FALSE);
> 
> +  }
> 
> +
> 
> +  ClearBusFromTable (&BridgeCleanupList);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Checks if given PCI device is capable of Latency Tolerance Reporting
> 
> +
> 
> +  @param[in] Sbdf            device's segment:bus:device:function coordinates
> 
> +
> 
> +  @retval TRUE if yes
> 
> +**/
> 
> +BOOLEAN
> 
> +IsLtrCapable (
> 
> +  SBDF Sbdf
> 
> +  )
> 
> +{
> 
> +  if (Sbdf.PcieCap == 0) {
> 
> +    return FALSE;
> 
> +  }
> 
> +  return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap +
> R_PCIE_DCAP2_OFFSET) & B_PCIE_DCAP2_LTRMS);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns combination of two LTR override values
> 
> +  The resulting LTR override separately chooses stricter limits for snoop and
> nosnoop
> 
> +
> 
> +  @param[in] LtrA      LTR override values to be combined
> 
> +  @param[in] LtrB      LTR override values to be combined
> 
> +
> 
> +  @retval LTR override value
> 
> +**/
> 
> +LTR_OVERRIDE
> 
> +CombineLtr (
> 
> +  LTR_OVERRIDE LtrA,
> 
> +  LTR_OVERRIDE LtrB
> 
> +  )
> 
> +{
> 
> +  UINT64        DecodedLatencyA;
> 
> +  UINT64        DecodedLatencyB;
> 
> +  LTR_OVERRIDE  Result;
> 
> +  static UINT32 ScaleEncoding [8] = {1, 32, 1024, 32768, 1048576, 33554432, 0,
> 0};
> 
> +
> 
> +  ZeroMem (&Result, sizeof (LTR_OVERRIDE));
> 
> +  DecodedLatencyA = ScaleEncoding[LtrA.MaxSnoopLatencyScale] *
> LtrA.MaxSnoopLatencyValue;
> 
> +  DecodedLatencyB = ScaleEncoding[LtrB.MaxSnoopLatencyScale] *
> LtrB.MaxSnoopLatencyValue;
> 
> +  if ((!LtrB.MaxSnoopLatencyRequirement) || ((DecodedLatencyA <
> DecodedLatencyB) && LtrA.MaxSnoopLatencyRequirement)) {
> 
> +    Result.MaxSnoopLatencyValue       = LtrA.MaxSnoopLatencyValue;
> 
> +    Result.MaxSnoopLatencyScale       = LtrA.MaxSnoopLatencyScale;
> 
> +    Result.MaxSnoopLatencyRequirement =
> LtrA.MaxSnoopLatencyRequirement;
> 
> +  } else {
> 
> +    Result.MaxSnoopLatencyValue       = LtrB.MaxSnoopLatencyValue;
> 
> +    Result.MaxSnoopLatencyScale       = LtrB.MaxSnoopLatencyScale;
> 
> +    Result.MaxSnoopLatencyRequirement =
> LtrB.MaxSnoopLatencyRequirement;
> 
> +  }
> 
> +  DecodedLatencyA = ScaleEncoding[LtrA.MaxNoSnoopLatencyScale] *
> LtrA.MaxNoSnoopLatencyValue;
> 
> +  DecodedLatencyB = ScaleEncoding[LtrB.MaxNoSnoopLatencyScale] *
> LtrB.MaxNoSnoopLatencyValue;
> 
> +  if ((!LtrB.MaxNoSnoopLatencyRequirement) || ((DecodedLatencyA <
> DecodedLatencyB) && LtrA.MaxNoSnoopLatencyRequirement)) {
> 
> +    Result.MaxNoSnoopLatencyValue       = LtrA.MaxNoSnoopLatencyValue;
> 
> +    Result.MaxNoSnoopLatencyScale       = LtrA.MaxNoSnoopLatencyScale;
> 
> +    Result.MaxNoSnoopLatencyRequirement =
> LtrA.MaxNoSnoopLatencyRequirement;
> 
> +  } else {
> 
> +    Result.MaxNoSnoopLatencyValue       = LtrB.MaxNoSnoopLatencyValue;
> 
> +    Result.MaxNoSnoopLatencyScale       = LtrB.MaxNoSnoopLatencyScale;
> 
> +    Result.MaxNoSnoopLatencyRequirement =
> LtrB.MaxNoSnoopLatencyRequirement;
> 
> +  }
> 
> +  if (LtrA.ForceOverride || LtrB.ForceOverride) {
> 
> +    Result.ForceOverride = TRUE;
> 
> +  }
> 
> +  DEBUG ((DEBUG_INFO, "CombineLtr: A(V%d S%d E%d : V%d S%d E%d,
> F%d)\n",
> 
> +    LtrA.MaxSnoopLatencyValue, LtrA.MaxSnoopLatencyScale,
> LtrA.MaxSnoopLatencyRequirement,
> 
> +    LtrA.MaxNoSnoopLatencyValue, LtrA.MaxNoSnoopLatencyScale,
> LtrA.MaxNoSnoopLatencyRequirement,
> 
> +    LtrA.ForceOverride
> 
> +    ));
> 
> +  DEBUG ((DEBUG_INFO, "          : B(V%d S%d E%d : V%d S%d E%d, F%d)\n",
> 
> +    LtrB.MaxSnoopLatencyValue, LtrB.MaxSnoopLatencyScale,
> LtrB.MaxSnoopLatencyRequirement,
> 
> +    LtrB.MaxNoSnoopLatencyValue, LtrB.MaxNoSnoopLatencyScale,
> LtrB.MaxNoSnoopLatencyRequirement,
> 
> +    LtrB.ForceOverride
> 
> +    ));
> 
> +  DEBUG ((DEBUG_INFO, "          : R(V%d S%d E%d : V%d S%d E%d, F%d)\n",
> 
> +    Result.MaxSnoopLatencyValue, Result.MaxSnoopLatencyScale,
> Result.MaxSnoopLatencyRequirement,
> 
> +    Result.MaxNoSnoopLatencyValue, Result.MaxNoSnoopLatencyScale,
> Result.MaxNoSnoopLatencyRequirement,
> 
> +    Result.ForceOverride
> 
> +    ));
> 
> +  return Result;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Returns LTR override value for given device
> 
> +  The value is extracted from Device Override table. If the device is not
> found,
> 
> +  the returned value will have Requirement bits clear
> 
> +
> 
> +  @param[in] Base            device's base address
> 
> +  @param[in] Override        device override table
> 
> +
> 
> +  @retval LTR override value
> 
> +**/
> 
> +LTR_OVERRIDE
> 
> +GetOverrideLtr (
> 
> +  UINT64         Base,
> 
> +  OVERRIDE_TABLE *Override
> 
> +  )
> 
> +{
> 
> +  UINT16       DevId;
> 
> +  UINT16       VenId;
> 
> +  UINT16       RevId;
> 
> +  UINT32       Index;
> 
> +  LTR_OVERRIDE ReturnValue = {0};
> 
> +
> 
> +  VenId = PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);
> 
> +  DevId = PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);
> 
> +  RevId = PciSegmentRead16 (Base + PCI_REVISION_ID_OFFSET);
> 
> +
> 
> +  for (Index = 0; Index < Override->Size; Index++) {
> 
> +    if (((Override->Table[Index].OverrideConfig & PchPcieLtrOverride) ==
> PchPcieLtrOverride) &&
> 
> +        (Override->Table[Index].VendorId == VenId) &&
> 
> +        ((Override->Table[Index].DeviceId == DevId) || (Override-
> >Table[Index].DeviceId == 0xFFFF)) &&
> 
> +        ((Override->Table[Index].RevId == RevId) || (Override-
> >Table[Index].RevId == 0xFF))) {
> 
> +      if (Override->Table[Index].SnoopLatency & 0x8000) {
> 
> +        ReturnValue.MaxSnoopLatencyRequirement = 1;
> 
> +        ReturnValue.MaxSnoopLatencyValue = Override-
> >Table[Index].SnoopLatency & 0x3FF;
> 
> +        ReturnValue.MaxSnoopLatencyScale = (Override-
> >Table[Index].SnoopLatency & 0x1C00) >> 10;
> 
> +      }
> 
> +      if (Override->Table[Index].NonSnoopLatency & 0x8000) {
> 
> +        ReturnValue.MaxNoSnoopLatencyRequirement = 1;
> 
> +        ReturnValue.MaxNoSnoopLatencyValue = Override-
> >Table[Index].NonSnoopLatency & 0x3FF;
> 
> +        ReturnValue.MaxNoSnoopLatencyScale = (Override-
> >Table[Index].NonSnoopLatency & 0x1C00) >> 10;
> 
> +      }
> 
> +      ReturnValue.ForceOverride = Override->Table[Index].ForceLtrOverride;
> 
> +      break;
> 
> +    }
> 
> +  }
> 
> +  return ReturnValue;
> 
> +}
> 
> +
> 
> +/**
> 
> +  In accordance with PCIe spec, devices with no LTR support are considered
> to have no LTR requirements
> 
> +  which means infinite latency tolerance. This was found to cause problems
> with HID and Audio devices without LTR
> 
> +  support placed behind PCIe switches with LTR support, as Switch's
> upstream link would be allowed to enter L1.2
> 
> +  and cause large latency downstream. To work around such issues and to fix
> some devices with broken
> 
> +  LTR reporting, Device Override table was introduced.
> 
> +  This function scans PCIe tree for devices mentioned in override table and
> calculates the strictest
> 
> +  LTR requirement between them. That value will be programmed into
> rootport's LTR override register
> 
> +
> 
> +  This function expects that bridges have bus numbers already configured
> 
> +
> 
> +  @param[in] BusLimit                       maximum Bus number that can be
> assigned below this port
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] AspmOverride                   Device specific ASPM policy override
> items
> 
> +
> 
> +  @retval MaxLTR programmed in this device
> 
> +**/
> 
> +LTR_OVERRIDE
> 
> +RecursiveLtrOverrideCheck (
> 
> +  SBDF           Sbdf,
> 
> +  OVERRIDE_TABLE *AspmOverride
> 
> +  )
> 
> +{
> 
> +  UINT64       Base;
> 
> +  SBDF         ChildSbdf;
> 
> +  LTR_OVERRIDE MyLtrOverride;
> 
> +  LTR_OVERRIDE ChildLtr;
> 
> +  PCI_DEV_TYPE DevType;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RecursiveLtrOverrideCheck %x:%x:%x\n",
> Sbdf.Bus, Sbdf.Dev, Sbdf.Func));
> 
> +
> 
> +  Base = SbdfToBase(Sbdf);
> 
> +
> 
> +  MyLtrOverride = GetOverrideLtr (Base, AspmOverride);
> 
> +  if (HasChildBus (Sbdf, &ChildSbdf)) {
> 
> +    DevType = GetDeviceType (Sbdf);
> 
> +    while (FindNextPcieChild (DevType, &ChildSbdf)) {
> 
> +      ChildLtr = RecursiveLtrOverrideCheck (ChildSbdf, AspmOverride);
> 
> +      MyLtrOverride = CombineLtr (MyLtrOverride, ChildLtr);
> 
> +    }
> 
> +  }
> 
> +  return MyLtrOverride;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures the following power-management related features in rootport
> and devices behind it:
> 
> +  LTR limit (generic)
> 
> +  LTR override (proprietary)
> 
> +  Clock Power Management (generic)
> 
> +  L1 substates (generic except for the override table)
> 
> +  L1.LOW substate (proprietary)
> 
> +  L0s and L1 (generic)
> 
> +
> 
> +  Generic: any code written according to PCIE Express base specification can
> do that.
> 
> +  Proprietary: code uses registers and features that are specific to Intel
> silicon
> 
> +  and probably only this Reference Code knows how to handle that.
> 
> +
> 
> +  If OEM implemented generic feature enabling in his platform code or
> trusts Operating System
> 
> +  to do it, then those features can be deleted from here.
> 
> +
> 
> +  @param[in] RpSegment                address of rootport on PCIe
> 
> +  @param[in] RpBus                    address of rootport on PCIe
> 
> +  @param[in] RpDevice                 address of rootport on PCIe
> 
> +  @param[in] RpFunction               address of rootport on PCIe
> 
> +  @param[in] BusLimit                 maximum Bus number that can be assigned
> below this rootport
> 
> +  @param[in] PcieRpLtrConfig          address of LTR Policy struct
> 
> +  @param[in] PcieRpCommonConfig       address of Common PCIe Policy
> struct
> 
> +  @param[in] AspmOverrideTableSize    size of override array
> 
> +  @param[in] AspmOverrideTable        array of device that need exceptions
> in configuration
> 
> +**/
> 
> +VOID
> 
> +RootportDownstreamPmConfiguration (
> 
> +  UINT8                               RpSegment,
> 
> +  UINT8                               RpBus,
> 
> +  UINT8                               RpDevice,
> 
> +  UINT8                               RpFunction,
> 
> +  UINT8                               BusMin,
> 
> +  UINT8                               BusMax,
> 
> +  PCIE_ROOT_PORT_COMMON_CONFIG        *PcieRpCommonConfig,
> 
> +  UINT32                              AspmOverrideTableSize,
> 
> +  PCH_PCIE_DEVICE_OVERRIDE            *AspmOverrideTable
> 
> +  )
> 
> +{
> 
> +  LTR_LIMIT      PolicyLtr;
> 
> +  LTR_OVERRIDE   TreeLtr;
> 
> +  OVERRIDE_TABLE PmOverrideTable;
> 
> +  UINT64         RpBase;
> 
> +  SBDF           RpSbdf;
> 
> +  SBDF_TABLE     BridgeCleanupList;
> 
> +
> 
> +  RpBase = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice,
> RpFunction, 0);
> 
> +  if (!(IsDevicePresent (RpBase))) {
> 
> +    return;
> 
> +  }
> 
> +  PmOverrideTable.Size = AspmOverrideTableSize;
> 
> +  PmOverrideTable.Table = AspmOverrideTable;
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "RootportDownstreamPmConfiguration
> %x:%x\n", RpDevice, RpFunction));
> 
> +  PolicyLtr.MaxNoSnoopLatencyScale = (PcieRpCommonConfig-
> >PcieRpLtrConfig.LtrMaxNoSnoopLatency & 0x1c00) >> 10;
> 
> +  PolicyLtr.MaxNoSnoopLatencyValue = PcieRpCommonConfig-
> >PcieRpLtrConfig.LtrMaxNoSnoopLatency & 0x3FF;
> 
> +  PolicyLtr.MaxSnoopLatencyScale   = (PcieRpCommonConfig-
> >PcieRpLtrConfig.LtrMaxSnoopLatency & 0x1c00) >> 10;
> 
> +  PolicyLtr.MaxSnoopLatencyValue   = PcieRpCommonConfig-
> >PcieRpLtrConfig.LtrMaxSnoopLatency & 0x3FF;
> 
> +
> 
> +  RpSbdf.Seg = RpSegment;
> 
> +  RpSbdf.Bus = RpBus;
> 
> +  RpSbdf.Dev = RpDevice;
> 
> +  RpSbdf.Func = RpFunction;
> 
> +  RpSbdf.PcieCap = PcieBaseFindCapId (RpBase,
> EFI_PCI_CAPABILITY_ID_PCIEXP);
> 
> +  //
> 
> +  // This code could execute either before or after enumeration. If before,
> then buses would not yet be assigned to bridges,
> 
> +  // making devices deeper in the hierarchy inaccessible.
> 
> +  // RecursiveBusAssignment will scan whole PCie tree and assign bus
> numbers to uninitialized bridges, if there are any
> 
> +  // List of such bridges will be kept in CleanupList, so that after PM
> programming is done, bus numbers can brought to original state
> 
> +  //
> 
> +  BridgeCleanupList.Count = 0;
> 
> +  RecursiveBusAssignment(RpSbdf, BusMin, BusMax, &BridgeCleanupList);
> 
> +  //
> 
> +  // The 'Recursive...' functions below expect bus numbers to be already
> assigned
> 
> +  //
> 
> +  RecursiveLtrConfiguration (RpSbdf, PolicyLtr);
> 
> +  TreeLtr = RecursiveLtrOverrideCheck (RpSbdf, &PmOverrideTable);
> 
> +  ConfigureRpLtrOverride (RpBase, RpSbdf.Dev, &TreeLtr,
> &(PcieRpCommonConfig->PcieRpLtrConfig));
> 
> +  DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride %x:%x\n", RpSbdf.Dev,
> RpSbdf.Func));
> 
> +  if (PcieRpCommonConfig->EnableCpm) {
> 
> +    RecursiveCpmConfiguration (RpSbdf);
> 
> +  }
> 
> +  //
> 
> +  // L1 substates can be modified only when L1 is disabled, so this function
> must execute
> 
> +  // before Aspm configuration which enables L1
> 
> +  //
> 
> +  RecursiveL1ssConfiguration (RpSbdf, &PmOverrideTable);
> 
> +  L1ssProprietaryConfiguration (RpBase, IsLtrCapable (RpSbdf));
> 
> +  RecursiveAspmConfiguration (RpSbdf, 0, &PmOverrideTable);
> 
> +
> 
> +  ClearBusFromTable (&BridgeCleanupList);
> 
> +}
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.h
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.h
> new file mode 100644
> index 0000000000..19c1051771
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PciExpressHelpersLibrary.h
> @@ -0,0 +1,40 @@
> +/** @file
> 
> +  Header file for Pci Express helps library implementation.
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#ifndef _PCI_EXPRESS_HELPERS_LIBRARY_H_
> 
> +#define _PCI_EXPRESS_HELPERS_LIBRARY_H_
> 
> +
> 
> +#include <Uefi/UefiBaseType.h>
> 
> +#include <Library/BaseLib.h>
> 
> +#include <Library/IoLib.h>
> 
> +#include <Library/DebugLib.h>
> 
> +#include <IndustryStandard/Pci.h>
> 
> +#include <PchPolicyCommon.h>
> 
> +#include <Library/PchPcieRpLib.h>
> 
> +#include <Library/PchPcrLib.h>
> 
> +#include <Library/PchInfoLib.h>
> 
> +#include <Library/PciSegmentLib.h>
> 
> +#include <Library/GpioNativeLib.h>
> 
> +#include <Library/TimerLib.h>
> 
> +#include <Library/PciExpressHelpersLib.h>
> 
> +#include <Library/PcieRpLib.h>
> 
> +#include <PcieRegs.h>
> 
> +#include <Register/CpuPcieRegs.h>
> 
> +#include <Register/PchPcieRpRegs.h>
> 
> +
> 
> +#define LTR_VALUE_MASK (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 +
> BIT7 + BIT8 + BIT9)
> 
> +#define LTR_SCALE_MASK (BIT10 + BIT11 + BIT12)
> 
> +
> 
> +  #define CONFIG_WRITE_LOOP_COUNT   100000
> 
> +
> 
> +//
> 
> +// LTR related macros
> 
> +//
> 
> +#define LTR_LATENCY_VALUE(x)           ((x) & LTR_VALUE_MASK)
> 
> +#define LTR_SCALE_VALUE(x)             (((x) & LTR_SCALE_MASK) >> 10)
> 
> +#define LTR_LATENCY_NS(x)              (LTR_LATENCY_VALUE(x) * (1 << (5 *
> LTR_SCALE_VALUE(x))))
> 
> +
> 
> +#endif
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf
> new file mode 100644
> index 0000000000..8f673d14c2
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress
> HelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf
> @@ -0,0 +1,49 @@
> +## @file
> 
> +# Component description file for the PeiDxeSmmPciExpressHelpersLib
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +
> 
> +[Defines]
> 
> +  INF_VERSION = 0x00010017
> 
> +  BASE_NAME = PeiDxeSmmPciExpressHelpersLib
> 
> +  FILE_GUID = 07E3F76D-6D26-419d-9053-58696A15B519
> 
> +  VERSION_STRING = 1.0
> 
> +  MODULE_TYPE = BASE
> 
> +LIBRARY_CLASS = PciExpressHelpersLib
> 
> +#
> 
> +# The following information is for reference only and not required by the
> build tools.
> 
> +#
> 
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> 
> +#
> 
> +
> 
> +
> 
> +
> 
> +
> 
> +[LibraryClasses]
> 
> +  IoLib
> 
> +  DebugLib
> 
> +  PchPcieRpLib
> 
> +  PchPcrLib
> 
> +  PchInfoLib
> 
> +  GpioLib
> 
> +  TimerLib
> 
> +  BasePcieHelperLib
> 
> +  PchPciBdfLib
> 
> +  HobLib
> 
> +  PcieRpLib
> 
> +
> 
> +[Packages]
> 
> +  MdePkg/MdePkg.dec
> 
> +  TigerlakeSiliconPkg/SiPkg.dec
> 
> +
> 
> +
> 
> +[Sources]
> 
> +  PciExpressHelpersLibrary.c
> 
> +  PciExpressHelpersLibrary.h
> 
> +
> 
> +[Guids]
> 
> +  gCpuPcieHobGuid
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.c
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.c
> new file mode 100644
> index 0000000000..15d295a573
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.c
> @@ -0,0 +1,247 @@
> +/** @file
> 
> +  This file contains routines that support PCI Express initialization
> 
> +
> 
> +  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +**/
> 
> +#include <Uefi/UefiBaseType.h>
> 
> +#include <IndustryStandard/Pci.h>
> 
> +#include <Library/BaseMemoryLib.h>
> 
> +#include <Library/PcieHelperLib.h>
> 
> +#include <Library/PchSbiAccessLib.h>
> 
> +#include <Library/PchPciBdfLib.h>
> 
> +#include <Library/PcieRpLib.h>
> 
> +#include <Library/PchInfoLib.h>
> 
> +#include <Library/PchPcieRpLib.h>
> 
> +#include <Library/PsfLib.h>
> 
> +#include <Library/HobLib.h>
> 
> +#include <Register/PchPcieRpRegs.h>
> 
> +#include <Register/PcieSipRegs.h>
> 
> +#include <PcieRegs.h>
> 
> +#include <PchPcieRpInfo.h>
> 
> +#include <CpuPcieInfo.h>
> 
> +#include <CpuPcieHob.h>
> 
> +
> 
> +/**
> 
> +  Get PCIe port number for enabled port.
> 
> +  @param[in] RpBase    Root Port pci segment base address
> 
> +
> 
> +  @retval Root Port number (1 based)
> 
> +**/
> 
> +UINT32
> 
> +PciePortNum (
> 
> +  IN     UINT64  RpBase
> 
> +  )
> 
> +{
> 
> +  return PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) >>
> N_PCH_PCIE_CFG_LCAP_PN;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Get PCIe root port index
> 
> +
> 
> +  @param[in] RpBase    Root Port pci segment base address
> 
> +
> 
> +  @retval Root Port index (0 based)
> 
> +**/
> 
> +UINT32
> 
> +PciePortIndex (
> 
> +  IN     UINT64  RpBase
> 
> +  )
> 
> +{
> 
> +  return PciePortNum (RpBase) - 1;
> 
> +}
> 
> +
> 
> +/**
> 
> +  This function checks whether PHY lane power gating is enabled on the
> port.
> 
> +
> 
> +  @param[in] RpBase                 Root Port base address
> 
> +
> 
> +  @retval TRUE                      PHY power gating is enabled
> 
> +  @retval FALSE                     PHY power gating disabled
> 
> +**/
> 
> +BOOLEAN
> 
> +PcieIsPhyLanePgEnabled (
> 
> +  IN     UINT64  RpBase
> 
> +  )
> 
> +{
> 
> +  UINT32 Data32;
> 
> +
> 
> +  Data32 = PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL);
> 
> +  return (Data32 & B_PCH_PCIE_CFG_PCIEPMECTL_DLSULPPGE) != 0;
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures Root Port packet split.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] Mps                            maximum packet size
> 
> +**/
> 
> +VOID
> 
> +ConfigureRpPacketSplit (
> 
> +  UINT64 RpBase,
> 
> +  UINT8  Mps
> 
> +  )
> 
> +{
> 
> +  PciSegmentAndThenOr32 (RpBase + R_PCIE_CFG_CCFG, (UINT32)
> ~(B_PCIE_CFG_CCFG_UNRS), Mps << N_PCIE_CFG_CCFG_UNRS);
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures LTR override in Root Port's proprietary registers.
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] DevNum                         currently visited device number
> 
> +  @param[in] RpConfig                       Root Port LTR configuration
> 
> +  @param[in] AspmOverride                   combination of LTR override values
> from all devices under this Root Port
> 
> +**/
> 
> +VOID
> 
> +ConfigureRpLtrOverride (
> 
> +  UINT64           RpBase,
> 
> +  UINT32           DevNum,
> 
> +  LTR_OVERRIDE     *TreeLtr,
> 
> +  PCIE_LTR_CONFIG  *LtrConfig
> 
> +  )
> 
> +{
> 
> +  UINT32       OvrEn;
> 
> +  UINT32       OvrVal;
> 
> +  BOOLEAN      IsCpuPcie;
> 
> +  UINT32       LtrCfgLock;
> 
> +
> 
> +  IsCpuPcie = FALSE;
> 
> +  OvrEn = 0;
> 
> +  OvrVal = 0;
> 
> +  LtrCfgLock = 0;
> 
> +
> 
> +  if (DevNum == SA_PEG0_DEV_NUM || DevNum == SA_PEG3_DEV_NUM)
> {
> 
> +    IsCpuPcie = TRUE;
> 
> +  }
> 
> +
> 
> +  //
> 
> +  // LTR settings from LTROVR register only get acknowledged on rising edge
> of LTROVR2[1:0]
> 
> +  // If those bits were already set (that can happen on a plug-hotUnplug-
> hotPlug scenario),
> 
> +  // they need to be toggled
> 
> +  //
> 
> +  if (PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LTROVR2) != 0) {
> 
> +    PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, 0);
> 
> +  }
> 
> +  //
> 
> +  // (*)LatencyOverrideMode = 0 -> no override
> 
> +  //                          1 -> override with RP policy values
> 
> +  //                          2 -> override with endpoint's override values
> 
> +  //
> 
> +
> 
> +  if (LtrConfig->ForceLtrOverride || TreeLtr->ForceOverride) {
> 
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_FORCE_OVERRIDE;
> 
> +  }
> 
> +  if (LtrConfig->LtrConfigLock == TRUE) {
> 
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LOCK;
> 
> +  }
> 
> +
> 
> +  if (LtrConfig->SnoopLatencyOverrideMode == 1) {
> 
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;
> 
> +    OvrVal |= LtrConfig->SnoopLatencyOverrideValue;
> 
> +    OvrVal |= LtrConfig->SnoopLatencyOverrideMultiplier << 10;
> 
> +    OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRSROVR;
> 
> +  } else if (LtrConfig->SnoopLatencyOverrideMode == 2) {
> 
> +    if (TreeLtr->MaxSnoopLatencyRequirement) {
> 
> +      OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;
> 
> +      OvrVal |= TreeLtr->MaxSnoopLatencyValue;
> 
> +      OvrVal |= TreeLtr->MaxSnoopLatencyScale << 10;
> 
> +      OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRSROVR;
> 
> +    }
> 
> +  }
> 
> +  if (LtrConfig->NonSnoopLatencyOverrideMode == 1) {
> 
> +    OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;
> 
> +    OvrVal |= LtrConfig->NonSnoopLatencyOverrideValue << 16;
> 
> +    OvrVal |= LtrConfig->NonSnoopLatencyOverrideMultiplier << 26;
> 
> +    OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;
> 
> +  } else if (LtrConfig->NonSnoopLatencyOverrideMode == 2) {
> 
> +    if (TreeLtr->MaxNoSnoopLatencyRequirement) {
> 
> +      OvrEn |= B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;
> 
> +      OvrVal |= TreeLtr->MaxNoSnoopLatencyValue << 16;
> 
> +      OvrVal |= TreeLtr->MaxNoSnoopLatencyScale << 26;
> 
> +      OvrVal |= B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;
> 
> +    }
> 
> +  }
> 
> +  PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR, OvrVal);
> 
> +  PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, OvrEn);
> 
> +
> 
> +  DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride IsCpuPcie=%d\n",
> IsCpuPcie));
> 
> +  DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride %x Val %x En %x\n",
> RpBase, OvrVal, OvrEn));
> 
> +}
> 
> +
> 
> +/**
> 
> +  This function configures EOI message forwarding for PCIe port.
> 
> +  If there's an IoAPIC behind this port, forwarding will be enabled
> 
> +  Otherwise it will be disabled to minimize bus traffic
> 
> +
> 
> +  @param[in] Segment,Bus,Device,Function    address of currently visited
> PCIe device
> 
> +  @param[in] IoApicPresent  TRUE if there's IoAPIC behind this Root Port
> 
> +**/
> 
> +VOID
> 
> +ConfigureEoiForwarding (
> 
> +  UINT64   RpBase,
> 
> +  BOOLEAN  IoApicPresent
> 
> +  )
> 
> +{
> 
> +  UINT32 RpIndex;
> 
> +
> 
> +  RpIndex = PciePortIndex (RpBase);
> 
> +
> 
> +  if (IoApicPresent == FALSE) {
> 
> +   PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC2,
> B_PCH_PCIE_CFG_MPC2_EOIFD);
> 
> +  } else {
> 
> +    ///
> 
> +    /// If there is an IOAPIC discovered behind Root Port, program PSF
> Multicast registers
> 
> +    /// in accordance with PCH PCIe BWG  PSF EOI Multicast Configuration
> 
> +    ///
> 
> +    PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_MPC2,
> (UINT32)~B_PCH_PCIE_CFG_MPC2_EOIFD);
> 
> +    PsfConfigurEoiForPciePort (RpIndex);
> 
> +  }
> 
> +}
> 
> +
> 
> +/**
> 
> +  Configures proprietary parts of L1 substates configuration in Root Port
> 
> +
> 
> +  @param[in] RpSbdf       segment:bus:device:function coordinates of Root
> Port
> 
> +  @param[in] LtrCapable   TRUE if Root Port is LTR capable
> 
> +**/
> 
> +VOID
> 
> +L1ssProprietaryConfiguration (
> 
> +  UINT64  RpBase,
> 
> +  BOOLEAN LtrCapable
> 
> +  )
> 
> +{
> 
> +  BOOLEAN ClkreqSupported;
> 
> +  BOOLEAN L1ssEnabled;
> 
> +  UINT16  PcieCapOffset;
> 
> +  UINT32  Data32;
> 
> +  BOOLEAN L1LowSupported;
> 
> +
> 
> +  ClkreqSupported = PcieIsPhyLanePgEnabled (RpBase);
> 
> +
> 
> +  PcieCapOffset = PcieBaseFindExtendedCapId (RpBase,
> V_PCIE_EX_L1S_CID);
> 
> +  if (PcieCapOffset == 0) {
> 
> +    L1ssEnabled = FALSE;
> 
> +  } else {
> 
> +    Data32 = PciSegmentRead32 (RpBase + PcieCapOffset +
> R_PCIE_EX_L1SCTL1_OFFSET);
> 
> +    L1ssEnabled = Data32 & (B_PCIE_EX_L1SCAP_AL1SS |
> B_PCIE_EX_L1SCAP_AL12S | B_PCIE_EX_L1SCAP_PPL11S
> |B_PCIE_EX_L1SCAP_PPL12S);
> 
> +  }
> 
> +  L1LowSupported = ClkreqSupported && LtrCapable && !L1ssEnabled;
> 
> +
> 
> +  ///
> 
> +  /// If L1.SNOOZ and L1.OFF (L1 Sub-States) are not supported and per-port
> CLKREQ# is supported, and LTR is supported:
> 
> +  /// Enable L1.LOW by setting Dxx:Fn:420[17] = 1b
> 
> +  ///
> 
> +  if (L1LowSupported) {
> 
> +    PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32)
> B_PCH_PCIE_CFG_PCIEPMECTL_L1LE);
> 
> +  } else {
> 
> +    PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32)
> ~B_PCH_PCIE_CFG_PCIEPMECTL_L1LE);
> 
> +  }
> 
> +
> 
> +  if (L1LowSupported || L1ssEnabled) {
> 
> +    ///
> 
> +    /// f.  Set Dxx:Fn:420h[0] to 1b prior to L1 enabling if any L1substate is
> enabled (including L1.LOW)
> 
> +    ///
> 
> +    PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL,
> B_PCH_PCIE_CFG_PCIEPMECTL_L1FSOE);
> 
> +  }
> 
> +}
> 
> diff --git
> a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.inf
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.inf
> new file mode 100644
> index 0000000000..86dceb14ee
> --- /dev/null
> +++
> b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientR
> pLib/PcieClientRpLib.inf
> @@ -0,0 +1,43 @@
> +## @file
> 
> +# Component description file for the PcieClientRpLib
> 
> +#
> 
> +#  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
> 
> +#  SPDX-License-Identifier: BSD-2-Clause-Patent
> 
> +#
> 
> +##
> 
> +
> 
> +
> 
> +[Defines]
> 
> +  INF_VERSION = 0x00010017
> 
> +  BASE_NAME = PcieClientRpLib
> 
> +  FILE_GUID = 77EB467D-674C-4C20-A13E-381600E182C4
> 
> +  VERSION_STRING = 1.0
> 
> +  MODULE_TYPE = BASE
> 
> +  LIBRARY_CLASS = PcieRpLib
> 
> +#
> 
> +# The following information is for reference only and not required by the
> build tools.
> 
> +#
> 
> +# VALID_ARCHITECTURES = IA32 X64 IPF EBC
> 
> +#
> 
> +
> 
> +
> 
> +
> 
> +[LibraryClasses]
> 
> +  IoLib
> 
> +  DebugLib
> 
> +  PchPcieRpLib
> 
> +  PchPcrLib
> 
> +  PchInfoLib
> 
> +  GpioLib
> 
> +  TimerLib
> 
> +  PsfLib
> 
> +  BasePcieHelperLib
> 
> +  PchPciBdfLib
> 
> +
> 
> +[Packages]
> 
> +  MdePkg/MdePkg.dec
> 
> +  TigerlakeSiliconPkg/SiPkg.dec
> 
> +
> 
> +
> 
> +[Sources]
> 
> +  PcieClientRpLib.c
> 
> --
> 2.24.0.windows.2


  reply	other threads:[~2021-02-04  3:55 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 [this message]
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
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=BN6PR1101MB214775A7976A423C4442B4E0CDB39@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