/** @file
|
|
` Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
**/
|
|
//
|
// Module specific Includes
|
//
|
#include <Library/BaseMemoryLib.h>
|
#include <Library/BaseLib.h>
|
#include <Library/GpioLib.h>
|
#include <TbtBoardInfo.h>
|
#include <Protocol/TbtNvsArea.h>
|
#include <PchAccess.h>
|
#include <Library/BaseLib.h>
|
#include <Library/PciSegmentLib.h>
|
#include <Library/PchInfoLib.h>
|
#include <Library/IoLib.h>
|
#include <Library/SmmServicesTableLib.h>
|
#include <Protocol/SmmSxDispatch2.h>
|
#include <Protocol/SmmSwDispatch2.h>
|
#include <Uefi/UefiSpec.h>
|
#include <Library/UefiLib.h>
|
#include <Library/UefiRuntimeServicesTableLib.h>
|
#include <Library/UefiBootServicesTableLib.h>
|
#include <Library/DebugLib.h>
|
#include <Library/HobLib.h>
|
#include <Guid/HobList.h>
|
#include "TbtSmiHandler.h"
|
#include <PcieRegs.h>
|
#include <Protocol/SaPolicy.h>
|
#include <Protocol/DxeTbtPolicy.h>
|
#include <Library/PchPmcLib.h>
|
#define P2P_BRIDGE (((PCI_CLASS_BRIDGE) << 8) | (PCI_CLASS_BRIDGE_P2P))
|
|
#define CMD_BM_MEM_IO (CMD_BUS_MASTER | BIT1 | BIT0)
|
|
#define DISBL_IO_REG1C 0x01F1
|
#define DISBL_MEM32_REG20 0x0000FFF0
|
#define DISBL_PMEM_REG24 0x0001FFF1
|
|
#define DOCK_BUSSES 8
|
|
#define PCI_CAPABILITY_ID_PCIEXP 0x10
|
#define PCI_CAPBILITY_POINTER_OFFSET 0x34
|
|
#define LTR_MAX_SNOOP_LATENCY_VALUE 0x0846 ///< Intel recommended maximum value for Snoop Latency can we put like this ?
|
#define LTR_MAX_NON_SNOOP_LATENCY_VALUE 0x0846 ///< Intel recommended maximum value for Non-Snoop Latency can we put like this ?
|
|
|
GLOBAL_REMOVE_IF_UNREFERENCED TBT_NVS_AREA *mTbtNvsAreaPtr;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 gCurrentDiscreteTbtRootPort;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 gCurrentDiscreteTbtRootPortType;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 TbtLtrMaxSnoopLatency;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT16 TbtLtrMaxNoSnoopLatency;
|
GLOBAL_REMOVE_IF_UNREFERENCED UINT8 gDTbtPcieRstSupport;
|
GLOBAL_REMOVE_IF_UNREFERENCED TBT_INFO_HOB *gTbtInfoHob = NULL;
|
STATIC UINTN mPciExpressBaseAddress;
|
STATIC UINT8 TbtSegment = 0;
|
VOID
|
GpioWrite (
|
IN UINT32 GpioNumber,
|
IN BOOLEAN Value
|
)
|
{
|
GpioSetOutputValue (GpioNumber, (UINT32)Value);
|
}
|
|
/**
|
Search and return the offset of desired Pci Express Capability ID
|
CAPID list:
|
0x0001 = Advanced Error Reporting Capability
|
0x0002 = Virtual Channel Capability
|
0x0003 = Device Serial Number Capability
|
0x0004 = Power Budgeting Capability
|
|
@param[in] 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
|
**/
|
UINT16
|
PcieFindExtendedCapId (
|
IN UINT8 Bus,
|
IN UINT8 Device,
|
IN UINT8 Function,
|
IN UINT16 CapId
|
)
|
{
|
UINT16 CapHeaderOffset;
|
UINT16 CapHeaderId;
|
UINT64 DeviceBase;
|
|
DeviceBase = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Device, Function, 0);
|
|
///
|
/// Start to search at Offset 0x100
|
/// Get Capability Header, A pointer value of 00h is used to indicate the last capability in the list.
|
///
|
CapHeaderId = 0;
|
CapHeaderOffset = 0x100;
|
while (CapHeaderOffset != 0 && CapHeaderId != 0xFFFF) {
|
CapHeaderId = PciSegmentRead16 (DeviceBase + CapHeaderOffset);
|
if (CapHeaderId == CapId) {
|
return CapHeaderOffset;
|
}
|
///
|
/// Each capability must be DWORD aligned.
|
/// The bottom two bits of all pointers are reserved and must be implemented as 00b
|
/// although software must mask them to allow for future uses of these bits.
|
///
|
CapHeaderOffset = (PciSegmentRead16 (DeviceBase + CapHeaderOffset + 2) >> 4) & ((UINT16) ~(BIT0 | BIT1));
|
}
|
|
return 0;
|
}
|
|
/**
|
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] Bus Pci Bus Number
|
@param[in] Device Pci Device Number
|
@param[in] Function Pci Function Number
|
@param[in] CapId CAPID to search for
|
|
@retval 0 CAPID not found
|
@retval Other CAPID found, Offset of desired CAPID
|
**/
|
UINT8
|
PcieFindCapId (
|
IN UINT8 Segment,
|
IN UINT8 Bus,
|
IN UINT8 Device,
|
IN UINT8 Function,
|
IN UINT8 CapId
|
)
|
{
|
UINT8 CapHeaderOffset;
|
UINT8 CapHeaderId;
|
UINT64 DeviceBase;
|
|
DeviceBase = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0);
|
|
if ((PciSegmentRead8 (DeviceBase + PCI_PRIMARY_STATUS_OFFSET) & EFI_PCI_STATUS_CAPABILITY) == 0x00) {
|
///
|
/// Function has no capability pointer
|
///
|
return 0;
|
}
|
|
///
|
/// Check the header layout to determine the Offset of Capabilities Pointer Register
|
///
|
if ((PciSegmentRead8 (DeviceBase + PCI_HEADER_TYPE_OFFSET) & HEADER_LAYOUT_CODE) == (HEADER_TYPE_CARDBUS_BRIDGE)) {
|
///
|
/// If CardBus bridge, start at Offset 0x14
|
///
|
CapHeaderOffset = 0x14;
|
} else {
|
///
|
/// Otherwise, start at Offset 0x34
|
///
|
CapHeaderOffset = 0x34;
|
}
|
///
|
/// Get Capability Header, A pointer value of 00h is used to indicate the last capability in the list.
|
///
|
CapHeaderId = 0;
|
CapHeaderOffset = PciSegmentRead8 (DeviceBase + CapHeaderOffset) & ((UINT8) ~(BIT0 | BIT1));
|
while (CapHeaderOffset != 0 && CapHeaderId != 0xFF) {
|
CapHeaderId = PciSegmentRead8 (DeviceBase + CapHeaderOffset);
|
if (CapHeaderId == CapId) {
|
return CapHeaderOffset;
|
}
|
///
|
/// Each capability must be DWORD aligned.
|
/// The bottom two bits of all pointers (including the initial pointer at 34h) are reserved
|
/// and must be implemented as 00b although software must mask them to allow for future uses of these bits.
|
///
|
CapHeaderOffset = PciSegmentRead8 (DeviceBase + CapHeaderOffset + 1) & ((UINT8) ~(BIT0 | BIT1));
|
}
|
|
return 0;
|
}
|
/**
|
This function configures the L1 Substates.
|
It can be used for Rootport and endpoint devices.
|
|
@param[in] DownstreamPort Indicates if the device about to be programmed is a downstream port
|
@param[in] DeviceBase Device PCI configuration base address
|
@param[in] L1SubstateExtCapOffset Pointer to L1 Substate Capability Structure
|
@param[in] PortL1SubstateCapSupport L1 Substate capability setting
|
@param[in] PortCommonModeRestoreTime Common Mode Restore Time
|
@param[in] PortTpowerOnValue Tpower_on Power On Wait Time
|
@param[in] PortTpowerOnScale Tpower-on Scale
|
|
@retval none
|
**/
|
VOID
|
ConfigureL1s (
|
IN UINTN DeviceBase,
|
IN UINT16 L1SubstateExtCapOffset,
|
IN UINT32 PortL1SubstateCapSupport,
|
IN UINT32 PortCommonModeRestoreTime,
|
IN UINT32 PortTpowerOnValue,
|
IN UINT32 PortTpowerOnScale,
|
IN UINT16 MaxLevel
|
)
|
{
|
|
PciSegmentAndThenOr32 (
|
DeviceBase + L1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) ~(0xFF00),
|
(UINT32) PortCommonModeRestoreTime << 8
|
);
|
|
PciSegmentAnd32(DeviceBase + L1SubstateExtCapOffset + R_PCIE_EX_L1SCTL2_OFFSET, 0xFFFFFF04);
|
|
PciSegmentOr32(DeviceBase + L1SubstateExtCapOffset + R_PCIE_EX_L1SCTL2_OFFSET,(UINT32) ((PortTpowerOnValue << N_PCIE_EX_L1SCTL2_POWT) | PortTpowerOnScale));
|
|
PciSegmentAndThenOr32 (
|
DeviceBase + L1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) ~(0xE3FF0000),
|
(UINT32) (BIT30 | BIT23 | BIT21)
|
);
|
|
}
|
|
VOID
|
RootportL1sSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT16 RootL1SubstateExtCapOffset,
|
IN UINT16 MaxL1Level
|
)
|
{
|
UINTN ComponentABaseAddress;
|
UINTN ComponentBBaseAddress;
|
UINT8 SecBus;
|
UINT32 PortL1SubstateCapSupport;
|
UINT32 PortCommonModeRestoreTime;
|
UINT32 PortTpowerOnValue;
|
UINT32 PortTpowerOnScale;
|
UINT16 ComponentBL1SubstateExtCapOffset;
|
UINT32 ComponentBL1Substates;
|
UINT32 ComponentBCommonModeRestoreTime;
|
UINT32 ComponentBTpowerOnValue;
|
UINT32 ComponentBTpowerOnScale;
|
UINT32 Data32;
|
|
PortL1SubstateCapSupport = 0;
|
PortCommonModeRestoreTime = 0;
|
PortTpowerOnValue = 0;
|
PortTpowerOnScale = 0;
|
Data32 = 0;
|
|
ComponentABaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (RootL1SubstateExtCapOffset != 0) {
|
Data32 = PciSegmentRead32 (ComponentABaseAddress + RootL1SubstateExtCapOffset + R_PCIE_EX_L1SCAP_OFFSET);
|
PortL1SubstateCapSupport = (Data32) & 0x0F;
|
PortCommonModeRestoreTime = (Data32 >> 8) & 0xFF;
|
PortTpowerOnScale = (Data32 >> 16) & 0x3;
|
PortTpowerOnValue = (Data32 >> 19) & 0x1F;
|
} else {
|
MaxL1Level = 0; // If L1 Substates from Root Port side is disable, then Disable from Device side also.
|
}
|
|
SecBus = PciSegmentRead8 (ComponentABaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
ComponentBBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, SecBus, 0, 0, 0);
|
|
if (PciSegmentRead16 (ComponentBBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
ComponentBL1SubstateExtCapOffset = PcieFindExtendedCapId (
|
SecBus,
|
0,
|
0,
|
V_PCIE_EX_L1S_CID
|
);
|
if (ComponentBL1SubstateExtCapOffset != 0) {
|
ComponentBL1Substates = PciSegmentRead32 (ComponentBBaseAddress + ComponentBL1SubstateExtCapOffset + R_PCIE_EX_L1SCAP_OFFSET);
|
ComponentBCommonModeRestoreTime = (ComponentBL1Substates >> 8) & 0xFF;
|
ComponentBTpowerOnScale = (ComponentBL1Substates >> 16) & 0x3;
|
ComponentBTpowerOnValue = (ComponentBL1Substates >> 19) & 0x1F;
|
|
if (MaxL1Level == 3) {
|
if (Data32 >= ComponentBL1Substates) {
|
if (~(Data32 | BIT2)) {
|
MaxL1Level = 1;
|
}
|
}
|
else {
|
if (~(ComponentBL1Substates | BIT2)) {
|
MaxL1Level = 1;
|
}
|
}
|
}
|
|
if (MaxL1Level == 3) {
|
ConfigureL1s (
|
ComponentABaseAddress,
|
RootL1SubstateExtCapOffset,
|
PortL1SubstateCapSupport,
|
ComponentBCommonModeRestoreTime,
|
ComponentBTpowerOnValue,
|
ComponentBTpowerOnScale,
|
MaxL1Level
|
);
|
|
ConfigureL1s (
|
ComponentBBaseAddress,
|
ComponentBL1SubstateExtCapOffset,
|
ComponentBL1Substates,
|
PortCommonModeRestoreTime,
|
PortTpowerOnValue,
|
PortTpowerOnScale,
|
MaxL1Level
|
);
|
}
|
|
if (MaxL1Level == 1) {
|
PciSegmentOr32 (
|
ComponentABaseAddress + RootL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT3 | BIT1)
|
);
|
|
PciSegmentOr32 (
|
ComponentBBaseAddress + ComponentBL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT3 | BIT1)
|
);
|
}
|
else {
|
if (RootL1SubstateExtCapOffset != 0) {
|
PciSegmentOr32 (
|
ComponentABaseAddress + RootL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT3 | BIT1)
|
);
|
|
PciSegmentOr32 (
|
ComponentABaseAddress + RootL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT2 | BIT0)
|
);
|
}
|
if (ComponentBL1SubstateExtCapOffset != 0) {
|
PciSegmentOr32 (
|
ComponentBBaseAddress + ComponentBL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT3 | BIT1)
|
);
|
|
PciSegmentOr32 (
|
ComponentBBaseAddress + ComponentBL1SubstateExtCapOffset + R_PCIE_EX_L1SCTL1_OFFSET,
|
(UINT32) (BIT2 | BIT0)
|
);
|
}
|
}
|
}
|
}
|
}
|
|
VOID
|
MultiFunctionDeviceAspm (
|
IN UINT8 Bus,
|
IN UINT8 Dev
|
)
|
{
|
UINT16 LowerAspm;
|
UINT16 AspmVal;
|
UINT8 Fun;
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffset;
|
|
LowerAspm = 3; // L0s and L1 Supported
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
// Device not present
|
continue;
|
}
|
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Dev, Fun, 0x10);
|
|
AspmVal = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x00C) >> 10) & 3;
|
if (LowerAspm > AspmVal) {
|
LowerAspm = AspmVal;
|
}
|
} //Fun
|
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Dev, Fun, 0x10);
|
|
PciSegmentAndThenOr16 (DeviceBaseAddress + CapHeaderOffset + 0x10, 0xFFFC, LowerAspm);
|
} //Fun
|
}
|
|
UINT16
|
LimitAspmLevel (
|
IN UINT16 SelectedAspm,
|
IN UINT16 MaxAspmLevel
|
)
|
{
|
SelectedAspm = SelectedAspm & MaxAspmLevel;
|
|
return SelectedAspm;
|
}
|
|
UINT16
|
FindOptimalAspm (
|
IN UINT16 ComponentAaspm,
|
IN UINT16 ComponentBaspm
|
)
|
{
|
UINT16 SelectedAspm;
|
|
SelectedAspm = ComponentAaspm & ComponentBaspm;
|
|
return SelectedAspm;
|
}
|
|
UINT16
|
FindComponentBaspm (
|
IN UINT8 Bus,
|
IN UINT8 MaxBus
|
)
|
{
|
UINT8 BusNo;
|
UINT8 DevNo;
|
UINT8 FunNo;
|
UINT64 DevBaseAddress;
|
UINT8 RegVal;
|
UINT8 SecBusNo;
|
UINT16 SelectedAspm; // No ASPM Support
|
UINT8 CapHeaderOffset_B;
|
BOOLEAN AspmFound;
|
|
SelectedAspm = 0;
|
AspmFound = FALSE;
|
|
for (BusNo = MaxBus; (BusNo != 0xFF) && (!AspmFound); --BusNo) {
|
for (DevNo = 0; (DevNo <= PCI_MAX_DEVICE) && (!AspmFound); ++DevNo) {
|
for (FunNo = 0; (FunNo <= PCI_MAX_FUNC) && (!AspmFound); ++FunNo) {
|
//
|
// Check for Device availability
|
//
|
DevBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, BusNo, DevNo, FunNo, 0);
|
if (PciSegmentRead16 (DevBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
RegVal = PciSegmentRead8 (DevBaseAddress + PCI_HEADER_TYPE_OFFSET);
|
if ((RegVal & (BIT0 + BIT1 + BIT2 + BIT3 + BIT4 + BIT5 + BIT6)) != 0x01) {
|
//
|
// Not a PCI-to-PCI bridges device
|
//
|
continue;
|
}
|
|
SecBusNo = PciSegmentRead8 (DevBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
|
if (SecBusNo == Bus) {
|
//
|
// This is the Rootbridge for the given 'Bus' device
|
//
|
CapHeaderOffset_B = PcieFindCapId (TbtSegment, BusNo, DevNo, FunNo, 0x10);
|
SelectedAspm = (PciSegmentRead16 (DevBaseAddress + CapHeaderOffset_B + 0x00C) >> 10) & 3;
|
AspmFound = TRUE;
|
}
|
} //FunNo
|
} //DevNo
|
} //BusNo
|
|
return (SelectedAspm);
|
}
|
|
VOID
|
NoAspmSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT8 CapHeaderOffset
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
PciSegmentAndThenOr16 (DeviceBaseAddress + CapHeaderOffset + 0x10, 0xFFFC, 0x00);
|
}
|
|
VOID
|
EndpointAspmSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT8 CapHeaderOffset,
|
IN UINT8 MaxBus,
|
IN UINT16 MaxAspmLevel
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
UINT16 ComponentAaspm;
|
UINT16 ComponentBaspm;
|
UINT16 SelectedAspm;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
ComponentAaspm = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x00C) >> 10) & 3;
|
ComponentBaspm = FindComponentBaspm (Bus, MaxBus);
|
SelectedAspm = FindOptimalAspm (ComponentAaspm, ComponentBaspm);
|
SelectedAspm = LimitAspmLevel (SelectedAspm, MaxAspmLevel);
|
PciSegmentAndThenOr16 (DeviceBaseAddress + CapHeaderOffset + 0x10, 0xFFFC, SelectedAspm);
|
}
|
|
VOID
|
UpstreamAspmSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT8 CapHeaderOffset,
|
IN UINT8 MaxBus,
|
IN UINT16 MaxAspmLevel
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
UINT16 ComponentAaspm;
|
UINT16 ComponentBaspm;
|
UINT16 SelectedAspm;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
ComponentAaspm = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x00C) >> 10) & 3;
|
ComponentBaspm = FindComponentBaspm (Bus, MaxBus);
|
SelectedAspm = FindOptimalAspm (ComponentAaspm, ComponentBaspm);
|
SelectedAspm = LimitAspmLevel (SelectedAspm, MaxAspmLevel);
|
PciSegmentAndThenOr16 (DeviceBaseAddress + CapHeaderOffset + 0x10, 0xFFFC, SelectedAspm);
|
}
|
|
VOID
|
DownstreamAspmSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT8 CapHeaderOffset,
|
IN UINT16 MaxAspmLevel
|
)
|
{
|
UINT64 ComponentABaseAddress;
|
UINT64 ComponentBBaseAddress;
|
UINT16 ComponentAaspm;
|
UINT16 ComponentBaspm;
|
UINT16 SelectedAspm;
|
UINT8 SecBus;
|
UINT8 CapHeaderOffset_B;
|
|
ComponentABaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
ComponentAaspm = (PciSegmentRead16 (ComponentABaseAddress + CapHeaderOffset + 0x00C) >> 10) & 3;
|
|
SecBus = PciSegmentRead8 (ComponentABaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
ComponentBBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, SecBus, 0, 0, 0);
|
ComponentBaspm = 0; // No ASPM Support
|
if (PciSegmentRead16 (ComponentBBaseAddress + PCI_DEVICE_ID_OFFSET) != 0xFFFF) {
|
CapHeaderOffset_B = PcieFindCapId (TbtSegment, SecBus, 0, 0, 0x10);
|
ComponentBaspm = (PciSegmentRead16 (ComponentBBaseAddress + CapHeaderOffset_B + 0x00C) >> 10) & 3;
|
}
|
|
SelectedAspm = FindOptimalAspm (ComponentAaspm, ComponentBaspm);
|
SelectedAspm = LimitAspmLevel (SelectedAspm, MaxAspmLevel);
|
PciSegmentAndThenOr16 (ComponentABaseAddress + CapHeaderOffset + 0x10, 0xFFFC, SelectedAspm);
|
}
|
|
VOID
|
RootportAspmSupport (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT8 CapHeaderOffset,
|
IN UINT16 MaxAspmLevel
|
)
|
{
|
UINT64 ComponentABaseAddress;
|
UINT64 ComponentBBaseAddress;
|
UINT16 ComponentAaspm;
|
UINT16 ComponentBaspm;
|
UINT16 SelectedAspm;
|
UINT8 SecBus;
|
UINT8 CapHeaderOffset_B;
|
|
ComponentABaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
ComponentAaspm = (PciSegmentRead16 (ComponentABaseAddress + CapHeaderOffset + 0x00C) >> 10) & 3;
|
|
SecBus = PciSegmentRead8 (ComponentABaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
ComponentBBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, SecBus, 0, 0, 0);
|
ComponentBaspm = 0; // No ASPM Support
|
if (PciSegmentRead16 (ComponentBBaseAddress + PCI_DEVICE_ID_OFFSET) != 0xFFFF) {
|
CapHeaderOffset_B = PcieFindCapId (TbtSegment, SecBus, 0, 0, 0x10);
|
ComponentBaspm = (PciSegmentRead16 (ComponentBBaseAddress + CapHeaderOffset_B + 0x00C) >> 10) & 3;
|
}
|
|
SelectedAspm = FindOptimalAspm (ComponentAaspm, ComponentBaspm);
|
SelectedAspm = LimitAspmLevel (SelectedAspm, MaxAspmLevel);
|
PciSegmentAndThenOr16 (ComponentABaseAddress + CapHeaderOffset + 0x10, 0xFFFC, SelectedAspm);
|
}
|
|
VOID
|
ThunderboltEnableAspmWithoutLtr (
|
IN UINT16 MaxAspmLevel,
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
UINT8 Bus;
|
UINT8 Dev;
|
UINT8 Fun;
|
UINT8 RootBus;
|
UINT8 RootDev;
|
UINT8 RootFun;
|
UINT8 MinBus;
|
UINT8 MaxBus;
|
UINT16 DeviceId;
|
UINT64 DeviceBaseAddress;
|
UINT8 RegVal;
|
UINT8 CapHeaderOffset;
|
UINT16 DevicePortType;
|
|
MinBus = 0;
|
MaxBus = 0;
|
|
MinBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
|
MaxBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, MinBus, 0x00, 0x00, PCI_DEVICE_ID_OFFSET));
|
if (!(IsTbtHostRouter (DeviceId))) {
|
return;
|
}
|
|
TbtSegment = (UINT8)RpSegment;
|
|
RootBus = (UINT8)RpBus;
|
RootDev = (UINT8)RpDevice;
|
RootFun = (UINT8)RpFunction;
|
|
//
|
// Enumerate all the bridges and devices which are available on TBT host controller
|
//
|
for (Bus = MinBus; Bus <= MaxBus; ++Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, 0, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
RegVal = PciSegmentRead8 (DeviceBaseAddress + PCI_HEADER_TYPE_OFFSET);
|
if ((RegVal & BIT7) == 0) {
|
//
|
// Not a multi-function device
|
//
|
continue;
|
}
|
|
MultiFunctionDeviceAspm(Bus, Dev);
|
} //Dev
|
} //Bus
|
|
|
for (Bus = MinBus; Bus <= MaxBus; ++Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Dev, Fun, 0x10);
|
DevicePortType = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x002) >> 4) & 0xF;
|
if(PciSegmentRead8 (DeviceBaseAddress + PCI_CLASSCODE_OFFSET) == PCI_CLASS_SERIAL) {
|
MaxAspmLevel = (UINT16) 0x1;
|
}
|
|
switch (DevicePortType) {
|
case 0:
|
//
|
// PCI Express Endpoint
|
//
|
EndpointAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxBus, MaxAspmLevel);
|
break;
|
|
case 1:
|
//
|
// Legacy PCI Express Endpoint
|
//
|
EndpointAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxBus, MaxAspmLevel);
|
break;
|
|
case 4:
|
//
|
// Root Port of PCI Express Root Complex
|
//
|
RootportAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxAspmLevel);
|
break;
|
|
case 5:
|
//
|
// Upstream Port of PCI Express Switch
|
//
|
UpstreamAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxBus, MaxAspmLevel);
|
break;
|
|
case 6:
|
//
|
// Downstream Port of PCI Express Switch
|
//
|
DownstreamAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxAspmLevel);
|
break;
|
|
case 7:
|
//
|
// PCI Express to PCI/PCI-X Bridge
|
//
|
NoAspmSupport (Bus, Dev, Fun, CapHeaderOffset);
|
break;
|
|
case 8:
|
//
|
// PCI/PCI-X to PCI Express Bridge
|
//
|
NoAspmSupport (Bus, Dev, Fun, CapHeaderOffset);
|
break;
|
|
case 9:
|
//
|
// Root Complex Integrated Endpoint
|
//
|
EndpointAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxBus, MaxAspmLevel);
|
break;
|
|
case 10:
|
//
|
// Root Complex Event Collector
|
//
|
EndpointAspmSupport (Bus, Dev, Fun, CapHeaderOffset, MaxBus, MaxAspmLevel);
|
break;
|
|
default:
|
break;
|
}
|
//
|
// switch(DevicePortType)
|
//
|
}
|
//
|
// Fun
|
//
|
}
|
//
|
// Dev
|
//
|
}
|
//
|
// Bus
|
//
|
CapHeaderOffset = PcieFindCapId (TbtSegment, RootBus, RootDev, RootFun, 0x10);
|
RootportAspmSupport (RootBus, RootDev, RootFun, CapHeaderOffset, MaxAspmLevel);
|
}
|
|
|
|
VOID
|
ThunderboltEnableL1Sub (
|
IN UINT16 MaxL1Level,
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
UINT16 CapHeaderOffsetExtd;
|
|
RpBus = 0;
|
|
CapHeaderOffsetExtd = PcieFindExtendedCapId ((UINT8) RpBus, (UINT8) RpDevice, (UINT8) RpFunction, V_PCIE_EX_L1S_CID);
|
RootportL1sSupport ((UINT8) RpBus, (UINT8) RpDevice, (UINT8) RpFunction, CapHeaderOffsetExtd, MaxL1Level);
|
}
|
|
VOID
|
ThunderboltDisableAspmWithoutLtr (
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
UINT8 Bus;
|
UINT8 Dev;
|
UINT8 Fun;
|
UINT8 RootBus;
|
UINT8 RootDev;
|
UINT8 RootFun;
|
UINT8 MinBus;
|
UINT8 MaxBus;
|
UINT16 DeviceId;
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffset;
|
|
MinBus = 0;
|
MaxBus = 0;
|
|
MinBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
|
MaxBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, MinBus, 0x00, 0x00, PCI_DEVICE_ID_OFFSET));
|
if (!(IsTbtHostRouter (DeviceId))) {
|
return;
|
}
|
|
TbtSegment = (UINT8)RpSegment;
|
RootBus = (UINT8)RpBus;
|
RootDev = (UINT8)RpDevice;
|
RootFun = (UINT8)RpFunction;
|
|
//
|
// Enumerate all the bridges and devices which are available on TBT host controller
|
//
|
for (Bus = MinBus; Bus <= MaxBus; ++Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Dev, Fun, 0x10);
|
PciSegmentAndThenOr16 (DeviceBaseAddress + CapHeaderOffset + 0x10, 0xFFFC, 0x00);
|
} //Fun
|
} //Dev
|
} //Bus
|
|
CapHeaderOffset = PcieFindCapId (TbtSegment, RootBus, RootDev, RootFun, 0x10);
|
NoAspmSupport(RootBus, RootDev, RootFun, CapHeaderOffset);
|
}
|
|
VOID
|
TbtProgramClkReq (
|
IN UINT8 Bus,
|
IN UINT8 Device,
|
IN UINT8 Function,
|
IN UINT8 ClkReqSetup
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffset;
|
UINT16 Data16;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Device, Function, 0);
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Device, Function, 0x10);
|
|
//
|
// Check if CLKREQ# is supported
|
//
|
if ((PciSegmentRead32 (DeviceBaseAddress + CapHeaderOffset + 0x0C) & BIT18) != 0) {
|
Data16 = PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x010);
|
|
if (ClkReqSetup) {
|
Data16 = Data16 | BIT8; // Enable Clock Power Management
|
} else {
|
Data16 = Data16 & (UINT16)(~BIT8); // Disable Clock Power Management
|
}
|
|
PciSegmentWrite16 (DeviceBaseAddress + CapHeaderOffset + 0x010, Data16);
|
}
|
}
|
VOID
|
TbtProgramPtm(
|
IN UINT8 Bus,
|
IN UINT8 Device,
|
IN UINT8 Function,
|
IN UINT8 PtmSetup,
|
IN BOOLEAN IsRoot
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
UINT16 CapHeaderOffset;
|
UINT16 PtmControlRegister;
|
UINT16 PtmCapabilityRegister;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS(TbtSegment, Bus, Device, Function, 0);
|
CapHeaderOffset = PcieFindExtendedCapId(Bus, Device, Function, 0x001F /*V_PCIE_EX_PTM_CID*/);
|
if(CapHeaderOffset != 0) {
|
PtmCapabilityRegister = PciSegmentRead16(DeviceBaseAddress + CapHeaderOffset + 0x04);
|
//
|
// Check if PTM Requester/ Responder capability for the EP/Down stream etc
|
//
|
if ((PtmCapabilityRegister & (BIT1 | BIT0)) != 0) {
|
PtmControlRegister = PciSegmentRead16(DeviceBaseAddress + CapHeaderOffset + 0x08);
|
|
if (PtmSetup) {
|
PtmControlRegister = PtmControlRegister | BIT0; // Enable PTM
|
if(IsRoot) {
|
PtmControlRegister = PtmControlRegister | BIT1; // Enable PTM
|
}
|
PtmControlRegister = PtmControlRegister | (PtmCapabilityRegister & 0xFF00); // Programm Local Clock Granularity
|
} else {
|
PtmControlRegister = PtmControlRegister & (UINT16)(~(BIT0 | BIT1)); // Disable Clock Power Management
|
}
|
|
PciSegmentWrite16(DeviceBaseAddress + CapHeaderOffset + 0x08, PtmControlRegister);
|
}
|
}
|
}
|
|
VOID
|
ConfigureTbtPm (
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction,
|
IN UINT8 Configuration // 1- Clk Request , 2- PTM ,
|
)
|
{
|
UINT8 Bus;
|
UINT8 Dev;
|
UINT8 Fun;
|
UINT8 MinBus;
|
UINT8 MaxBus;
|
UINT16 DeviceId;
|
UINT64 DeviceBaseAddress;
|
|
MinBus = 0;
|
MaxBus = 0;
|
|
if ((Configuration != 1) && (Configuration != 2)) {
|
return;
|
}
|
MinBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
|
MaxBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, MinBus, 0x00, 0x00, PCI_DEVICE_ID_OFFSET));
|
if (!(IsTbtHostRouter (DeviceId))) {
|
return;
|
}
|
|
TbtSegment = (UINT8)RpSegment;
|
//
|
// Enumerate all the bridges and devices which are available on TBT host controller
|
//
|
for (Bus = MaxBus; Bus >= MinBus; --Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
if (Fun == 0) {
|
//
|
// IF Fun is zero, stop enumerating other functions of the particular bridge
|
//
|
break;
|
}
|
//
|
// otherwise, just skip checking for CLKREQ support
|
//
|
continue;
|
}
|
switch (Configuration) {
|
case 1:
|
TbtProgramClkReq (Bus, Dev, Fun, (UINT8) mTbtNvsAreaPtr->TbtSetClkReq);
|
break;
|
case 2:
|
TbtProgramPtm (Bus, Dev, Fun, (UINT8) mTbtNvsAreaPtr->TbtPtm, FALSE);
|
TbtProgramPtm((UINT8) RpBus, (UINT8) RpDevice, (UINT8) RpFunction, (UINT8) mTbtNvsAreaPtr->TbtPtm, TRUE);
|
break;
|
default:
|
break;
|
}
|
} //Fun
|
} // Dev
|
} // Bus
|
}
|
|
/**
|
1) Check LTR support in device capabilities 2 register (bit 11).
|
2) If supported enable LTR in device control 2 register (bit 10).
|
|
**/
|
VOID
|
TbtProgramLtr (
|
IN UINT8 Bus,
|
IN UINT8 Device,
|
IN UINT8 Function,
|
IN UINT8 LtrSetup
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffset;
|
UINT16 Data16;
|
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Device, Function, 0);
|
CapHeaderOffset = PcieFindCapId (TbtSegment, Bus, Device, Function, 0x10);
|
|
//
|
// Check if LTR# is supported
|
//
|
if ((PciSegmentRead32 (DeviceBaseAddress + CapHeaderOffset + 0x24) & BIT11) != 0) {
|
Data16 = PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffset + 0x028);
|
|
if (LtrSetup) {
|
Data16 = Data16 | BIT10; // LTR Mechanism Enable
|
} else {
|
Data16 = Data16 & (UINT16)(~BIT10); // LTR Mechanism Disable
|
}
|
|
PciSegmentWrite16 (DeviceBaseAddress + CapHeaderOffset + 0x028, Data16);
|
}
|
}
|
|
VOID
|
ConfigureLtr (
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
UINT8 Bus;
|
UINT8 Dev;
|
UINT8 Fun;
|
UINT8 MinBus;
|
UINT8 MaxBus;
|
UINT16 DeviceId;
|
UINT64 DeviceBaseAddress;
|
|
MinBus = 0;
|
MaxBus = 0;
|
|
MinBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
|
MaxBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, MinBus, 0x00, 0x00, PCI_DEVICE_ID_OFFSET));
|
if (!(IsTbtHostRouter (DeviceId))) {
|
return;
|
}
|
|
TbtSegment = (UINT8)RpSegment;
|
//
|
// Enumerate all the bridges and devices which are available on TBT host controller
|
//
|
for (Bus = MinBus; Bus <= MaxBus; ++Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
if (Fun == 0) {
|
//
|
// IF Fun is zero, stop enumerating other functions of the particular bridge
|
//
|
break;
|
}
|
//
|
// otherwise, just skip checking for LTR support
|
//
|
continue;
|
}
|
|
TbtProgramLtr (Bus, Dev, Fun, (UINT8) mTbtNvsAreaPtr->TbtLtr);
|
|
} //Fun
|
} // Dev
|
} // Bus
|
TbtProgramLtr ((UINT8) RpBus, (UINT8) RpDevice, (UINT8) RpFunction, (UINT8) mTbtNvsAreaPtr->TbtLtr);
|
}
|
|
/*
|
US ports and endpoints which declare support must also have the LTR capability structure (cap ID 18h).
|
In this structure you need to enter the max snoop latency and max non-snoop latency in accordance with the format specified in the PCIe spec.
|
The latency value itself is platform specific so you'll need to get it from the platform architect or whatever.
|
*/
|
VOID
|
ThunderboltGetLatencyLtr (
|
VOID
|
)
|
{
|
PCH_SERIES PchSeries;
|
|
PchSeries = GetPchSeries ();
|
|
if(gCurrentDiscreteTbtRootPortType == DTBT_TYPE_PEG) {
|
// PEG selector
|
TbtLtrMaxSnoopLatency = LTR_MAX_SNOOP_LATENCY_VALUE;
|
TbtLtrMaxNoSnoopLatency = LTR_MAX_NON_SNOOP_LATENCY_VALUE;
|
} else if (gCurrentDiscreteTbtRootPortType == DTBT_TYPE_PCH) {
|
// PCH selector
|
|
if (PchSeries == PchLp) {
|
TbtLtrMaxSnoopLatency = 0x1003;
|
TbtLtrMaxNoSnoopLatency = 0x1003;
|
}
|
if (PchSeries == PchH) {
|
TbtLtrMaxSnoopLatency = 0x0846;
|
TbtLtrMaxNoSnoopLatency = 0x0846;
|
}
|
}
|
}
|
|
VOID
|
SetLatencyLtr (
|
IN UINT8 Bus,
|
IN UINT8 Dev,
|
IN UINT8 Fun,
|
IN UINT16 CapHeaderOffsetExtd,
|
IN UINT16 LtrMaxSnoopLatency,
|
IN UINT16 LtrMaxNoSnoopLatency
|
)
|
{
|
UINT64 DeviceBaseAddress;
|
if(CapHeaderOffsetExtd == 0) {
|
return;
|
}
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
PciSegmentWrite16 (DeviceBaseAddress + CapHeaderOffsetExtd + 0x004, LtrMaxSnoopLatency);
|
PciSegmentWrite16 (DeviceBaseAddress + CapHeaderOffsetExtd + 0x006, LtrMaxNoSnoopLatency);
|
}
|
|
VOID
|
ThunderboltSetLatencyLtr (
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
UINT8 Bus;
|
UINT8 Dev;
|
UINT8 Fun;
|
UINT8 MinBus;
|
UINT8 MaxBus;
|
UINT16 DeviceId;
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffsetStd;
|
UINT16 CapHeaderOffsetExtd;
|
UINT16 DevicePortType;
|
|
MinBus = 0;
|
MaxBus = 0;
|
|
MinBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET));
|
MaxBus = PciSegmentRead8 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET));
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (RpSegment, MinBus, 0x00, 0x00, PCI_DEVICE_ID_OFFSET));
|
if (!(IsTbtHostRouter (DeviceId))) {
|
return;
|
}
|
|
TbtSegment = (UINT8)RpSegment;
|
|
for (Bus = MinBus; Bus <= MaxBus; ++Bus) {
|
for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
|
for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
|
//
|
// Check for Device availability
|
//
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
|
if (PciSegmentRead16 (DeviceBaseAddress + PCI_DEVICE_ID_OFFSET) == 0xFFFF) {
|
//
|
// Device not present
|
//
|
continue;
|
}
|
|
CapHeaderOffsetStd = PcieFindCapId (TbtSegment, Bus, Dev, Fun, 0x10);
|
DevicePortType = (PciSegmentRead16 (DeviceBaseAddress + CapHeaderOffsetStd + 0x002) >> 4) & 0xF;
|
|
CapHeaderOffsetExtd = PcieFindExtendedCapId (Bus, Dev, Fun, 0x0018);
|
|
switch (DevicePortType) {
|
case 0:
|
//
|
// PCI Express Endpoint
|
//
|
SetLatencyLtr (Bus, Dev, Fun, CapHeaderOffsetExtd, TbtLtrMaxSnoopLatency, TbtLtrMaxNoSnoopLatency);
|
break;
|
|
case 1:
|
//
|
// Legacy PCI Express Endpoint
|
//
|
SetLatencyLtr (Bus, Dev, Fun, CapHeaderOffsetExtd, TbtLtrMaxSnoopLatency, TbtLtrMaxNoSnoopLatency);
|
break;
|
|
case 4:
|
//
|
// Root Port of PCI Express Root Complex
|
//
|
// Do-nothing
|
break;
|
|
case 5:
|
//
|
// Upstream Port of PCI Express Switch
|
//
|
SetLatencyLtr (Bus, Dev, Fun, CapHeaderOffsetExtd, TbtLtrMaxSnoopLatency, TbtLtrMaxNoSnoopLatency);
|
break;
|
|
case 6:
|
//
|
// Downstream Port of PCI Express Switch
|
//
|
// Do-nothing
|
break;
|
|
case 7:
|
//
|
// PCI Express to PCI/PCI-X Bridge
|
//
|
// Do-nothing
|
break;
|
|
case 8:
|
//
|
// PCI/PCI-X to PCI Express Bridge
|
//
|
// Do-nothing
|
break;
|
|
case 9:
|
//
|
// Root Complex Integrated Endpoint
|
//
|
// Do-nothing
|
break;
|
|
case 10:
|
//
|
// Root Complex Event Collector
|
//
|
// Do-nothing
|
break;
|
|
default:
|
break;
|
}
|
//
|
// switch(DevicePortType)
|
//
|
}
|
//
|
// Fun
|
//
|
}
|
//
|
// Dev
|
//
|
}
|
//
|
// Bus
|
//
|
}
|
|
static
|
VOID
|
Stall (
|
UINTN Usec
|
)
|
{
|
UINTN Index;
|
UINT32 Data32;
|
UINT32 PrevData;
|
UINTN Counter;
|
|
Counter = (UINTN) ((Usec * 10) / 3);
|
//
|
// Call WaitForTick for Counter + 1 ticks to try to guarantee Counter tick
|
// periods, thus attempting to ensure Microseconds of stall time.
|
//
|
if (Counter != 0) {
|
|
PrevData = IoRead32 (PcdGet16 (PcdAcpiBaseAddress) + R_PCH_ACPI_PM1_TMR);
|
for (Index = 0; Index < Counter;) {
|
Data32 = IoRead32 (PcdGet16 (PcdAcpiBaseAddress) + R_PCH_ACPI_PM1_TMR);
|
if (Data32 < PrevData) {
|
//
|
// Reset if there is a overlap
|
//
|
PrevData = Data32;
|
continue;
|
}
|
|
Index += (Data32 - PrevData);
|
PrevData = Data32;
|
}
|
}
|
|
return ;
|
}
|
/**
|
Called during Sx entry, initates TbtSetPcie2TbtCommand HandShake to set GO2SX_NO_WAKE
|
for Tbt devices if WakeupSupport is not present.
|
|
@param[in] DispatchHandle - The unique handle assigned to this handler by SmiHandlerRegister().
|
@param[in] DispatchContext - Points to an optional handler context which was specified when the
|
handler was registered.
|
@param[in, out] CommBuffer - A pointer to a collection of data in memory that will
|
be conveyed from a non-SMM environment into an SMM environment.
|
@param[in, out] CommBufferSize - The size of the CommBuffer.
|
|
@retval EFI_SUCCESS - The interrupt was handled successfully.
|
**/
|
EFI_STATUS
|
EFIAPI
|
SxDTbtEntryCallback (
|
IN EFI_HANDLE DispatchHandle,
|
IN CONST VOID *DispatchContext,
|
IN OUT VOID *CommBuffer OPTIONAL,
|
IN UINTN *CommBufferSize OPTIONAL
|
)
|
{
|
UINT16 DeviceId;
|
UINT8 CableConnected;
|
UINT8 RootportSelected;
|
UINT8 HoustRouteBus;
|
volatile UINT32 *PowerState;
|
UINT32 PowerStatePrev;
|
BOOLEAN SecSubBusAssigned;
|
UINT64 DeviceBaseAddress;
|
UINT8 CapHeaderOffset;
|
UINTN RpDev;
|
UINTN RpFunc;
|
EFI_STATUS Status;
|
UINT32 Timeout;
|
UINT32 RegisterValue;
|
UINT64 Tbt2Pcie;
|
UINTN Index;
|
UINT32 TbtCioPlugEventGpioNo;
|
UINT32 TbtFrcPwrGpioNo;
|
UINT8 TbtFrcPwrGpioLevel;
|
UINT32 TbtPcieRstGpioNo;
|
UINT8 TbtPcieRstGpioLevel;
|
EFI_SMM_SX_REGISTER_CONTEXT *EntryDispatchContext;
|
|
CableConnected = 0;
|
HoustRouteBus = 3;
|
SecSubBusAssigned = FALSE;
|
Timeout = 600;
|
RootportSelected = 0;
|
TbtCioPlugEventGpioNo = 0;
|
TbtFrcPwrGpioNo = 0;
|
TbtFrcPwrGpioLevel = 0;
|
TbtPcieRstGpioNo = 0;
|
TbtPcieRstGpioLevel = 0;
|
Index = 0;
|
|
EntryDispatchContext = (EFI_SMM_SX_REGISTER_CONTEXT*) DispatchContext;
|
|
// CableConnected = GetTbtHostRouterStatus ();
|
//SaveTbtHostRouterStatus (CableConnected & 0xF0);
|
//
|
// Get the Power State and Save
|
//
|
if (((mTbtNvsAreaPtr->DTbtControllerEn0 == 0) && (Index == 0))) {
|
|
RootportSelected = mTbtNvsAreaPtr->RootportSelected0;
|
TbtCioPlugEventGpioNo = mTbtNvsAreaPtr->TbtCioPlugEventGpioNo0;
|
TbtFrcPwrGpioNo = mTbtNvsAreaPtr->TbtFrcPwrGpioNo0;
|
TbtFrcPwrGpioLevel = mTbtNvsAreaPtr->TbtFrcPwrGpioLevel0;
|
TbtPcieRstGpioNo = mTbtNvsAreaPtr->TbtPcieRstGpioNo0;
|
TbtPcieRstGpioLevel = mTbtNvsAreaPtr->TbtPcieRstGpioLevel0;
|
}
|
|
Status = GetDTbtRpDevFun (gCurrentDiscreteTbtRootPortType, RootportSelected - 1, &RpDev, &RpFunc);
|
ASSERT_EFI_ERROR (Status);
|
CapHeaderOffset = PcieFindCapId (TbtSegment, 0x00, (UINT8)RpDev, (UINT8)RpFunc, 0x01);
|
DeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, 0x00, (UINT32)RpDev, (UINT32)RpFunc, 0);
|
PowerState = &*((volatile UINT32 *) (mPciExpressBaseAddress + DeviceBaseAddress + CapHeaderOffset + 4)); //PMCSR
|
PowerStatePrev = *PowerState;
|
*PowerState &= 0xFFFFFFFC;
|
|
HoustRouteBus = PciSegmentRead8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
|
//
|
// Check the Subordinate bus .If it is Zero ,assign temporary bus to
|
// find the device presence .
|
//
|
if (HoustRouteBus == 0) {
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 0xF0);
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0xF0);
|
HoustRouteBus = 0xF0;
|
SecSubBusAssigned = TRUE;
|
}
|
//
|
// Clear Interrupt capability of TBT CIO Plug Event Pin to make sure no SCI is getting generated,
|
// This GPIO will be reprogrammed while resuming as part of Platform GPIO Programming.
|
//
|
GpioSetPadInterruptConfig (TbtCioPlugEventGpioNo, GpioIntDis);
|
//
|
// Read the TBT Host router DeviceID
|
//
|
DeviceId = PciSegmentRead16 (PCI_SEGMENT_LIB_ADDRESS (TbtSegment, HoustRouteBus, 0, 0, PCI_DEVICE_ID_OFFSET));
|
|
//
|
// Check For HostRouter Presence
|
//
|
if (IsTbtHostRouter (DeviceId)) {
|
// CableConnected = GetTbtHostRouterStatus ();
|
if (!((CableConnected & (DTBT_SAVE_STATE_OFFSET << Index)) == (DTBT_SAVE_STATE_OFFSET << Index))) {
|
CableConnected = CableConnected | (DTBT_SAVE_STATE_OFFSET << Index);
|
// SaveTbtHostRouterStatus (CableConnected);
|
}
|
}
|
|
//
|
// Check value of Tbt2Pcie reg, if Tbt is not present, bios needs to apply force power prior to sending mailbox command
|
//
|
GET_TBT2PCIE_REGISTER_ADDRESS(TbtSegment, HoustRouteBus, 0x00, 0x00, Tbt2Pcie)
|
RegisterValue = PciSegmentRead32 (Tbt2Pcie);
|
if (0xFFFFFFFF == RegisterValue) {
|
|
GpioWrite (TbtFrcPwrGpioNo,TbtFrcPwrGpioLevel);
|
|
while (Timeout -- > 0) {
|
RegisterValue = PciSegmentRead32 (Tbt2Pcie);
|
if (0xFFFFFFFF != RegisterValue) {
|
break;
|
}
|
Stall(1* (UINTN)1000);
|
}
|
//
|
// Before entering Sx state BIOS should execute GO2SX/NO_WAKE mailbox command for AIC.
|
// However BIOS shall not execute go2sx mailbox command on S5/reboot cycle.
|
//
|
|
if( (EntryDispatchContext->Type == SxS3) || (EntryDispatchContext->Type == SxS4))
|
{
|
if(!mTbtNvsAreaPtr->TbtWakeupSupport) {
|
//Wake Disabled, GO2SX_NO_WAKE Command
|
TbtSetPcie2TbtCommand (PCIE2TBT_GO2SX_NO_WAKE, HoustRouteBus, 0, 0, TBT_5S_TIMEOUT);
|
} else {
|
//Wake Enabled, GO2SX Command
|
TbtSetPcie2TbtCommand (PCIE2TBT_GO2SX, HoustRouteBus, 0, 0, TBT_5S_TIMEOUT);
|
}
|
}
|
if (mTbtNvsAreaPtr->TbtFrcPwrEn == 0) {
|
GpioWrite (TbtFrcPwrGpioNo,!(TbtFrcPwrGpioLevel));
|
}
|
} else {
|
//
|
// Before entering Sx state BIOS should execute GO2SX/NO_WAKE mailbox command for AIC.
|
// However BIOS shall not execute go2sx mailbox command on S5/reboot cycle.
|
//
|
if( (EntryDispatchContext->Type == SxS3) || (EntryDispatchContext->Type == SxS4))
|
{
|
if(!mTbtNvsAreaPtr->TbtWakeupSupport) {
|
//Wake Disabled, GO2SX_NO_WAKE Command
|
TbtSetPcie2TbtCommand (PCIE2TBT_GO2SX_NO_WAKE, HoustRouteBus, 0, 0, TBT_5S_TIMEOUT);
|
} else {
|
//Wake Enabled, GO2SX Command
|
TbtSetPcie2TbtCommand (PCIE2TBT_GO2SX, HoustRouteBus, 0, 0, TBT_5S_TIMEOUT);
|
}
|
}
|
}
|
*PowerState = PowerStatePrev;
|
//
|
// Restore the bus number in case we assigned temporarily
|
//
|
if (SecSubBusAssigned) {
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 0x00);
|
PciSegmentWrite8 (DeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0x00);
|
}
|
if (gDTbtPcieRstSupport) {
|
GpioWrite (TbtPcieRstGpioNo,TbtPcieRstGpioLevel);
|
}
|
return EFI_SUCCESS;
|
}
|
|
VOID
|
ThunderboltSwSmiCallback (
|
IN UINT8 Type
|
)
|
{
|
UINT8 ThunderboltSmiFunction;
|
|
DEBUG ((DEBUG_INFO, "ThunderboltSwSmiCallback Entry\n"));
|
ThunderboltSmiFunction = mTbtNvsAreaPtr->ThunderboltSmiFunction;
|
DEBUG ((DEBUG_INFO, "ThunderboltSwSmiCallback. ThunderboltSmiFunction=%d\n", ThunderboltSmiFunction));
|
if (Type == DTBT_CONTROLLER) {
|
gCurrentDiscreteTbtRootPort = mTbtNvsAreaPtr->CurrentDiscreteTbtRootPort;
|
gCurrentDiscreteTbtRootPortType = mTbtNvsAreaPtr->CurrentDiscreteTbtRootPortType;
|
}
|
|
switch (ThunderboltSmiFunction) {
|
case 21:
|
ThunderboltCallback (Type);
|
break;
|
|
case 22:
|
TbtDisablePCIDevicesAndBridges (Type);
|
break;
|
|
case 23:
|
ConfigureTbtAspm (Type, (UINT16) 0x02);
|
break;
|
|
case 24:
|
ConfigureTbtAspm (Type, (UINT16) 0x01);
|
break;
|
|
default:
|
break;
|
}
|
DEBUG ((DEBUG_INFO, "ThunderboltSwSmiCallback Exit.\n"));
|
}
|
STATIC
|
EFI_STATUS
|
EFIAPI
|
DiscreteThunderboltSwSmiCallback (
|
IN EFI_HANDLE DispatchHandle,
|
IN CONST VOID *DispatchContext,
|
IN OUT VOID *CommBuffer OPTIONAL,
|
IN UINTN *CommBufferSize OPTIONAL
|
)
|
{
|
ThunderboltSwSmiCallback(DTBT_CONTROLLER);
|
return EFI_SUCCESS;
|
}
|
EFI_STATUS
|
TbtRegisterHandlers (
|
IN BOOLEAN Type
|
)
|
{
|
EFI_STATUS Status;
|
UINTN SmiInputValue;
|
EFI_SMM_HANDLER_ENTRY_POINT2 SxHandler;
|
EFI_SMM_HANDLER_ENTRY_POINT2 SwHandler;
|
EFI_SMM_SX_DISPATCH2_PROTOCOL *SxDispatchProtocol;
|
EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;
|
EFI_SMM_SX_REGISTER_CONTEXT EntryDispatchContext;
|
EFI_SMM_SW_REGISTER_CONTEXT SwContext;
|
EFI_HANDLE SwDispatchHandle;
|
EFI_HANDLE S3DispatchHandle;
|
EFI_HANDLE S4DispatchHandle;
|
EFI_HANDLE S5DispatchHandle;
|
|
Status = EFI_UNSUPPORTED;
|
|
if(Type == DTBT_CONTROLLER) {
|
SxHandler = SxDTbtEntryCallback;
|
SwHandler = DiscreteThunderboltSwSmiCallback;
|
SmiInputValue = PcdGet8 (PcdSwSmiDTbtEnumerate);
|
gDTbtPcieRstSupport = gTbtInfoHob->DTbtCommonConfig.PcieRstSupport;
|
Status = EFI_SUCCESS;
|
}
|
if (EFI_ERROR (Status)) {
|
return Status;
|
}
|
|
SwDispatchHandle = NULL;
|
S3DispatchHandle = NULL;
|
S4DispatchHandle = NULL;
|
S5DispatchHandle = NULL;
|
|
Status = gSmst->SmmLocateProtocol (
|
&gEfiSmmSxDispatch2ProtocolGuid,
|
NULL,
|
(VOID **) &SxDispatchProtocol
|
);
|
ASSERT_EFI_ERROR (Status);
|
//
|
// Register S3 entry phase call back function
|
//
|
EntryDispatchContext.Type = SxS3;
|
EntryDispatchContext.Phase = SxEntry;
|
Status = SxDispatchProtocol->Register (
|
SxDispatchProtocol,
|
SxHandler,
|
&EntryDispatchContext,
|
&S3DispatchHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
//
|
// Register S4 entry phase call back function
|
//
|
EntryDispatchContext.Type = SxS4;
|
EntryDispatchContext.Phase = SxEntry;
|
Status = SxDispatchProtocol->Register (
|
SxDispatchProtocol,
|
SxHandler,
|
&EntryDispatchContext,
|
&S4DispatchHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
//
|
// Register S5 entry phase call back function
|
//
|
EntryDispatchContext.Type = SxS5;
|
EntryDispatchContext.Phase = SxEntry;
|
Status = SxDispatchProtocol->Register (
|
SxDispatchProtocol,
|
SxHandler,
|
&EntryDispatchContext,
|
&S5DispatchHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
//
|
// Locate the SMM SW dispatch protocol
|
//
|
Status = gSmst->SmmLocateProtocol (
|
&gEfiSmmSwDispatch2ProtocolGuid,
|
NULL,
|
(VOID **) &SwDispatch
|
);
|
|
ASSERT_EFI_ERROR (Status);
|
//
|
// Register SWSMI handler
|
//
|
SwContext.SwSmiInputValue = SmiInputValue;
|
Status = SwDispatch->Register (
|
SwDispatch,
|
SwHandler,
|
&SwContext,
|
&SwDispatchHandle
|
);
|
ASSERT_EFI_ERROR (Status);
|
|
return Status;
|
}
|
EFI_STATUS
|
InSmmFunction (
|
IN EFI_HANDLE ImageHandle,
|
IN EFI_SYSTEM_TABLE *SystemTable
|
)
|
{
|
EFI_STATUS Status;
|
|
Status = EFI_SUCCESS;
|
|
Status = TbtRegisterHandlers(DTBT_CONTROLLER);
|
return Status;
|
}
|
|
EFI_STATUS
|
EFIAPI
|
TbtSmmEntryPoint (
|
IN EFI_HANDLE ImageHandle,
|
IN EFI_SYSTEM_TABLE *SystemTable
|
)
|
{
|
TBT_NVS_AREA_PROTOCOL *TbtNvsAreaProtocol;
|
EFI_STATUS Status;
|
|
DEBUG ((DEBUG_INFO, "TbtSmmEntryPoint\n"));
|
|
mPciExpressBaseAddress = PcdGet64 (PcdPciExpressBaseAddress);
|
//
|
// Locate Tbt shared data area
|
//
|
Status = gBS->LocateProtocol (&gTbtNvsAreaProtocolGuid, NULL, (VOID **) &TbtNvsAreaProtocol);
|
ASSERT_EFI_ERROR (Status);
|
mTbtNvsAreaPtr = TbtNvsAreaProtocol->Area;
|
|
//
|
// Get TBT INFO HOB
|
//
|
gTbtInfoHob = (TBT_INFO_HOB *) GetFirstGuidHob (&gTbtInfoHobGuid);
|
if (gTbtInfoHob == NULL) {
|
return EFI_NOT_FOUND;
|
}
|
|
return InSmmFunction (ImageHandle, SystemTable);
|
}
|
|
VOID
|
EndOfThunderboltCallback (
|
IN UINTN RpSegment,
|
IN UINTN RpBus,
|
IN UINTN RpDevice,
|
IN UINTN RpFunction
|
)
|
{
|
if(mTbtNvsAreaPtr->TbtL1SubStates != 0) {
|
ThunderboltEnableL1Sub (mTbtNvsAreaPtr->TbtL1SubStates, RpSegment, RpBus, RpDevice, RpFunction);
|
}
|
ConfigureTbtPm(RpSegment, RpBus, RpDevice, RpFunction, 1);
|
if (!mTbtNvsAreaPtr->TbtAspm) { //Aspm disable case
|
ThunderboltDisableAspmWithoutLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
} else { //Aspm enable case
|
ThunderboltEnableAspmWithoutLtr ((UINT16)mTbtNvsAreaPtr->TbtAspm, RpSegment, RpBus, RpDevice, RpFunction);
|
}
|
|
if (mTbtNvsAreaPtr->TbtLtr) {
|
ThunderboltGetLatencyLtr ();
|
ThunderboltSetLatencyLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
}
|
ConfigureLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
ConfigureTbtPm(RpSegment, RpBus, RpDevice, RpFunction, 2);
|
} // EndOfThunderboltCallback
|
|
VOID
|
ConfigureTbtAspm (
|
IN UINT8 Type,
|
IN UINT16 Aspm
|
)
|
{
|
UINTN RpSegment = 0;
|
UINTN RpBus = 0;
|
UINTN RpDevice;
|
UINTN RpFunction;
|
|
if(Type == DTBT_CONTROLLER) {
|
if (gCurrentDiscreteTbtRootPort == 0) {
|
return;
|
}
|
GetDTbtRpDevFun(DTBT_CONTROLLER, gCurrentDiscreteTbtRootPort - 1, &RpDevice, &RpFunction);
|
|
ConfigureTbtPm (RpSegment, RpBus, RpDevice, RpFunction, 1);
|
if (!mTbtNvsAreaPtr->TbtAspm) { //Aspm disable case
|
ThunderboltDisableAspmWithoutLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
} else { //Aspm enable case
|
ThunderboltEnableAspmWithoutLtr ((UINT16) Aspm, RpSegment, RpBus, RpDevice, RpFunction);
|
}
|
|
if (mTbtNvsAreaPtr->TbtLtr) {
|
ThunderboltGetLatencyLtr ();
|
ThunderboltSetLatencyLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
}
|
ConfigureLtr (RpSegment, RpBus, RpDevice, RpFunction);
|
} // EndOfThunderboltCallback
|
}
|
|