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
next prev parent 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