/** @file Routines for Rst remapping Copyright (c) 2017, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include /** 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; }