summaryrefslogtreecommitdiff
path: root/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm
diff options
context:
space:
mode:
Diffstat (limited to 'Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm')
-rw-r--r--Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.c1615
-rw-r--r--Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.h185
-rw-r--r--Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.c1771
-rw-r--r--Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.inf83
4 files changed, 3654 insertions, 0 deletions
diff --git a/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.c b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.c
new file mode 100644
index 0000000000..5280f9e1c8
--- /dev/null
+++ b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.c
@@ -0,0 +1,1615 @@
+/**@file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "TbtSmiHandler.h"
+#include <Library/IoLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Protocol/SmmVariable.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/PciSegmentLib.h>
+#define MEM_PER_SLOT (DEF_RES_MEM_PER_DEV << 4)
+#define PMEM_PER_SLOT (DEF_RES_PMEM_PER_DEV << 4)
+#define IO_PER_SLOT (DEF_RES_IO_PER_DEV << 2)
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN gDeviceBaseAddress;
+//
+//US(X:0:0), DS(X+1:3:0),DS(X+1:4:0),DS(X+1:5:0),DS(X+1:6:0)
+//
+GLOBAL_REMOVE_IF_UNREFERENCED BRDG_CONFIG HrConfigs[MAX_CFG_PORTS];
+
+extern UINT8 gCurrentDiscreteTbtRootPort;
+extern UINT8 gCurrentDiscreteTbtRootPortType;
+
+BOOLEAN isLegacyDevice = FALSE;
+STATIC UINT8 TbtSegment = 0;
+
+STATIC
+VOID
+PortInfoInit (
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ PortInfo->BusNumLimit = 4;
+}
+
+STATIC
+VOID
+UnsetVesc (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Fun
+ )
+{
+ UINT8 Dbus;
+ UINT32 Data32;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
+
+ //
+ // Check for abcence of DS bridge
+ //
+ if(0xFFFF == PciSegmentRead16(gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET)) {
+ return;
+ }
+
+ //
+ // Unset vesc_reg2[23] bit (to have an option to access below DS)
+ //
+ Data32 = PciSegmentRead32 (gDeviceBaseAddress + PCI_TBT_VESC_REG2);
+ Data32 &= 0xFF7FFFFF;
+ PciSegmentWrite32(gDeviceBaseAddress + PCI_TBT_VESC_REG2, Data32);
+ //
+ // Go to Device behind DS
+ //
+ Dbus = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ DEBUG((DEBUG_INFO, "Dbus = %d\n",Dbus));
+ //
+ // Check if there is something behind this Downstream Port (Up or Ep)
+ // If there nothing behind Downstream Port Set vesc_reg2[23] bit -> this will flush all future MemWr
+ //
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Dbus, 0x00, 0x00, 0);
+ if(0xFFFF == PciSegmentRead16(gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET))
+ {
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
+ Data32 = PciSegmentRead32 (gDeviceBaseAddress + PCI_TBT_VESC_REG2);
+ Data32 |= 0x00800000;
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_TBT_VESC_REG2, Data32);
+ }
+}// Unset_VESC_REG2
+
+STATIC
+UINT16
+MemPerSlot (
+ IN UINT16 CurrentUsage
+ )
+{
+ if (CurrentUsage == 0) {
+ return 0;
+ }
+
+ if (CurrentUsage <= 16) {
+ return 16;
+ }
+
+ if (CurrentUsage <= 64) {
+ return 64;
+ }
+
+ if (CurrentUsage <= 128) {
+ return 128;
+ }
+
+ if (CurrentUsage <= 256) {
+ return 256;
+ }
+
+ if (CurrentUsage <= 512) {
+ return 512;
+ }
+
+ if (CurrentUsage <= 1024) {
+ return 1024;
+ }
+
+ return CurrentUsage;
+} // MemPerSlot
+
+STATIC
+UINT64
+PMemPerSlot (
+ IN UINT64 CurrentUsage
+ )
+{
+ if (CurrentUsage == 0) {
+ return 0;
+ }
+
+ if (CurrentUsage <= 1024ULL) {
+ return 1024ULL;
+ }
+
+ if (CurrentUsage <= 4096ULL) {
+ return 4096ULL;
+ }
+
+ return CurrentUsage;
+} // PMemPerSlot
+
+STATIC
+VOID
+SetPhyPortResources (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 SubBus,
+ IN INT8 Depth,
+ IN PORT_INFO *CurrentPi,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 Cmd;
+ UINT16 DeltaMem;
+ UINT64 DeltaPMem;
+
+ Cmd = CMD_BUS_MASTER;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, 0x00, 0);
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, SubBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, Cmd);
+
+ DeltaMem = PortInfo->MemBase - CurrentPi->MemBase;
+ if (isLegacyDevice) {
+ if (Depth >= 0 && (DeltaMem < MEM_PER_SLOT)) {
+ PortInfo->MemBase += MEM_PER_SLOT - DeltaMem;
+ }
+ } else {
+ if (DeltaMem < MemPerSlot (DeltaMem)) {
+ PortInfo->MemBase += MemPerSlot (DeltaMem) - DeltaMem;
+ }
+ }
+
+ if (PortInfo->MemBase > CurrentPi->MemBase && (PortInfo->MemBase - 0x10) <= PortInfo->MemLimit) {
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), CurrentPi->MemBase);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), PortInfo->MemBase - 0x10);
+ Cmd |= CMD_BM_MEM;
+ } else {
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), DISBL_MEM32_REG20);
+ PortInfo->MemBase = CurrentPi->MemBase;
+ }
+
+ DeltaPMem = PortInfo->PMemBase64 - CurrentPi->PMemBase64;
+ if (isLegacyDevice) {
+ if ((Depth >= 0) && ((UINTN)DeltaPMem < (UINTN)PMEM_PER_SLOT)) {
+ PortInfo->PMemBase64 += PMEM_PER_SLOT - DeltaPMem;
+ }
+ } else {
+ if (DeltaPMem < PMemPerSlot (DeltaPMem)) {
+ PortInfo->PMemBase64 += PMemPerSlot (DeltaPMem) - DeltaPMem;
+ }
+ }
+
+ if (PortInfo->PMemBase64 > CurrentPi->PMemBase64 && (PortInfo->PMemBase64 - 0x10) <= PortInfo->PMemLimit64) {
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), (UINT16) (CurrentPi->PMemBase64 & 0xFFFF));
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit), (UINT16) ((PortInfo->PMemBase64 - 0x10) & 0xFFFF));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), (UINT32) (CurrentPi->PMemBase64 >> 16));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32), (UINT32) ((PortInfo->PMemBase64 - 0x10) >> 16));
+ Cmd |= CMD_BM_MEM;
+ } else {
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), DISBL_PMEM_REG24);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32), 0);
+ PortInfo->PMemBase64 = CurrentPi->PMemBase64;
+ }
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, Cmd);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, DEF_CACHE_LINE_SIZE);
+} // SetPhyPortResources
+
+STATIC
+UINT32
+SaveSetGetRestoreBar (
+ IN UINTN Bar
+ )
+{
+ UINT32 BarReq;
+ UINT32 OrigBar;
+
+ OrigBar = PciSegmentRead32(Bar); // Save BAR
+ PciSegmentWrite32(Bar, 0xFFFFFFFF); // Set BAR
+ BarReq = PciSegmentRead32(Bar); // Get BAR
+ PciSegmentWrite32(Bar, OrigBar); // Restore BAR
+
+ return BarReq;
+} // SaveSetGetRestoreBar
+
+STATIC
+VOID
+SetIoBar (
+ IN UINTN BAR,
+ IN UINT32 BarReq,
+ IN OUT UINT8 *Cmd,
+ IN OUT IO_REGS *IoReg
+ )
+{
+ UINT16 Alignment;
+ UINT16 Size;
+ UINT16 NewBase;
+
+ Alignment = ~(BarReq & 0xFFFC);
+ Size = Alignment + 1;
+
+ if (IoReg->Base > IoReg->Limit || !Size) {
+ return ;
+
+ }
+
+ NewBase = BAR_ALIGN (IoReg->Base, Alignment);
+ if (NewBase > IoReg->Limit || NewBase + Size - 1 > IoReg->Limit) {
+ return ;
+
+ }
+ PciSegmentWrite16(BAR, NewBase);
+ IoReg->Base = NewBase + Size; // Advance to new position
+ *Cmd |= CMD_BM_IO; // Set Io Space Enable
+} // SetIoBar
+
+STATIC
+VOID
+SetMemBar (
+ IN UINTN BAR,
+ IN UINT32 BarReq,
+ IN OUT UINT8 *Cmd,
+ IN OUT MEM_REGS *MemReg
+ )
+{
+ UINT32 Alignment;
+ UINT32 Size;
+ UINT32 NewBase;
+
+ Alignment = ~(BarReq & 0xFFFFFFF0);
+ Size = Alignment + 1;
+
+ if (MemReg->Base > MemReg->Limit || !Size) {
+ return ;
+
+ }
+
+ NewBase = BAR_ALIGN (MemReg->Base, Alignment);
+ if (NewBase > MemReg->Limit || NewBase + Size - 1 > MemReg->Limit) {
+ return ;
+
+ }
+
+ PciSegmentWrite32(BAR, NewBase);
+ MemReg->Base = NewBase + Size; // Advance to new position
+ *Cmd |= CMD_BM_MEM; // Set Memory Space Enable
+} // SetMemBar
+
+STATIC
+VOID
+SetPMem64Bar (
+ IN UINTN BAR,
+ IN BOOLEAN IsMaxBar,
+ IN UINT32 BarReq,
+ IN OUT UINT8 *Cmd,
+ IN OUT PMEM_REGS *MemReg
+ )
+{
+ UINT32 Alignment;
+ UINT32 Size;
+ UINT64 NewBase;
+
+ Alignment = ~(BarReq & 0xFFFFFFF0);
+ Size = Alignment + 1;
+
+ if (MemReg->Base64 > MemReg->Limit64 || !Size) {
+ return ;
+ }
+
+ NewBase = BAR_ALIGN (MemReg->Base64, Alignment);
+ if (NewBase > MemReg->Limit64 || NewBase + Size - 1 > MemReg->Limit64) {
+ return ;
+ }
+ PciSegmentWrite32(BAR, (UINT32)(NewBase & 0xFFFFFFFF));
+ if (!IsMaxBar) {
+ BAR++;
+ PciSegmentWrite32(BAR, (UINT32)(NewBase >> 32));
+ }
+ MemReg->Base64 = NewBase + Size; // Advance to new position
+ *Cmd |= CMD_BM_MEM; // Set Memory Space Enable
+} // SetPMem64Bar
+
+STATIC
+VOID
+SetDevResources (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 MaxFun, // PCI_MAX_FUNC for devices, 1 for bridge
+ IN UINT8 MaxBar, // PCI_BAR5 for devices, PCI_BAR1 for bridge
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 Fun;
+ UINT8 Reg;
+ UINT32 BarReq;
+ IO_REGS Io;
+ MEM_REGS Mem;
+ PMEM_REGS PMem;
+ UINT8 Cmd;
+
+ Io.Base = PortInfo->IoBase << 8;
+ Io.Limit = (PortInfo->IoLimit << 8) | 0xFF;
+ Mem.Base = PortInfo->MemBase << 16;
+ Mem.Limit = (PortInfo->MemLimit << 16) | 0xFFFF;
+ PMem.Base64 = PortInfo->PMemBase64 << 16;
+ PMem.Limit64 = (PortInfo->PMemLimit64 << 16) | 0xFFFF;
+
+ for (Fun = 0; Fun < MaxFun; ++Fun) {
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Dev, Fun, 0);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, CMD_BUS_MASTER);
+ Cmd = PciSegmentRead8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET);
+ if (0xFFFF == PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET)) {
+ continue;
+
+ }
+
+ for (Reg = PCI_BASE_ADDRESSREG_OFFSET; Reg <= MaxBar; Reg += 4) {
+ BarReq = SaveSetGetRestoreBar(gDeviceBaseAddress + Reg); // Perform BAR sizing
+
+ if (BarReq & BIT0) {
+ //
+ // I/O BAR
+ //
+ SetIoBar (
+ (gDeviceBaseAddress + Reg),
+ BarReq,
+ &Cmd,
+ &Io
+ );
+ continue;
+ }
+
+ if (BarReq & BIT3) {
+ //
+ // P-Memory BAR
+ //
+ SetPMem64Bar ((gDeviceBaseAddress + Reg), MaxBar == Reg, BarReq, &Cmd, &PMem);
+ } else {
+ SetMemBar ((gDeviceBaseAddress + Reg), BarReq, &Cmd, &Mem);
+ }
+
+ if (BIT2 == (BarReq & (BIT2 | BIT1))) {
+ //
+ // Base address is 64 bits wide
+ //
+ Reg += 4;
+ if (!(BarReq & BIT3)) {
+ //
+ // 64-bit memory bar
+ //
+ PciSegmentWrite32 (gDeviceBaseAddress + Reg, 0);
+ }
+ }
+ }
+
+ if (Cmd & BIT1) {
+ //
+ // If device uses I/O and MEM mapping use only MEM mepping
+ //
+ Cmd &= ~BIT0;
+ }
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, Cmd);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, DEF_CACHE_LINE_SIZE);
+ }
+ //
+ // Update PortInfo if any changes
+ //
+ if (Io.Base > ((UINT32) PortInfo->IoBase << 8)) {
+ PortInfo->IoBase = (UINT8) (BAR_ALIGN (Io.Base, 0xFFF) >> 8);
+ }
+
+ if (Mem.Base > ((UINT32) PortInfo->MemBase << 16)) {
+ PortInfo->MemBase = (UINT16) (BAR_ALIGN (Mem.Base, 0xFFFFF) >> 16);
+ }
+
+ if (PMem.Base64 > (PortInfo->PMemBase64 << 16)) {
+ PortInfo->PMemBase64 = (BAR_ALIGN (PMem.Base64, 0xFFFFF) >> 16);
+ }
+} // SetDevResources
+
+STATIC
+VOID
+InitARHRConfigs(
+ IN HR_CONFIG *Hr_Config,
+ IN UINT8 BusNumLimit,
+ IN OUT BRDG_RES_CONFIG* HrResConf
+)
+{
+ UINT8 i,j;
+
+ //
+ // DS port for USB device
+ //
+ HrConfigs[AR_DS_PORT2].DevId.Bus = HrConfigs[HR_US_PORT].DevId.Bus + 1;
+ HrConfigs[AR_DS_PORT2].DevId.Dev = 2;
+ HrConfigs[AR_DS_PORT2].DevId.Fun = 0;
+ HrConfigs[AR_DS_PORT2].PBus = HrConfigs[AR_DS_PORT2].DevId.Bus;
+ HrConfigs[AR_DS_PORT2].SBus = HrConfigs[AR_DS_PORT2].PBus + 1;
+ HrConfigs[AR_DS_PORT2].SubBus = HrConfigs[AR_DS_PORT2].PBus + 1;
+ //
+ // CIO port
+ //
+ HrConfigs[AR_DS_PORT1].DevId.Bus = HrConfigs[HR_US_PORT].DevId.Bus + 1;
+ HrConfigs[AR_DS_PORT1].DevId.Dev = 1;
+ HrConfigs[AR_DS_PORT1].DevId.Fun = 0;
+ HrConfigs[AR_DS_PORT1].PBus = HrConfigs[AR_DS_PORT1].DevId.Bus;
+ HrConfigs[AR_DS_PORT1].SBus = HrConfigs[HR_DS_PORT0].SubBus + 1;
+ HrConfigs[AR_DS_PORT1].SubBus = BusNumLimit;
+
+ switch(Hr_Config->DeviceId)
+ {
+ //
+ // HR with 1 DS and 1 USB
+ //
+ case AR_HR_2C:
+ case AR_HR_LP:
+ case AR_HR_C0_2C:
+ case TR_HR_2C:
+ Hr_Config->MinDSNumber = HrConfigs[AR_DS_PORT1].DevId.Dev;
+ Hr_Config->MaxDSNumber = HrConfigs[AR_DS_PORT2].DevId.Dev;
+ Hr_Config->BridgeLoops = 4;
+ break;
+ //
+ // HR with 2 DS and 1 USB
+ //
+ case AR_HR_4C:
+ case TR_HR_4C:
+ case AR_HR_C0_4C:
+ Hr_Config->MinDSNumber = 1;
+ Hr_Config->MaxDSNumber = 4;
+ Hr_Config->BridgeLoops = 6;
+ for(j = 2, i = Hr_Config->MinDSNumber; j < count(HrConfigs) && i <= Hr_Config->MaxDSNumber; ++j, ++i)
+ {
+ HrConfigs[j].DevId.Bus = HrConfigs[HR_US_PORT].DevId.Bus + 1;
+ HrConfigs[j].DevId.Dev = i;
+ HrConfigs[j].DevId.Fun = 0;
+ HrConfigs[j].PBus = HrConfigs[j].DevId.Bus;
+ HrConfigs[j].Res.Cls = DEF_CACHE_LINE_SIZE;
+ }
+ break;
+ }
+}//InitARHRConfigs
+
+
+STATIC
+VOID
+InitCommonHRConfigs (
+ IN HR_CONFIG *Hr_Config,
+ IN UINT8 BusNumLimit,
+ IN OUT BRDG_RES_CONFIG *HrResConf
+ )
+{
+ UINT8 i;
+
+ UINT8 j;
+ for(i = 0; i < count(HrConfigs); ++i) {
+ HrConfigs[i].IsDSBridge = TRUE;
+ }
+ //
+ // US(HRBus:0:0)
+ //
+ HrConfigs[HR_US_PORT].DevId.Bus = Hr_Config->HRBus;
+ HrConfigs[HR_US_PORT].DevId.Dev = 0;
+ HrConfigs[HR_US_PORT].DevId.Fun = 0;
+ HrConfigs[HR_US_PORT].Res = *HrResConf;
+ HrConfigs[HR_US_PORT].Res.IoBase = 0xF1;
+ HrConfigs[HR_US_PORT].Res.IoLimit = 0x01;
+ HrConfigs[HR_US_PORT].PBus = HrConfigs[HR_US_PORT].DevId.Bus;
+ HrConfigs[HR_US_PORT].SBus = HrConfigs[HR_US_PORT].PBus + 1;
+ HrConfigs[HR_US_PORT].SubBus = BusNumLimit;
+ HrConfigs[HR_US_PORT].IsDSBridge = FALSE;
+
+ //
+ // HIA resides here
+ //
+ HrConfigs[HR_DS_PORT0].DevId.Bus = HrConfigs[HR_US_PORT].DevId.Bus + 1;
+ HrConfigs[HR_DS_PORT0].DevId.Dev = 0;
+ HrConfigs[HR_DS_PORT0].DevId.Fun = 0;
+ HrConfigs[HR_DS_PORT0].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[HR_DS_PORT0].Res.MemBase = HrResConf->MemLimit;
+ HrConfigs[HR_DS_PORT0].Res.MemLimit = HrResConf->MemLimit;
+ HrResConf->MemLimit -= 0x10; //This 1 MB chunk will be used by HIA
+ HrConfigs[HR_DS_PORT0].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[HR_DS_PORT0].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[HR_DS_PORT0].PBus = HrConfigs[HR_DS_PORT0].DevId.Bus;
+ HrConfigs[HR_DS_PORT0].SBus = HrConfigs[HR_DS_PORT0].PBus + 1;
+ HrConfigs[HR_DS_PORT0].SubBus = HrConfigs[HR_DS_PORT0].PBus + 1;
+
+ switch (Hr_Config->DeviceId) {
+ //
+ // Alpine Ridge
+ //
+ case AR_HR_2C:
+ case AR_HR_C0_2C:
+ case AR_HR_LP:
+ case AR_HR_4C:
+ case AR_HR_C0_4C:
+ //
+ // Titan Ridge
+ //
+ case TR_HR_2C:
+ case TR_HR_4C:
+ InitARHRConfigs(Hr_Config, BusNumLimit, HrResConf);
+ break;
+
+ default:
+ //
+ // DS(HRBus+2:3-6:0)
+ //
+ Hr_Config->MinDSNumber = 3;
+ Hr_Config->MaxDSNumber = 6;
+ Hr_Config->BridgeLoops = count (HrConfigs);
+
+ for (j = 2, i = Hr_Config->MinDSNumber; j < count (HrConfigs) && i <= Hr_Config->MaxDSNumber; ++j, ++i) {
+ HrConfigs[j].DevId.Bus = HrConfigs[HR_US_PORT].DevId.Bus + 1;
+ HrConfigs[j].DevId.Dev = i;
+ HrConfigs[j].DevId.Fun = 0;
+ HrConfigs[j].PBus = HrConfigs[j].DevId.Bus;
+ HrConfigs[j].Res.Cls = DEF_CACHE_LINE_SIZE;
+ }
+ }
+} // InitCommonHRConfigs
+
+STATIC
+VOID
+InitHRDSPort_Disable (
+ IN UINT8 id,
+ IN OUT BRDG_CONFIG *BrdgConf
+ )
+{
+ HrConfigs[id].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[id].SBus = BrdgConf->SBus;
+ HrConfigs[id].SubBus = BrdgConf->SBus;
+
+ BrdgConf->SBus++;
+} // InitHRDSPort_Disable
+
+//AR only
+
+STATIC
+VOID
+InitARDSPort_1Port(
+ IN OUT BRDG_CONFIG* BrdgConf
+)
+{
+ UINT16 MemBase = BrdgConf->Res.MemBase & 0xFFF0;
+ UINT64 PMemBase64 = BrdgConf->Res.PMemBase64 & ~0xFULL;
+ UINT8 BusRange = BrdgConf->SubBus - BrdgConf->PBus - 2;
+
+ HrConfigs[AR_DS_PORT1].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[AR_DS_PORT1].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[AR_DS_PORT1].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[AR_DS_PORT1].Res.MemBase = MemBase;
+ HrConfigs[AR_DS_PORT1].Res.MemLimit = BrdgConf->Res.MemLimit - 1;
+ HrConfigs[AR_DS_PORT1].Res.PMemBase64 = PMemBase64;
+ HrConfigs[AR_DS_PORT1].Res.PMemLimit64 = BrdgConf->Res.PMemLimit64;
+ HrConfigs[AR_DS_PORT1].SBus = BrdgConf->SBus;
+ HrConfigs[AR_DS_PORT1].SubBus = BrdgConf->SBus + BusRange;
+
+ BrdgConf->SBus = HrConfigs[AR_DS_PORT1].SubBus + 1;
+
+ HrConfigs[AR_DS_PORT2].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[AR_DS_PORT2].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[AR_DS_PORT2].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[AR_DS_PORT2].Res.MemBase = BrdgConf->Res.MemLimit;
+ HrConfigs[AR_DS_PORT2].Res.MemLimit = BrdgConf->Res.MemLimit;
+ HrConfigs[AR_DS_PORT2].SBus = BrdgConf->SBus;
+ HrConfigs[AR_DS_PORT2].SubBus = BrdgConf->SBus;
+
+ BrdgConf->SBus = HrConfigs[AR_DS_PORT2].SubBus + 1;
+}//InitARDSPort_1Port
+
+STATIC
+VOID
+InitARDSPort_2Port(
+ IN OUT BRDG_CONFIG* BrdgConf
+)
+{
+ UINT16 MemBase = BrdgConf->Res.MemBase & 0xFFF0;
+ UINT64 PMemBase64 = BrdgConf->Res.PMemBase64 & ~0xFULL;
+ UINT8 BusRange = BrdgConf->SubBus - BrdgConf->PBus - 3;
+
+ // Busses are split between ports 1 and 4
+ BusRange /= 2;
+
+ HrConfigs[AR_DS_PORT1].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[AR_DS_PORT1].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[AR_DS_PORT1].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[AR_DS_PORT1].Res.MemBase = MemBase;
+ HrConfigs[AR_DS_PORT1].Res.MemLimit = MemBase + 0x17F0 - 1;
+ HrConfigs[AR_DS_PORT1].Res.PMemBase64 = PMemBase64;
+ HrConfigs[AR_DS_PORT1].Res.PMemLimit64 = PMemBase64 + 0x2000 - 1;
+ HrConfigs[AR_DS_PORT1].SBus = BrdgConf->SBus;
+ HrConfigs[AR_DS_PORT1].SubBus = BrdgConf->SBus + BusRange;
+
+ BrdgConf->SBus = HrConfigs[AR_DS_PORT1].SubBus + 1;
+
+ HrConfigs[AR_DS_PORT2].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[AR_DS_PORT2].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[AR_DS_PORT2].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[AR_DS_PORT2].Res.MemBase = MemBase + 0x17F0;
+ HrConfigs[AR_DS_PORT2].Res.MemLimit = MemBase + 0x1800 - 1;
+ HrConfigs[AR_DS_PORT2].SBus = BrdgConf->SBus;
+ HrConfigs[AR_DS_PORT2].SubBus = BrdgConf->SBus;
+
+ BrdgConf->SBus = HrConfigs[AR_DS_PORT2].SubBus + 1;
+
+
+ HrConfigs[AR_DS_PORT4].Res = NOT_IN_USE_BRIDGE;
+ HrConfigs[AR_DS_PORT4].Res.Cls = DEF_CACHE_LINE_SIZE;
+ HrConfigs[AR_DS_PORT4].Res.Cmd = CMD_BM_MEM;
+ HrConfigs[AR_DS_PORT4].Res.MemBase = MemBase + 0x1800;
+ HrConfigs[AR_DS_PORT4].Res.MemLimit = BrdgConf->Res.MemLimit;
+ HrConfigs[AR_DS_PORT4].Res.PMemBase64 = PMemBase64 + 0x2000;
+ HrConfigs[AR_DS_PORT4].Res.PMemLimit64 = BrdgConf->Res.PMemLimit64;
+ HrConfigs[AR_DS_PORT4].SBus = BrdgConf->SBus;
+ HrConfigs[AR_DS_PORT4].SubBus = BrdgConf->SubBus;
+
+ BrdgConf->SBus = HrConfigs[AR_DS_PORT4].SubBus + 1;
+}//InitARDSPort_2Port
+
+
+STATIC
+BOOLEAN
+CheckLimits (
+ IN BOOLEAN Is2PortDev,
+ IN BRDG_RES_CONFIG *HrResConf,
+ IN UINT8 BusRange
+ )
+{
+ UINT16 MemBase;
+ UINT16 MemLimit;
+ UINT64 PMemBase64;
+ UINT64 PMemLimit64;
+
+ MemBase = HrResConf->MemBase & 0xFFF0;
+ MemLimit = HrResConf->MemLimit & 0xFFF0;
+ PMemBase64 = HrResConf->PMemBase64 & 0xFFF0;
+ PMemLimit64 = HrResConf->PMemLimit64 & 0xFFF0;
+ //
+ // Check memoty alignment
+ //
+ if (MemBase & 0x3FF) {
+ DEBUG((DEBUG_INFO, "M alig\n"));
+ return FALSE;
+ }
+
+ if (PMemBase64 & 0xFFF) {
+ DEBUG((DEBUG_INFO, "PM alig\n"));
+ return FALSE;
+ }
+
+ if (Is2PortDev) {
+ //
+ // Check mem size
+ //
+ if (MemLimit + 0x10 - MemBase < 0x2E00) {
+ DEBUG((DEBUG_INFO, "M size\n"));
+ return FALSE;
+ }
+ //
+ // Check P-mem size
+ //
+ if (PMemLimit64 + 0x10 - PMemBase64 < 0x4A00) {
+ DEBUG((DEBUG_INFO, "PM size\n"));
+ return FALSE;
+ }
+ //
+ // Check bus range
+ //
+ if (BusRange < 106) {
+ DEBUG((DEBUG_INFO, "Bus range\n"));
+ return FALSE;
+ }
+ } else {
+ //
+ // Check mem size
+ //
+ if (MemLimit + 0x10 - MemBase < 0x1600) {
+ DEBUG((DEBUG_INFO, "M size\n"));
+ return FALSE;
+ }
+ //
+ // Check P-mem size
+ //
+ if (PMemLimit64 + 0x10 - PMemBase64 < 0x2200) {
+ DEBUG((DEBUG_INFO, "PM size\n"));
+ return FALSE;
+ }
+ //
+ // Check bus range
+ //
+ if (BusRange < 56) {
+ DEBUG((DEBUG_INFO, "Bus range\n"));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+} // CheckLimits
+
+STATIC
+BOOLEAN
+InitHRResConfigs (
+ IN OUT HR_CONFIG *Hr_Config,
+ IN UINT8 BusNumLimit,
+ IN OUT BRDG_RES_CONFIG*HrResConf
+ )
+{
+ BRDG_CONFIG BrdgConf = { { 0 } };
+
+ InitCommonHRConfigs (Hr_Config, BusNumLimit, HrResConf);
+ BrdgConf.PBus = Hr_Config->HRBus + 2;// Take into account busses
+ BrdgConf.SBus = Hr_Config->HRBus + 3;// for US and DS of HIA
+ BrdgConf.SubBus = BusNumLimit;
+ BrdgConf.Res = *HrResConf;
+ while (TRUE) {
+ switch (Hr_Config->DeviceId) {
+ case AR_HR_4C:
+ case TR_HR_4C:
+ case AR_HR_C0_4C:
+ //
+ // 2 Port host
+ //
+ if (CheckLimits (TRUE, HrResConf, BusNumLimit - Hr_Config->HRBus)) {
+
+
+ InitARDSPort_2Port(&BrdgConf);
+ DEBUG((DEBUG_INFO, "AR2\n"));
+
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ // AR only
+ case AR_HR_2C: // 1 port host
+ case AR_HR_C0_2C:
+ case AR_HR_LP:
+ case TR_HR_2C:
+ DEBUG((DEBUG_INFO, "AR1\n"));
+ InitARDSPort_1Port(&BrdgConf);
+ return TRUE;
+
+ default:
+ InitHRDSPort_Disable (HR_DS_PORT3, &BrdgConf);
+ InitHRDSPort_Disable (HR_DS_PORT4, &BrdgConf);
+ InitHRDSPort_Disable (HR_DS_PORT5, &BrdgConf);
+ InitHRDSPort_Disable (HR_DS_PORT6, &BrdgConf);
+ return FALSE;
+ }
+ }
+} // InitHRResConfigs
+
+STATIC
+BOOLEAN
+InitializeHostRouter (
+ OUT HR_CONFIG *Hr_Config,
+ IN UINTN RpSegment,
+ IN UINTN RpBus,
+ IN UINTN RpDevice,
+ IN UINTN RpFunction
+ )
+{
+ UINT8 BusNumLimit;
+ BRDG_RES_CONFIG HrResConf = { 0 };
+ UINT8 i;
+ BOOLEAN Ret;
+
+ Ret = TRUE;
+
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, 0);
+ Hr_Config->HRBus = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (RpSegment, Hr_Config->HRBus, 0x00, 0x00, 0);
+ Hr_Config->DeviceId = PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+ if (!(IsTbtHostRouter (Hr_Config->DeviceId))) {
+ return FALSE;
+ }
+ TbtSegment = (UINT8)RpSegment;
+
+ HrResConf.Cmd = CMD_BM_MEM;
+ HrResConf.Cls = DEF_CACHE_LINE_SIZE;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (RpSegment, RpBus, RpDevice, RpFunction, 0);
+ HrResConf.IoBase = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
+ HrResConf.IoLimit = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
+ HrResConf.MemBase = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase));
+ HrResConf.MemLimit = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit));
+ HrResConf.PMemBase64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase));
+ HrResConf.PMemLimit64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit));
+ HrResConf.PMemBase64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32))) << 16;
+ HrResConf.PMemLimit64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32))) << 16;
+ BusNumLimit = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+
+ Ret = InitHRResConfigs (Hr_Config, BusNumLimit, &HrResConf);
+
+ for (i = 0; i < Hr_Config->BridgeLoops; ++i) {
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Fun;
+ Bus = HrConfigs[i].DevId.Bus;
+ Dev = HrConfigs[i].DevId.Dev;
+ Fun = HrConfigs[i].DevId.Fun;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, Fun, 0);
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, HrConfigs[i].Res.Cls);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, HrConfigs[i].PBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, HrConfigs[i].SBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, HrConfigs[i].SubBus);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), HrConfigs[i].Res.MemBase);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), HrConfigs[i].Res.MemLimit);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), (UINT16) (HrConfigs[i].Res.PMemBase64 & 0xFFFF));
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit), (UINT16) (HrConfigs[i].Res.PMemLimit64 & 0xFFFF));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), (UINT32) (HrConfigs[i].Res.PMemBase64 >> 16));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32), (UINT32) (HrConfigs[i].Res.PMemLimit64 >> 16));
+ PciSegmentWrite8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase), HrConfigs[i].Res.IoBase);
+ PciSegmentWrite8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit), HrConfigs[i].Res.IoLimit);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16), 0x00000000);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, HrConfigs[i].Res.Cmd);
+ }
+ if (Hr_Config->DeviceId == AR_HR_2C || Hr_Config->DeviceId == AR_HR_4C || Hr_Config->DeviceId == AR_HR_LP) {
+ for (i = 0; i < Hr_Config->BridgeLoops; ++i) {
+ if(HrConfigs[i].IsDSBridge) {
+ UnsetVesc(HrConfigs[i].DevId.Bus, HrConfigs[i].DevId.Dev, HrConfigs[i].DevId.Fun);
+ }
+ }
+ }
+
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,(Hr_Config->HRBus + 2), 0x00, 0x00, 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX0 * 4), HrConfigs[HR_DS_PORT0].Res.MemLimit << 16);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX1 * 4), (HrConfigs[HR_DS_PORT0].Res.MemLimit + 0x4) << 16);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, DEF_CACHE_LINE_SIZE);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, CMD_BM_MEM);
+ return Ret;
+} // InitializeHostRouter
+STATIC
+UINT8
+ConfigureSlot (
+ IN UINT8 Bus,
+ IN UINT8 MAX_DEVICE,
+ IN INT8 Depth,
+ IN BOOLEAN ArPcie,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 Device;
+ UINT8 SBus;
+ UINT8 UsedBusNumbers;
+ UINT8 RetBusNum;
+ PORT_INFO CurrentSlot;
+
+ RetBusNum = 0;
+
+ for (Device = 0; Device < MAX_DEVICE; Device++) {
+ //
+ // Continue if device is absent
+ //
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, Device, 0x00, 0);
+ if (0xFFFF == PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET)) {
+ continue;
+
+ }
+
+ if (P2P_BRIDGE != PciSegmentRead16 (gDeviceBaseAddress + (PCI_CLASSCODE_OFFSET + 1))) {
+ SetDevResources (
+ Bus,
+ Device,
+ PCI_MAX_FUNC,
+ PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX5 * 4),
+ PortInfo
+ );
+ continue;
+ }
+ //
+ // Else Bridge
+ //
+ CopyMem (&CurrentSlot, PortInfo, sizeof (PORT_INFO));
+
+ ++RetBusNum; // UP Bridge
+ SBus = Bus + RetBusNum; // DS Bridge
+
+ if (SBus + 1 >= PortInfo->BusNumLimit) {
+ continue;
+
+ }
+
+ SetDevResources (Bus, Device, 1, PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX1 * 4), PortInfo);
+
+ //
+ // Init UP Bridge to reach DS Bridge
+ //
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Bus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, SBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, PortInfo->BusNumLimit);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, CMD_BM_MEM);
+
+ if(ArPcie) {
+ UnsetVesc(Bus, Device, 0x00);
+ }
+
+ UsedBusNumbers = ConfigureSlot(SBus, PCI_MAX_DEVICE + 1, -1, FALSE, PortInfo);
+ RetBusNum += UsedBusNumbers;
+
+ SetPhyPortResources (
+ Bus,
+ Device,
+ SBus + UsedBusNumbers,
+ Depth,
+ &CurrentSlot,
+ PortInfo
+ );
+ }
+ //
+ // for (Device = 0; Device <= PCI_MAX_DEVICE; Device++)
+ //
+ return RetBusNum;
+} // ConfigureSlot
+
+STATIC
+VOID
+SetCioPortResources (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 SBus,
+ IN UINT8 SubBus,
+ IN PORT_INFO *portInfoBeforeChange,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 Cmd;
+ Cmd = CMD_BUS_MASTER;
+
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, 0x00, 0);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Bus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, SBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, SubBus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, Cmd);
+
+ if (PortInfo->IoBase <= PortInfo->IoLimit) {
+ PciSegmentWrite8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase), PortInfo->IoBase);
+ PciSegmentWrite8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit), PortInfo->IoLimit);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBaseUpper16), 0x00000000);
+ Cmd |= CMD_BM_IO;
+ } else {
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase), DISBL_IO_REG1C);
+ }
+
+ if (PortInfo->MemBase <= PortInfo->MemLimit) {
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), PortInfo->MemBase);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit), PortInfo->MemLimit);
+ Cmd |= CMD_BM_MEM;
+ } else {
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), DISBL_MEM32_REG20);
+ }
+
+ if (PortInfo->PMemBase64 <= PortInfo->PMemLimit64) {
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), (UINT16) (PortInfo->PMemBase64 & 0xFFFF));
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit), (UINT16) (PortInfo->PMemLimit64 & 0xFFFF));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), (UINT32) (PortInfo->PMemBase64 >> 16));
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32), (UINT32) (PortInfo->PMemLimit64 >> 16));
+ Cmd |= CMD_BM_MEM;
+ } else {
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), DISBL_PMEM_REG24);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32), 0);
+ }
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, Cmd);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, DEF_CACHE_LINE_SIZE);
+} // SetCioPortResources
+
+STATIC
+VOID
+SetSlotsAsUnused (
+ IN UINT8 Bus,
+ IN UINT8 MaxSlotNum,
+ IN UINT8 CioSlot,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 Slot;
+ for (Slot = MaxSlotNum; Slot > CioSlot; --Slot) {
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Slot, 0x00, 0);
+ if (0xFFFF == PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET)) {
+ continue;
+ }
+
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_CACHELINE_SIZE_OFFSET, DEF_CACHE_LINE_SIZE);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, Bus);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, PortInfo->BusNumLimit);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, PortInfo->BusNumLimit);
+ PciSegmentWrite16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase), DISBL_IO_REG1C);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase), DISBL_MEM32_REG20);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase), DISBL_PMEM_REG24);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, CMD_BUS_MASTER);
+ PortInfo->BusNumLimit--;
+ }
+} // SetSlotsAsUnused
+
+STATIC
+UINT16
+FindVendorSpecificHeader(
+ IN UINT8 Bus
+)
+{
+ PCI_EXP_EXT_HDR *ExtHdr;
+ UINT32 ExtHdrValue;
+ UINT16 ExtendedRegister;
+
+ ExtHdr = (PCI_EXP_EXT_HDR*) &ExtHdrValue;
+ ExtendedRegister = 0x100;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, 0x00, 0x00, 0);
+ while (ExtendedRegister) {
+ ExtHdrValue = PciSegmentRead32 (gDeviceBaseAddress + ExtendedRegister);
+ if (ExtHdr->CapabilityId == 0xFFFF) {
+ return 0x0000; // No Vendor-Specific Extended Capability header
+ }
+
+ if (PCI_EXPRESS_EXTENDED_CAPABILITY_VENDOR_SPECIFIC_ID == ExtHdr->CapabilityId) {
+ return ExtendedRegister;
+ }
+
+ ExtendedRegister = (UINT16) ExtHdr->NextCapabilityOffset;
+ }
+ return 0x0000; // No Vendor-Specific Extended Capability header
+}
+
+STATIC
+UINT8
+FindSsid_SsvidHeader (
+ IN UINT8 Bus
+ )
+{
+ UINT8 CapHeaderId;
+ UINT8 CapHeaderOffset;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, 0x00, 0x00, 0);
+ CapHeaderOffset = PciSegmentRead8 (gDeviceBaseAddress + PCI_CAPBILITY_POINTER_OFFSET);
+
+ while (CapHeaderOffset != 0) {
+ CapHeaderId = PciSegmentRead8 (gDeviceBaseAddress + CapHeaderOffset);
+
+ if (CapHeaderId == PCIE_CAP_ID_SSID_SSVID) {
+ return CapHeaderOffset;
+ }
+
+ CapHeaderOffset = PciSegmentRead8 (gDeviceBaseAddress + CapHeaderOffset + 1);
+ }
+
+ DEBUG((DEBUG_INFO, "SID0\n"));
+ return 0;
+} // FindSsid_SsvidHeader
+
+STATIC
+BOOLEAN
+GetCioSlotByDevId (
+ IN UINT8 Bus,
+ OUT UINT8 *CioSlot,
+ OUT UINT8 *MaxSlotNum,
+ OUT BOOLEAN *ArPcie
+ )
+{
+ UINT16 VSECRegister;
+ BRDG_CIO_MAP_REG BridgMap;
+ UINT32 BitScanRes;
+ UINT16 DevId;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, Bus, 0x00, 0x00, 0);
+ DevId = PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+
+ //
+ // Init out params in case device is not recognised
+ //
+ *CioSlot = 4;
+ *MaxSlotNum = 7;
+ *ArPcie = FALSE;
+
+ switch (DevId) {
+ //
+ // For known device IDs
+ //
+ case 0x1578:
+ *ArPcie = TRUE;
+ }
+
+ switch (DevId) {
+ //
+ // For known device IDs
+ //
+ case 0x1513:
+ case 0x151A:
+ case 0x151B:
+ case 0x1547:
+ case 0x1548:
+ return TRUE; // Just return
+ case 0x1549:
+ return FALSE; // Just return
+ }
+
+ VSECRegister = FindVendorSpecificHeader(Bus);
+ if (!VSECRegister) {
+ return TRUE; // Just return
+ }
+ //
+ // Go to Bridge/CIO map register
+ //
+ VSECRegister += 0x18;
+ BridgMap.AB_REG = PciSegmentRead32(gDeviceBaseAddress + VSECRegister);
+ //
+ // Check for range
+ //
+ if (BridgMap.Bits.NumOfDSPorts < 1 || BridgMap.Bits.NumOfDSPorts > 27) {
+ return TRUE;
+ //
+ // Not a valid register
+ //
+ }
+ //
+ // Set OUT params
+ //
+ *MaxSlotNum = (UINT8) BridgMap.Bits.NumOfDSPorts;
+
+#ifdef _MSC_VER
+ if(!_BitScanForward(&BitScanRes, BridgMap.Bits.CioPortMap)) { // No DS bridge which is CIO port
+ return FALSE;
+ }
+#else
+#ifdef __GNUC__
+ if (BridgMap.Bits.CioPortMap == 0) {
+ return FALSE;
+ }
+ BitScanRes = __builtin_ctz (BridgMap.Bits.CioPortMap);
+#else
+#error Unsupported Compiler
+#endif
+#endif
+
+ *CioSlot = (UINT8)BitScanRes;
+ return TRUE;
+} // GetCioSlotByDevId
+
+#define TBT_LEGACY_SUB_SYS_ID 0x11112222
+
+STATIC
+BOOLEAN
+IsLegacyDevice (
+ IN UINT8 Bus
+ )
+{
+ UINT32 Sid;
+ UINT8 SidRegister;
+ UINT16 DevId;
+
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, 0x00, 0x00, 0);
+ DevId = PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+ switch (DevId) {
+ //
+ // For known device IDs
+ //
+ case 0x1513:
+ case 0x151A:
+ case 0x151B:
+ DEBUG((DEBUG_INFO, "Legacy "));
+ DEBUG((DEBUG_INFO, "DevId = %d\n",DevId));
+ return TRUE;
+ //
+ // Legacy device by Device Id
+ //
+ }
+
+ SidRegister = FindSsid_SsvidHeader(Bus);
+
+ if (!SidRegister) {
+ return TRUE; // May be absent for legacy devices
+ }
+ //
+ // Go to register
+ //
+ SidRegister += 0x4;
+ Sid = PciSegmentRead32(gDeviceBaseAddress + SidRegister);
+ DEBUG((DEBUG_INFO, "SID"));
+ DEBUG((DEBUG_INFO, " = %d\n", Sid));
+
+return TBT_LEGACY_SUB_SYS_ID == Sid || 0 == Sid;
+} // IsLegacyDevice
+
+STATIC
+VOID
+UnsetVescEp(
+ IN UINT8 Bus,
+ IN UINT8 MaxSlotNum
+ )
+{
+ UINT8 i;
+
+ for (i = 0; i <= MaxSlotNum; ++i)
+ {
+ UnsetVesc(Bus, i, 0);
+ }
+}// Unset_VESC_REG2_EP
+
+STATIC
+BOOLEAN
+ConfigureEP (
+ IN INT8 Depth,
+ IN OUT UINT8 *Bus,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ UINT8 SBus;
+ UINT8 CioSlot;
+ UINT8 MaxSlotNum;
+ BOOLEAN ArPcie;
+ UINT8 MaxPHYSlots;
+ UINT8 UsedBusNumbers;
+ UINT8 cmd;
+ BOOLEAN CioSlotPresent;
+ BOOLEAN Continue;
+ PORT_INFO PortInfoOrg;
+ UINT8 CioBus;
+
+ CioSlot = 4;
+ MaxSlotNum = 7;
+ CopyMem (&PortInfoOrg, PortInfo, sizeof (PORT_INFO));
+
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, *Bus, 0x00, 0x00, 0);
+ cmd = PciSegmentRead8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET);
+ // AR ONLY
+ // Endpoint on CIO slot, but not a bridge device
+ if (P2P_BRIDGE != PciSegmentRead16 (gDeviceBaseAddress + (PCI_CLASSCODE_OFFSET + 1))) {
+ DEBUG((DEBUG_INFO, "UEP\n"));
+ // Check whether EP already configured by examining CMD register
+ if(cmd & CMD_BUS_MASTER) // Yes, no need to touch this EP
+ {
+ DEBUG((DEBUG_INFO, "BMF\n"));
+ return FALSE;
+ }
+ // Configure it as regular PCIe device
+ ConfigureSlot(*Bus, PCI_MAX_DEVICE + 1, -1, FALSE, PortInfo);
+
+ return FALSE;
+ }
+
+ //
+ // Based on Device ID assign Cio slot and max number of PHY slots to scan
+ //
+ CioSlotPresent = GetCioSlotByDevId(*Bus, &CioSlot, &MaxSlotNum, &ArPcie);
+ MaxPHYSlots = MaxSlotNum;
+ //
+ // Check whether EP already configured by examining CMD register
+ //
+
+ if (cmd & CMD_BUS_MASTER) {
+ //
+ // Yes no need to touch this EP, just move to next one in chain
+ //
+ CioBus = *Bus + 1;
+ if(ArPcie){
+ UnsetVescEp(CioBus, MaxSlotNum);
+ }
+ if (!CioSlotPresent) {
+ //
+ // Cio slot is not present in EP, just return FALSE
+ //
+ DEBUG((DEBUG_INFO, "BMF\n"));
+ return FALSE;
+ }
+ //
+ // Take all resources from Cio slot and return
+ //
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,CioBus, CioSlot, 0x00, 0);
+ PortInfo->BusNumLimit = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ PortInfo->IoBase = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase));
+ PortInfo->IoLimit = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit));
+ PortInfo->MemBase = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase));
+ PortInfo->MemLimit = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit));
+ PortInfo->PMemBase64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase)) & 0xFFF0;
+ PortInfo->PMemLimit64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit)) & 0xFFF0;
+ PortInfo->PMemBase64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32))) << 16;
+ PortInfo->PMemLimit64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32))) << 16;
+ PortInfo->PMemLimit64 |= 0xF;
+ //
+ // Jump to next EP
+ //
+ *Bus = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ //
+ // Should we continue?
+ //
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,*Bus, 0x00, 0x00, 0);
+ Continue = 0xFFFF != PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+ return Continue;
+ }
+ //
+ // Set is legacy dvice
+ //
+ isLegacyDevice = IsLegacyDevice (*Bus);
+
+ SetCioPortResources (
+ *Bus,
+ 0, // Assign all available resources to US port of EP
+ *Bus + 1,
+ PortInfo->BusNumLimit,
+ 0,
+ PortInfo
+ );
+
+ SBus = *Bus + 1;// Jump to DS port
+
+ if (CioSlotPresent) {
+ MaxPHYSlots = CioSlot;
+ }
+
+ UsedBusNumbers = ConfigureSlot(SBus, MaxPHYSlots, Depth, ArPcie, PortInfo);
+ if (!CioSlotPresent) {
+ return FALSE;
+ //
+ // Stop resource assignment on this chain
+ //
+ }
+ //
+ // Set rest of slots us unused
+ //
+ SetSlotsAsUnused (SBus, MaxSlotNum, CioSlot, PortInfo);
+
+ SetCioPortResources (
+ SBus,
+ CioSlot,
+ SBus + UsedBusNumbers + 1,
+ PortInfo->BusNumLimit,
+ &PortInfoOrg,
+ PortInfo
+ );
+ *Bus = SBus + UsedBusNumbers + 1;// Go to next EP
+ if(ArPcie) {
+ UnsetVesc(SBus, CioSlot, 0x00);
+ }
+ if (*Bus > PortInfo->BusNumLimit - 2) {
+ //
+ // In case of bus numbers are exhausted stop enumeration
+ //
+ return FALSE;
+ }
+ //
+ // Check whether we should continue on this chain
+ //
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,*Bus, 0x00, 0x00, 0);
+ Continue = 0xFFFF != PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+ return Continue;
+} // ConfigureEP
+
+STATIC
+VOID
+GetPortResources (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Fun,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, Fun, 0);
+ PortInfo->BusNumLimit = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ PortInfo->IoBase = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoBase)) & 0xF0;
+ PortInfo->IoLimit = PciSegmentRead8 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.IoLimit)) & 0xF0;
+ PortInfo->MemBase = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryBase)) & 0xFFF0;
+ PortInfo->MemLimit = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.MemoryLimit)) & 0xFFF0;
+ PortInfo->PMemBase64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryBase)) & 0xFFF0;
+ PortInfo->PMemLimit64 = PciSegmentRead16 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableMemoryLimit)) & 0xFFF0;
+ PortInfo->PMemBase64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32))) << 16;
+ PortInfo->PMemLimit64 |= (UINT64)(PciSegmentRead32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableLimitUpper32))) << 16;
+ PortInfo->IoLimit |= 0xF;
+ PortInfo->MemLimit |= 0xF;
+ PortInfo->PMemLimit64 |= 0xF;
+} // GetPortResources
+
+STATIC
+VOID
+ConfigurePort (
+ IN UINT8 Bus,
+ IN UINT8 Dev,
+ IN UINT8 Fun,
+ IN OUT PORT_INFO *PortInfo
+ )
+{
+ INT8 i;
+ UINT8 USBusNum;
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, Fun, 0);
+ USBusNum = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment, USBusNum, 0x00, 0x00, 0);
+ if (0xFFFF == PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET)) {
+ //
+ // Nothing to do if TBT device is not connected
+ //
+ return ;
+ }
+
+ GetPortResources(Bus, Dev, Fun, PortInfo);// Take reserved resources from DS port
+ //
+ // Assign resources to EPs
+ //
+ for (i = 0; i < MAX_TBT_DEPTH; ++i) {
+ PortInfo->ConfedEP++;
+ if (!ConfigureEP (i, &USBusNum, PortInfo)) {
+ return ;
+ }
+ }
+} // ConfigurePort
+
+VOID
+ThunderboltCallback (
+ IN UINT8 Type
+ )
+{
+ PORT_INFO PortInfoOrg = { 0 };
+ HR_CONFIG HrConfig = { 0 };
+ UINT8 i;
+ UINTN Segment = 0;
+ UINTN Bus = 0;
+ UINTN Device;
+ UINTN Function;
+
+ DEBUG((DEBUG_INFO, "ThunderboltCallback.Entry\n"));
+
+ DEBUG((DEBUG_INFO, "PortInfo Initialization\n"));
+ PortInfoInit (&PortInfoOrg);
+ if(Type == DTBT_CONTROLLER) {
+ if (gCurrentDiscreteTbtRootPort == 0) {
+ DEBUG((DEBUG_ERROR, "Invalid RP Input\n"));
+ return;
+ }
+ GetDTbtRpDevFun(gCurrentDiscreteTbtRootPortType, gCurrentDiscreteTbtRootPort - 1, &Device, &Function);
+ DEBUG((DEBUG_INFO, "InitializeHostRouter. \n"));
+ if (!InitializeHostRouter (&HrConfig, Segment, Bus, Device, Function)) {
+ return ;
+ }
+ //
+ // Configure DS ports
+ //
+ for (i = HrConfig.MinDSNumber; i <= HrConfig.MaxDSNumber; ++i) {
+ DEBUG((DEBUG_INFO, "ConfigurePort. \n"));
+ ConfigurePort (HrConfig.HRBus + 1, i,0, &PortInfoOrg);
+ }
+
+ DEBUG((DEBUG_INFO, "EndOfThunderboltCallback.\n"));
+ EndOfThunderboltCallback (Segment, Bus, Device, Function);
+
+ }
+ DEBUG((DEBUG_INFO, "ThunderboltCallback.Exit\n"));
+} // ThunderboltCallback
+
+VOID
+DisablePCIDevicesAndBridges (
+ IN UINT8 MinBus,
+ IN UINT8 MaxBus
+ )
+{
+ UINT8 Bus;
+ UINT8 Dev;
+ UINT8 Fun;
+ UINT8 RegVal;
+ //
+ // Disable PCI device First, and then Disable PCI Bridge
+ //
+ for (Bus = MaxBus; Bus > MinBus; --Bus) {
+ for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
+ for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, Fun, 0);
+ if (INVALID_PCI_DEVICE == PciSegmentRead32 (gDeviceBaseAddress + PCI_VENDOR_ID_OFFSET)) {
+ if (Fun == 0) {
+ break;
+
+ }
+
+ continue;
+ }
+
+ RegVal = PciSegmentRead8 (gDeviceBaseAddress + PCI_HEADER_TYPE_OFFSET);
+ if (HEADER_TYPE_DEVICE == (RegVal & 1)) {
+ //
+ // ******** Disable PCI Device ********
+ // BIT0 I/O Space Enabled BIT1 Memory Space Enabled
+ // BIT2 Bus Master Enabled BIT4 Memory Write and Invalidation Enable
+ //
+ PciSegmentAnd8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, (UINT8)~(BIT0 | BIT1 | BIT2 | BIT4));
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX0 * 4), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX1 * 4), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX2 * 4), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX3 * 4), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX4 * 4), 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + PCI_BASE_ADDRESSREG_OFFSET + (PCI_BAR_IDX5 * 4), 0);
+ }
+ }
+ }
+ }
+ //
+ // now no more PCI dev on another side of PCI Bridge can safty disable PCI Bridge
+ //
+ for (Bus = MaxBus; Bus > MinBus; --Bus) {
+ for (Dev = 0; Dev <= PCI_MAX_DEVICE; ++Dev) {
+ for (Fun = 0; Fun <= PCI_MAX_FUNC; ++Fun) {
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (TbtSegment,Bus, Dev, Fun, 0);
+ if (INVALID_PCI_DEVICE == PciSegmentRead32 (gDeviceBaseAddress + PCI_VENDOR_ID_OFFSET)) {
+ if (Fun == 0) {
+ break;
+ }
+
+ continue;
+ }
+
+ RegVal = PciSegmentRead8 (gDeviceBaseAddress + PCI_HEADER_TYPE_OFFSET);
+ if (HEADER_TYPE_PCI_TO_PCI_BRIDGE == (RegVal & BIT0)) {
+ PciSegmentAnd8 (gDeviceBaseAddress + PCI_COMMAND_OFFSET, (UINT8)~(BIT0 | BIT1 | BIT2 | BIT4));
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, 0);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET, 0);
+ PciSegmentWrite8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET, 0);
+ PciSegmentWrite32 (gDeviceBaseAddress + OFFSET_OF (PCI_TYPE01, Bridge.PrefetchableBaseUpper32), 0);
+ }
+ } // for ( Fun .. )
+ } // for ( Dev ... )
+ } // for ( Bus ... )
+} // DisablePCIDevicesAndBridges
+
+VOID
+TbtDisablePCIDevicesAndBridges (
+ IN UINT8 Type
+ )
+{
+ UINTN Segment = 0;
+ UINTN Bus = 0;
+ UINTN Device;
+ UINTN Function;
+ UINT8 MinBus;
+ UINT8 MaxBus;
+ UINT16 DeviceId;
+
+ MinBus = 1;
+ if(Type == DTBT_CONTROLLER) {
+ //
+ // for(Dev = 0; Dev < 8; ++Dev)
+ // {
+ // PciOr8(PCI_LIB_ADDRESS(2, Dev, 0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET), 0x40);
+ // gBS->Stall(2000); // 2msec
+ // PciAnd8(PCI_LIB_ADDRESS(2, Dev, 0, PCI_BRIDGE_CONTROL_REGISTER_OFFSET), 0xBF);
+ // }
+ // gBS->Stall(200 * 1000); // 200 msec
+ //
+ if (gCurrentDiscreteTbtRootPort == 0) {
+ DEBUG((DEBUG_ERROR, "Invalid RP Input\n"));
+ return;
+ }
+ GetDTbtRpDevFun(gCurrentDiscreteTbtRootPortType, gCurrentDiscreteTbtRootPort - 1, &Device, &Function);
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, Bus, Device, Function, 0);
+ MinBus = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SECONDARY_BUS_REGISTER_OFFSET);
+ MaxBus = PciSegmentRead8 (gDeviceBaseAddress + PCI_BRIDGE_SUBORDINATE_BUS_REGISTER_OFFSET);
+ gDeviceBaseAddress = PCI_SEGMENT_LIB_ADDRESS (Segment, MinBus, 0x00, 0x00, 0);
+ DeviceId = PciSegmentRead16 (gDeviceBaseAddress + PCI_DEVICE_ID_OFFSET);
+ if (!(IsTbtHostRouter (DeviceId))) {
+ return;
+ }
+ TbtSegment = (UINT8)Segment;
+ MinBus++;
+ //
+ // @todo : Move this out when we dont have Loop for ITBT
+ //
+ DisablePCIDevicesAndBridges(MinBus, MaxBus);
+
+ }
+} // DisablePCIDevicesAndBridges
+
+
diff --git a/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.h b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.h
new file mode 100644
index 0000000000..22f6aeeb7f
--- /dev/null
+++ b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmiHandler.h
@@ -0,0 +1,185 @@
+/**@file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef _TBT_SMI_HANDLER_H_
+#define _TBT_SMI_HANDLER_H_
+
+#include <Library/TbtCommonLib.h>
+#include <Library/IoLib.h>
+#include <IndustryStandard/Pci.h>
+
+#ifdef PROGRESS_CODE
+#undef PROGRESS_CODE
+#endif
+
+#define MAX_TBT_DEPTH 6
+
+#define P2P_BRIDGE (((PCI_CLASS_BRIDGE) << 8) | (PCI_CLASS_BRIDGE_P2P))
+
+#define BAR_ALIGN(v, a) ((((v) - 1) | (a)) + 1)
+
+#define CMD_BUS_MASTER BIT2
+#define CMD_BM_IO (CMD_BUS_MASTER | BIT0)
+#define CMD_BM_MEM (CMD_BUS_MASTER | BIT1)
+#define CMD_BM_MEM_IO (CMD_BUS_MASTER | BIT1 | BIT0)
+
+#define DEF_CACHE_LINE_SIZE 0x20
+#define DEF_RES_IO_PER_DEV 4
+#define DEF_RES_MEM_PER_DEV 32
+#define DEF_RES_PMEM_PER_DEV 32
+
+#define DOCK_BUSSES 8
+
+#define DISBL_IO_REG1C 0x01F1
+#define DISBL_MEM32_REG20 0x0000FFF0
+#define DISBL_PMEM_REG24 0x0001FFF1
+
+#define count(x) (sizeof (x) / sizeof ((x)[0]))
+
+#define PCIE_CAP_ID_SSID_SSVID 0x0D
+#define INVALID_PCI_DEVICE 0xFFFFFFFF
+#define PCI_TBT_VESC_REG2 0x510
+
+typedef struct _PortInfo {
+ UINT8 IoBase;
+ UINT8 IoLimit;
+ UINT16 MemBase;
+ UINT16 MemLimit;
+ UINT64 PMemBase64;
+ UINT64 PMemLimit64;
+ UINT8 BusNumLimit;
+ UINT8 ConfedEP;
+} PORT_INFO;
+
+typedef struct _MEM_REGS {
+ UINT32 Base;
+ UINT32 Limit;
+} MEM_REGS;
+
+typedef struct _PMEM_REGS {
+ UINT64 Base64;
+ UINT64 Limit64;
+} PMEM_REGS;
+
+typedef struct _IO_REGS {
+ UINT16 Base;
+ UINT16 Limit;
+} IO_REGS;
+
+typedef struct _BRDG_RES_CONFIG {
+ UINT8 Cmd;
+ UINT8 Cls;
+ UINT8 IoBase;
+ UINT8 IoLimit;
+ UINT16 MemBase;
+ UINT16 MemLimit;
+ UINT64 PMemBase64;
+ UINT64 PMemLimit64;
+} BRDG_RES_CONFIG;
+
+typedef struct _BRDG_CONFIG {
+ DEV_ID DevId;
+ UINT8 PBus;
+ UINT8 SBus;
+ UINT8 SubBus;
+ BOOLEAN IsDSBridge;
+ BRDG_RES_CONFIG Res;
+} BRDG_CONFIG;
+
+enum {
+ HR_US_PORT,
+ HR_DS_PORT0,
+ HR_DS_PORT3,
+ HR_DS_PORT4,
+ HR_DS_PORT5,
+ HR_DS_PORT6,
+ MAX_CFG_PORTS
+};
+
+enum {
+ HR_DS_PORT1 = HR_DS_PORT3
+};
+
+//
+// Alpine Ridge
+//
+enum {
+ AR_DS_PORT1 = HR_DS_PORT3,
+ AR_DS_PORT2,
+ AR_DS_PORT3,
+ AR_DS_PORT4
+};
+
+typedef struct _HR_CONFIG {
+ UINT16 DeviceId;
+ UINT8 HRBus;
+ UINT8 MinDSNumber;
+ UINT8 MaxDSNumber;
+ UINT8 BridgeLoops;
+} HR_CONFIG;
+
+STATIC const BRDG_RES_CONFIG NOT_IN_USE_BRIDGE = {
+ CMD_BUS_MASTER,
+ 0,
+ DISBL_IO_REG1C & 0xFF,
+ DISBL_IO_REG1C >> 8,
+ DISBL_MEM32_REG20 & 0xFFFF,
+ DISBL_MEM32_REG20 >> 16,
+ DISBL_PMEM_REG24 & 0xFFFF,
+ DISBL_PMEM_REG24 >> 16
+};
+
+typedef union _BRDG_CIO_MAP_REG {
+ UINT32 AB_REG;
+ struct {
+ UINT32 NumOfDSPorts : 5;
+ UINT32 CioPortMap : 27;
+ } Bits;
+} BRDG_CIO_MAP_REG;
+
+//
+// Functions
+//
+VOID
+ThunderboltCallback (
+ IN UINT8 Type
+ );
+
+VOID
+TbtDisablePCIDevicesAndBridges (
+ IN UINT8 Type
+ );
+
+VOID
+EndOfThunderboltCallback(
+ IN UINTN RpSegment,
+ IN UINTN RpBus,
+ IN UINTN RpDevice,
+ IN UINTN RpFunction
+);
+
+VOID
+ConfigureTbtAspm(
+ IN UINT8 Type,
+ IN UINT16 Aspm
+);
+
+UINT8
+PcieFindCapId (
+ IN UINT8 Segment,
+ IN UINT8 Bus,
+ IN UINT8 Device,
+ IN UINT8 Function,
+ IN UINT8 CapId
+ );
+
+#endif
diff --git a/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.c b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.c
new file mode 100644
index 0000000000..f2abfb0db9
--- /dev/null
+++ b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.c
@@ -0,0 +1,1771 @@
+/** @file
+
+Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// 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
+} \ No newline at end of file
diff --git a/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.inf b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.inf
new file mode 100644
index 0000000000..31ecb9767a
--- /dev/null
+++ b/Platform/Intel/KabylakeOpenBoardPkg/Features/Tbt/TbtInit/Smm/TbtSmm.inf
@@ -0,0 +1,83 @@
+### @file
+# Component information file for the ThunderBolt Smm module.
+#
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are licensed and made available under
+# the terms and conditions of the BSD License which accompanies this distribution.
+# The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+###
+
+[Defines]
+ INF_VERSION = 0x00010017
+ BASE_NAME = TbtSmm
+ FILE_GUID = 5BDCD685-D80A-42E6-9867-A84CCE7F828E
+ VERSION_STRING = 1.0
+ MODULE_TYPE = DXE_SMM_DRIVER
+ PI_SPECIFICATION_VERSION = 1.10
+ ENTRY_POINT = TbtSmmEntryPoint
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ IoLib
+ PciExpressLib
+ HobLib
+ ReportStatusCodeLib
+ PciSegmentLib
+ UefiLib
+ SmmServicesTableLib
+ GpioLib
+ PchInfoLib
+ TbtCommonLib
+ PchPmcLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MinPlatformPkg/MinPlatformPkg.dec
+ KabylakeOpenBoardPkg/OpenBoardPkg.dec
+ KabylakeSiliconPkg/SiPkg.dec
+
+[Pcd]
+ gBoardModuleTokenSpaceGuid.PcdSwSmiDTbtEnumerate ## CONSUMES
+ gSiPkgTokenSpaceGuid.PcdPciExpressRegionLength ## CONSUMES
+
+[FixedPcd]
+ gSiPkgTokenSpaceGuid.PcdAcpiBaseAddress ## CONSUMES
+
+[Sources]
+ TbtSmiHandler.h
+ TbtSmiHandler.c
+ TbtSmm.c
+
+[Protocols]
+ gTbtNvsAreaProtocolGuid ## CONSUMES
+ gEfiSmmSxDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmSwDispatch2ProtocolGuid ## CONSUMES
+ gEfiSmmVariableProtocolGuid ## CONSUMES
+ gDxeTbtPolicyProtocolGuid
+
+[Guids]
+ gTbtInfoHobGuid ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress ## CONSUMES
+
+[Depex]
+ gEfiSmmBase2ProtocolGuid AND
+ gEfiSmmSxDispatch2ProtocolGuid AND
+ gEfiSmmSwDispatch2ProtocolGuid AND
+ gEfiGlobalNvsAreaProtocolGuid AND
+ gEfiVariableWriteArchProtocolGuid AND
+ gEfiVariableArchProtocolGuid AND
+ gEfiSmmVariableProtocolGuid