/** @file This driver does SA PCI Express ACPI table initialization. Copyright (c) 2019 - 2020 Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "PciExpressInit.h" #include extern SYSTEM_AGENT_NVS_AREA_PROTOCOL mSaNvsAreaProtocol; extern SA_CONFIG_HOB *mSaConfigHob; /** PCI Express Dxe Initialization. Run before PCI Bus Init, where assignment of Bus, Memory, and I/O Resources are assigned. @param[in] SaPolicy - SA DXE Policy protocol @retval EFI_SUCCESS - Pci Express successfully started and ready to be used **/ EFI_STATUS PciExpressInit ( IN SA_POLICY_PROTOCOL *SaPolicy ) { EFI_STATUS Status; PCIE_DXE_CONFIG *PcieDxeConfig; MSR_BROADWELL_PKG_CST_CONFIG_CONTROL_REGISTER Msr; Status = GetConfigBlock ((VOID *) SaPolicy, &gPcieDxeConfigGuid, (VOID *)&PcieDxeConfig); ASSERT_EFI_ERROR (Status); Msr.Uint64 = AsmReadMsr64 (MSR_BROADWELL_PKG_CST_CONFIG_CONTROL); mSaNvsAreaProtocol.Area->PackageCstateLimit = (UINT8) Msr.Bits.Limit; mSaNvsAreaProtocol.Area->PwrDnBundlesGlobalEnable = 0; if (mSaConfigHob != NULL) { mSaNvsAreaProtocol.Area->Peg0PowerDownUnusedBundles = mSaConfigHob->PowerDownUnusedBundles[0]; mSaNvsAreaProtocol.Area->Peg1PowerDownUnusedBundles = mSaConfigHob->PowerDownUnusedBundles[1]; mSaNvsAreaProtocol.Area->Peg2PowerDownUnusedBundles = mSaConfigHob->PowerDownUnusedBundles[2]; if (SA_PEG_MAX_FUN > 3) { mSaNvsAreaProtocol.Area->Peg3PowerDownUnusedBundles = mSaConfigHob->PowerDownUnusedBundles[3]; } } /// /// LTR/OBFF /// mSaNvsAreaProtocol.Area->Peg0LtrEnable = PcieDxeConfig->PegPwrOpt[0].LtrEnable; mSaNvsAreaProtocol.Area->Peg0ObffEnable = PcieDxeConfig->PegPwrOpt[0].ObffEnable; mSaNvsAreaProtocol.Area->Peg1LtrEnable = PcieDxeConfig->PegPwrOpt[1].LtrEnable; mSaNvsAreaProtocol.Area->Peg1ObffEnable = PcieDxeConfig->PegPwrOpt[1].ObffEnable; mSaNvsAreaProtocol.Area->Peg2LtrEnable = PcieDxeConfig->PegPwrOpt[2].LtrEnable; mSaNvsAreaProtocol.Area->Peg2ObffEnable = PcieDxeConfig->PegPwrOpt[2].ObffEnable; mSaNvsAreaProtocol.Area->PegLtrMaxSnoopLatency = LTR_MAX_SNOOP_LATENCY_VALUE; mSaNvsAreaProtocol.Area->PegLtrMaxNoSnoopLatency = LTR_MAX_NON_SNOOP_LATENCY_VALUE; return EFI_SUCCESS; } /** Find the Offset to a given Capabilities ID CAPID list: 0x01 = PCI Power Management Interface 0x04 = Slot Identification 0x05 = MSI Capability 0x10 = PCI Express Capability @param[in] Segment - Pci Segment Number @param[in] Bus - Pci Bus Number @param[in] Device - Pci Device Number @param[in] Function - Pci Function Number @param[in] CapId - CAPID to search for @retval 0 - CAPID not found @retval Other - CAPID found, Offset of desired CAPID **/ UINT32 PcieFindCapId ( IN UINT8 Segment, IN UINT8 Bus, IN UINT8 Device, IN UINT8 Function, IN UINT8 CapId ) { UINT64 DeviceBaseAddress; UINT8 CapHeader; /// /// Always start at Offset 0x34 /// DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0); CapHeader = PciSegmentRead8 (DeviceBaseAddress + PCI_CAPBILITY_POINTER_OFFSET); if (CapHeader == 0xFF) { return 0; } while (CapHeader != 0) { /// /// Bottom 2 bits of the pointers are reserved per PCI Local Bus Spec 2.2 /// CapHeader &= ~(BIT1 + BIT0); /// /// Search for desired CapID /// if (PciSegmentRead8 (DeviceBaseAddress + CapHeader) == CapId) { return CapHeader; } CapHeader = PciSegmentRead8 (DeviceBaseAddress + CapHeader + 1); } return 0; } /** Search and return the offset of desired Pci Express Capability ID CAPID list: 0x0001 = Advanced Error Rreporting Capability 0x0002 = Virtual Channel Capability 0x0003 = Device Serial Number Capability 0x0004 = Power Budgeting Capability @param[in] Segment - Pci Segment Number @param[in] Bus - Pci Bus Number @param[in] Device - Pci Device Number @param[in] Function - Pci Function Number @param[in] CapId - Extended CAPID to search for @retval 0 - CAPID not found @retval Other - CAPID found, Offset of desired CAPID **/ UINT32 PcieFindExtendedCapId ( IN UINT8 Segment, IN UINT8 Bus, IN UINT8 Device, IN UINT8 Function, IN UINT16 CapId ) { UINT64 DeviceBaseAddress; UINT16 CapHeaderOffset; UINT16 CapHeaderId; /// /// Start to search at Offset 0x100 /// Get Capability Header /// DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0); CapHeaderId = 0; CapHeaderOffset = 0x100; while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) { /// /// Search for desired CapID /// CapHeaderId = PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset); if (CapHeaderId == CapId) { return CapHeaderOffset; } CapHeaderOffset = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 2) >> 4); } return 0; }