/** @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;
}