From: "Heng Luo" <heng.luo@intel.com>
To: devel@edk2.groups.io
Cc: Sai Chaganty <rangasai.v.chaganty@intel.com>,
Nate DeSimone <nathaniel.l.desimone@intel.com>
Subject: [Patch V3 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component
Date: Fri, 5 Feb 2021 15:40:28 +0800 [thread overview]
Message-ID: <20210205074045.3916-23-heng.luo@intel.com> (raw)
In-Reply-To: <20210205074045.3916-1-heng.luo@intel.com>
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/DxePchPcieRpPolicyLib.h | 55 ++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PciExpressHelpersLib.h | 173 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PcieRpLib.h | 109 ++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/PcieSipRegs.h | 45 ++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib/BasePcieHelperLib.c | 315 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelperLib/BasePcieHelperLib.inf | 37 +++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLib.c | 69 ++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLibInternal.h | 20 +++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLibVer2.c | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PeiDxeSmmPchPcieRpLibVer2.inf | 39 +++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.c | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.inf | 30 ++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciExpressHelpersLibrary.c | 1997 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciExpressHelpersLibrary.h | 40 ++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf | 49 ++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.c | 247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.inf | 43 +++++++++++++++++++
17 files changed, 3575 insertions(+)
diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/DxePchPcieRpPolicyLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/DxePchPcieRpPolicyLib.h
new file mode 100644
index 0000000000..1dea61388e
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/DxePchPcieRpPolicyLib.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/PciExpressHelpersLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PciExpressHelpersLib.h
new file mode 100644
index 0000000000..d7ca34dc38
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PciExpressHelpersLib.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/PcieRpLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PcieRpLib.h
new file mode 100644
index 0000000000..ed75e438c7
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/PcieRpLib.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/PcieSipRegs.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/PcieSipRegs.h
new file mode 100644
index 0000000000..1fc470b8ba
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/PcieSipRegs.h
@@ -0,0 +1,45 @@
+/** @file
+ Register names for PCIe SIP specific registers
+
+ Conventions:
+
+ - Register definition format:
+ Prefix_[GenerationName]_[ComponentName]_SubsystemName_RegisterSpace_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/PeiDxeSmmPchPcieRpLib/PchPcieRpLib.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLib.c
new file mode 100644
index 0000000000..153c073093
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/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/PeiDxeSmmPchPcieRpLib/PchPcieRpLibInternal.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLibInternal.h
new file mode 100644
index 0000000000..1766cff618
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/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/PeiDxeSmmPchPcieRpLib/PchPcieRpLibVer2.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLibVer2.c
new file mode 100644
index 0000000000..df90a87df7
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/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/PeiDxeSmmPchPcieRpLib/PeiDxeSmmPchPcieRpLibVer2.inf b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PeiDxeSmmPchPcieRpLibVer2.inf
new file mode 100644
index 0000000000..4fc217581b
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/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/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.c
new file mode 100644
index 0000000000..577e436e32
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/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/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.inf b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.inf
new file mode 100644
index 0000000000..6158e77a35
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/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/PciExpressHelpersLibrary/PciExpressHelpersLibrary.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciExpressHelpersLibrary.c
new file mode 100644
index 0000000000..401a9fbe7b
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/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/PciExpressHelpersLibrary/PciExpressHelpersLibrary.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciExpressHelpersLibrary.h
new file mode 100644
index 0000000000..19c1051771
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/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/PciExpressHelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf
new file mode 100644
index 0000000000..8f673d14c2
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/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/PcieClientRpLib/PcieClientRpLib.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.c
new file mode 100644
index 0000000000..15d295a573
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/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/PcieClientRpLib/PcieClientRpLib.inf b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.inf
new file mode 100644
index 0000000000..86dceb14ee
--- /dev/null
+++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClientRpLib/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-05 7:41 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-02-05 7:40 [Patch V3 01/40] TigerlakeSiliconPkg: Add package and Include/ConfigBlock headers Heng Luo
2021-02-05 7:40 ` [Patch V3 02/40] TigerlakeSiliconPkg/Include: Add Library, PPI and Protocol include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 03/40] TigerlakeSiliconPkg/Include: Add Pins, Register and other " Heng Luo
2021-02-05 7:40 ` [Patch V3 04/40] TigerlakeSiliconPkg/Cpu: Add Include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 05/40] TigerlakeSiliconPkg/Pch: Add include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 06/40] TigerlakeSiliconPkg/Pch: Add IncludePrivate headers Heng Luo
2021-02-05 7:40 ` [Patch V3 07/40] TigerlakeSiliconPkg/SystemAgent: Add include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 08/40] TigerlakeSiliconPkg/SystemAgent: Add IncludePrivate headers Heng Luo
2021-02-05 7:40 ` [Patch V3 09/40] TigerlakeSiliconPkg/Fru: Add TglCpu/Include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 10/40] TigerlakeSiliconPkg/Fru: Add TglCpu/IncludePrivate headers Heng Luo
2021-02-05 7:40 ` [Patch V3 11/40] TigerlakeSiliconPkg/Fru: Add TglPch/Include headers Heng Luo
2021-02-05 7:40 ` [Patch V3 12/40] TigerlakeSiliconPkg/Fru: Add TglPch/IncludePrivate headers Heng Luo
2021-02-05 7:40 ` [Patch V3 13/40] TigerlakeSiliconPkg/IpBlock: Add Cnvi component Heng Luo
2021-02-05 7:40 ` [Patch V3 14/40] TigerlakeSiliconPkg/IpBlock: Add CpuPcieRp component Heng Luo
2021-02-05 7:40 ` [Patch V3 15/40] TigerlakeSiliconPkg/IpBlock: Add Espi component Heng Luo
2021-02-05 7:40 ` [Patch V3 16/40] TigerlakeSiliconPkg/IpBlock: Add Gbe component Heng Luo
2021-02-05 7:40 ` [Patch V3 17/40] TigerlakeSiliconPkg/IpBlock: Add Gpio component Heng Luo
2021-02-05 7:40 ` [Patch V3 18/40] TigerlakeSiliconPkg/IpBlock: Add Graphics component Heng Luo
2021-02-05 7:40 ` [Patch V3 19/40] TigerlakeSiliconPkg/IpBlock: Add Hda component Heng Luo
2021-02-05 7:40 ` [Patch V3 20/40] TigerlakeSiliconPkg/IpBlock: Add HostBridge component Heng Luo
2021-02-05 7:40 ` [Patch V3 21/40] TigerlakeSiliconPkg/IpBlock: Add P2sb component Heng Luo
2021-02-05 7:40 ` [Patch V3 22/40] TigerlakeSiliconPkg/IpBlock: Add PchDmi component Heng Luo
2021-02-05 7:40 ` Heng Luo [this message]
2021-02-05 7:40 ` [Patch V3 24/40] TigerlakeSiliconPkg/IpBlock: Add Pmc component Heng Luo
2021-02-05 7:40 ` [Patch V3 25/40] TigerlakeSiliconPkg/IpBlock: Add Psf component Heng Luo
2021-02-05 7:40 ` [Patch V3 26/40] TigerlakeSiliconPkg/IpBlock: Add Sata component Heng Luo
2021-02-05 7:40 ` [Patch V3 27/40] TigerlakeSiliconPkg/IpBlock: Add SerialIo component Heng Luo
2021-02-05 7:40 ` [Patch V3 28/40] TigerlakeSiliconPkg/IpBlock: Add Smbus component Heng Luo
2021-02-05 7:40 ` [Patch V3 29/40] TigerlakeSiliconPkg/IpBlock: Add Spi component Heng Luo
2021-02-05 7:40 ` [Patch V3 30/40] TigerlakeSiliconPkg/IpBlock: Add Vtd component Heng Luo
2021-02-05 7:40 ` [Patch V3 31/40] TigerlakeSiliconPkg/Library: Add package common library instances Heng Luo
2021-02-05 7:40 ` [Patch V3 32/40] TigerlakeSiliconPkg/Pch: Add Pch " Heng Luo
2021-02-05 7:40 ` [Patch V3 33/40] TigerlakeSiliconPkg/Pch: Add Pch private " Heng Luo
2021-02-05 7:40 ` [Patch V3 34/40] TigerlakeSiliconPkg/SystemAgent: Add Acpi Tables and " Heng Luo
2021-02-05 7:40 ` [Patch V3 35/40] TigerlakeSiliconPkg/Fru/TglCpu: Add CpuPcieRp and Vtd " Heng Luo
2021-02-05 7:40 ` [Patch V3 36/40] TigerlakeSiliconPkg/Pch: Add Pch modules Heng Luo
2021-02-05 7:40 ` [Patch V3 37/40] TigerlakeSiliconPkg/SystemAgent: Add SystemAgent modules Heng Luo
2021-02-05 7:40 ` [Patch V3 38/40] TigerlakeSiliconPkg/Fru: Add Fru DSC files Heng Luo
2021-02-05 7:40 ` [Patch V3 39/40] TigerlakeSiliconPkg: Add package " Heng Luo
2021-02-05 7:40 ` [Patch V3 40/40] Maintainers.txt: Add TigerlakeSiliconPkg maintainers Heng Luo
2021-02-05 18:36 ` Nate DeSimone
2021-02-05 18:57 ` Chaganty, Rangasai V
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=20210205074045.3916-23-heng.luo@intel.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