From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga01.intel.com (mga01.intel.com []) by mx.groups.io with SMTP id smtpd.web12.5221.1612510911208301148 for ; Thu, 04 Feb 2021 23:41:53 -0800 Authentication-Results: mx.groups.io; dkim=missing; spf=fail (domain: intel.com, ip: , mailfrom: heng.luo@intel.com) IronPort-SDR: l0lNCBF1xh+eoRWvHYSgpkWDkkiL7fbwasBy9pfC19s+ZGh3u1G8ITHVz4AyDClq2/B8AbVyz3 cODiEI39mH6w== X-IronPort-AV: E=McAfee;i="6000,8403,9885"; a="200397264" X-IronPort-AV: E=Sophos;i="5.81,154,1610438400"; d="scan'208";a="200397264" Received: from fmsmga008.fm.intel.com ([10.253.24.58]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 04 Feb 2021 23:41:49 -0800 IronPort-SDR: Uv9duvJFlfq/8BoGJUH6ll/tsD8jKudE1WiufdEVoLZEQ9nkNM5/AEL7PIDbZo7jip2ydxC8QK 6tk1JWYi4oNg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.81,154,1610438400"; d="scan'208";a="373260447" Received: from hengluo-dev.ccr.corp.intel.com ([10.239.153.154]) by fmsmga008.fm.intel.com with ESMTP; 04 Feb 2021 23:41:47 -0800 From: "Heng Luo" To: devel@edk2.groups.io Cc: Sai Chaganty , Nate DeSimone Subject: [Patch V3 23/40] TigerlakeSiliconPkg/IpBlock: Add PcieRp component Date: Fri, 5 Feb 2021 15:40:28 +0800 Message-Id: <20210205074045.3916-23-heng.luo@intel.com> X-Mailer: git-send-email 2.24.0.windows.2 In-Reply-To: <20210205074045.3916-1-heng.luo@intel.com> References: <20210205074045.3916-1-heng.luo@intel.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3171 Adds the following files: * IpBlock/PcieRp/IncludePrivate * IpBlock/PcieRp/Library * IpBlock/PcieRp/LibraryPrivate Cc: Sai Chaganty Cc: Nate DeSimone Signed-off-by: Heng Luo --- Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Dx= ePchPcieRpPolicyLib.h | 55 +++++++++++++++++++= +++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pc= iExpressHelpersLib.h | 173 +++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Library/Pc= ieRpLib.h | 109 +++++++++++++++++++= +++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Register/P= cieSipRegs.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/PeiDxeSmmPchPcieR= pLib/PchPcieRpLib.c | 69 +++++++++++++++++++= +++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieR= pLib/PchPcieRpLibInternal.h | 20 +++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieR= pLib/PchPcieRpLibVer2.c | 128 +++++++++++++++++++= +++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieR= pLib/PeiDxeSmmPchPcieRpLibVer2.inf | 39 +++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcie= RpPolicyLib/DxePchPcieRpPolicyLib.c | 179 +++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcie= RpPolicyLib/DxePchPcieRpPolicyLib.inf | 30 ++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress= HelpersLibrary/PciExpressHelpersLibrary.c | 1997 +++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress= HelpersLibrary/PciExpressHelpersLibrary.h | 40 ++++++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpress= HelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf | 49 +++++++++++++++++++= +++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClient= RpLib/PcieClientRpLib.c | 247 +++++++++++++++++++= +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++= ++++++++++++++ Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieClient= RpLib/PcieClientRpLib.inf | 43 +++++++++++++++++++ 17 files changed, 3575 insertions(+) diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivat= e/Library/DxePchPcieRpPolicyLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlo= ck/PcieRp/IncludePrivate/Library/DxePchPcieRpPolicyLib.h new file mode 100644 index 0000000000..1dea61388e --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Libra= ry/DxePchPcieRpPolicyLib.h @@ -0,0 +1,55 @@ +/** @file=0D + DXE PcieRp policy library.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _DXE_PCH_PCIERP_POLICY_LIB_H_=0D +#define _DXE_PCH_PCIERP_POLICY_LIB_H_=0D +=0D +#include =0D +=0D +/**=0D + Load DXE Config block default for Pch PCIE RP=0D +=0D + @param[in] ConfigBlockPointer Pointer to config block=0D +**/=0D +VOID=0D +LoadPchPcieRpDxeConfigDefault (=0D + IN VOID *ConfigBlockPointer=0D + );=0D +=0D +/**=0D + Print PCIE_RP_DXE_CONFIG.=0D +=0D + @param[in] PchPolicy Pointer to a PCH_POLICY_PROTOCOL=0D +**/=0D +VOID=0D +PchPcieRpDxePrintConfig (=0D + IN PCH_POLICY_PROTOCOL *PchPolicy=0D + );=0D +=0D +/**=0D + Get PchPcieRp config block table size.=0D +=0D + @retval Size of config block=0D +**/=0D +UINT16=0D +PchPcieRpDxeGetConfigBlockTotalSize (=0D + VOID=0D + );=0D +=0D +/**=0D + Add PchPcieRp ConfigBlock.=0D +=0D + @param[in] ConfigBlockTableAddress The pointer to config block table= =0D +=0D + @retval EFI_SUCCESS The policy default is initialized.= =0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create b= uffer=0D +**/=0D +EFI_STATUS=0D +PchPcieRpDxeAddConfigBlock (=0D + IN VOID *ConfigBlockTableAddress=0D + );=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivat= e/Library/PciExpressHelpersLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBloc= k/PcieRp/IncludePrivate/Library/PciExpressHelpersLib.h new file mode 100644 index 0000000000..d7ca34dc38 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Libra= ry/PciExpressHelpersLib.h @@ -0,0 +1,173 @@ +/** @file=0D + Header file for PCI Express helpers library=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCI_EXPRESS_HELPERS_LIB_H_=0D +#define _PCI_EXPRESS_HELPERS_LIB_H_=0D +=0D +#include =0D +#include =0D +=0D +typedef enum {=0D + TpoScale2us,=0D + TpoScale10us,=0D + TpoScale100us,=0D + TpoScaleMax=0D +} T_PO_SCALE;=0D +//=0D +// This structure keeps segment:bus:device:function coordinates of a PCIe = device=0D +// in a single variable. PcieCap is offset to PCI Express capabilities.=0D +//=0D +typedef struct {=0D + UINT32 Seg : 8;=0D + UINT32 Bus : 8;=0D + UINT32 Dev : 5;=0D + UINT32 Func : 3;=0D + UINT32 PcieCap : 8;=0D +} SBDF;=0D +=0D +/*=0D + Converts Tpower_on from value:scale notation to microseconds=0D +=0D + @param[in] TpoScale T power on scale=0D + @param[in] TpoValue T power on value=0D +=0D + @retval number of microseconds=0D +*/=0D +UINT32=0D +TpoToUs (=0D + UINT32 TpoScale,=0D + UINT32 TpoValue=0D + );=0D +=0D +/**=0D +PCIe controller Sku.=0D +**/=0D +=0D +typedef enum {=0D + EnumPchPcie =3D 0,=0D + EnumiTbtPcie =3D 1,=0D + EnumCpuPcie =3D 2,=0D + EnumPciSkuMax =3D 3=0D +} PCI_SKU;=0D +=0D +/*=0D + Initializes the following features in rootport and devices behind it:=0D + Maximum Payload Size (generic)=0D + Rootport packet split (proprietary)=0D + EonOfInterrupt forwarding (proprietary)=0D + Common Clock Configuration (generic)=0D +=0D + Generic: any code written according to PCIE Express base specification c= an do that.=0D + Proprietary: code uses registers and features that are specific to Intel= silicon=0D + and probably only this Reference Code knows how to handle that.=0D +=0D + If OEM implemented generic feature enabling in his platform code or trus= ts Operating System=0D + to do it, then those features can be deleted from here.=0D +=0D + CCC requires link retrain, which takes a while. CCC must happen before L= 0s/L1 programming.=0D + If there was guarantee no code would access PCI while links retrain, it = would be possible to skip this waiting=0D +=0D + @param[in] RpSegment address of rootport on PCIe=0D + @param[in] RpBus address of rootport on PCIe=0D + @param[in] RpDevice address of rootport on PCIe=0D + @param[in] RpFunction address of rootport on PCIe=0D + @param[in] BusMin minimum Bus number that can be assigned below this= rootport=0D + @param[in] BusMax maximum Bus number that can be assigned below this= rootport=0D +*/=0D +VOID=0D +RootportDownstreamConfiguration (=0D + UINT8 RpSegment,=0D + UINT8 RpBus,=0D + UINT8 RpDevice,=0D + UINT8 RpFunction,=0D + UINT8 BusMin,=0D + UINT8 BusMax,=0D + PCI_SKU PciSku=0D + );=0D +=0D +/*=0D + Configures the following power-management related features in rootport a= nd devices behind it:=0D + LTR limit (generic)=0D + LTR override (proprietary)=0D + Clock Power Management (generic)=0D + L1 substates (generic except for the override table)=0D + L1.LOW substate (proprietary)=0D + L0s and L1 (generic)=0D +=0D + Generic: any code written according to PCIE Express base specification c= an do that.=0D + Proprietary: code uses registers and features that are specific to Intel= silicon=0D + and probably only this Reference Code knows how to handle that.=0D +=0D + If OEM implemented generic feature enabling in his platform code or trus= ts Operating System=0D + to do it, then those features can be deleted from here.=0D +=0D + @param[in] RpSegment address of rootport on PCIe=0D + @param[in] RpBus address of rootport on PCIe=0D + @param[in] RpDevice address of rootport on PCIe=0D + @param[in] RpFunction address of rootport on PCIe=0D + @param[in] BusMin minimal Bus number that can be assig= ned below this rootport=0D + @param[in] BusMax maximum Bus number that can be assig= ned below this rootport=0D + @param[in] PcieRpCommonConfig a pointer to Pcie Root Port Common C= onfig=0D + @param[in] AspmOverrideTableSize size of override array=0D + @param[in] AspmOverrideTable array of device that need exceptions= in configuration=0D +*/=0D +VOID=0D +RootportDownstreamPmConfiguration (=0D + UINT8 RpSegment,=0D + UINT8 RpBus,=0D + UINT8 RpDevice,=0D + UINT8 RpFunction,=0D + UINT8 BusMin,=0D + UINT8 BusMax,=0D + PCIE_ROOT_PORT_COMMON_CONFIG *PcieRpCommonConfig,=0D + UINT32 AspmOverrideTableSize,=0D + PCH_PCIE_DEVICE_OVERRIDE *AspmOverrideTable=0D + );=0D +=0D +typedef struct {=0D + UINT32 MaxSnoopLatencyValue : 10;=0D + UINT32 MaxSnoopLatencyScale : 3;=0D + UINT32 MaxNoSnoopLatencyValue : 10;=0D + UINT32 MaxNoSnoopLatencyScale : 3;=0D + UINT32 Reserved : 6;=0D +} LTR_LIMIT;=0D +=0D +/**=0D + Checks if given PCI device is capable of Latency Tolerance Reporting=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordina= tes=0D +=0D + @retval TRUE if yes=0D +**/=0D +BOOLEAN=0D +IsLtrCapable (=0D + SBDF Sbdf=0D + );=0D +=0D +/**=0D + Returns combination of two LTR override values=0D + The resulting LTR override separately chooses stricter limits for snoop = and nosnoop=0D +=0D + @param[in] LtrA LTR override values to be combined=0D + @param[in] LtrB LTR override values to be combined=0D +=0D + @retval LTR override value=0D +**/=0D +LTR_OVERRIDE=0D +CombineLtr (=0D + LTR_OVERRIDE LtrA,=0D + LTR_OVERRIDE LtrB=0D + );=0D +=0D +/**=0D + Extended Virtual Channel Configuration=0D +**/=0D +typedef struct {=0D + UINT16 CapOffset;=0D + UINT8 ExtVcCount;=0D +} MULTI_VC_SUPPORT;=0D +=0D +#endif // _PCI_EXPRESS_HELPERS_LIB_H_=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivat= e/Library/PcieRpLib.h b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/In= cludePrivate/Library/PcieRpLib.h new file mode 100644 index 0000000000..ed75e438c7 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivate/Libra= ry/PcieRpLib.h @@ -0,0 +1,109 @@ +/** @file=0D + Header file for PCH PCI Express helpers library=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCIE_RP_LIB_=0D +#define _PCIE_RP_LIB_=0D +=0D +#include =0D +=0D +typedef struct {=0D + UINT32 MaxSnoopLatencyValue : 10;=0D + UINT32 MaxSnoopLatencyScale : 3;=0D + UINT32 MaxSnoopLatencyRequirement : 1;=0D + UINT32 MaxNoSnoopLatencyValue : 10;=0D + UINT32 MaxNoSnoopLatencyScale : 3;=0D + UINT32 MaxNoSnoopLatencyRequirement : 1;=0D + UINT32 ForceOverride : 1;=0D +} LTR_OVERRIDE;=0D +=0D +/**=0D + Get PCIe port number for enabled Root Port.=0D +=0D + @param[in] RpBase Root Port pci segment base address=0D +=0D + @retval Root Port number (1 based)=0D +**/=0D +UINT32=0D +PciePortNum (=0D + IN UINT64 RpBase=0D + );=0D +=0D +/**=0D + Get PCIe root port index=0D + @param[in] RpBase Root Port pci segment base address=0D + @return Root Port index (0 based)=0D +**/=0D +UINT32=0D +PciePortIndex (=0D + IN UINT64 RpBase=0D + );=0D +=0D +/**=0D + This function checks whether PHY lane power gating is enabled on the por= t.=0D +=0D + @param[in] RpBase Root Port base address=0D +=0D + @retval TRUE PHY power gating is enabled=0D + @retval FALSE PHY power gating disabled=0D +**/=0D +BOOLEAN=0D +PcieIsPhyLanePgEnabled (=0D + IN UINT64 RpBase=0D + );=0D +=0D +/**=0D + Configures Root Port packet split.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] Mps maximum packet size=0D +**/=0D +VOID=0D +ConfigureRpPacketSplit (=0D + UINT64 RpBase,=0D + UINT8 Mps=0D + );=0D +=0D +/**=0D + Configures LTR override in Root Port's proprietary registers.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] LtrConfig Root Port LTR configuration=0D + @param[in] AspmOverride combination of LTR override va= lues from all devices under this Root Port=0D +**/=0D +VOID=0D +ConfigureRpLtrOverride (=0D + UINT64 RpBase,=0D + UINT32 DevNum,=0D + LTR_OVERRIDE *TreeLtr,=0D + PCIE_LTR_CONFIG *LtrConfig=0D + );=0D +=0D +/**=0D + This function configures EOI message forwarding for PCIe port.=0D + If there's an IoAPIC behind this port, forwarding will be enabled=0D + Otherwise it will be disabled to minimize bus traffic=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] IoApicPresent TRUE if there's IoAPIC behind this Root Port=0D +**/=0D +VOID=0D +ConfigureEoiForwarding (=0D + UINT64 RpBase,=0D + BOOLEAN IoApicPresent=0D + );=0D +=0D +/**=0D + Configures proprietary parts of L1 substates configuration in Root Port= =0D +=0D + @param[in] RpSbdf segment:bus:device:function coordinates of Root = Port=0D + @param[in] LtrCapable TRUE if Root Port is LTR capable=0D +**/=0D +VOID=0D +L1ssProprietaryConfiguration (=0D + UINT64 RpBase,=0D + BOOLEAN LtrCapable=0D + );=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/IncludePrivat= e/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/Regis= ter/PcieSipRegs.h @@ -0,0 +1,45 @@ +/** @file=0D + Register names for PCIe SIP specific registers=0D +=0D + Conventions:=0D +=0D + - Register definition format:=0D + Prefix_[GenerationName]_[ComponentName]_SubsystemName_RegisterSpace_Regi= sterName=0D + - Prefix:=0D + Definitions beginning with "R_" are registers=0D + Definitions beginning with "B_" are bits within registers=0D + Definitions beginning with "V_" are meaningful values within the bits=0D + Definitions beginning with "S_" are register size=0D + Definitions beginning with "N_" are the bit position=0D + - [GenerationName]:=0D + Three letter acronym of the generation is used (e.g. SKL,KBL,CNL etc.).= =0D + Register name without GenerationName applies to all generations.=0D + - [ComponentName]:=0D + This field indicates the component name that the register belongs to (e.= g. PCH, SA etc.)=0D + Register name without ComponentName applies to all components.=0D + Register that is specific to -LP denoted by "_PCH_LP_" in component name= .=0D + - SubsystemName:=0D + This field indicates the subsystem name of the component that the regist= er belongs to=0D + (e.g. PCIE, USB, SATA, GPIO, PMC etc.).=0D + - RegisterSpace:=0D + MEM - MMIO space register of subsystem.=0D + IO - IO space register of subsystem.=0D + PCR - Private configuration register of subsystem.=0D + CFG - PCI configuration space register of subsystem.=0D + - RegisterName:=0D + Full register name.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef _PCIE_SIP_RP_REGS_H_=0D +#define _PCIE_SIP_RP_REGS_H_=0D +=0D +#include =0D +=0D +#define R_PCIE_CFG_CCFG 0xD0=0D +#define B_PCIE_CFG_CCFG_UNRS (BIT6 | BIT5 | BIT4)= =0D +#define N_PCIE_CFG_CCFG_UNRS 4=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BaseP= cieHelperLib/BasePcieHelperLib.c b/Silicon/Intel/TigerlakeSiliconPkg/IpBloc= k/PcieRp/Library/BasePcieHelperLib/BasePcieHelperLib.c new file mode 100644 index 0000000000..1b3e629431 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelp= erLib/BasePcieHelperLib.c @@ -0,0 +1,315 @@ +/** @file=0D + This file contains routines that support PCI Express initialization=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +=0D +#define ASPM_L1_NO_LIMIT 0xFF=0D +#define LINK_RETRAIN_WAIT_TIME 1000 // microseconds=0D +=0D +/**=0D + Finds the Offset to a given Capabilities ID=0D + Each capability has an ID and a pointer to next Capability, so they form= a linked list.=0D + This function walks the list of Capabilities present in device's pci cfg= . If requested capability=0D + can be found, its offset is returned.=0D + If the capability can't be found or if device doesn't exist, function re= turns 0=0D + CAPID list:=0D + 0x01 =3D PCI Power Management Interface=0D + 0x04 =3D Slot Identification=0D + 0x05 =3D MSI Capability=0D + 0x10 =3D PCI Express Capability=0D +=0D + @param[in] DeviceBase device's base address=0D + @param[in] CapId CAPID to search for=0D +=0D + @retval 0 CAPID not found (this includes situation= where device doesn't exit)=0D + @retval Other CAPID found, Offset of desired CAPID=0D +**/=0D +UINT8=0D +PcieBaseFindCapId (=0D + IN UINT64 DeviceBase,=0D + IN UINT8 CapId=0D + )=0D +{=0D + UINT8 CapHeaderOffset;=0D + UINT8 CapHeaderId;=0D + UINT16 Data16;=0D + //=0D + // We do not explicitly check if device exists to save time and avoid un= necessary PCI access=0D + // If the device doesn't exist, check for CapHeaderId !=3D 0xFF will fai= l and function will return offset 0=0D + //=0D + if ((PciSegmentRead8 (DeviceBase + PCI_PRIMARY_STATUS_OFFSET) & EFI_PCI_= STATUS_CAPABILITY) =3D=3D 0x00) {=0D + ///=0D + /// Function has no capability pointer=0D + ///=0D + return 0;=0D + } else {=0D + ///=0D + /// Check the header layout to determine the Offset of Capabilities Po= inter Register=0D + ///=0D + if ((PciSegmentRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_LA= YOUT_CODE) =3D=3D (HEADER_TYPE_CARDBUS_BRIDGE)) {=0D + ///=0D + /// If CardBus bridge, start at Offset 0x14=0D + ///=0D + CapHeaderOffset =3D EFI_PCI_CARDBUS_BRIDGE_CAPABILITY_PTR;=0D + } else {=0D + ///=0D + /// Otherwise, start at Offset 0x34=0D + ///=0D + CapHeaderOffset =3D PCI_CAPBILITY_POINTER_OFFSET;=0D + }=0D + ///=0D + /// Get Capability Header, A pointer value of 00h is used to indicate = the last capability in the list.=0D + ///=0D + CapHeaderId =3D 0;=0D + CapHeaderOffset =3D PciSegmentRead8 (DeviceBase + CapHeaderOffset) & (= (UINT8) ~(BIT0 | BIT1));=0D + while (CapHeaderOffset !=3D 0 && CapHeaderId !=3D 0xFF) {=0D + Data16 =3D PciSegmentRead16 (DeviceBase + CapHeaderOffset);=0D + CapHeaderId =3D (UINT8)(Data16 & 0xFF);=0D + if (CapHeaderId =3D=3D CapId) {=0D + if (CapHeaderOffset > PCI_MAXLAT_OFFSET) {=0D + ///=0D + /// Return valid capability offset=0D + ///=0D + return CapHeaderOffset;=0D + } else {=0D + ASSERT ((FALSE));=0D + return 0;=0D + }=0D + }=0D + ///=0D + /// Each capability must be DWORD aligned.=0D + /// The bottom two bits of all pointers (including the initial point= er at 34h) are reserved=0D + /// and must be implemented as 00b although software must mask them = to allow for future uses of these bits.=0D + ///=0D + CapHeaderOffset =3D (UINT8)(Data16 >> 8);=0D + }=0D + return 0;=0D + }=0D +}=0D +=0D +/**=0D + Find the Offset to a given Capabilities ID=0D + CAPID list:=0D + 0x01 =3D PCI Power Management Interface=0D + 0x04 =3D Slot Identification=0D + 0x05 =3D MSI Capability=0D + 0x10 =3D PCI Express Capability=0D +=0D + @param[in] Segment Pci Segment Number=0D + @param[in] Bus Pci Bus Number=0D + @param[in] Device Pci Device Number=0D + @param[in] Function Pci Function Number=0D + @param[in] CapId CAPID to search for=0D +=0D + @retval 0 CAPID not found=0D + @retval Other CAPID found, Offset of desired CAPID=0D +**/=0D +UINT8=0D +PcieFindCapId (=0D + IN UINT8 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function,=0D + IN UINT8 CapId=0D + )=0D +{=0D + UINT64 DeviceBase;=0D +=0D + DeviceBase =3D PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, = 0);=0D + return PcieBaseFindCapId (DeviceBase, CapId);=0D +}=0D +=0D +/**=0D + Search and return the offset of desired Pci Express Capability ID=0D + CAPID list:=0D + 0x0001 =3D Advanced Error Reporting Capability=0D + 0x0002 =3D Virtual Channel Capability=0D + 0x0003 =3D Device Serial Number Capability=0D + 0x0004 =3D Power Budgeting Capability=0D +=0D + @param[in] DeviceBase device base address=0D + @param[in] CapId Extended CAPID to search for=0D +=0D + @retval 0 CAPID not found, this includes situation= where device doesn't exist=0D + @retval Other CAPID found, Offset of desired CAPID=0D +**/=0D +UINT16=0D +PcieBaseFindExtendedCapId (=0D + IN UINT64 DeviceBase,=0D + IN UINT16 CapId=0D + )=0D +{=0D + UINT16 CapHeaderOffset;=0D + UINT16 CapHeaderId;=0D + ///=0D + /// Start to search at Offset 0x100=0D + /// Get Capability Header, A pointer value of 00h is used to indicate th= e last capability in the list.=0D + ///=0D + CapHeaderId =3D 0;=0D + CapHeaderOffset =3D R_PCIE_CFG_EXCAP_OFFSET;=0D + while (CapHeaderOffset !=3D 0 && CapHeaderId !=3D MAX_UINT16) {=0D + CapHeaderId =3D PciSegmentRead16 (DeviceBase + CapHeaderOffset);=0D + if (CapHeaderId =3D=3D CapId) {=0D + return CapHeaderOffset;=0D + }=0D + ///=0D + /// Each capability must be DWORD aligned.=0D + /// The bottom two bits of all pointers are reserved and must be imple= mented as 00b=0D + /// although software must mask them to allow for future uses of these= bits.=0D + ///=0D + CapHeaderOffset =3D (PciSegmentRead16 (DeviceBase + CapHeaderOffset + = 2) >> 4) & ((UINT16) ~(BIT0 | BIT1));=0D + }=0D +=0D + return 0;=0D +}=0D +=0D +/**=0D + Search and return the offset of desired Pci Express Capability ID=0D + CAPID list:=0D + 0x0001 =3D Advanced Error Reporting Capability=0D + 0x0002 =3D Virtual Channel Capability=0D + 0x0003 =3D Device Serial Number Capability=0D + 0x0004 =3D Power Budgeting Capability=0D +=0D + @param[in] Segment Pci Segment Number=0D + @param[in] Bus Pci Bus Number=0D + @param[in] Device Pci Device Number=0D + @param[in] Function Pci Function Number=0D + @param[in] CapId Extended CAPID to search for=0D +=0D + @retval 0 CAPID not found, this includes situation= where device doesn't exist=0D + @retval Other CAPID found, Offset of desired CAPID=0D +**/=0D +UINT16=0D +PcieFindExtendedCapId (=0D + IN UINT8 Segment,=0D + IN UINT8 Bus,=0D + IN UINT8 Device,=0D + IN UINT8 Function,=0D + IN UINT16 CapId=0D + )=0D +{=0D + UINT64 DeviceBase;=0D +=0D + DeviceBase =3D PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, = 0);=0D + return PcieBaseFindExtendedCapId (DeviceBase, CapId);=0D +}=0D +=0D +/**=0D + Checks if PCI device at given address exists=0D +=0D + @param[in] Base device's base address=0D +=0D + @retval TRUE if exists=0D +**/=0D +BOOLEAN=0D +IsDevicePresent (=0D + UINT64 Base=0D + )=0D +{=0D + if (PciSegmentRead16 (Base) =3D=3D 0xFFFF) {=0D + return FALSE;=0D + }=0D + return TRUE;=0D +}=0D +=0D +/**=0D + Checks if device is a multifunction device=0D + Besides comparing Multifunction bit (BIT7) it checks if contents of HEAD= ER_TYPE register=0D + make sense (header !=3D 0xFF) to prevent false positives when called on = devices which do not exist=0D +=0D + @param[in] Base device's base address=0D +=0D + @retval TRUE if multifunction; FALSE otherwise=0D +**/=0D +BOOLEAN=0D +IsMultifunctionDevice (=0D + UINT64 Base=0D + )=0D +{=0D + UINT8 HeaderType;=0D + HeaderType =3D PciSegmentRead8(Base + PCI_HEADER_TYPE_OFFSET);=0D + if ((HeaderType =3D=3D 0xFF) || ((HeaderType & HEADER_TYPE_MULTI_FUNCTIO= N) =3D=3D 0)) {=0D + return FALSE;=0D + }=0D + return TRUE;=0D +}=0D +=0D +/**=0D + Checks device's Slot Clock Configuration=0D +=0D + @param[in] Base device's base address=0D + @param[in] PcieCapOffset devices Pci express capability list register = offset=0D +=0D + @retval TRUE when device uses slot clock, FALSE otherwise=0D +**/=0D +BOOLEAN=0D +GetScc (=0D + UINT64 Base,=0D + UINT8 PcieCapOffset=0D + )=0D +{=0D + return !!(PciSegmentRead16 (Base + PcieCapOffset + R_PCIE_LSTS_OFFSET) &= B_PCIE_LSTS_SCC);=0D +}=0D +=0D +/**=0D + Sets Common Clock Configuration bit for given device.=0D +=0D + @param[in] PcieCapOffset devices Pci express capability list register = offset=0D + @param[in] Base device's base address=0D +**/=0D +VOID=0D +EnableCcc (=0D + UINT64 Base,=0D + UINT8 PcieCapOffset=0D + )=0D +{=0D + PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET, B_PCIE_LCTL_CC= C);=0D +}=0D +=0D +/**=0D + Retrains link behind given device.=0D + It only makes sense to call it for downstream ports. If called for upstr= eam port nothing will happen.=0D + If WaitUntilDone is TRUE function will wait until link retrain had finis= hed, otherwise it will return immediately.=0D + Link must finish retrain before software can access the device on the ot= her side. If it's not going to access it=0D + then considerable time can be saved by not waiting here.=0D +=0D + @param[in] Base device's base address=0D + @param[in] PcieCapOffset devices Pci express capability list register= offset=0D + @param[in] WaitUntilDone when TRUE, function waits until link has ret= rained=0D +**/=0D +VOID=0D +RetrainLink (=0D + UINT64 Base,=0D + UINT8 PcieCapOffset,=0D + BOOLEAN WaitUntilDone=0D + )=0D +{=0D + UINT16 LinkTraining;=0D + UINT32 TimeoutUs;=0D +=0D + TimeoutUs =3D LINK_RETRAIN_WAIT_TIME;=0D + //=0D + // Before triggering link retrain make sure it's not already retraining.= Otherwise=0D + // settings recently entered in LCTL register might go unnoticed=0D + //=0D + do {=0D + LinkTraining =3D (PciSegmentRead16 (Base + PcieCapOffset + R_PCIE_LSTS= _OFFSET) & B_PCIE_LSTS_LT);=0D + TimeoutUs--;=0D + } while (LinkTraining && (TimeoutUs !=3D 0));=0D +=0D + PciSegmentOr8 (Base + PcieCapOffset + R_PCIE_LCTL_OFFSET, B_PCIE_LCTL_RL= );=0D +=0D + TimeoutUs =3D LINK_RETRAIN_WAIT_TIME;=0D + if (WaitUntilDone) {=0D + do {=0D + LinkTraining =3D (PciSegmentRead16 (Base + PcieCapOffset + R_PCIE_LS= TS_OFFSET) & B_PCIE_LSTS_LT);=0D + TimeoutUs--;=0D + } while (LinkTraining && (TimeoutUs !=3D 0));=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BaseP= cieHelperLib/BasePcieHelperLib.inf b/Silicon/Intel/TigerlakeSiliconPkg/IpBl= ock/PcieRp/Library/BasePcieHelperLib/BasePcieHelperLib.inf new file mode 100644 index 0000000000..458a540859 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/BasePcieHelp= erLib/BasePcieHelperLib.inf @@ -0,0 +1,37 @@ +## @file=0D +# Component description file for the BasePcieHelperLib=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D BasePcieHelperLib=0D +FILE_GUID =3D 568F5812-A9A8-4A4A-AD4D-471DD5F0BC11=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D BASE=0D +LIBRARY_CLASS =3D BasePcieHelperLib=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC=0D +#=0D +=0D +=0D +=0D +[LibraryClasses]=0D +DebugLib=0D +PciSegmentLib=0D +=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Sources]=0D +BasePcieHelperLib.c=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDx= eSmmPchPcieRpLib/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/PeiDxeSmmPch= PcieRpLib/PchPcieRpLib.c @@ -0,0 +1,69 @@ +/** @file=0D + PCIE root port library.=0D + All function in this library is available for PEI, DXE, and SMM,=0D + But do not support UEFI RUNTIME environment call.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchPcieRpLibInternal.h"=0D +=0D +/**=0D + Gets pci segment base address of PCIe root port.=0D +=0D + @param RpIndex Root Port Index (0 based)=0D + @return PCIe port base address.=0D +**/=0D +UINT64=0D +PchPcieBase (=0D + IN UINT32 RpIndex=0D + )=0D +{=0D + return PchPcieRpPciCfgBase (RpIndex);=0D +}=0D +=0D +/**=0D + Determines whether L0s is supported on current stepping.=0D +=0D + @return TRUE if L0s is supported, FALSE otherwise=0D +**/=0D +BOOLEAN=0D +PchIsPcieL0sSupported (=0D + VOID=0D + )=0D +{=0D + return TRUE;=0D +}=0D +=0D +/**=0D + Some early PCH steppings require Native ASPM to be disabled due to hardw= are issues:=0D + - RxL0s exit causes recovery=0D + - Disabling PCIe L0s capability disables L1=0D + Use this function to determine affected steppings.=0D +=0D + @return TRUE if Native ASPM is supported, FALSE otherwise=0D +**/=0D +BOOLEAN=0D +PchIsPcieNativeAspmSupported (=0D + VOID=0D + )=0D +{=0D + return PchIsPcieL0sSupported ();=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDx= eSmmPchPcieRpLib/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/PeiDxeSmmPch= PcieRpLib/PchPcieRpLibInternal.h @@ -0,0 +1,20 @@ +/** @file=0D + PCIE root port library.=0D + All function in this library is available for PEI, DXE, and SMM,=0D + But do not support UEFI RUNTIME environment call.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#ifndef _PCH_PCIE_RP_LIB_INTERNAL_H_=0D +#define _PCH_PCIE_RP_LIB_INTERNAL_H_=0D +=0D +typedef struct {=0D + UINT8 DevNum;=0D + UINT8 Pid;=0D + UINT8 RpNumBase;=0D +} PCH_PCIE_CONTROLLER_INFO;=0D +=0D +#endif=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDx= eSmmPchPcieRpLib/PchPcieRpLibVer2.c b/Silicon/Intel/TigerlakeSiliconPkg/IpB= lock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PchPcieRpLibVer2.c new file mode 100644 index 0000000000..df90a87df7 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPch= PcieRpLib/PchPcieRpLibVer2.c @@ -0,0 +1,128 @@ +/** @file=0D + PCIE root port library.=0D + All function in this library is available for PEI, DXE, and SMM,=0D + But do not support UEFI RUNTIME environment call.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#include "PchPcieRpLibInternal.h"=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_CONTROLLER_INFO mPchPcieControllerI= nfo[] =3D {=0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_1, PID_SPA, 0 },=0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_5, PID_SPB, 4 },=0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_9, PID_SPC, 8 },=0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_13, PID_SPD, 12 },=0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_17, PID_SPE, 16 }, // PCH-H only= =0D + { PCI_DEVICE_NUMBER_PCH_PCIE_ROOT_PORT_21, PID_SPF, 20 } // PCH-H only= =0D +};=0D +=0D +/**=0D + Get Pch Pcie Root Port Device and Function Number by Root Port physical = Number=0D +=0D + @param[in] RpNumber Root port physical number. (0-based)=0D + @param[out] RpDev Return corresponding root port device = number.=0D + @param[out] RpFun Return corresponding root port functio= n number.=0D +=0D + @retval EFI_SUCCESS Root port device and function is retri= eved=0D + @retval EFI_INVALID_PARAMETER RpNumber is invalid=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +GetPchPcieRpDevFun (=0D + IN UINTN RpNumber,=0D + OUT UINTN *RpDev,=0D + OUT UINTN *RpFun=0D + )=0D +{=0D + UINTN Index;=0D + UINTN FuncIndex;=0D + UINT32 PciePcd;=0D +=0D + if (RpNumber >=3D GetPchMaxPciePortNum ()) {=0D + DEBUG ((DEBUG_ERROR, "GetPchPcieRpDevFun invalid RpNumber %x", RpNumbe= r));=0D + ASSERT (FALSE);=0D + return EFI_INVALID_PARAMETER;=0D + }=0D +=0D + Index =3D RpNumber / PCH_PCIE_CONTROLLER_PORTS;=0D + FuncIndex =3D RpNumber - mPchPcieControllerInfo[Index].RpNumBase;=0D + *RpDev =3D mPchPcieControllerInfo[Index].DevNum;=0D + PciePcd =3D PchPcrRead32 (mPchPcieControllerInfo[Index].Pid, R_SPX_PCR_P= CD);=0D + *RpFun =3D (PciePcd >> (FuncIndex * S_SPX_PCR_PCD_RP_FIELD)) & B_SPX_PCR= _PCD_RP1FN;=0D +=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + Get Root Port physical Number by Pch Pcie Root Port Device and Function = Number=0D +=0D + @param[in] RpDev Root port device number.=0D + @param[in] RpFun Root port function number.=0D + @param[out] RpNumber Return corresponding physical Root Por= t index (0-based)=0D +=0D + @retval EFI_SUCCESS Physical root port is retrieved=0D +**/=0D +EFI_STATUS=0D +EFIAPI=0D +GetPchPcieRpNumber (=0D + IN UINTN RpDev,=0D + IN UINTN RpFun,=0D + OUT UINTN *RpNumber=0D + )=0D +{=0D + UINT64 RpBase;=0D +=0D + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (DEFAULT_PCI_SEGMENT_NUMBER_PCH, DEFA= ULT_PCI_BUS_NUMBER_PCH, RpDev, RpFun, 0);=0D + *RpNumber =3D (PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) >> N_PCH_= PCIE_CFG_LCAP_PN) -1;=0D + return EFI_SUCCESS;=0D +}=0D +=0D +/**=0D + This function returns PID according to PCIe controller index=0D +=0D + @param[in] ControllerIndex PCIe controller index=0D +=0D + @retval PCH_SBI_PID Returns PID for SBI Access=0D +**/=0D +PCH_SBI_PID=0D +PchGetPcieControllerSbiPid (=0D + IN UINT32 ControllerIndex=0D + )=0D +{=0D + ASSERT (ControllerIndex < ARRAY_SIZE (mPchPcieControllerInfo));=0D + return mPchPcieControllerInfo[ControllerIndex].Pid;=0D +}=0D +=0D +/**=0D + This function returns PID according to Root Port Number=0D +=0D + @param[in] RpIndex Root Port Index (0-based)=0D +=0D + @retval PCH_SBI_PID Returns PID for SBI Access=0D +**/=0D +PCH_SBI_PID=0D +GetRpSbiPid (=0D + IN UINTN RpIndex=0D + )=0D +{=0D + return PchGetPcieControllerSbiPid ((UINT32) (RpIndex / PCH_PCIE_CONTROLL= ER_PORTS));=0D +}=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDx= eSmmPchPcieRpLib/PeiDxeSmmPchPcieRpLibVer2.inf b/Silicon/Intel/TigerlakeSil= iconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPchPcieRpLib/PeiDxeSmmPchPcieRpLibV= er2.inf new file mode 100644 index 0000000000..4fc217581b --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/Library/PeiDxeSmmPch= PcieRpLib/PeiDxeSmmPchPcieRpLibVer2.inf @@ -0,0 +1,39 @@ +## @file=0D +# PCIE root port Library.=0D +#=0D +# All function in this library is available for PEI, DXE, and SMM,=0D +# But do not support UEFI RUNTIME environment call.=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D PeiDxeSmmPchPcieRpLib=0D +FILE_GUID =3D B522981C-E0C5-4E04-A82A-C61D4F0B2C75=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D BASE=0D +LIBRARY_CLASS =3D PchPcieRpLib=0D +=0D +=0D +[LibraryClasses]=0D +BaseLib=0D +IoLib=0D +DebugLib=0D +PciSegmentLib=0D +PchInfoLib=0D +PchPcrLib=0D +=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Sources]=0D +PchPcieRpLib.c=0D +PchPcieRpLibVer2.c=0D +=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.c b/Silicon/Intel/TigerlakeSi= liconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRpPo= licyLib.c new file mode 100644 index 0000000000..577e436e32 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePc= hPcieRpPolicyLib/DxePchPcieRpPolicyLib.c @@ -0,0 +1,179 @@ +/** @file=0D + This file provides services for PcieRp policy function=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define PCI_CLASS_NETWORK 0x02=0D +#define PCI_CLASS_NETWORK_ETHERNET 0x00=0D +#define PCI_CLASS_NETWORK_OTHER 0x80=0D +=0D +GLOBAL_REMOVE_IF_UNREFERENCED PCH_PCIE_DEVICE_OVERRIDE mPcieDeviceTable[] = =3D {=0D + //=0D + // Intel PRO/Wireless=0D + //=0D + { 0x8086, 0x422b, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x422c, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x4238, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x4239, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel WiMAX/WiFi Link=0D + //=0D + { 0x8086, 0x0082, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0085, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0083, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0084, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0086, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0087, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0088, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0089, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x008F, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0090, 0xff, 0xff, 0xff, PchPcieAspmL1, PchPcieL1L2Override, = 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Crane Peak WLAN NIC=0D + //=0D + { 0x8086, 0x08AE, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x08AF, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Crane Peak w/BT WLAN NIC=0D + //=0D + { 0x8086, 0x0896, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0897, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Kelsey Peak WiFi, WiMax=0D + //=0D + { 0x8086, 0x0885, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0886, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Centrino Wireless-N 105=0D + //=0D + { 0x8086, 0x0894, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0895, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Centrino Wireless-N 135=0D + //=0D + { 0x8086, 0x0892, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0893, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Centrino Wireless-N 2200=0D + //=0D + { 0x8086, 0x0890, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0891, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Centrino Wireless-N 2230=0D + //=0D + { 0x8086, 0x0887, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x0888, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel Centrino Wireless-N 6235=0D + //=0D + { 0x8086, 0x088E, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x088F, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel CampPeak 2 Wifi=0D + //=0D + { 0x8086, 0x08B5, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + { 0x8086, 0x08B6, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Intel WilkinsPeak 1 Wifi=0D + //=0D + { 0x8086, 0x08B3, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, = 0, 0 },=0D + { 0x8086, 0x08B4, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, = 0, 0 },=0D + //=0D + // Intel Wilkins Peak 2 Wifi=0D + //=0D + { 0x8086, 0x08B1, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, = 0, 0 },=0D + { 0x8086, 0x08B2, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2AndL1SubstatesOverride, 0x0158, 0x0000000F, 0, 0, 0, = 0, 0 },=0D + //=0D + // Intel Wilkins Peak PF Wifi=0D + //=0D + { 0x8086, 0x08B0, 0xff, PCI_CLASS_NETWORK, PCI_CLASS_NETWORK_OTHER, PchP= cieAspmL1, PchPcieL1L2Override, 0, 0, 0, 0, 0, 0, 0 },=0D + //=0D + // Teton Glacier Endpoint=0D + //=0D + { 0x8086, 0x0975, 0xff, 0, 0, 0, PchPcieL1SubstatesOverride, 0, 0xff, 0x= 3C, 0, 5, 0, 0, 0, 0 },=0D +=0D + //=0D + // End of Table=0D + //=0D + { 0 }=0D +};=0D +=0D +/**=0D + Print PCIE_RP_DXE_CONFIG.=0D +=0D + @param[in] PchPolicy Pointer to a PCH_POLICY_PROTOCOL=0D +**/=0D +VOID=0D +PchPcieRpDxePrintConfig (=0D + IN PCH_POLICY_PROTOCOL *PchPolicy=0D + )=0D +{=0D + EFI_STATUS Status;=0D + PCIE_RP_DXE_CONFIG *PchPcieRpDxeConfig;=0D +=0D + Status =3D GetConfigBlock ((VOID *) PchPolicy, &gPchPcieRpDxeConfigGuid,= (VOID *) &PchPcieRpDxeConfig);=0D + ASSERT_EFI_ERROR (Status);=0D +=0D + DEBUG ((DEBUG_INFO, "------------------ PCH PCIE DXE CONFIG ------------= ------\n"));=0D + DEBUG ((DEBUG_INFO, " PcieDeviceOverrideTablePtr : 0x%x\n",PchPcieRpDxeC= onfig->PcieDeviceOverrideTablePtr));=0D +}=0D +=0D +/**=0D + Load DXE Config block default for Pch PCIE RP=0D +=0D + @param[in] ConfigBlockPointer Pointer to config block=0D +**/=0D +VOID=0D +LoadPchPcieRpDxeConfigDefault (=0D + IN VOID *ConfigBlockPointer=0D + )=0D +{=0D + PCIE_RP_DXE_CONFIG *PchPcieRpDxeConfig;=0D +=0D + PchPcieRpDxeConfig =3D ConfigBlockPointer;=0D + PchPcieRpDxeConfig->PcieDeviceOverrideTablePtr =3D mPcieDeviceTable;=0D +}=0D +=0D +STATIC COMPONENT_BLOCK_ENTRY mPchPcieRpBlocks =3D {=0D + &gPchPcieRpDxeConfigGuid,=0D + sizeof (PCIE_RP_DXE_CONFIG),=0D + PCIE_RP_DXE_CONFIG_REVISION,=0D + LoadPchPcieRpDxeConfigDefault=0D +};=0D +=0D +/**=0D + Get PchPcieRp config block table size.=0D +=0D + @retval Size of config block=0D +**/=0D +UINT16=0D +PchPcieRpDxeGetConfigBlockTotalSize (=0D + VOID=0D + )=0D +{=0D + return mPchPcieRpBlocks.Size;=0D +}=0D +=0D +/**=0D + Add PchPcieRp ConfigBlock.=0D +=0D + @param[in] ConfigBlockTableAddress The pointer to config block table= =0D +=0D + @retval EFI_SUCCESS The policy default is initialized.= =0D + @retval EFI_OUT_OF_RESOURCES Insufficient resources to create b= uffer=0D +**/=0D +EFI_STATUS=0D +PchPcieRpDxeAddConfigBlock (=0D + IN VOID *ConfigBlockTableAddress=0D + )=0D +{=0D + return AddComponentConfigBlocks (ConfigBlockTableAddress, &mPchPcieRpBlo= cks, 1);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/DxePchPcieRpPolicyLib/DxePchPcieRpPolicyLib.inf b/Silicon/Intel/Tigerlake= SiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePchPcieRpPolicyLib/DxePchPcieRp= PolicyLib.inf new file mode 100644 index 0000000000..6158e77a35 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/DxePc= hPcieRpPolicyLib/DxePchPcieRpPolicyLib.inf @@ -0,0 +1,30 @@ +## @file=0D +# Component description file for the PchPcieRp policy library=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +[Defines]=0D +INF_VERSION =3D 0x00010017=0D +BASE_NAME =3D DxePchPcieRpPolicyLib=0D +FILE_GUID =3D 328B0DE5-189A-4DB0-BFE1-557F4F89010B=0D +VERSION_STRING =3D 1.0=0D +MODULE_TYPE =3D BASE=0D +LIBRARY_CLASS =3D DxePchPcieRpPolicyLib=0D +=0D +[LibraryClasses]=0D +DebugLib=0D +ConfigBlockLib=0D +SiConfigBlockLib=0D +=0D +[Packages]=0D +MdePkg/MdePkg.dec=0D +TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +[Sources]=0D +DxePchPcieRpPolicyLib.c=0D +=0D +[Guids]=0D +gPchPcieRpDxeConfigGuid ## CONSUMES=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/PciExpressHelpersLibrary/PciExpressHelpersLibrary.c b/Silicon/Intel/Tiger= lakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciEx= pressHelpersLibrary.c new file mode 100644 index 0000000000..401a9fbe7b --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciEx= pressHelpersLibrary/PciExpressHelpersLibrary.c @@ -0,0 +1,1997 @@ +/** @file=0D + This file contains routines that support PCI Express initialization=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include "PciExpressHelpersLibrary.h"=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define ASPM_L1_NO_LIMIT 0xFF=0D +#define ASPM_L0s_NO_LIMIT 0x7=0D +#define LINK_RETRAIN_WAIT_TIME 1000 // microseconds=0D +=0D +typedef union {=0D + struct {=0D + UINT32 RequesterCapable : 1;=0D + UINT32 ResponderCapable : 1;=0D + UINT32 RootCapable : 1;=0D + UINT32 Reserved : 5;=0D + UINT32 LocalClockGranularity : 8;=0D + UINT32 Reserved2 : 16;=0D + } Bits;=0D + UINT32 Uint32;=0D +} PTM_CAPS;=0D +=0D +typedef union {=0D + struct {=0D + UINT32 Enable : 1;=0D + UINT32 RootSelect : 1;=0D + UINT32 Reserved : 6;=0D + UINT32 EffectiveGranularity : 8;=0D + UINT32 Reserved2 : 16;=0D + } Bits;=0D + UINT32 Uint32;=0D +} PTM_CTRL;=0D +=0D +typedef struct {=0D + UINT32 Size;=0D + const PCH_PCIE_DEVICE_OVERRIDE* Table;=0D +} OVERRIDE_TABLE;=0D +=0D +typedef enum {=0D + DevTypePci,=0D + DevTypePcieEndpoint,=0D + DevTypePcieUpstream,=0D + DevTypePcieDownstream,=0D + DevTypeMax=0D +} PCI_DEV_TYPE;=0D +=0D +//=0D +// This structure keeps in one place all data relevant to enabling L0s and= L1.=0D +// L0s latencies are encoded in the same way as in hardware registers. The= only operation=0D +// that will be performed on them is comparison=0D +// L1 latencies are decoded to microseconds, because they will be used in = subtractions and additions=0D +//=0D +typedef struct {=0D + UINT32 L0sSupported : 1;=0D + UINT32 L1Supported : 1;=0D + UINT32 L0sAcceptableLatency : 3; // encoded as in hardware register=0D + UINT32 L1AcceptableLatencyUs : 8; // decoded to microseconds=0D + UINT32 LinkL0sExitLatency : 3; // encoded as in hardware register=0D + UINT32 LinkL1ExitLatencyUs : 8; // decoded to microseconds=0D +} ASPM_CAPS;=0D +=0D +typedef struct {=0D + UINT32 AspmL11 : 1;=0D + UINT32 AspmL12 : 1;=0D + UINT32 PmL11 : 1;=0D + UINT32 PmL12 : 1;=0D + UINT32 Cmrt : 8; // Common Mode Restore Time=0D + UINT32 TpoScale : 2; // T power_on scale=0D + UINT32 TpoValue : 6; // T power_on value=0D +} L1SS_CAPS;=0D +=0D +#define MAX_SBDF_TABLE_SIZE 50 //arbitrary table size; big enough to accom= odate even full length TBT chain.=0D +=0D +typedef struct {=0D + UINT32 Count;=0D + SBDF Entry [MAX_SBDF_TABLE_SIZE];=0D +} SBDF_TABLE;=0D +=0D +/**=0D + Converts device's segment:bus:device:function coordinates to flat addres= s=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordinates=0D +=0D + @retval address of device's PCI cfg space=0D +**/=0D +STATIC=0D +UINT64=0D +SbdfToBase (=0D + SBDF Sbdf=0D + )=0D +{=0D + return PCI_SEGMENT_LIB_ADDRESS (Sbdf.Seg, Sbdf.Bus, Sbdf.Dev, Sbdf.Func,= 0);=0D +}=0D +=0D +/*=0D + Converts Tpower_on from value:scale notation to microseconds=0D +=0D + @param[in] TpoScale T power on scale=0D + @param[in] TpoValue T power on value=0D +=0D + @retval number of microseconds=0D +*/=0D +UINT32=0D +TpoToUs (=0D + UINT32 TpoScale,=0D + UINT32 TpoValue=0D + )=0D +{=0D + static const UINT8 TpoScaleMultiplier[] =3D {2, 10, 100};=0D +=0D + ASSERT (TpoScale < TpoScaleMax);=0D + if (TpoScale >=3D TpoScaleMax) {=0D + return 0;=0D + }=0D + return (TpoScaleMultiplier[TpoScale] * TpoValue);=0D +}=0D +=0D +/**=0D + Get max payload size supported by device.=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordinates=0D +=0D + @retval Max payload size, encoded in the same way as in register (0= =3D128b, 1=3D256b, etc)=0D +**/=0D +STATIC=0D +UINT8=0D +GetMps (=0D + SBDF Sbdf=0D + )=0D +{=0D + return (PciSegmentRead16 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_DCAP= _OFFSET) & B_PCIE_DCAP_MPS);=0D +}=0D +=0D +/**=0D + Sets Maximum Payload Size to be used by device=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordinates=0D + @param[in] Mps Max payload size, encoded in the same way as in regist= er (0=3D128b, 1=3D256b, etc)=0D +**/=0D +STATIC=0D +VOID=0D +SetMps (=0D + SBDF Sbdf,=0D + UINT8 Mps=0D + )=0D +{=0D + PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_DCTL_OF= FSET, (UINT16) ~B_PCIE_DCTL_MPS, Mps << N_PCIE_DCTL_MPS);=0D +}=0D +=0D +/**=0D + Enables LTR feature in given device=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordina= tes=0D +**/=0D +STATIC=0D +VOID=0D +EnableLtr (=0D + SBDF Sbdf=0D + )=0D +{=0D + if (Sbdf.PcieCap =3D=3D 0) {=0D + return;=0D + }=0D + PciSegmentOr32 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_DCTL2_OFFSET, = B_PCIE_DCTL2_LTREN);=0D +}=0D +=0D +/**=0D + Returns information about type of device.=0D +=0D + @param[out] Sbdf device's segment:bus:device:function coordin= ates=0D +=0D + @retval one of: not a PCIe device (legacy PCI), PCIe endpoint, PCIe = upstream port or PCIe downstream port (including rootport)=0D +**/=0D +STATIC=0D +PCI_DEV_TYPE=0D +GetDeviceType (=0D + SBDF Sbdf=0D + )=0D +{=0D + UINT8 DeviceType;=0D +=0D + if (Sbdf.PcieCap =3D=3D 0) {=0D + return DevTypePci;=0D + }=0D + DeviceType =3D (UINT8) ((PciSegmentRead16 (SbdfToBase (Sbdf) + Sbdf.Pcie= Cap + R_PCIE_XCAP_OFFSET) & B_PCIE_XCAP_DT) >> N_PCIE_XCAP_DT);=0D + if (DeviceType =3D=3D PCIE_DEVICE_PORT_TYPE_UPSTREAM_PORT) {=0D + return DevTypePcieUpstream;=0D + } else if (DeviceType =3D=3D PCIE_DEVICE_PORT_TYPE_DOWNSTREAM_PORT || De= viceType =3D=3D PCIE_DEVICE_PORT_TYPE_ROOT_PORT) {=0D + return DevTypePcieDownstream;=0D + } else {=0D + return DevTypePcieEndpoint;=0D + }=0D +}=0D +=0D +/**=0D + Initializes Dev:Func numbers for use in FindNextPcieChild or FindNextLeg= alSbdf functions.=0D +=0D + @param[out] Sbdf device's segment:bus:device:function coordin= ates=0D +**/=0D +STATIC=0D +VOID=0D +InitChildFinder (=0D + OUT SBDF *Sbdf=0D + )=0D +{=0D + //=0D + // Initialize Dev/Func to maximum values, so that when FindNextLegalSbdf= ()=0D + // is called on those input parameters, it will return 1st legal address= (Dev 0 Func 0).=0D + //=0D + Sbdf->Dev =3D PCI_MAX_DEVICE;=0D + Sbdf->Func =3D PCI_MAX_FUNC;=0D +}=0D +=0D +/**=0D + Checks the device is a bridge and has non-zero secondary bus number assi= gned.=0D + If so, it returns TRUE and initializes ChildSbdf with such values that=0D + allow searching for devices on the secondary bus.=0D + ChildSbdf will be mangled even if this function returns FALSE.=0D +=0D + Legal bus assignment is assumed. This function doesn't check subordinate= bus numbers of=0D + the the device it was called on or any bridges between it and root compl= ex=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordinates= =0D + @param[out] ChildSbdf SBDF initialized in such way that calling FindNex= tPcieChild( ) on it will find all children devices=0D +=0D + @retval TRUE if device is a bridge and has a bus behind it; FALSE otherw= ise=0D +**/=0D +STATIC=0D +BOOLEAN=0D +HasChildBus (=0D + SBDF Sbdf,=0D + SBDF *ChildSbdf=0D + )=0D +{=0D + UINT32 Data32;=0D + UINT64 Base;=0D + UINT8 SecondaryBus;=0D +=0D + ChildSbdf->Seg =3D Sbdf.Seg;=0D + InitChildFinder (ChildSbdf);=0D +=0D + Base =3D SbdfToBase (Sbdf);=0D +=0D + if (PciSegmentRead8 (Base + R_PCI_BCC_OFFSET) !=3D PCI_CLASS_BRIDGE) {=0D + DEBUG ((DEBUG_INFO, "HasChildBus%02:%02:%02: no\n", Sbdf.Bus, Sbdf.Dev= , Sbdf.Func));=0D + return FALSE;=0D + }=0D + Data32 =3D PciSegmentRead32 (Base + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFS= ET);=0D + SecondaryBus =3D (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);=0D + ChildSbdf->Bus =3D SecondaryBus;=0D + if (SecondaryBus =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: no\n", Sbdf.Bus, Sbdf.= Dev, Sbdf.Func));=0D + return FALSE;=0D + } else {=0D + DEBUG ((DEBUG_INFO, "HasChildBus%02x:%02x:%02x: yes, %x\n", Sbdf.Bus, = Sbdf.Dev, Sbdf.Func, SecondaryBus));=0D + return TRUE;=0D + }=0D +}=0D +=0D +/**=0D + Sets LTR limit in a device.=0D +=0D + @param[in] Base device's base address=0D + @param[in] Ltr LTR limit=0D +**/=0D +STATIC=0D +VOID=0D +SetLtrLimit (=0D + UINT64 Base,=0D + LTR_LIMIT Ltr=0D + )=0D +{=0D + UINT16 LtrCapOffset;=0D + UINT16 Data16;=0D +=0D + LtrCapOffset =3D PcieBaseFindExtendedCapId (Base, R_PCIE_LTRECH_CID);=0D + if (LtrCapOffset =3D=3D 0) {=0D + return;=0D + }=0D + Data16 =3D (UINT16)((Ltr.MaxSnoopLatencyValue << N_PCIE_LTRECH_MSLR_VALU= E) | (Ltr.MaxSnoopLatencyScale << N_PCIE_LTRECH_MSLR_SCALE));=0D + PciSegmentWrite16(Base + LtrCapOffset + R_PCIE_LTRECH_MSLR_OFFSET, Data1= 6);=0D +=0D + Data16 =3D (UINT16)((Ltr.MaxNoSnoopLatencyValue << N_PCIE_LTRECH_MNSLR_V= ALUE) | (Ltr.MaxNoSnoopLatencyScale << N_PCIE_LTRECH_MNSLR_SCALE));=0D + PciSegmentWrite16(Base + LtrCapOffset + R_PCIE_LTRECH_MNSLR_OFFSET, Data= 16);=0D +}=0D +=0D +/**=0D + Checks if device at given address exists and is a PCI Express device.=0D + PCI express devices are distinguished from PCI by having Capability ID 0= x10=0D + If the device is PCI express then its SDBF structure gets updated with p= ointer to=0D + the PCIe Capability. This is an optimization feature. It greatly decreas= es the number=0D + of bus accesses, since most features configured by this library depend o= n registers=0D + whose location is relative to PCIe capability.=0D +=0D + @param[in,out] Sbdf on entry, segment:bus:device:function coordinates= =0D + on exit, PcieCap offset is updated=0D +=0D + @retval TRUE when PCIe device exists; FALSE if it's not PC= Ie or there's no device at all=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsPcieDevice (=0D + SBDF *Sbdf=0D + )=0D +{=0D + UINT8 PcieCapOffset;=0D + UINT64 Base;=0D +=0D + Base =3D SbdfToBase(*Sbdf);=0D +=0D + if (PciSegmentRead16 (Base) =3D=3D 0xFFFF) {=0D + return FALSE;=0D + }=0D +=0D +=0D + PcieCapOffset =3D PcieBaseFindCapId (Base, EFI_PCI_CAPABILITY_ID_PCIEXP)= ;=0D + if (PcieCapOffset =3D=3D 0) {=0D + DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - legacy\n", Sbdf->Bu= s, Sbdf->Dev, Sbdf->Func));=0D + return FALSE;=0D + } else {=0D + Sbdf->PcieCap =3D PcieCapOffset;=0D + DEBUG ((DEBUG_INFO, "IsPcieDevice %02x:%02x:%02x - yes\n", Sbdf->Bus, = Sbdf->Dev, Sbdf->Func));=0D + return TRUE;=0D + }=0D +}=0D +=0D +/**=0D + Returns TRUE and Dev:Func numbers where a PCIe device could legally be l= ocated, or FALSE if there=0D + no such coordinates left.=0D +=0D + Segment and Bus fields of SBDF structure are input only and determine wh= ich bus will be scanned.=0D + This function should be called in a while() loop. It replaces the less e= fficient method of=0D + using nested FOR loops that iterate over all device and function numbers= . It is optimized for=0D + the amount of bus access. If function0 doesn't exist or doesn't have Mul= tifunction bit set,=0D + then higher function numbers are skipped. If parent of this bus is a dow= nstream port, then=0D + Device numbers 1-31 get skipped too (there can be only Dev0 behind downs= tream ports)=0D + If device/function number =3D=3D 0x1F/0x7, this function returns first p= ossible address, that is 0:0=0D + Any other device number means Dev:Func contain address of last found chi= ld device=0D + and this function should search for next one=0D +=0D + @param[in] ParentDevType type of bridge who's partent of this bus=0D + @param[in,out] Sbdf On entry: location returned previously fro= m this function=0D + Dev:Func value of 1F:07 means se= arch should start from the beginning=0D + On exit: if legal Dev:Func combination wa= s found, that Dev:Func is returned=0D + otherwise, Dev:Func are initiali= zed to 1F:07 for convenience=0D +=0D + @retval TRUE when next legal Dev:Func address was found; FALSE otherwise= =0D +**/=0D +STATIC=0D +BOOLEAN=0D +FindNextLegalSbdf (=0D + IN PCI_DEV_TYPE ParentDevType,=0D + IN OUT SBDF *Sbdf=0D + )=0D +{=0D + UINT8 MaxDev;=0D + UINT64 Func0Base;=0D +=0D + if (ParentDevType =3D=3D DevTypePcieEndpoint) {=0D + return FALSE;=0D + }=0D + if (ParentDevType =3D=3D DevTypePcieUpstream) {=0D + MaxDev =3D PCI_MAX_DEVICE;=0D + } else {=0D + MaxDev =3D 0;=0D + }=0D + Func0Base =3D PCI_SEGMENT_LIB_ADDRESS (Sbdf->Seg, Sbdf->Bus, Sbdf->Dev, = 0, 0);=0D + if ((Sbdf->Dev =3D=3D PCI_MAX_DEVICE) && Sbdf->Func =3D=3D PCI_MAX_FUNC)= {=0D + Sbdf->Dev =3D 0;=0D + Sbdf->Func =3D 0;=0D + return TRUE;=0D + } else if ((Sbdf->Func =3D=3D PCI_MAX_FUNC) || (Sbdf->Func =3D=3D 0 && != IsMultifunctionDevice (Func0Base))) {=0D + //=0D + // if it's the last function of a device, then return Func0 of new devic= e or FALSE in case there are no more devices=0D + //=0D + if (Sbdf->Dev =3D=3D MaxDev) {=0D + InitChildFinder (Sbdf);=0D + return FALSE;=0D + }=0D + (Sbdf->Dev)++;=0D + Sbdf->Func =3D 0;=0D + return TRUE;=0D + } else {=0D + (Sbdf->Func)++;=0D + return TRUE;=0D + }=0D +}=0D +=0D +/**=0D + Finds next PCIe (not legacy PCI) device behind given device=0D + If device/function number =3D=3D 0x1F/0x7, this function searches for ch= ildren from scratch=0D + Any other device number means Dev:Func contain address of last found chi= ld device=0D + and this function should search for next one=0D +=0D + @param[in] ParentDevType type of bridge who's partent of this bus=0D + @param[in,out] Sbdf On entry: location returned previously fro= m this function=0D + Dev:Func value of 0x1F:0x07 mean= s search should start from the beginning=0D + On exit: if PCIe device was found, its SB= DF coordinates are returned=0D + otherwise, Dev:Func are initiali= zed to 0x1F:0x07 for convenience=0D + @retval TRUE when next PCIe device was found; FALSE otherwise=0D +**/=0D +BOOLEAN=0D +FindNextPcieChild (=0D + IN PCI_DEV_TYPE ParentDevType,=0D + IN OUT SBDF *Sbdf=0D + )=0D +{=0D + while ( FindNextLegalSbdf (ParentDevType, Sbdf)) {=0D + if (IsPcieDevice (Sbdf)) {=0D + return TRUE;=0D + }=0D + }=0D + return FALSE;=0D +}=0D +=0D +/**=0D + Checks if given device supports Clock Power Management=0D +=0D + @param[in] Sbdf segment:bus:device:function coordinates of a device= =0D +=0D + @retval TRUE when device supports it, FALSE otherwise=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsCpmSupported (=0D + SBDF Sbdf=0D + )=0D +{=0D + return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_LC= AP_OFFSET) & B_PCIE_LCAP_CPM);=0D +}=0D +=0D +/**=0D + Sets Enable Clock Power Management bit for given device=0D +=0D + @param[in] Sbdf segment:bus:device:function coordinates of a = device=0D +**/=0D +STATIC=0D +VOID=0D +EnableCpm (=0D + SBDF Sbdf=0D + )=0D +{=0D + PciSegmentOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_LCTL_OFFSET, B= _PCIE_LCTL_ECPM);=0D +}=0D +=0D +/**=0D + Checks if given device is an IoAPIC=0D +=0D + @param[in] Base device's base address=0D +=0D + @retval TRUE if it's an IoAPIC=0D +**/=0D +BOOLEAN=0D +IsIoApicDevice (=0D + UINT64 Base=0D + )=0D +{=0D + UINT8 BaseClassCode;=0D + UINT8 SubClassCode;=0D + UINT8 ProgInterface;=0D +=0D + BaseClassCode =3D PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 2);=0D + SubClassCode =3D PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET + 1);=0D + ProgInterface =3D PciSegmentRead8 (Base + PCI_CLASSCODE_OFFSET);=0D + if ((BaseClassCode =3D=3D PCI_CLASS_SYSTEM_PERIPHERAL) &&=0D + (SubClassCode =3D=3D PCI_SUBCLASS_PIC) &&=0D + ((ProgInterface =3D=3D PCI_IF_APIC_CONTROLLER) ||=0D + (ProgInterface =3D=3D PCI_IF_APIC_CONTROLLER2))) {=0D + return TRUE;=0D + }=0D + return FALSE;=0D +}=0D +=0D +/**=0D + There are some devices which support L1 substates, but due to silicon bu= gs the corresponding register=0D + cannot be found by scanning PCIe capabilities. This function checks list= of such devices and if one=0D + is found, returns its L1ss capability register offset=0D +=0D + @param[in] Base base address of device=0D + @param[in] Override table of devices that need override=0D +=0D + @retval offset to L1ss capability register=0D +**/=0D +UINT16=0D +GetOverrideL1ssCapsOffset (=0D + UINT64 Base,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + UINT16 DeviceId;=0D + UINT16 VendorId;=0D + UINT8 Revision;=0D + UINT32 Index;=0D +=0D + VendorId =3D PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);=0D + DeviceId =3D PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);=0D + Revision =3D PciSegmentRead8 (Base + PCI_REVISION_ID_OFFSET);=0D +=0D + for (Index =3D 0; Index < Override->Size; Index++) {=0D + if (((Override->Table[Index].OverrideConfig & PchPcieL1SubstatesOverri= de) =3D=3D PchPcieL1SubstatesOverride) &&=0D + (Override->Table[Index].VendorId =3D=3D VendorId) &&=0D + (Override->Table[Index].DeviceId =3D=3D DeviceId) &&=0D + (Override->Table[Index].RevId =3D=3D Revision || Override->Table[I= ndex].RevId =3D=3D 0xFFFF)) {=0D + return Override->Table[Index].L1SubstatesCapOffset;=0D + }=0D + }=0D + return 0;=0D +}=0D +=0D +/**=0D + There are some devices whose implementation of L1 substates is partially= broken. This function checks=0D + list of such devices and if one is found, overrides their L1ss-related c= apabilities=0D +=0D + @param[in] Base base address of device=0D + @param[in] Override table of devices that need override=0D + @param[in,out] L1ss on entry, capabilities read from register; on = exit, capabilities modified according ot override table=0D +**/=0D +STATIC=0D +VOID=0D +OverrideL1ssCaps (=0D + UINT64 Base,=0D + OVERRIDE_TABLE *Override,=0D + L1SS_CAPS *L1ss=0D + )=0D +{=0D + UINT16 DeviceId;=0D + UINT16 VendorId;=0D + UINT8 Revision;=0D + UINT32 Index;=0D +=0D + VendorId =3D PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);=0D + DeviceId =3D PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);=0D + Revision =3D PciSegmentRead8 (Base + PCI_REVISION_ID_OFFSET);=0D +=0D + for (Index =3D 0; Index < Override->Size; Index++) {=0D + if (((Override->Table[Index].OverrideConfig & PchPcieL1SubstatesOverri= de) =3D=3D PchPcieL1SubstatesOverride) &&=0D + (Override->Table[Index].VendorId =3D=3D VendorId) &&=0D + (Override->Table[Index].DeviceId =3D=3D DeviceId) &&=0D + (Override->Table[Index].RevId =3D=3D Revision || Override->Table[I= ndex].RevId =3D=3D 0xFF)) {=0D +=0D + L1ss->PmL12 &=3D !!(Override->Table[Index].L1SubstatesCapMask & B_= PCIE_EX_L1SCAP_PPL12S);=0D + L1ss->PmL11 &=3D !!(Override->Table[Index].L1SubstatesCapMask & B_= PCIE_EX_L1SCAP_PPL11S);=0D + L1ss->AspmL12 &=3D !!(Override->Table[Index].L1SubstatesCapMask & B_= PCIE_EX_L1SCAP_AL12S);=0D + L1ss->AspmL11 &=3D !!(Override->Table[Index].L1SubstatesCapMask & B_= PCIE_EX_L1SCAP_AL1SS);=0D + if (Override->Table[Index].L1sTpowerOnValue !=3D 0) {=0D + L1ss->Cmrt =3D Override->Table[Index].L1sCommonModeRestoreTime;=0D + L1ss->TpoScale =3D Override->Table[Index].L1sTpowerOnScale;=0D + L1ss->TpoValue =3D Override->Table[Index].L1sTpowerOnValue;=0D + }=0D + return;=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Returns L1 sub states capabilities of a device=0D +=0D + @param[in] Base base address of a device=0D +=0D + @retval L1SS_CAPS structure filled with device's capabilities=0D +**/=0D +STATIC=0D +L1SS_CAPS=0D +GetL1ssCaps (=0D + UINT64 Base,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + L1SS_CAPS Capabilities =3D {0};=0D + UINT16 PcieCapOffset;=0D + UINT32 CapsRegister;=0D +=0D + PcieCapOffset =3D GetOverrideL1ssCapsOffset (Base, Override);=0D + if (PcieCapOffset =3D=3D 0) {=0D + PcieCapOffset =3D PcieBaseFindExtendedCapId (Base, V_PCIE_EX_L1S_CID);= =0D + }=0D + if (PcieCapOffset =3D=3D 0) {=0D + return Capabilities;=0D + }=0D + CapsRegister =3D PciSegmentRead32 (Base + PcieCapOffset + R_PCIE_EX_L1SC= AP_OFFSET);=0D + if (CapsRegister & B_PCIE_EX_L1SCAP_L1PSS) {=0D + //=0D + // Skip L1.1 checking since some device only indecate L1.2 support.=0D + // [1604452805]=0D + //=0D + Capabilities.PmL11 =3D !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL11S);=0D + Capabilities.PmL12 =3D !!(CapsRegister & B_PCIE_EX_L1SCAP_PPL12S);=0D + Capabilities.AspmL12 =3D !!(CapsRegister & B_PCIE_EX_L1SCAP_AL12S);=0D + Capabilities.AspmL11 =3D !!(CapsRegister & B_PCIE_EX_L1SCAP_AL1SS);=0D + Capabilities.Cmrt =3D (CapsRegister & B_PCIE_EX_L1SCAP_CMRT) >> N_PCIE= _EX_L1SCAP_CMRT;=0D + Capabilities.TpoValue =3D (CapsRegister & B_PCIE_EX_L1SCAP_PTV) >> N_P= CIE_EX_L1SCAP_PTV;=0D + Capabilities.TpoScale =3D (CapsRegister & B_PCIE_EX_L1SCAP_PTPOS) >> N= _PCIE_EX_L1SCAP_PTPOS;=0D + }=0D + OverrideL1ssCaps (Base, Override, &Capabilities);=0D + return Capabilities;=0D +}=0D +=0D +/**=0D + Returns combination of two sets of L1 substate capabilities=0D + Given feature is supported by the link only if both sides support it=0D + Time parameters for link (Cmrt and Tpo) depend on the bigger value betwe= en two sides=0D +=0D + @param[in] L1ssA L1 substate capabilities of first device=0D + @param[in] L1ssB L1 substate capabilities of second device=0D +=0D + @retval Link's L1 substate capabilities=0D +**/=0D +STATIC=0D +L1SS_CAPS=0D +CombineL1ss (=0D + L1SS_CAPS L1ssA,=0D + L1SS_CAPS L1ssB=0D + )=0D +{=0D + L1SS_CAPS Combined;=0D +=0D + Combined.PmL12 =3D L1ssA.PmL12 && L1ssB.PmL12;=0D + Combined.PmL11 =3D L1ssA.PmL11 && L1ssB.PmL11;=0D + Combined.AspmL12 =3D L1ssA.AspmL12 && L1ssB.AspmL12;=0D + Combined.AspmL11 =3D L1ssA.AspmL11 && L1ssB.AspmL11;=0D + Combined.Cmrt =3D MAX (L1ssA.Cmrt, L1ssB.Cmrt);=0D + if (TpoToUs (L1ssA.TpoScale, L1ssA.TpoValue) > TpoToUs (L1ssB.TpoScale, = L1ssB.TpoValue)) {=0D + Combined.TpoScale =3D L1ssA.TpoScale;=0D + Combined.TpoValue =3D L1ssA.TpoValue;=0D + } else {=0D + Combined.TpoScale =3D L1ssB.TpoScale;=0D + Combined.TpoValue =3D L1ssB.TpoValue;=0D + }=0D + return Combined;=0D +}=0D +=0D +/**=0D + Configures L1 substate feature in a device=0D +=0D + @param[in] Sbdf segment:bus:device:function coordinates of a device= =0D + @param[in] L1ss configuration to be programmed=0D + @param[in] Override table of devices that require special handling=0D +**/=0D +STATIC=0D +VOID=0D +SetL1ss (=0D + SBDF Sbdf,=0D + L1SS_CAPS L1ss,=0D + OVERRIDE_TABLE *Override,=0D + BOOLEAN IsCpuPcie=0D +=0D + )=0D +{=0D + UINT16 PcieCapOffset;=0D + UINT32 Ctrl1Register;=0D + UINT32 Ctrl2Register;=0D + UINT64 Base;=0D +=0D + Base =3D SbdfToBase(Sbdf);=0D + Ctrl1Register =3D 0;=0D + Ctrl2Register =3D 0;=0D +=0D + PcieCapOffset =3D GetOverrideL1ssCapsOffset (Base, Override);=0D + if (PcieCapOffset =3D=3D 0) {=0D + PcieCapOffset =3D PcieBaseFindExtendedCapId (Base, V_PCIE_EX_L1S_CID);= =0D + }=0D + if (PcieCapOffset =3D=3D 0) {=0D + return;=0D + }=0D +=0D + Ctrl1Register |=3D (L1ss.PmL12 ? B_PCIE_EX_L1SCAP_PPL12S : 0);=0D + Ctrl1Register |=3D (L1ss.PmL11 ? B_PCIE_EX_L1SCAP_PPL11S : 0);=0D + Ctrl1Register |=3D (L1ss.AspmL12 ? B_PCIE_EX_L1SCAP_AL12S : 0);=0D + Ctrl1Register |=3D (L1ss.AspmL11 ? B_PCIE_EX_L1SCAP_AL1SS : 0);=0D + if ((GetDeviceType (Sbdf) =3D=3D DevTypePcieDownstream)) {=0D + Ctrl1Register |=3D (L1ss.Cmrt << N_PCIE_EX_L1SCAP_CMRT);=0D + }=0D + ///=0D + /// BWG 1.3 Section 5.5.7.6 LTR Threshold Latency=0D + /// Set L1.2 LTR threshold using formula (TpoToUs (L1ss.TpoScale, L1ss.T= poValue) + L1ss.Cmrt + 10)=0D + ///=0D + Ctrl1Register |=3D ((TpoToUs (L1ss.TpoScale, L1ss.TpoValue) + L1ss.Cmrt = + 10) << N_PCIE_EX_L1SCTL1_L12LTRTLV);=0D + Ctrl1Register |=3D (2 << N_PCIE_EX_L1SCTL1_L12LTRTLSV);=0D +=0D + Ctrl2Register |=3D (L1ss.TpoScale);=0D + Ctrl2Register |=3D (L1ss.TpoValue << N_PCIE_EX_L1SCTL2_POWT);=0D + //=0D + // Set CLKREQ Acceleration Interrupt Enable=0D + //=0D + Ctrl1Register |=3D B_PCIE_EX_L1SCTL1_L1SSEIE;=0D + PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET, 0);= =0D + PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL2_OFFSET, Ctrl= 2Register);=0D + PciSegmentWrite32 (Base + PcieCapOffset + R_PCIE_EX_L1SCTL1_OFFSET, Ctrl= 1Register);=0D +}=0D +=0D +/**=0D + Converts L1 latency from enumerated register value to microseconds=0D +=0D + @param[in] L1Latency latency value retrieved from register; see PCIE= specification for encoding=0D +=0D + @retval L1 latency converted to microseconds=0D +**/=0D +UINT32=0D +L1LatencyToUs (=0D + UINT32 L1Latency=0D + )=0D +{=0D + if (L1Latency < 7) {=0D + return 1 * (BIT0 << L1Latency);=0D + } else {=0D + return ASPM_L1_NO_LIMIT;=0D + }=0D +}=0D +=0D +/**=0D + Modifies L1 latency by provided value=0D +=0D + @param[in] Aspm Structure that contains ASPM capabilities of a link,= including L1 acceptable latency=0D + @param[in] Value Value, in microseconds, to be added to L1 acceptable= latency. Can be negative.=0D +=0D + @retval Aspm structure with modified L1 acceptable latency=0D +**/=0D +STATIC=0D +ASPM_CAPS=0D +PatchL1AcceptableLatency (=0D + ASPM_CAPS Aspm,=0D + INT8 Value=0D + )=0D +{=0D + if (Aspm.L1AcceptableLatencyUs !=3D ASPM_L1_NO_LIMIT) {=0D + if (Value > 0) {=0D + Aspm.L1AcceptableLatencyUs +=3D Value;=0D + } else {=0D + if (Aspm.L1AcceptableLatencyUs > (UINT32)(-1*Value)) {=0D + Aspm.L1AcceptableLatencyUs =3D Aspm.L1AcceptableLatencyUs + Value;= =0D + } else {=0D + Aspm.L1AcceptableLatencyUs =3D 0;=0D + }=0D + }=0D + }=0D + return Aspm;=0D +}=0D +=0D +/**=0D + Reads ASPM capabilities of a device=0D +=0D + @param[in] Sbdf segment:bus:device:function coordinates of a device=0D +=0D + @retval structure containing device's ASPM capabilities=0D +**/=0D +STATIC=0D +ASPM_CAPS=0D +GetAspmCaps (=0D + SBDF Sbdf=0D + )=0D +{=0D +=0D + UINT32 LinkCapRegister;=0D + UINT32 DevCapRegister;=0D + UINT64 Base;=0D + ASPM_CAPS Aspm =3D {0};=0D +=0D + Base =3D SbdfToBase (Sbdf);=0D +=0D + LinkCapRegister =3D PciSegmentRead32 (Base + Sbdf.PcieCap + R_PCIE_LCAP_= OFFSET);=0D + DevCapRegister =3D PciSegmentRead32 (Base + Sbdf.PcieCap + R_PCIE_DCAP_O= FFSET);=0D +=0D + ///=0D + /// Check endpoint for pre-1.1 devices based on the Role based Error Rep= orting Capability bit. Don't report L0s support for old devices=0D + ///=0D + if (DevCapRegister & B_PCIE_DCAP_RBER) {=0D + Aspm.L0sSupported =3D !!(LinkCapRegister & B_PCIE_LCAP_APMS_L0S);=0D + }=0D + Aspm.L1Supported =3D !!(LinkCapRegister & B_PCIE_LCAP_APMS_L1);=0D +=0D + Aspm.LinkL0sExitLatency =3D (LinkCapRegister & B_PCIE_LCAP_EL0) >> N_PCI= E_LCAP_EL0;=0D + Aspm.LinkL1ExitLatencyUs =3D L1LatencyToUs( (LinkCapRegister & B_PCIE_LC= AP_EL1) >> N_PCIE_LCAP_EL1);=0D +=0D + if (GetDeviceType (Sbdf) =3D=3D DevTypePcieEndpoint) {=0D + Aspm.L0sAcceptableLatency =3D (DevCapRegister & B_PCIE_DCAP_E0AL) >> N= _PCIE_DCAP_E0AL;=0D + Aspm.L1AcceptableLatencyUs =3D L1LatencyToUs( (DevCapRegister & B_PCIE= _DCAP_E1AL) >> N_PCIE_DCAP_E1AL);=0D + DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:%d L1%c %d:%d= \n", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,=0D + = Aspm.L0sSupported?'+':'-', Aspm.LinkL0sExitLatency, Aspm.L0sAcceptableLate= ncy,=0D + = Aspm.L1Supported?'+':'-', Aspm.LinkL1ExitLatencyUs, Aspm.L1AcceptableLaten= cyUs));=0D + } else {=0D + Aspm.L0sAcceptableLatency =3D ASPM_L0s_NO_LIMIT;=0D + Aspm.L1AcceptableLatencyUs =3D ASPM_L1_NO_LIMIT;=0D + DEBUG ((DEBUG_INFO, "GetAspmCaps %02x:%02x:%02x L0s%c %d:x L1%c %d:x\n= ", Sbdf.Bus, Sbdf.Dev, Sbdf.Func,=0D + = Aspm.L0sSupported?'+':'-', Aspm.LinkL0sExitLatency,=0D + = Aspm.L1Supported?'+':'-', Aspm.LinkL1ExitLatencyUs));=0D + }=0D + return Aspm;=0D +}=0D +=0D +/**=0D + Get ASPM L0s and L1 override of given device.=0D +=0D + @param[in] Sbdf Segment,Bus,Device,Function address of cu= rrently visited PCIe device=0D + @param[in,out] MyAspm Current device's ASPM capabilities struct= ure=0D + @param[in] Override Pch Pcie devices OverrideTable=0D +**/=0D +STATIC=0D +VOID=0D +GetOverrideAspm (=0D + SBDF Sbdf,=0D + ASPM_CAPS *MyAspm,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + UINT16 DeviceId;=0D + UINT16 VendorId;=0D + UINT8 Revision;=0D + UINT32 Index;=0D + UINT64 Base;=0D +=0D + Base =3D SbdfToBase (Sbdf);=0D +=0D + VendorId =3D PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);=0D + DeviceId =3D PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);=0D + Revision =3D PciSegmentRead8 (Base + PCI_REVISION_ID_OFFSET);=0D +=0D + for (Index =3D 0; Index < Override->Size; Index++) {=0D + if (((Override->Table[Index].OverrideConfig & PchPcieL1L2Override) =3D= =3D PchPcieL1L2Override) &&=0D + (Override->Table[Index].VendorId =3D=3D VendorId) &&=0D + (Override->Table[Index].DeviceId =3D=3D DeviceId) &&=0D + (Override->Table[Index].RevId =3D=3D Revision || Override->Table[I= ndex].RevId =3D=3D 0xFF)) {=0D + DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, original L0sSup= ported =3D 0x%x, L1Supported =3D 0x%x\n",=0D + Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported, MyAspm-= >L1Supported));=0D + if (MyAspm->L0sSupported) {=0D + //=0D + // If L0s is supported in capability, apply platform override.=0D + //=0D + MyAspm->L0sSupported =3D Override->Table[Index].EndPointAspm & BIT= 0;=0D + }=0D + if (MyAspm->L1Supported) {=0D + //=0D + // If L1 is supported in capability, apply platform override.=0D + //=0D + MyAspm->L1Supported =3D (Override->Table[Index].EndPointAspm & BIT= 1) >> 1;=0D + }=0D + DEBUG ((DEBUG_INFO, "GetOverrideAspm %02x:%02x:%02x, override L0sSup= ported =3D 0x%x, L1Supported =3D 0x%x\n",=0D + Sbdf.Bus, Sbdf.Dev, Sbdf.Func, MyAspm->L0sSupported, MyAspm-= >L1Supported));=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Combines ASPM capabilities of two devices on both ends of a link to dete= rmine link's ASPM capabilities=0D +=0D + @param[in] AspmA, AspmB ASPM capabilities of two devices=0D +=0D + @retval ASPM_CAPS structure containing combined ASPM capabilities=0D +**/=0D +STATIC=0D +ASPM_CAPS=0D +CombineAspm (=0D + ASPM_CAPS AspmA,=0D + ASPM_CAPS AspmB,=0D + BOOLEAN DownstreamPort=0D + )=0D +{=0D + ASPM_CAPS Combined;=0D +=0D + if (DownstreamPort) {=0D + //=0D + // When combining ASPM in downstream ports, combination must reflect s= tate of link just below=0D + // and consider all acceptable latencies of all endpoints anywhere dow= n below that port=0D + //=0D + Combined.L0sSupported =3D AspmA.L0sSupported & AspmB.L0sSupported;=0D + Combined.L1Supported =3D AspmA.L1Supported & AspmB.L1Supported;=0D + Combined.LinkL0sExitLatency =3D MAX (AspmA.LinkL0sExitLatency, AspmB.L= inkL0sExitLatency);=0D + Combined.LinkL1ExitLatencyUs =3D MAX (AspmA.LinkL1ExitLatencyUs, AspmB= .LinkL1ExitLatencyUs);=0D + Combined.L0sAcceptableLatency =3D MIN (AspmA.L0sAcceptableLatency, Asp= mB.L0sAcceptableLatency);=0D + Combined.L1AcceptableLatencyUs =3D MIN (AspmA.L1AcceptableLatencyUs, A= spmB.L1AcceptableLatencyUs);=0D + } else {=0D + //=0D + // When combining ASPM in switch upstream ports,=0D + // Supported and ExitLatency must only reflect capabilities of upstrea= m port itself=0D + // But acceptable latencies must consider all endpoints anywhere below= =0D + //=0D + Combined.L0sSupported =3D AspmA.L0sSupported;=0D + Combined.L1Supported =3D AspmA.L1Supported;=0D + Combined.LinkL0sExitLatency =3D AspmA.LinkL0sExitLatency;=0D + Combined.LinkL1ExitLatencyUs =3D AspmA.LinkL1ExitLatencyUs;=0D + Combined.L0sAcceptableLatency =3D MIN (AspmA.L0sAcceptableLatency, Asp= mB.L0sAcceptableLatency);=0D + Combined.L1AcceptableLatencyUs =3D MIN (AspmA.L1AcceptableLatencyUs, A= spmB.L1AcceptableLatencyUs);=0D + }=0D + DEBUG ((DEBUG_INFO, "CombineAspm %x:%x -> %x\n", AspmA.L1AcceptableLaten= cyUs, AspmB.L1AcceptableLatencyUs, Combined.L1AcceptableLatencyUs));=0D + return Combined;=0D +}=0D +=0D +/**=0D + Checks if L1 can be enabled on given link, according to ASPM parameters = of that link=0D +=0D + @param[in] Aspm set of parameters describing this link and en= dpoint devices below it=0D +=0D + @retval TRUE if L1 can be enabled=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsL1Allowed (=0D + ASPM_CAPS Aspm=0D + )=0D +{=0D + return (Aspm.L1Supported && (Aspm.L1AcceptableLatencyUs >=3D Aspm.LinkL1= ExitLatencyUs));=0D +}=0D +=0D +/**=0D + Checks if L0s can be enabled on given link, according to ASPM parameters= of that link=0D +=0D + @param[in] Aspm set of parameters describing this link and en= dpoint devices below it=0D +=0D + @retval TRUE if L0s can be enabled=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsL0sAllowed (=0D + ASPM_CAPS Aspm=0D + )=0D +{=0D + return (Aspm.L0sSupported && (Aspm.L0sAcceptableLatency >=3D Aspm.LinkL0= sExitLatency));=0D +}=0D +=0D +/**=0D + Enables L0s and L1 for given port, if possible.=0D + L0s/L1 can be enabled if it's supported on both sides of a link and if l= ink's latency doesn't exceed=0D + acceptable latency of any endpoint below this link=0D +=0D + @param[in] Base device's base address=0D + @param[in] Aspm set of parameters describing this link and en= dpoint devices below it=0D +**/=0D +STATIC=0D +VOID=0D +SetAspm (=0D + SBDF Sbdf,=0D + ASPM_CAPS Aspm=0D + )=0D +{=0D + UINT16 DataOr;=0D +=0D + DataOr =3D 0;=0D + if (IsL0sAllowed (Aspm)) {=0D + DataOr |=3D V_PCIE_LCTL_ASPM_L0S;=0D + }=0D + if (IsL1Allowed (Aspm)) {=0D + DataOr |=3D V_PCIE_LCTL_ASPM_L1;=0D + }=0D + DEBUG ((DEBUG_INFO, "SetAspm on %02x:%02x:%02x to %d\n", Sbdf.Bus,Sbdf.D= ev,Sbdf.Func, DataOr));=0D + PciSegmentAndThenOr16 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_LCTL_OF= FSET, (UINT16)~B_PCIE_LCTL_ASPM, DataOr);=0D +}=0D +=0D +/**=0D + Adds device entry to a list of devices.=0D +=0D + @param[in,out] Table array of devices=0D + @param[in] Sbdf segment:bus:device:function coordinates of devic= e to be added to table=0D +**/=0D +STATIC=0D +VOID=0D +AddToDeviceTable (=0D + SBDF_TABLE *Table,=0D + SBDF Sbdf=0D + )=0D +{=0D + if (Table->Count < MAX_SBDF_TABLE_SIZE) {=0D + Table->Entry[Table->Count++] =3D Sbdf;=0D + } else {=0D + ASSERT (FALSE);=0D + }=0D +}=0D +=0D +/**=0D + Remove device entry from a list and clear its bus assignment=0D +=0D + @param[in,out] Table array of devices=0D +**/=0D +STATIC=0D +VOID=0D +ClearBusFromTable (=0D + SBDF_TABLE *Table=0D + )=0D +{=0D + while (Table->Count > 0) {=0D + PciSegmentWrite32 (SbdfToBase (Table->Entry[Table->Count - 1]) + PCI_B= RIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);=0D + Table->Count--;=0D + }=0D +}=0D +=0D +/**=0D + Attempts to assign secondary and subordinate bus numbers to uninitialize= d bridges in PCIe tree=0D + If the device is a bridge and already has bus numbers assigned, they won= 't be changed=0D + Otherwise new bus number will be assigned below this bridge.=0D + This function can be called from SMM, where BIOS must not modify bus num= bers to prevent=0D + conflict with OS enumerator. To prevent this, this function returns list= of bridges whose=0D + bus numbers were changed. All devices from that list must have buses cle= ared afterwards.=0D +=0D + @param[in] Sbdf segment:bus:device:function coordinates o= f device to be added to table=0D + @param[in] MinBus minimum Bus number that can be assigned b= elow this port=0D + @param[in] MaxBus maximum Bus number that can be assigned b= elow this port=0D + @param[in] BridgeCleanupList list of bridges where bus numbers were mo= dified=0D +=0D + @retval maximum bus number assigned anywhere below this device=0D +**/=0D +STATIC=0D +UINT8=0D +RecursiveBusAssignment (=0D + SBDF Sbdf,=0D + UINT8 MinBus,=0D + UINT8 MaxBus,=0D + SBDF_TABLE *BridgeCleanupList=0D + )=0D +{=0D + UINT64 Base;=0D + SBDF ChildSbdf;=0D + PCI_DEV_TYPE DevType;=0D + UINT32 Data32;=0D + UINT8 BelowBus;=0D + UINT8 SecondaryBus;=0D + UINT8 SubordinateBus;=0D +=0D + ChildSbdf.Seg =3D Sbdf.Seg;=0D + InitChildFinder (&ChildSbdf);=0D + Base =3D SbdfToBase (Sbdf);=0D +=0D + //=0D + // On way down:=0D + // assign secondary bus, then increase it by one before stepping down;= temporarily assign max subordinate bus=0D + // On way up:=0D + // fix subordinate bus assignment to equal max bus number assigned any= where below; return that number=0D + //=0D + DevType =3D GetDeviceType (Sbdf);=0D + if ((Sbdf.Bus >=3D MaxBus) || (DevType =3D=3D DevTypePcieEndpoint) || (D= evType =3D=3D DevTypePci)) {=0D + return (UINT8) Sbdf.Bus;=0D + } else {=0D + Data32 =3D PciSegmentRead32 (Base + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OF= FSET);=0D + SecondaryBus =3D (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SCBN) >> 8);=0D + SubordinateBus =3D (UINT8)((Data32 & B_PCI_BRIDGE_BNUM_SBBN) >> 16);=0D + if (SecondaryBus !=3D 0) {=0D + ChildSbdf.Bus =3D SecondaryBus;=0D + MinBus =3D SecondaryBus + 1;=0D + DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentP %x:%x:%x -> %x,%x,%x \n= ", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus, SubordinateBus));=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + BelowBus =3D RecursiveBusAssignment (ChildSbdf, MinBus, Subordinat= eBus, BridgeCleanupList);=0D + MinBus =3D BelowBus + 1;=0D + }=0D + return SubordinateBus;=0D + } else {=0D + Data32 =3D Sbdf.Bus + (MinBus << 8) + (MaxBus << 16);=0D + PciSegmentWrite32(Base + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Dat= a32);=0D + AddToDeviceTable (BridgeCleanupList, Sbdf);=0D + DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentE %x:%x:%x -> %x,%x,%x \n= ", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, MinBus, MaxBus));=0D + BelowBus =3D MinBus;=0D + ChildSbdf.Bus =3D MinBus;=0D + MinBus++;=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + BelowBus =3D RecursiveBusAssignment (ChildSbdf, MinBus, MaxBus, Br= idgeCleanupList);=0D + MinBus =3D BelowBus + 1;=0D + }=0D + Data32 &=3D ~B_PCI_BRIDGE_BNUM_SBBN;=0D + Data32 |=3D (BelowBus << 16);=0D + PciSegmentWrite32 (Base + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Da= ta32);=0D + DEBUG ((DEBUG_INFO, "RecursiveBusAssignmentL %x:%x:%x -> %x,%x,%x \n= ", Sbdf.Bus, Sbdf.Dev, Sbdf.Func, Sbdf.Bus, (Data32&0xFF00)>>8, BelowBus));= =0D + return BelowBus;=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Enables L0s and/or L1 for PCIE links in the hierarchy below=0D + L0s/L1 can be enabled when both sides of a link support it and link late= ncy is smaller than acceptable latency=0D + ASPM of a given link is independend from any other link (except 1ms L1 a= djustment, read below), so it's possible to=0D + have a hierarchy when RP link has no ASPM but links below do.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] Depth How many links there are betwe= en this port and root complex=0D + @param[in] Override Pch Pcie devices OverrideTable= =0D +=0D + @retval structure that describes acceptable latencies of all endpoints b= elow plus ASPM parameters of last link=0D +**/=0D +STATIC=0D +ASPM_CAPS=0D +RecursiveAspmConfiguration (=0D + SBDF Sbdf,=0D + UINT8 Depth,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + ASPM_CAPS MyAspm;=0D + ASPM_CAPS ChildAspm;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveAspmConfiguration %x:%x:%x\n", Sbdf.Bus, S= bdf.Dev, Sbdf.Func));=0D +=0D + //=0D + // On way down:=0D + // pass number of links traversed; increase it per upstream port visit= ed (not endpoint)=0D + // On way up:=0D + // EndPoint: read Acceptable Latencies; subtract Depth From L1Acceptab= leLat to account for "1us per switch additional delay"=0D + // Downstreamport: AND L0s/L1 caps; calculate LinkLatency; enable L0s/= L1 if supported and if acceptable latency is bigger than link latency;=0D + // if L1 not enabled, add back 1us to Acceptable Latency to cancel e= arlier Depth subtraction=0D + // UpstreamPort: calculate minimum of below Acceptable Latencies; retu= rn that, with upper link's Latency and L0s/L1 support=0D + //=0D + DevType =3D GetDeviceType(Sbdf);=0D + if (DevType =3D=3D DevTypePcieUpstream) {=0D + Depth++;=0D + }=0D + MyAspm =3D GetAspmCaps (Sbdf);=0D + //=0D + // Get ASPM L0s and L1 override=0D + //=0D + if (Override !=3D NULL) {=0D + GetOverrideAspm (Sbdf, &MyAspm, Override);=0D + }=0D + if (DevType =3D=3D DevTypePcieEndpoint) {=0D + //=0D + // Every switch between endpoint and CPU introduces 1us additional lat= ency on L1 exit. This is reflected by=0D + // subtracting 1us per switch from endpoint's acceptable L1 latency.=0D + // In case L1 doesn't get enabled in one of switches, that 1us will be= added back.=0D + // This calculation is not precise. It ignores that some switches' add= ed delay may be shadowed by=0D + // other links' exit latency. But it guarantees that acceptable latenc= y won't be exceeded and is simple=0D + // enough to perform in a single iteration without backtracking.=0D + //=0D + return PatchL1AcceptableLatency (MyAspm, (-1 * Depth));=0D + }=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + ChildAspm =3D RecursiveAspmConfiguration (ChildSbdf, Depth, Override= );=0D + MyAspm =3D CombineAspm (MyAspm, ChildAspm, (DevType =3D=3D DevTypePc= ieDownstream));=0D + }=0D + if (DevType =3D=3D DevTypePcieDownstream) {=0D + SetAspm (Sbdf, MyAspm);=0D + //=0D + // ASPM config must be consistent across all functions of a device. = That's why there's while loop.=0D + //=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + SetAspm (ChildSbdf, MyAspm);=0D + }=0D + if (!IsL1Allowed (MyAspm)) {=0D + MyAspm =3D PatchL1AcceptableLatency (MyAspm, 1);=0D + }=0D + }=0D + }=0D + return MyAspm;=0D +}=0D +=0D +/**=0D + Enables L1 substates for PCIE links in the hierarchy below=0D + L1.1 / L1.2 can be enabled if both sides of a link support it.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D +=0D + @retval structure that describes L1ss capabilities of the device=0D +**/=0D +STATIC=0D +L1SS_CAPS=0D +RecursiveL1ssConfiguration (=0D + SBDF Sbdf,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + UINT64 Base;=0D + SBDF ChildSbdf;=0D + L1SS_CAPS CombinedCaps;=0D + L1SS_CAPS ChildCaps;=0D + PCI_DEV_TYPE DevType;=0D + BOOLEAN IsCpuPcie;=0D + UINT32 DevNum;=0D +=0D + IsCpuPcie =3D FALSE;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveL1ssConfiguration %x:%x:%x\n", Sbdf.Bus, S= bdf.Dev, Sbdf.Func));=0D +=0D + Base =3D SbdfToBase (Sbdf);=0D + DevNum =3D Sbdf.Dev;=0D + if (DevNum =3D=3D SA_PEG0_DEV_NUM || DevNum =3D=3D SA_PEG3_DEV_NUM) {=0D + IsCpuPcie =3D TRUE;=0D + }=0D + //=0D + // On way down:=0D + // do nothing=0D + // On way up:=0D + // In downstream ports, combine L1ss capabilities of that port and dev= ice behind it, then enable L1.1 and/or L1.2 if possible=0D + // Return L1ss capabilities=0D + //=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + ChildCaps =3D RecursiveL1ssConfiguration (ChildSbdf, Override);=0D + if (DevType =3D=3D DevTypePcieDownstream && ChildSbdf.Func =3D=3D 0)= {=0D + CombinedCaps =3D CombineL1ss (GetL1ssCaps (Base, Override), ChildC= aps);=0D + SetL1ss (Sbdf, CombinedCaps, Override, IsCpuPcie);=0D + SetL1ss (ChildSbdf, CombinedCaps, Override, IsCpuPcie);=0D + }=0D + }=0D + }=0D + return GetL1ssCaps (Base, Override);=0D +}=0D +=0D +/**=0D + Checks if there is an IoAPIC device in the PCIe hierarchy.=0D + If one is found, this function doesn't check for more and returns=0D +=0D + @param[in] BusLimit maximum Bus number that can be= assigned below this port=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D +=0D + @retval TRUE if IoAPIC device was found=0D +**/=0D +STATIC=0D +BOOLEAN=0D +RecursiveIoApicCheck (=0D + SBDF Sbdf=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + UINT8 IoApicPresent;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveIoApicCheck %x:%x:%x\n", Sbdf.Bus, Sbdf.De= v, Sbdf.Func));=0D +=0D + IoApicPresent =3D FALSE;=0D +=0D + if (IsIoApicDevice (SbdfToBase (Sbdf))) {=0D + DEBUG ((DEBUG_INFO, "IoApicFound @%x:%x:%x:%x\n", Sbdf.Bus, Sbdf.Dev, = Sbdf.Func));=0D + return TRUE;=0D + }=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + IoApicPresent =3D RecursiveIoApicCheck (ChildSbdf);=0D + if (IoApicPresent) {=0D + break;=0D + }=0D + }=0D + }=0D + DEBUG ((DEBUG_INFO, "IoApic status %d @%x:%x:%x:%x\n", IoApicPresent, Sb= df.Seg, Sbdf.Bus, Sbdf.Dev, Sbdf.Func));=0D + return IoApicPresent;=0D +}=0D +=0D +/**=0D + Calculates Maximum Payload Size supported by PCIe hierarchy.=0D + Starting from a device, it finds the minimum MPS supported by devices be= low it.=0D + There are many valid strategies for setting MPS. This implementation cho= oses=0D + one that is safest, but doesn't guarantee maximum performance:=0D + Find minimum MPS under given rootport, then program that minimum value= everywhere below that rootport=0D +=0D + @param[in] BusLimit maximum Bus number that can be= assigned below this port=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D +=0D + @retval MPS supported by PCIe hierarchy, calculated as MIN(MPS of all d= evices below)=0D +**/=0D +STATIC=0D +UINT8=0D +RecursiveMpsCheck (=0D + SBDF Sbdf=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + UINT8 MyMps;=0D + UINT8 SubtreeMps;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveMpsCheck %x:%x:%x\n", Sbdf.Bus, Sbdf.Dev, = Sbdf.Func));=0D +=0D + MyMps =3D GetMps (Sbdf);=0D + if (MyMps =3D=3D 0) {=0D + return MyMps;=0D + }=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + SubtreeMps =3D RecursiveMpsCheck (ChildSbdf);=0D + MyMps =3D MIN(MyMps, SubtreeMps);=0D + }=0D + }=0D + return MyMps;=0D +}=0D +=0D +/**=0D + Sets Maximum Payload Size in PCIe hierarchy.=0D + Starting from a device, it programs the same MPS value to it and all dev= ices below it.=0D + There are many valid strategies for setting MPS. This implementation cho= oses=0D + one that is safest, but doesn't guarantee maximum performance:=0D + Find minimum MPS under given rootport, then program that minimum value= everywhere below that rootport=0D +=0D + @param[in] BusLimit maximum Bus number that can be= assigned below this port=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] Mps Maximum Payload Size to be pro= grammed=0D +**/=0D +STATIC=0D +VOID=0D +RecursiveMpsConfiguration (=0D + SBDF Sbdf,=0D + UINT8 Mps=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveMpsConfiguration %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + RecursiveMpsConfiguration (ChildSbdf, Mps);=0D + }=0D + }=0D + SetMps (Sbdf, Mps);=0D +}=0D +=0D +/**=0D + Sets Enable Clock Power Management bit for devices that support it.=0D + A device supports CPM only if all function of this device report CPM sup= port.=0D + Downstream ports never report CPM capability, so it's only relevant for = upstream ports.=0D + When this function executes on upstream component, it will check CPM & s= et ECPM of downstream component=0D + When this function executes on downstream component, all devices below i= t are guaranteed to=0D + return CPM=3D0 so it will do nothing=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D +=0D + @retval TRUE =3D this device supports CPM, FALSE =3D it doesn't=0D +**/=0D +STATIC=0D +BOOLEAN=0D +RecursiveCpmConfiguration (=0D + SBDF Sbdf=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + BOOLEAN ChildCpm;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveCpmConfiguration %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + ChildCpm =3D FALSE;=0D +=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + ChildCpm =3D TRUE;=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + ChildCpm &=3D RecursiveCpmConfiguration (ChildSbdf);=0D + }=0D + if (ChildCpm) {=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + EnableCpm (ChildSbdf);=0D + }=0D + }=0D + }=0D + return IsCpmSupported (Sbdf);=0D +}=0D +=0D +/**=0D + Sets Common Clock Configuration bit for devices that share common clock = across link=0D + Devices on both sides of a PCIE link share common clock if both upstream= component=0D + and function 0 of downstream component report Slot Clock Configuration b= it =3D 1.=0D + When this function executes on upstream component, it checks SCC of both= sides of the link=0D + If they both support it, sets CCC for both sides (this means all functio= ns of downstream component)=0D + When this function executes on downstream component, it only returns SCC= capability=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] WaitForRetrain decides if this function shoul= d busy-wait for link retrain=0D +=0D + @retval TRUE =3D this device supports SCC, FALSE =3D it doesn't=0D +**/=0D +STATIC=0D +BOOLEAN=0D +RecursiveCccConfiguration (=0D + SBDF Sbdf,=0D + BOOLEAN WaitForRetrain=0D + )=0D +{=0D + UINT64 Base;=0D + SBDF ChildSbdf;=0D + BOOLEAN MyScc;=0D + BOOLEAN ChildScc;=0D + BOOLEAN LinkScc;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveCccConfiguration %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + ChildScc =3D 0;=0D + Base =3D SbdfToBase(Sbdf);=0D + MyScc =3D GetScc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + ChildScc |=3D RecursiveCccConfiguration (ChildSbdf, WaitForRetrain);= =0D + }=0D + if (DevType =3D=3D DevTypePcieDownstream) {=0D + LinkScc =3D MyScc & ChildScc;=0D + if (LinkScc) {=0D + EnableCcc (SbdfToBase(Sbdf), (UINT8)Sbdf.PcieCap);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + EnableCcc (SbdfToBase(ChildSbdf), (UINT8)ChildSbdf.PcieCap);=0D + }=0D + RetrainLink(Base, (UINT8)Sbdf.PcieCap, WaitForRetrain);=0D + }=0D + }=0D + }=0D + return MyScc;=0D +}=0D +=0D +/**=0D + Configures Latency Tolerance Reporting in given device and in PCIe tree = below it.=0D + This function configures Maximum LTR and enables LTR mechanism. It visit= s devices using depth-first search=0D + and skips branches behind devices which do not support LTR.=0D + Maximum LTR:=0D + This function will set LTR's upper bound for every visited device. Max= LTR value is provided as a parameter=0D + Enable LTR:=0D + LTR should be enabled top-to-bottom in every visited device that suppo= rts LTR. This function does not=0D + iterate down behind devices with no LTR support. In effect, LTR will b= e enabled in given device if that device=0D + and all devices above it on the way to RootComplex do support LTR.=0D +=0D + This function expects that bridges have bus numbers already configured=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] LtrLimit Ltr to be programmed to every = endpoint=0D +=0D + @retval MaxLTR programmed in this device=0D +**/=0D +STATIC=0D +VOID=0D +RecursiveLtrConfiguration (=0D + SBDF Sbdf,=0D + LTR_LIMIT LtrLimit=0D + )=0D +{=0D + UINT64 Base;=0D + SBDF ChildSbdf;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveLtrConfiguration %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + Base =3D SbdfToBase(Sbdf);=0D +=0D + if (!IsLtrCapable (Sbdf)) {=0D + DEBUG ((DEBUG_INFO, "Not LtrCapable %02x:%02x:%02x\n", Sbdf.Bus, Sbdf.= Dev, Sbdf.Func));=0D + return;=0D + }=0D + EnableLtr (Sbdf);=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + RecursiveLtrConfiguration (ChildSbdf, LtrLimit);=0D + }=0D + }=0D + SetLtrLimit (Base, LtrLimit);=0D +}=0D +=0D +/**=0D + Checks to see device is PTM Capable=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordinates=0D +=0D + @retval TRUE =3D PTM Capability found, FALSE =3D Not PTM capable=0D +**/=0D +STATIC=0D +BOOLEAN=0D +IsPtmCapable (=0D + SBDF Sbdf=0D + )=0D +{=0D + UINT16 CapHeaderOffset;=0D +=0D + CapHeaderOffset =3D PcieFindExtendedCapId ((UINT8) Sbdf.Seg, (UINT8) Sbd= f.Bus, (UINT8) Sbdf.Dev, (UINT8) Sbdf.Func, V_PCIE_EX_PTM_CID);=0D +=0D + return (CapHeaderOffset !=3D 0);=0D +}=0D +=0D +/**=0D + Get PTM Capability register from PCIe Extended Capability Space.=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coor= dinates=0D + @param[in] PtmCapHeaderOffset PTM Capability Header Offset=0D +=0D + @retval LocalPtm Returns PTM Capability.=0D + If Device is not PTM capable then PTM Capability = is zeroed out.=0D +**/=0D +STATIC=0D +PTM_CAPS=0D +GetPtmCapability (=0D + SBDF Sbdf,=0D + UINT16 PtmCapHeaderOffset=0D + )=0D +{=0D + PTM_CAPS PtmCaps;=0D +=0D + PtmCaps.Uint32 =3D 0;=0D +=0D + if (PtmCapHeaderOffset !=3D 0) {=0D + PtmCaps.Uint32 =3D PciSegmentRead32 (SbdfToBase (Sbdf) + PtmCapHeaderO= ffset + R_PCIE_EX_PTMCAP_OFFSET);=0D + }=0D +=0D + return PtmCaps;=0D +}=0D +=0D +/**=0D + Get PTM Control register from PCIe Extended Capability Space.=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coor= dinates=0D + @param[in] PtmCapHeaderOffset PTM Capability Header Offset=0D +=0D + @retval LocalPtm Returns PTM Control.=0D + If Device is not PTM capable then PTM Control is = zeroed out.=0D +**/=0D +STATIC=0D +PTM_CTRL=0D +GetPtmControl (=0D + SBDF Sbdf,=0D + UINT16 PtmCapHeaderOffset=0D + )=0D +{=0D + PTM_CTRL PtmCtrl;=0D +=0D + PtmCtrl.Uint32 =3D 0;=0D +=0D + if (PtmCapHeaderOffset !=3D 0) {=0D + PtmCtrl.Uint32 =3D PciSegmentRead32 (SbdfToBase (Sbdf) + PtmCapHeaderO= ffset + R_PCIE_EX_PTMCTL_OFFSET);=0D + }=0D +=0D + return PtmCtrl;=0D +}=0D +=0D +/**=0D + Set PTM Control register in the PCIe Extended Capability Space.=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coor= dinates=0D + @param[in] PtmCapHeaderOffset PTM Capability Header Offset=0D + @param[in] PtmCtrl PTM Control Register=0D +**/=0D +STATIC=0D +VOID=0D +SetPtmControl (=0D + SBDF Sbdf,=0D + UINT16 PtmCapHeaderOffset,=0D + PTM_CTRL PtmCtrl=0D + )=0D +{=0D + if (PtmCapHeaderOffset !=3D 0) {=0D + PciSegmentWrite32 (SbdfToBase (Sbdf) + PtmCapHeaderOffset + R_PCIE_EX_= PTMCTL_OFFSET, PtmCtrl.Uint32);=0D + }=0D +}=0D +=0D +/**=0D + Enable PTM on device's control register. Set the Effective Clock Granula= rity.=0D +=0D + @param[in] Sbdf device's segment:bus:device:function= coordinates=0D + @param[in out] EffectiveGranularity Effective Clock Granularity of the P= TM hierarchy=0D + @param[in out] PtmHierarchy Indicates if the current device is w= ithin a PTM hierarchy=0D +**/=0D +STATIC=0D +VOID=0D +SetPtm (=0D + IN SBDF Sbdf,=0D + IN OUT UINT8 *EffectiveGranularity,=0D + IN OUT BOOLEAN *PtmHierarchy=0D + )=0D +{=0D + PTM_CTRL CurrentPtmCtrl;=0D + PTM_CAPS CurrentPtmCaps;=0D + PTM_CTRL OrigPtmCtrl;=0D + UINT16 PtmCapHeaderOffset;=0D +=0D + PtmCapHeaderOffset =3D PcieFindExtendedCapId ((UINT8) Sbdf.Seg, (UINT8) = Sbdf.Bus, (UINT8) Sbdf.Dev, (UINT8) Sbdf.Func, V_PCIE_EX_PTM_CID);=0D + CurrentPtmCtrl =3D GetPtmControl (Sbdf, PtmCapHeaderOffset);=0D + CurrentPtmCaps =3D GetPtmCapability (Sbdf, PtmCapHeaderOffset);=0D +=0D + OrigPtmCtrl.Uint32 =3D CurrentPtmCtrl.Uint32;=0D +=0D + if ( (*PtmHierarchy =3D=3D FALSE) && CurrentPtmCaps.Bits.RootCapable) {= =0D + // Select device as PTM Root if PTM Root is not selected.=0D + CurrentPtmCtrl.Bits.RootSelect =3D TRUE;=0D + *EffectiveGranularity =3D (UINT8) CurrentPtmCaps.Bits.LocalClockGranul= arity;=0D + *PtmHierarchy =3D TRUE;=0D + }=0D +=0D + if (*PtmHierarchy =3D=3D TRUE) {=0D + // Enable PTM if device is part of a ptm hierarchy=0D + CurrentPtmCtrl.Bits.Enable =3D TRUE;=0D +=0D + if (CurrentPtmCaps.Bits.RequesterCapable) {=0D + // Set Effective Granularity if PTM device is Requester roles.=0D + CurrentPtmCtrl.Bits.EffectiveGranularity =3D *EffectiveGranularity;= =0D + }=0D + }=0D +=0D + if (OrigPtmCtrl.Uint32 !=3D CurrentPtmCtrl.Uint32) {=0D + SetPtmControl (Sbdf, PtmCapHeaderOffset, CurrentPtmCtrl);=0D + }=0D +=0D + // Update EffectiveGranularity.=0D + // Set to zero if 1 or more switches between the root and endpoint repor= t local granularity =3D 0.=0D + // Otherwise set to the max local granularity of the hierarchy.=0D + if ( ((CurrentPtmCaps.Bits.LocalClockGranularity =3D=3D 0) && CurrentPtm= Caps.Bits.RequesterCapable) ||=0D + (*EffectiveGranularity =3D=3D 0) ) {=0D + *EffectiveGranularity =3D 0;=0D + } else {=0D + *EffectiveGranularity =3D MAX (*EffectiveGranularity, (UINT8) CurrentP= tmCaps.Bits.LocalClockGranularity);=0D + }=0D +}=0D +=0D +/**=0D + Configures PTM hierarchies by searching for Endpoints and Upstream Switc= hes=0D + that are PTM capable. Each PTM device role is identified and configured = accordingly.=0D + PTM root capable devices are selected as PTM root if the device is not a= lready in a=0D + PTM hierarchy.=0D + PTM capable Root Ports must be configured before calling this function.= =0D + @note: This function has not been tested with switches.=0D +=0D + @param[in] Sbdf Address of curretly visited Pcie device= =0D + @param[in] EffectiveGranularity The largest Clock Granularity from Upstr= eam Devices=0D + @param[in] PtmHierarchy TRUE =3D Device in a PTM Hierarchy, FALS= E =3D Not in PTM Hierarchy=0D +**/=0D +STATIC=0D +VOID=0D +RecursivePtmConfiguration (=0D + SBDF Sbdf,=0D + UINT8 EffectiveGranularity,=0D + BOOLEAN PtmHierarchy=0D + )=0D +{=0D + SBDF ChildSbdf;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursivePtmConfiguration %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + DevType =3D GetDeviceType (Sbdf);=0D +=0D + if (IsPtmCapable (Sbdf)) {=0D + //=0D + // Enable PTM for PTM Capable devices (Endpoints, Upstream Switch, and= Root Ports).=0D + // @Note: Switches have not been tested.=0D + //=0D + SetPtm (Sbdf, &EffectiveGranularity, &PtmHierarchy);=0D + } else if (!IsPtmCapable (Sbdf) && (DevType =3D=3D DevTypePcieUpstream) = ) {=0D + //=0D + // Non-PTM UpStream Switch Ports breaks the PTM Hierarchy.=0D + // No other downstream PTM devices should be PTM enabled until a PTM R= oot capable device is selected.=0D + //=0D + PtmHierarchy =3D FALSE;=0D + EffectiveGranularity =3D 0;=0D + }=0D +=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + RecursivePtmConfiguration (ChildSbdf, EffectiveGranularity, PtmHiera= rchy);=0D + }=0D + }=0D +}=0D +=0D +/**=0D + Initializes the following features in rootport and devices behind it:=0D + Maximum Payload Size (generic)=0D + Rootport packet split (proprietary)=0D + EonOfInterrupt forwarding (proprietary)=0D + Common Clock Configuration (generic)=0D +=0D + Generic: any code written according to PCIE Express base specification c= an do that.=0D + Proprietary: code uses registers and features that are specific to Intel= silicon=0D + and probably only this Reference Code knows how to handle that.=0D +=0D + If OEM implemented generic feature enabling in his platform code or trus= ts Operating System=0D + to do it, then those features can be deleted from here.=0D +=0D + CCC requires link retrain, which takes a while. CCC must happen before L= 0s/L1 programming.=0D + If there was guarantee no code would access PCI while links retrain, it = would be possible to skip this waiting=0D +=0D + @param[in] RpSegment address of rootport on PCIe=0D + @param[in] RpBus address of rootport on PCIe=0D + @param[in] RpDevice address of rootport on PCIe=0D + @param[in] RpFunction address of rootport on PCIe=0D + @param[in] BusMin minimum Bus number that can be assigned below this= rootport=0D + @param[in] BusMax maximum Bus number that can be assigned below this= rootport=0D +**/=0D +VOID=0D +RootportDownstreamConfiguration (=0D + UINT8 RpSegment,=0D + UINT8 RpBus,=0D + UINT8 RpDevice,=0D + UINT8 RpFunction,=0D + UINT8 BusMin,=0D + UINT8 BusMax,=0D + PCI_SKU PciSku=0D + )=0D +{=0D + UINT8 Mps;=0D + BOOLEAN IoApicPresent;=0D + UINT64 RpBase;=0D + SBDF RpSbdf;=0D + SBDF_TABLE BridgeCleanupList;=0D +=0D + IoApicPresent =3D FALSE;=0D + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFuncti= on, 0);=0D + if (!(IsDevicePresent (RpBase))) {=0D + return;=0D + }=0D + RpSbdf.Seg =3D RpSegment;=0D + RpSbdf.Bus =3D RpBus;=0D + RpSbdf.Dev =3D RpDevice;=0D + RpSbdf.Func =3D RpFunction;=0D + RpSbdf.PcieCap =3D PcieBaseFindCapId (RpBase, EFI_PCI_CAPABILITY_ID_PCIE= XP);=0D +=0D + DEBUG ((DEBUG_INFO, "RootportDownstreamConfiguration %x:%x\n", RpDevice,= RpFunction));=0D + BridgeCleanupList.Count =3D 0;=0D + RecursiveBusAssignment (RpSbdf, BusMin, BusMax, &BridgeCleanupList);=0D +=0D + Mps =3D RecursiveMpsCheck (RpSbdf);=0D + RecursiveMpsConfiguration (RpSbdf, Mps);=0D + if (PciSku =3D=3D EnumPchPcie) {=0D + RpBase =3D SbdfToBase (RpSbdf);=0D + ConfigureRpPacketSplit(RpBase, Mps);=0D + IoApicPresent =3D RecursiveIoApicCheck(RpSbdf);=0D + }=0D + if ((PciSku =3D=3D EnumPchPcie) || (PciSku =3D=3D EnumCpuPcie)) {=0D + ConfigureEoiForwarding (RpBase, IoApicPresent);=0D + }=0D + RecursiveCccConfiguration (RpSbdf, TRUE);=0D +=0D + if (IsPtmCapable (RpSbdf)) {=0D + RecursivePtmConfiguration (RpSbdf, 0, FALSE);=0D + }=0D +=0D + ClearBusFromTable (&BridgeCleanupList);=0D +}=0D +=0D +/**=0D + Checks if given PCI device is capable of Latency Tolerance Reporting=0D +=0D + @param[in] Sbdf device's segment:bus:device:function coordina= tes=0D +=0D + @retval TRUE if yes=0D +**/=0D +BOOLEAN=0D +IsLtrCapable (=0D + SBDF Sbdf=0D + )=0D +{=0D + if (Sbdf.PcieCap =3D=3D 0) {=0D + return FALSE;=0D + }=0D + return !!(PciSegmentRead32 (SbdfToBase (Sbdf) + Sbdf.PcieCap + R_PCIE_DC= AP2_OFFSET) & B_PCIE_DCAP2_LTRMS);=0D +}=0D +=0D +/**=0D + Returns combination of two LTR override values=0D + The resulting LTR override separately chooses stricter limits for snoop = and nosnoop=0D +=0D + @param[in] LtrA LTR override values to be combined=0D + @param[in] LtrB LTR override values to be combined=0D +=0D + @retval LTR override value=0D +**/=0D +LTR_OVERRIDE=0D +CombineLtr (=0D + LTR_OVERRIDE LtrA,=0D + LTR_OVERRIDE LtrB=0D + )=0D +{=0D + UINT64 DecodedLatencyA;=0D + UINT64 DecodedLatencyB;=0D + LTR_OVERRIDE Result;=0D + static UINT32 ScaleEncoding [8] =3D {1, 32, 1024, 32768, 1048576, 335544= 32, 0, 0};=0D +=0D + ZeroMem (&Result, sizeof (LTR_OVERRIDE));=0D + DecodedLatencyA =3D ScaleEncoding[LtrA.MaxSnoopLatencyScale] * LtrA.MaxS= noopLatencyValue;=0D + DecodedLatencyB =3D ScaleEncoding[LtrB.MaxSnoopLatencyScale] * LtrB.MaxS= noopLatencyValue;=0D + if ((!LtrB.MaxSnoopLatencyRequirement) || ((DecodedLatencyA < DecodedLat= encyB) && LtrA.MaxSnoopLatencyRequirement)) {=0D + Result.MaxSnoopLatencyValue =3D LtrA.MaxSnoopLatencyValue;=0D + Result.MaxSnoopLatencyScale =3D LtrA.MaxSnoopLatencyScale;=0D + Result.MaxSnoopLatencyRequirement =3D LtrA.MaxSnoopLatencyRequirement;= =0D + } else {=0D + Result.MaxSnoopLatencyValue =3D LtrB.MaxSnoopLatencyValue;=0D + Result.MaxSnoopLatencyScale =3D LtrB.MaxSnoopLatencyScale;=0D + Result.MaxSnoopLatencyRequirement =3D LtrB.MaxSnoopLatencyRequirement;= =0D + }=0D + DecodedLatencyA =3D ScaleEncoding[LtrA.MaxNoSnoopLatencyScale] * LtrA.Ma= xNoSnoopLatencyValue;=0D + DecodedLatencyB =3D ScaleEncoding[LtrB.MaxNoSnoopLatencyScale] * LtrB.Ma= xNoSnoopLatencyValue;=0D + if ((!LtrB.MaxNoSnoopLatencyRequirement) || ((DecodedLatencyA < DecodedL= atencyB) && LtrA.MaxNoSnoopLatencyRequirement)) {=0D + Result.MaxNoSnoopLatencyValue =3D LtrA.MaxNoSnoopLatencyValue;=0D + Result.MaxNoSnoopLatencyScale =3D LtrA.MaxNoSnoopLatencyScale;=0D + Result.MaxNoSnoopLatencyRequirement =3D LtrA.MaxNoSnoopLatencyRequirem= ent;=0D + } else {=0D + Result.MaxNoSnoopLatencyValue =3D LtrB.MaxNoSnoopLatencyValue;=0D + Result.MaxNoSnoopLatencyScale =3D LtrB.MaxNoSnoopLatencyScale;=0D + Result.MaxNoSnoopLatencyRequirement =3D LtrB.MaxNoSnoopLatencyRequirem= ent;=0D + }=0D + if (LtrA.ForceOverride || LtrB.ForceOverride) {=0D + Result.ForceOverride =3D TRUE;=0D + }=0D + DEBUG ((DEBUG_INFO, "CombineLtr: A(V%d S%d E%d : V%d S%d E%d, F%d)\n",=0D + LtrA.MaxSnoopLatencyValue, LtrA.MaxSnoopLatencyScale, LtrA.MaxSnoopLat= encyRequirement,=0D + LtrA.MaxNoSnoopLatencyValue, LtrA.MaxNoSnoopLatencyScale, LtrA.MaxNoSn= oopLatencyRequirement,=0D + LtrA.ForceOverride=0D + ));=0D + DEBUG ((DEBUG_INFO, " : B(V%d S%d E%d : V%d S%d E%d, F%d)\n",=0D + LtrB.MaxSnoopLatencyValue, LtrB.MaxSnoopLatencyScale, LtrB.MaxSnoopLat= encyRequirement,=0D + LtrB.MaxNoSnoopLatencyValue, LtrB.MaxNoSnoopLatencyScale, LtrB.MaxNoSn= oopLatencyRequirement,=0D + LtrB.ForceOverride=0D + ));=0D + DEBUG ((DEBUG_INFO, " : R(V%d S%d E%d : V%d S%d E%d, F%d)\n",=0D + Result.MaxSnoopLatencyValue, Result.MaxSnoopLatencyScale, Result.MaxSn= oopLatencyRequirement,=0D + Result.MaxNoSnoopLatencyValue, Result.MaxNoSnoopLatencyScale, Result.M= axNoSnoopLatencyRequirement,=0D + Result.ForceOverride=0D + ));=0D + return Result;=0D +}=0D +=0D +/**=0D + Returns LTR override value for given device=0D + The value is extracted from Device Override table. If the device is not = found,=0D + the returned value will have Requirement bits clear=0D +=0D + @param[in] Base device's base address=0D + @param[in] Override device override table=0D +=0D + @retval LTR override value=0D +**/=0D +LTR_OVERRIDE=0D +GetOverrideLtr (=0D + UINT64 Base,=0D + OVERRIDE_TABLE *Override=0D + )=0D +{=0D + UINT16 DevId;=0D + UINT16 VenId;=0D + UINT16 RevId;=0D + UINT32 Index;=0D + LTR_OVERRIDE ReturnValue =3D {0};=0D +=0D + VenId =3D PciSegmentRead16 (Base + PCI_VENDOR_ID_OFFSET);=0D + DevId =3D PciSegmentRead16 (Base + PCI_DEVICE_ID_OFFSET);=0D + RevId =3D PciSegmentRead16 (Base + PCI_REVISION_ID_OFFSET);=0D +=0D + for (Index =3D 0; Index < Override->Size; Index++) {=0D + if (((Override->Table[Index].OverrideConfig & PchPcieLtrOverride) =3D= =3D PchPcieLtrOverride) &&=0D + (Override->Table[Index].VendorId =3D=3D VenId) &&=0D + ((Override->Table[Index].DeviceId =3D=3D DevId) || (Override->Tabl= e[Index].DeviceId =3D=3D 0xFFFF)) &&=0D + ((Override->Table[Index].RevId =3D=3D RevId) || (Override->Table[I= ndex].RevId =3D=3D 0xFF))) {=0D + if (Override->Table[Index].SnoopLatency & 0x8000) {=0D + ReturnValue.MaxSnoopLatencyRequirement =3D 1;=0D + ReturnValue.MaxSnoopLatencyValue =3D Override->Table[Index].SnoopL= atency & 0x3FF;=0D + ReturnValue.MaxSnoopLatencyScale =3D (Override->Table[Index].Snoop= Latency & 0x1C00) >> 10;=0D + }=0D + if (Override->Table[Index].NonSnoopLatency & 0x8000) {=0D + ReturnValue.MaxNoSnoopLatencyRequirement =3D 1;=0D + ReturnValue.MaxNoSnoopLatencyValue =3D Override->Table[Index].NonS= noopLatency & 0x3FF;=0D + ReturnValue.MaxNoSnoopLatencyScale =3D (Override->Table[Index].Non= SnoopLatency & 0x1C00) >> 10;=0D + }=0D + ReturnValue.ForceOverride =3D Override->Table[Index].ForceLtrOverrid= e;=0D + break;=0D + }=0D + }=0D + return ReturnValue;=0D +}=0D +=0D +/**=0D + In accordance with PCIe spec, devices with no LTR support are considered= to have no LTR requirements=0D + which means infinite latency tolerance. This was found to cause problems= with HID and Audio devices without LTR=0D + support placed behind PCIe switches with LTR support, as Switch's upstre= am link would be allowed to enter L1.2=0D + and cause large latency downstream. To work around such issues and to fi= x some devices with broken=0D + LTR reporting, Device Override table was introduced.=0D + This function scans PCIe tree for devices mentioned in override table an= d calculates the strictest=0D + LTR requirement between them. That value will be programmed into rootpor= t's LTR override register=0D +=0D + This function expects that bridges have bus numbers already configured=0D +=0D + @param[in] BusLimit maximum Bus number that can be= assigned below this port=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] AspmOverride Device specific ASPM policy ov= erride items=0D +=0D + @retval MaxLTR programmed in this device=0D +**/=0D +LTR_OVERRIDE=0D +RecursiveLtrOverrideCheck (=0D + SBDF Sbdf,=0D + OVERRIDE_TABLE *AspmOverride=0D + )=0D +{=0D + UINT64 Base;=0D + SBDF ChildSbdf;=0D + LTR_OVERRIDE MyLtrOverride;=0D + LTR_OVERRIDE ChildLtr;=0D + PCI_DEV_TYPE DevType;=0D +=0D + DEBUG ((DEBUG_INFO, "RecursiveLtrOverrideCheck %x:%x:%x\n", Sbdf.Bus, Sb= df.Dev, Sbdf.Func));=0D +=0D + Base =3D SbdfToBase(Sbdf);=0D +=0D + MyLtrOverride =3D GetOverrideLtr (Base, AspmOverride);=0D + if (HasChildBus (Sbdf, &ChildSbdf)) {=0D + DevType =3D GetDeviceType (Sbdf);=0D + while (FindNextPcieChild (DevType, &ChildSbdf)) {=0D + ChildLtr =3D RecursiveLtrOverrideCheck (ChildSbdf, AspmOverride);=0D + MyLtrOverride =3D CombineLtr (MyLtrOverride, ChildLtr);=0D + }=0D + }=0D + return MyLtrOverride;=0D +}=0D +=0D +/**=0D + Configures the following power-management related features in rootport a= nd devices behind it:=0D + LTR limit (generic)=0D + LTR override (proprietary)=0D + Clock Power Management (generic)=0D + L1 substates (generic except for the override table)=0D + L1.LOW substate (proprietary)=0D + L0s and L1 (generic)=0D +=0D + Generic: any code written according to PCIE Express base specification c= an do that.=0D + Proprietary: code uses registers and features that are specific to Intel= silicon=0D + and probably only this Reference Code knows how to handle that.=0D +=0D + If OEM implemented generic feature enabling in his platform code or trus= ts Operating System=0D + to do it, then those features can be deleted from here.=0D +=0D + @param[in] RpSegment address of rootport on PCIe=0D + @param[in] RpBus address of rootport on PCIe=0D + @param[in] RpDevice address of rootport on PCIe=0D + @param[in] RpFunction address of rootport on PCIe=0D + @param[in] BusLimit maximum Bus number that can be assig= ned below this rootport=0D + @param[in] PcieRpLtrConfig address of LTR Policy struct=0D + @param[in] PcieRpCommonConfig address of Common PCIe Policy struct= =0D + @param[in] AspmOverrideTableSize size of override array=0D + @param[in] AspmOverrideTable array of device that need exceptions= in configuration=0D +**/=0D +VOID=0D +RootportDownstreamPmConfiguration (=0D + UINT8 RpSegment,=0D + UINT8 RpBus,=0D + UINT8 RpDevice,=0D + UINT8 RpFunction,=0D + UINT8 BusMin,=0D + UINT8 BusMax,=0D + PCIE_ROOT_PORT_COMMON_CONFIG *PcieRpCommonConfig,=0D + UINT32 AspmOverrideTableSize,=0D + PCH_PCIE_DEVICE_OVERRIDE *AspmOverrideTable=0D + )=0D +{=0D + LTR_LIMIT PolicyLtr;=0D + LTR_OVERRIDE TreeLtr;=0D + OVERRIDE_TABLE PmOverrideTable;=0D + UINT64 RpBase;=0D + SBDF RpSbdf;=0D + SBDF_TABLE BridgeCleanupList;=0D +=0D + RpBase =3D PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFuncti= on, 0);=0D + if (!(IsDevicePresent (RpBase))) {=0D + return;=0D + }=0D + PmOverrideTable.Size =3D AspmOverrideTableSize;=0D + PmOverrideTable.Table =3D AspmOverrideTable;=0D +=0D + DEBUG ((DEBUG_INFO, "RootportDownstreamPmConfiguration %x:%x\n", RpDevic= e, RpFunction));=0D + PolicyLtr.MaxNoSnoopLatencyScale =3D (PcieRpCommonConfig->PcieRpLtrConfi= g.LtrMaxNoSnoopLatency & 0x1c00) >> 10;=0D + PolicyLtr.MaxNoSnoopLatencyValue =3D PcieRpCommonConfig->PcieRpLtrConfig= .LtrMaxNoSnoopLatency & 0x3FF;=0D + PolicyLtr.MaxSnoopLatencyScale =3D (PcieRpCommonConfig->PcieRpLtrConfi= g.LtrMaxSnoopLatency & 0x1c00) >> 10;=0D + PolicyLtr.MaxSnoopLatencyValue =3D PcieRpCommonConfig->PcieRpLtrConfig= .LtrMaxSnoopLatency & 0x3FF;=0D +=0D + RpSbdf.Seg =3D RpSegment;=0D + RpSbdf.Bus =3D RpBus;=0D + RpSbdf.Dev =3D RpDevice;=0D + RpSbdf.Func =3D RpFunction;=0D + RpSbdf.PcieCap =3D PcieBaseFindCapId (RpBase, EFI_PCI_CAPABILITY_ID_PCIE= XP);=0D + //=0D + // This code could execute either before or after enumeration. If before= , then buses would not yet be assigned to bridges,=0D + // making devices deeper in the hierarchy inaccessible.=0D + // RecursiveBusAssignment will scan whole PCie tree and assign bus numbe= rs to uninitialized bridges, if there are any=0D + // List of such bridges will be kept in CleanupList, so that after PM pr= ogramming is done, bus numbers can brought to original state=0D + //=0D + BridgeCleanupList.Count =3D 0;=0D + RecursiveBusAssignment(RpSbdf, BusMin, BusMax, &BridgeCleanupList);=0D + //=0D + // The 'Recursive...' functions below expect bus numbers to be already a= ssigned=0D + //=0D + RecursiveLtrConfiguration (RpSbdf, PolicyLtr);=0D + TreeLtr =3D RecursiveLtrOverrideCheck (RpSbdf, &PmOverrideTable);=0D + ConfigureRpLtrOverride (RpBase, RpSbdf.Dev, &TreeLtr, &(PcieRpCommonConf= ig->PcieRpLtrConfig));=0D + DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride %x:%x\n", RpSbdf.Dev, RpSbdf= .Func));=0D + if (PcieRpCommonConfig->EnableCpm) {=0D + RecursiveCpmConfiguration (RpSbdf);=0D + }=0D + //=0D + // L1 substates can be modified only when L1 is disabled, so this functi= on must execute=0D + // before Aspm configuration which enables L1=0D + //=0D + RecursiveL1ssConfiguration (RpSbdf, &PmOverrideTable);=0D + L1ssProprietaryConfiguration (RpBase, IsLtrCapable (RpSbdf));=0D + RecursiveAspmConfiguration (RpSbdf, 0, &PmOverrideTable);=0D +=0D + ClearBusFromTable (&BridgeCleanupList);=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/PciExpressHelpersLibrary/PciExpressHelpersLibrary.h b/Silicon/Intel/Tiger= lakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrary/PciEx= pressHelpersLibrary.h new file mode 100644 index 0000000000..19c1051771 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciEx= pressHelpersLibrary/PciExpressHelpersLibrary.h @@ -0,0 +1,40 @@ +/** @file=0D + Header file for Pci Express helps library implementation.=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#ifndef _PCI_EXPRESS_HELPERS_LIBRARY_H_=0D +#define _PCI_EXPRESS_HELPERS_LIBRARY_H_=0D +=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +#define LTR_VALUE_MASK (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6 + B= IT7 + BIT8 + BIT9)=0D +#define LTR_SCALE_MASK (BIT10 + BIT11 + BIT12)=0D +=0D + #define CONFIG_WRITE_LOOP_COUNT 100000=0D +=0D +//=0D +// LTR related macros=0D +//=0D +#define LTR_LATENCY_VALUE(x) ((x) & LTR_VALUE_MASK)=0D +#define LTR_SCALE_VALUE(x) (((x) & LTR_SCALE_MASK) >> 10)=0D +#define LTR_LATENCY_NS(x) (LTR_LATENCY_VALUE(x) * (1 << (5 * = LTR_SCALE_VALUE(x))))=0D +=0D +#endif=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/PciExpressHelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf b/Silicon/Inte= l/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciExpressHelpersLibrar= y/PeiDxeSmmPciExpressHelpersLib.inf new file mode 100644 index 0000000000..8f673d14c2 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PciEx= pressHelpersLibrary/PeiDxeSmmPciExpressHelpersLib.inf @@ -0,0 +1,49 @@ +## @file=0D +# Component description file for the PeiDxeSmmPciExpressHelpersLib=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010017=0D + BASE_NAME =3D PeiDxeSmmPciExpressHelpersLib=0D + FILE_GUID =3D 07E3F76D-6D26-419d-9053-58696A15B519=0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D BASE=0D +LIBRARY_CLASS =3D PciExpressHelpersLib=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC=0D +#=0D +=0D +=0D +=0D +=0D +[LibraryClasses]=0D + IoLib=0D + DebugLib=0D + PchPcieRpLib=0D + PchPcrLib=0D + PchInfoLib=0D + GpioLib=0D + TimerLib=0D + BasePcieHelperLib=0D + PchPciBdfLib=0D + HobLib=0D + PcieRpLib=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Sources]=0D + PciExpressHelpersLibrary.c=0D + PciExpressHelpersLibrary.h=0D +=0D +[Guids]=0D + gCpuPcieHobGuid=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/PcieClientRpLib/PcieClientRpLib.c b/Silicon/Intel/TigerlakeSiliconPkg/IpB= lock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.c new file mode 100644 index 0000000000..15d295a573 --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieC= lientRpLib/PcieClientRpLib.c @@ -0,0 +1,247 @@ +/** @file=0D + This file contains routines that support PCI Express initialization=0D +=0D + Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D + SPDX-License-Identifier: BSD-2-Clause-Patent=0D +**/=0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +#include =0D +=0D +/**=0D + Get PCIe port number for enabled port.=0D + @param[in] RpBase Root Port pci segment base address=0D +=0D + @retval Root Port number (1 based)=0D +**/=0D +UINT32=0D +PciePortNum (=0D + IN UINT64 RpBase=0D + )=0D +{=0D + return PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LCAP) >> N_PCH_PCIE_CFG= _LCAP_PN;=0D +}=0D +=0D +/**=0D + Get PCIe root port index=0D +=0D + @param[in] RpBase Root Port pci segment base address=0D +=0D + @retval Root Port index (0 based)=0D +**/=0D +UINT32=0D +PciePortIndex (=0D + IN UINT64 RpBase=0D + )=0D +{=0D + return PciePortNum (RpBase) - 1;=0D +}=0D +=0D +/**=0D + This function checks whether PHY lane power gating is enabled on the por= t.=0D +=0D + @param[in] RpBase Root Port base address=0D +=0D + @retval TRUE PHY power gating is enabled=0D + @retval FALSE PHY power gating disabled=0D +**/=0D +BOOLEAN=0D +PcieIsPhyLanePgEnabled (=0D + IN UINT64 RpBase=0D + )=0D +{=0D + UINT32 Data32;=0D +=0D + Data32 =3D PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL);=0D + return (Data32 & B_PCH_PCIE_CFG_PCIEPMECTL_DLSULPPGE) !=3D 0;=0D +}=0D +=0D +/**=0D + Configures Root Port packet split.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] Mps maximum packet size=0D +**/=0D +VOID=0D +ConfigureRpPacketSplit (=0D + UINT64 RpBase,=0D + UINT8 Mps=0D + )=0D +{=0D + PciSegmentAndThenOr32 (RpBase + R_PCIE_CFG_CCFG, (UINT32) ~(B_PCIE_CFG_C= CFG_UNRS), Mps << N_PCIE_CFG_CCFG_UNRS);=0D +}=0D +=0D +/**=0D + Configures LTR override in Root Port's proprietary registers.=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] DevNum currently visited device numbe= r=0D + @param[in] RpConfig Root Port LTR configuration=0D + @param[in] AspmOverride combination of LTR override va= lues from all devices under this Root Port=0D +**/=0D +VOID=0D +ConfigureRpLtrOverride (=0D + UINT64 RpBase,=0D + UINT32 DevNum,=0D + LTR_OVERRIDE *TreeLtr,=0D + PCIE_LTR_CONFIG *LtrConfig=0D + )=0D +{=0D + UINT32 OvrEn;=0D + UINT32 OvrVal;=0D + BOOLEAN IsCpuPcie;=0D + UINT32 LtrCfgLock;=0D +=0D + IsCpuPcie =3D FALSE;=0D + OvrEn =3D 0;=0D + OvrVal =3D 0;=0D + LtrCfgLock =3D 0;=0D +=0D + if (DevNum =3D=3D SA_PEG0_DEV_NUM || DevNum =3D=3D SA_PEG3_DEV_NUM) {=0D + IsCpuPcie =3D TRUE;=0D + }=0D +=0D + //=0D + // LTR settings from LTROVR register only get acknowledged on rising edg= e of LTROVR2[1:0]=0D + // If those bits were already set (that can happen on a plug-hotUnplug-h= otPlug scenario),=0D + // they need to be toggled=0D + //=0D + if (PciSegmentRead32 (RpBase + R_PCH_PCIE_CFG_LTROVR2) !=3D 0) {=0D + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, 0);=0D + }=0D + //=0D + // (*)LatencyOverrideMode =3D 0 -> no override=0D + // 1 -> override with RP policy values=0D + // 2 -> override with endpoint's override value= s=0D + //=0D +=0D + if (LtrConfig->ForceLtrOverride || TreeLtr->ForceOverride) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_FORCE_OVERRIDE;=0D + }=0D + if (LtrConfig->LtrConfigLock =3D=3D TRUE) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_LOCK;=0D + }=0D +=0D + if (LtrConfig->SnoopLatencyOverrideMode =3D=3D 1) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;=0D + OvrVal |=3D LtrConfig->SnoopLatencyOverrideValue;=0D + OvrVal |=3D LtrConfig->SnoopLatencyOverrideMultiplier << 10;=0D + OvrVal |=3D B_PCH_PCIE_CFG_LTROVR_LTRSROVR;=0D + } else if (LtrConfig->SnoopLatencyOverrideMode =3D=3D 2) {=0D + if (TreeLtr->MaxSnoopLatencyRequirement) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_LTRSOVREN;=0D + OvrVal |=3D TreeLtr->MaxSnoopLatencyValue;=0D + OvrVal |=3D TreeLtr->MaxSnoopLatencyScale << 10;=0D + OvrVal |=3D B_PCH_PCIE_CFG_LTROVR_LTRSROVR;=0D + }=0D + }=0D + if (LtrConfig->NonSnoopLatencyOverrideMode =3D=3D 1) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;=0D + OvrVal |=3D LtrConfig->NonSnoopLatencyOverrideValue << 16;=0D + OvrVal |=3D LtrConfig->NonSnoopLatencyOverrideMultiplier << 26;=0D + OvrVal |=3D B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;=0D + } else if (LtrConfig->NonSnoopLatencyOverrideMode =3D=3D 2) {=0D + if (TreeLtr->MaxNoSnoopLatencyRequirement) {=0D + OvrEn |=3D B_PCH_PCIE_CFG_LTROVR2_LTRNSOVREN;=0D + OvrVal |=3D TreeLtr->MaxNoSnoopLatencyValue << 16;=0D + OvrVal |=3D TreeLtr->MaxNoSnoopLatencyScale << 26;=0D + OvrVal |=3D B_PCH_PCIE_CFG_LTROVR_LTRNSROVR;=0D + }=0D + }=0D + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR, OvrVal);=0D + PciSegmentWrite32 (RpBase + R_PCH_PCIE_CFG_LTROVR2, OvrEn);=0D +=0D + DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride IsCpuPcie=3D%d\n", IsCpuPcie= ));=0D + DEBUG ((DEBUG_INFO, "ConfigureRpLtrOverride %x Val %x En %x\n", RpBase, = OvrVal, OvrEn));=0D +}=0D +=0D +/**=0D + This function configures EOI message forwarding for PCIe port.=0D + If there's an IoAPIC behind this port, forwarding will be enabled=0D + Otherwise it will be disabled to minimize bus traffic=0D +=0D + @param[in] Segment,Bus,Device,Function address of currently visited P= CIe device=0D + @param[in] IoApicPresent TRUE if there's IoAPIC behind this Root Port=0D +**/=0D +VOID=0D +ConfigureEoiForwarding (=0D + UINT64 RpBase,=0D + BOOLEAN IoApicPresent=0D + )=0D +{=0D + UINT32 RpIndex;=0D +=0D + RpIndex =3D PciePortIndex (RpBase);=0D +=0D + if (IoApicPresent =3D=3D FALSE) {=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_MPC2, B_PCH_PCIE_CFG_MPC2_EOIFD= );=0D + } else {=0D + ///=0D + /// If there is an IOAPIC discovered behind Root Port, program PSF Mul= ticast registers=0D + /// in accordance with PCH PCIe BWG PSF EOI Multicast Configuration=0D + ///=0D + PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_MPC2, (UINT32)~B_PCH_PCIE_CFG= _MPC2_EOIFD);=0D + PsfConfigurEoiForPciePort (RpIndex);=0D + }=0D +}=0D +=0D +/**=0D + Configures proprietary parts of L1 substates configuration in Root Port= =0D +=0D + @param[in] RpSbdf segment:bus:device:function coordinates of Root = Port=0D + @param[in] LtrCapable TRUE if Root Port is LTR capable=0D +**/=0D +VOID=0D +L1ssProprietaryConfiguration (=0D + UINT64 RpBase,=0D + BOOLEAN LtrCapable=0D + )=0D +{=0D + BOOLEAN ClkreqSupported;=0D + BOOLEAN L1ssEnabled;=0D + UINT16 PcieCapOffset;=0D + UINT32 Data32;=0D + BOOLEAN L1LowSupported;=0D +=0D + ClkreqSupported =3D PcieIsPhyLanePgEnabled (RpBase);=0D +=0D + PcieCapOffset =3D PcieBaseFindExtendedCapId (RpBase, V_PCIE_EX_L1S_CID);= =0D + if (PcieCapOffset =3D=3D 0) {=0D + L1ssEnabled =3D FALSE;=0D + } else {=0D + Data32 =3D PciSegmentRead32 (RpBase + PcieCapOffset + R_PCIE_EX_L1SCTL= 1_OFFSET);=0D + L1ssEnabled =3D Data32 & (B_PCIE_EX_L1SCAP_AL1SS | B_PCIE_EX_L1SCAP_AL= 12S | B_PCIE_EX_L1SCAP_PPL11S |B_PCIE_EX_L1SCAP_PPL12S);=0D + }=0D + L1LowSupported =3D ClkreqSupported && LtrCapable && !L1ssEnabled;=0D +=0D + ///=0D + /// If L1.SNOOZ and L1.OFF (L1 Sub-States) are not supported and per-por= t CLKREQ# is supported, and LTR is supported:=0D + /// Enable L1.LOW by setting Dxx:Fn:420[17] =3D 1b=0D + ///=0D + if (L1LowSupported) {=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32) B_PCH_PCI= E_CFG_PCIEPMECTL_L1LE);=0D + } else {=0D + PciSegmentAnd32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, (UINT32) ~B_PCH_P= CIE_CFG_PCIEPMECTL_L1LE);=0D + }=0D +=0D + if (L1LowSupported || L1ssEnabled) {=0D + ///=0D + /// f. Set Dxx:Fn:420h[0] to 1b prior to L1 enabling if any L1substat= e is enabled (including L1.LOW)=0D + ///=0D + PciSegmentOr32 (RpBase + R_PCH_PCIE_CFG_PCIEPMECTL, B_PCH_PCIE_CFG_PCI= EPMECTL_L1FSOE);=0D + }=0D +}=0D diff --git a/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivat= e/PcieClientRpLib/PcieClientRpLib.inf b/Silicon/Intel/TigerlakeSiliconPkg/I= pBlock/PcieRp/LibraryPrivate/PcieClientRpLib/PcieClientRpLib.inf new file mode 100644 index 0000000000..86dceb14ee --- /dev/null +++ b/Silicon/Intel/TigerlakeSiliconPkg/IpBlock/PcieRp/LibraryPrivate/PcieC= lientRpLib/PcieClientRpLib.inf @@ -0,0 +1,43 @@ +## @file=0D +# Component description file for the PcieClientRpLib=0D +#=0D +# Copyright (c) 2021, Intel Corporation. All rights reserved.
=0D +# SPDX-License-Identifier: BSD-2-Clause-Patent=0D +#=0D +##=0D +=0D +=0D +[Defines]=0D + INF_VERSION =3D 0x00010017=0D + BASE_NAME =3D PcieClientRpLib=0D + FILE_GUID =3D 77EB467D-674C-4C20-A13E-381600E182C4=0D + VERSION_STRING =3D 1.0=0D + MODULE_TYPE =3D BASE=0D + LIBRARY_CLASS =3D PcieRpLib=0D +#=0D +# The following information is for reference only and not required by the = build tools.=0D +#=0D +# VALID_ARCHITECTURES =3D IA32 X64 IPF EBC=0D +#=0D +=0D +=0D +=0D +[LibraryClasses]=0D + IoLib=0D + DebugLib=0D + PchPcieRpLib=0D + PchPcrLib=0D + PchInfoLib=0D + GpioLib=0D + TimerLib=0D + PsfLib=0D + BasePcieHelperLib=0D + PchPciBdfLib=0D +=0D +[Packages]=0D + MdePkg/MdePkg.dec=0D + TigerlakeSiliconPkg/SiPkg.dec=0D +=0D +=0D +[Sources]=0D + PcieClientRpLib.c=0D --=20 2.24.0.windows.2