/** @file
Configures the remapping for PCH Intel RST PCie Storage
In order to use this feature, Intel RST Driver is required
Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent
**/
#include "PchInit.h"
#include
#include
//
// Variables below indicate the memory range to be allocated to the PCIe storage device BAR usage when it is HIDDEN,
// thus it does not overlapped with the SGREG_BAR from the host perspective
//
#define RST_PCIE_STORAGE_MEMORY_START_RANGE PCH_PCR_BASE_ADDRESS
#define RST_PCIE_STORAGE_MEMORY_END_RANGE (PCH_PCR_BASE_ADDRESS + PCH_PCR_MMIO_SIZE - 1)
#define PCI_CARD_PM_CAP_ID 0x01
#define PCI_CARD_MSIX_CAP_ID 0x11
#define PCI_CARD_SATA_CAP_ID 0x12
#define PCI_CARD_BAR_TOTAL 6
#define PCI_CARD_LINK_SPEED_GEN1_GEN2 0
#define PCI_CARD_LINK_SPEED_GEN3 1
#define PCI_CARD_LINK_WIDTH_1 0
#define PCI_CARD_LINK_WIDTH_2 1
#define PCI_CARD_LINK_WIDTH_4 2
#define PCI_CARD_REVISION 0x08
#define PCI_CARD_BASE_ADDR0 0x10
#define PCI_CARD_BASE_ADDR1 0x14
#define PCI_CARD_BASE_ADDR5 0x24
GLOBAL_REMOVE_IF_UNREFERENCED PCH_RST_PCIE_STORAGE_DETECTION mRstPcieStorageDetection [PCH_MAX_RST_PCIE_STORAGE_CR];
UINT32 PchRstPcieStorageCurrentMemoryRange = RST_PCIE_STORAGE_MEMORY_START_RANGE;
/**
Function to perform dump for PCH_RST_PCIE_STORAGE_DETECTION
@param[in] Index Index for RST PCIe Storage Cycle Router Instance
@retval None
**/
VOID
PchRstPcieStorageRemappingDump (
IN UINTN Index
)
{
DEBUG_CODE_BEGIN ();
DEBUG ((DEBUG_INFO, "PchRstPcieStorageRemappingDump() Started\n"));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].SupportRstPcieStoragRemapping = %x\n", Index, mRstPcieStorageDetection[Index].SupportRstPcieStoragRemapping));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].RootPortNum = %x\n", Index, mRstPcieStorageDetection[Index].RootPortNum));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].RootPortLane = %x\n", Index, mRstPcieStorageDetection[Index].RootPortLane));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].DeviceInterface = %x\n", Index, mRstPcieStorageDetection[Index].DeviceInterface));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].IsMsixSupported = %x\n", Index, mRstPcieStorageDetection[Index].IsMsixSupported));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].MsixStartingVector = %x\n", Index, mRstPcieStorageDetection[Index].MsixStartingVector));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].MsixEndingVector = %x\n", Index, mRstPcieStorageDetection[Index].MsixEndingVector));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointBarSize = %x\n", Index, mRstPcieStorageDetection[Index].EndPointBarSize));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixTableBar = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBar));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixTableBarValue = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixTableBarValue));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixPbaBar = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBar));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointUniqueMsixPbaBarValue = %x\n", Index, mRstPcieStorageDetection[Index].EndPointUniqueMsixPbaBarValue));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointBcc = %x\n", Index, mRstPcieStorageDetection[Index].EndPointBcc));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointScc = %x\n", Index, mRstPcieStorageDetection[Index].EndPointScc));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].EndPointPi = %x\n", Index, mRstPcieStorageDetection[Index].EndPointPi));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.PmCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PmCapPtr));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.PcieCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.PcieCapPtr));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.L1ssCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.L1ssCapPtr));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointL1ssControl2 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl2));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointL1ssControl1 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointL1ssControl1));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.LtrCapPtr = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.LtrCapPtr));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointLtrData = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLtrData));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointLctlData16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointLctlData16));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointDctlData16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctlData16));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.EndpointDctl2Data16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.EndpointDctl2Data16));
DEBUG ((DEBUG_INFO, "mRstPcieStorageDetection[%d].PchRstPcieStorageSaveRestore.RootPortDctl2Data16 = %x\n", Index, mRstPcieStorageDetection[Index].PchRstPcieStorageSaveRestore.RootPortDctl2Data16));
DEBUG ((DEBUG_INFO, "PchRstPcieStorageRemappingDump() Ended\n"));
DEBUG_CODE_END ();
}
/**
Perform memory space allocation or free memory pool for AHCI BAR
@param[in] Operation True: Perform memory space allocation for AHCI BAR
False: Perform memory pool free for AHCI BAR
@param[in,out] MemBaseAddress The base memory address used by AHCI BAR
**/
VOID
AbarMemorySpaceOperation (
IN BOOLEAN Operation,
IN OUT EFI_PHYSICAL_ADDRESS *MemBaseAddress
)
{
EFI_STATUS Status;
EFI_PHYSICAL_ADDRESS BaseAddress;
UINTN AhciBarAlignment;
UINTN AhciBarLength;
//
// Assign a 512k size memory space to the ABAR when NVM Remapping is enabled
//
AhciBarAlignment = N_PCH_SATA_AHCI_BAR_ALIGNMENT_512K; // 2^19: 512K Alignment
AhciBarLength = V_PCH_SATA_AHCI_BAR_LENGTH_512K; // 512K Length
if (Operation == TRUE) {
///
/// If MemBaseAddress is not allocated yet, allocate the AHCI BAR
///
if ((PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchBottomUp) || (PcdGet8 (PcdEfiGcdAllocateType) == EfiGcdAllocateMaxAddressSearchTopDown)) {
BaseAddress = 0x0ffffffff;
}
Status = gDS->AllocateMemorySpace (
PcdGet8 (PcdEfiGcdAllocateType),
EfiGcdMemoryTypeMemoryMappedIo,
AhciBarAlignment,
AhciBarLength,
&BaseAddress,
mImageHandle,
NULL
);
ASSERT_EFI_ERROR (Status);
*MemBaseAddress = BaseAddress;
} else {
///
/// Else, free the GCD pool
///
gDS->FreeMemorySpace (
*MemBaseAddress,
AhciBarLength
);
}
}
/**
Function to perform memory allocation for PCIe storage device that support unique BAR
@param[in] BarSize The BAR size required for memory allocation
@param[in,out] AllocAddr The Address that been allocated by this function
@retval EFI_SUCCESS The function completed successfully
@retval EFI_OUT_OF_RESOURCES Memory or storage is not enough
**/
EFI_STATUS
PchRstPcieStorageMemAllocation (
IN UINT32 BarSize,
IN OUT UINT32 *AllocAddr
)
{
if ((PchRstPcieStorageCurrentMemoryRange + BarSize) > RST_PCIE_STORAGE_MEMORY_END_RANGE) {
return EFI_OUT_OF_RESOURCES;
}
if ((PchRstPcieStorageCurrentMemoryRange & (BarSize - 1)) != 0) {
*AllocAddr = (PchRstPcieStorageCurrentMemoryRange + BarSize) & ~(BarSize-1);
} else {
*AllocAddr = PchRstPcieStorageCurrentMemoryRange;
}
PchRstPcieStorageCurrentMemoryRange = *AllocAddr + BarSize;
return EFI_SUCCESS;
}
/**
Check and detect PCIe storage device per policies, and if existed, indicate if it should be subjected for remapping
Populate the mRstPcieStorageDetection structure along with it for later usages
@param[in, out] RemappingRequired Boolean value with TRUE indicates that RST PCIe Storage Remapping is required
@param[in] TempPciBusMin The temporary minimum Bus number for root port initialization
@param[in] SataRegBase SATA Register Base
@retval None
**/
VOID
DetectPcieStorageDevices (
IN OUT BOOLEAN *RemappingRequired,
IN UINT8 TempPciBusMin,
IN UINTN SataRegBase
)
{
EFI_STATUS Status;
PCH_SERIES PchSeries;
UINT8 DeviceInterface;
UINT32 PortNum;
UINTN PciRootPortRegBase;
UINTN RpDev;
UINTN RpFunc;
UINT8 RootPortLane;
PCIE_STORAGE_INFO_HOB *PcieStorageInfoHob;
VOID *Hob;
UINT32 CycleRouterNum;
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: DetectPcieStorageDevices Started\n"));
Hob = NULL;
Hob = GetFirstGuidHob (&gPchPcieStorageDetectHobGuid);
if (Hob != NULL) {
PcieStorageInfoHob = (PCIE_STORAGE_INFO_HOB *) GET_GUID_HOB_DATA (Hob);
} else {
return;
}
PchSeries = GetPchSeries ();
for (PortNum = 0; PortNum < GetPchMaxPciePortNum (); PortNum++) {
//
// Check Info hob for Cycle Router avaliable
// skip to next root port if Cr is not avaliable
//
CycleRouterNum = PcieStorageInfoHob->RstCycleRouterMap[PortNum / 4];
if (CycleRouterNum == RST_PCIE_STORAGE_CR_INVALID) {
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: cycle router not avaliable on Rp = %d\n", PortNum));
continue;
}
Status = GetPchPcieRpDevFun (PortNum, &RpDev, &RpFunc);
ASSERT_EFI_ERROR (Status);
PciRootPortRegBase = MmPciBase (DEFAULT_PCI_BUS_NUMBER_PCH, (UINT32) RpDev, (UINT32) RpFunc);
RootPortLane = RstGetRpLaneOccupyMask (PortNum);
if (RootPortLane == 0) {
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: root port lane is not occupied\n"));
continue;
}
///
/// Check if the RST PCIe Storage Cycle Router is enabled, continue to the next root port in the next x4 lane if it is disabled
///
if (mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].Enable == 0) {
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: RST PCIe Storage Cycle Router %d is disabled\n", CycleRouterNum));
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: Proceed to root port in the next x4 lane (@ port %d)\n", PortNum + 1));
PortNum += 3 - (PortNum % 4);
continue;
}
///
/// Check if the current root port is matching selected root port from policy, continue to next port if they are not matched
///
if ((mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].RstPcieStoragePort != 0) &&
(mPchConfigHob->Sata.RstPcieStorageRemap[CycleRouterNum].RstPcieStoragePort != PortNum + 1)) {
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: root port %d not matched with selected root port, proceed to next port\n", PortNum + 1));
continue;
}
// Read device programming interface from info hob
// if no device is present continue
if (PcieStorageInfoHob->PcieStorageLinkWidth[PortNum]) {
DeviceInterface = PcieStorageInfoHob->PcieStorageProgrammingInterface[PortNum];
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: Device present on RP# %d, PiInterface = %d\n", PortNum + 1, DeviceInterface));
} else {
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: RP# %d no device present\n", PortNum + 1));
continue;
}
///
/// Update the remapping detail for detected PCIe storage device, and move to the root port in the next x4 lane
///
if ((DeviceInterface != RST_PCIE_STORAGE_INTERFACE_NONE)) {
mRstPcieStorageDetection[CycleRouterNum].SupportRstPcieStoragRemapping = TRUE;
mRstPcieStorageDetection[CycleRouterNum].RootPortNum = (UINT8) PortNum;
mRstPcieStorageDetection[CycleRouterNum].RootPortLane = RootPortLane;
mRstPcieStorageDetection[CycleRouterNum].DeviceInterface = DeviceInterface;
PortNum += 3 - (PortNum % 4);
*RemappingRequired = TRUE;
} else {
continue;
}
}
DEBUG ((DEBUG_INFO, "DetectPcieStorageDevices: DetectPcieStorageDevices() Ended\n"));
}