/** @file
|
Routines for Rst remapping
|
|
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
**/
|
|
#include <Library/RstPrivateLib.h>
|
#include <PchPcieStorageDetectHob.h>
|
|
/**
|
Checks whether device on given Root Port is remap capable
|
|
@param[in] RpNumber Root Port Number
|
@param[in] TempPciBus Temporary Pci Bus
|
|
@retval UINT8 Device Programming Interface
|
**/
|
UINT8
|
RstGetProgInterfaceForRemapDevice (
|
IN UINT32 RpNumber,
|
IN UINT32 TempPciBus
|
)
|
{
|
UINTN RpDevice;
|
UINTN RpFunction;
|
UINT8 BusNumber;
|
UINTN EpBase;
|
UINT8 PiInterface;
|
UINTN RpBase;
|
UINT8 ClassCode;
|
UINT8 SubClassCode;
|
|
|
DEBUG ((DEBUG_INFO, "Detect storage device on Rp: %d\n", RpNumber));
|
|
GetPchPcieRpDevFun (RpNumber, &RpDevice, &RpFunction);
|
BusNumber = DEFAULT_PCI_BUS_NUMBER_PCH;
|
PiInterface = RST_PCIE_STORAGE_INTERFACE_NONE;
|
RpBase = MmPciBase (BusNumber, (UINT32) RpDevice, (UINT32) RpFunction);
|
|
if (MmioRead16 (RpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
DEBUG((DEBUG_INFO, "RstGetProgInterfaceForRemapDevices: RootPort does not exists Rp = %d\n", RpNumber));
|
|
return PiInterface;
|
}
|
|
//
|
// Assign Temporary Bus Number
|
//
|
MmioAndThenOr32 (
|
RpBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET,
|
(UINT32) ~B_PCI_BRIDGE_BNUM_SBBN_SCBN,
|
((UINT32) (TempPciBus << 8)) | ((UINT32) (TempPciBus << 16))
|
);
|
|
//
|
// A config write is required in order for the device to re-capture the Bus number,
|
// according to PCI Express Base Specification, 2.2.6.2
|
// Write to a read-only register VendorID to not cause any side effects.
|
//
|
EpBase = MmPciBase (TempPciBus, 0, 0);
|
MmioWrite16 (EpBase + PCI_VENDOR_ID_OFFSET, 0);
|
|
//
|
// Read Vendor Id to check if device exists
|
// if not clear bus number and return RST_PCIE_STORAGE_INTERFACE_NONE
|
//
|
if (MmioRead16 (EpBase + PCI_VENDOR_ID_OFFSET) == 0xFFFF) {
|
MmioAnd32 (RpBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, (UINT32) ~B_PCI_BRIDGE_BNUM_SBBN_SCBN);
|
return PiInterface;
|
}
|
|
ClassCode = MmioRead8 (EpBase + R_PCI_BCC_OFFSET);
|
SubClassCode = MmioRead8 (EpBase + R_PCI_SCC_OFFSET);
|
PiInterface = MmioRead8 (EpBase + R_PCI_PI_OFFSET);
|
|
if ( ClassCode == PCI_CLASS_MASS_STORAGE) {
|
DEBUG ((DEBUG_INFO, "RstGetProgInterfaceForRemapDevice: ClassCode = %X, SubClassCode = %X, PiInterface = %X\n", ClassCode, SubClassCode, PiInterface));
|
|
if (SubClassCode == PCI_CLASS_MASS_STORAGE_AHCI) {
|
if (PiInterface == RST_PCIE_STORAGE_INTERFACE_AHCI) {
|
DEBUG ((DEBUG_INFO, "RstGetProgInterfaceForRemapDevice: AHCI Card found on Rp: %d\n", RpNumber));
|
|
}
|
} else if (SubClassCode == PCI_CLASS_MASS_STORAGE_NVME) {
|
if (PiInterface == RST_PCIE_STORAGE_INTERFACE_NVME) {
|
DEBUG ((DEBUG_INFO, "RstGetProgInterfaceForRemapDevice: NVMe Card found on Rp: %d\n", RpNumber));
|
|
}
|
} else if (SubClassCode == PCI_CLASS_MASS_STORAGE_RAID) {
|
DEBUG ((DEBUG_INFO, "RstGetProgInterfaceForRemapDevice: RAID Card found on Rp: %d\n", RpNumber));
|
|
PiInterface = RST_PCIE_STORAGE_INTERFACE_NVME;
|
}
|
}
|
//
|
// Clear temporary bus number
|
//
|
MmioAnd32 (RpBase + PCI_BRIDGE_PRIMARY_BUS_REGISTER_OFFSET, (UINT32) ~B_PCI_BRIDGE_BNUM_SBBN_SCBN);
|
|
return PiInterface;
|
|
}
|
|
/**
|
Check the lane occupied by certain root port according to the root port number and configuration strap
|
Return 8-bit bitmap where each bit represents the lane number (e.g.: return 00000011b means the root port owns 2 lane)
|
|
@param[in] RootPortNum Root Port Number
|
|
@retval UINT8 Lane Occupied by the Root Port (bitmap)
|
**/
|
UINT8
|
RstGetRpLaneOccupyMask (
|
IN UINT32 RootPortNum
|
)
|
{
|
EFI_STATUS Status;
|
UINT32 CtrlNum;
|
UINT32 CtrlFirstRpNum;
|
UINT32 Data32;
|
UINT8 LaneOccupied;
|
|
LaneOccupied = 0;
|
|
CtrlNum = RootPortNum / PCH_PCIE_CONTROLLER_PORTS;
|
CtrlFirstRpNum = CtrlNum * PCH_PCIE_CONTROLLER_PORTS;
|
|
//
|
// Read the Root Port Configuration Straps for the link width, and return LaneOccupied by the Root Port accordingly
|
//
|
Status = PchSbiRpPciRead32 (CtrlFirstRpNum, R_PCH_PCIE_STRPFUSECFG, &Data32);
|
ASSERT_EFI_ERROR (Status);
|
|
switch ((Data32 & B_PCH_PCIE_STRPFUSECFG_RPC) >> N_PCH_PCIE_STRPFUSECFG_RPC) {
|
case V_PCH_PCIE_STRPFUSECFG_RPC_4:
|
if (RootPortNum % 4 == 0) {
|
LaneOccupied = (BIT3|BIT2|BIT1|BIT0);
|
}
|
break;
|
case V_PCH_PCIE_STRPFUSECFG_RPC_2_2:
|
if ((RootPortNum % 2 == 0)) {
|
LaneOccupied = (BIT1|BIT0);
|
}
|
break;
|
case V_PCH_PCIE_STRPFUSECFG_RPC_2_1_1:
|
if (RootPortNum % 4 == 0) {
|
LaneOccupied = (BIT1|BIT0);
|
} else if (RootPortNum % 4 != 1) {
|
LaneOccupied = BIT0;
|
}
|
break;
|
case V_PCH_PCIE_STRPFUSECFG_RPC_1_1_1_1:
|
LaneOccupied = BIT0;
|
break;
|
default:
|
break;
|
}
|
|
return LaneOccupied;
|
}
|
|
/**
|
Checks PCH generation and returns SATA's GCR.PLS bit number according to root port number with a PCIe storage device
|
connected to.
|
|
@param[in] RootPortNum Root port number which PCIe storage device is connected to
|
|
@retval UINT32 Number of GCR.PLS bit representing root port
|
**/
|
UINT32
|
RstPlsBitNumber (
|
IN UINT32 RootPortNum
|
)
|
{
|
if ((GetPchGeneration () == KblPch) && (RstGetCycleRouterNumber (RootPortNum) == RST_PCIE_STORAGE_CR_2)) {
|
return RootPortNum - 2 * PCH_PCIE_CONTROLLER_PORTS;
|
} else {
|
return RootPortNum;
|
}
|
}
|
|
/**
|
Checks if device with given PCI config space address is Intel's Stony Beach.
|
|
@param[in] EndPointPciBase Address of device's PCI config space
|
|
@retval BOOLEAN TRUE if device is Intel's Stony Beach, FALSE othrwise
|
**/
|
BOOLEAN
|
RstIsStonyBeach (
|
IN UINTN EndPointPciBase
|
)
|
{
|
UINT16 DeviceVendorId;
|
UINT16 DeviceDeviceId;
|
|
DeviceVendorId = MmioRead16 (EndPointPciBase + PCI_VENDOR_ID_OFFSET);
|
DeviceDeviceId = MmioRead16 (EndPointPciBase + PCI_DEVICE_ID_OFFSET);
|
|
if (DeviceVendorId == RST_STONY_BEACH_VENDOR_ID && DeviceDeviceId == RST_STONY_BEACH_DEVICE_ID) {
|
return TRUE;
|
}
|
|
return FALSE;
|
}
|
|
|