From: Vu Nguyen <vungu...@os.amperecomputing.com> This patch updates the following: - Check End Point configuration space is accessible or not before getting its capability. - Add new function to check PCIe card is present or not. - Set CRS (Configuration Request Retry Status) to follow PCIe specifications.
Signed-off-by: Nhi Pham <n...@os.amperecomputing.com> --- .../Library/Ac01PcieLib/PcieCore.h | 8 +- .../Library/Ac01PcieLib/PcieCore.c | 150 ++++++++++++++---- 2 files changed, 128 insertions(+), 30 deletions(-) diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h index 1db8a68b3df4..a18fff7dbb75 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.h @@ -1,6 +1,6 @@ /** @file - Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR> + Copyright (c) 2020 - 2023, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent @@ -39,6 +39,7 @@ #define PIPE_CLOCK_TIMEOUT 20000 // 20,000 us #define LTSSM_TRANSITION_TIMEOUT 100000 // 100 ms in total #define EP_LINKUP_TIMEOUT (10 * 1000) // 10ms +#define EP_LINKUP_EXTRA_TIMEOUT (500 * 1000) // 500ms #define LINK_WAIT_INTERVAL_US 50 #define PFA_MODE_ENABLE 0 @@ -80,6 +81,7 @@ #define AC01_PCIE_CORE_IRQ_ENABLE_REG 0x30 #define AC01_PCIE_CORE_IRQ_EVENT_STAT_REG 0x38 #define AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG 0x3C +#define AC01_PCIE_CORE_BUS_CONTROL_REG 0x40 #define AC01_PCIE_CORE_RESET_REG 0xC000 #define AC01_PCIE_CORE_CLOCK_REG 0xC004 #define AC01_PCIE_CORE_MEM_READY_REG 0xC104 @@ -87,6 +89,7 @@ // AC01_PCIE_CORE_LINK_CTRL_REG #define LTSSMENB_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1)) +#define LTSSMENB_GET(dst) ((dst) & (BIT0)) #define HOLD_LINK_TRAINING 0 #define START_LINK_TRAINING 1 #define DEVICETYPE_SET(dst, src) (((dst) & ~0xF0) | (((UINT32) (src) << 4) & 0xF0)) @@ -120,6 +123,9 @@ // AC01_PCIE_CORE_BLOCK_EVENT_STAT_REG #define LINKUP_MASK 0x1 +// AC01_PCIE_CORE_BUS_CONTROL_REG +#define BUS_CTL_CFG_UR_MASK 0x8 + // AC01_PCIE_CORE_RESET_REG #define DWC_PCIE_SET(dst, src) (((dst) & ~0x1) | (((UINT32) (src)) & 0x1)) #define RESET_MASK 0x1 diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c index ad648b1b9efd..855b094f7948 100644 --- a/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c +++ b/Silicon/Ampere/AmpereAltraPkg/Library/Ac01PcieLib/PcieCore.c @@ -1,6 +1,6 @@ /** @file - Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR> + Copyright (c) 2020 - 2023, Ampere Computing LLC. All rights reserved.<BR> SPDX-License-Identifier: BSD-2-Clause-Patent @@ -10,8 +10,10 @@ #include <Guid/PlatformInfoHob.h> #include <Guid/RootComplexInfoHob.h> +#include <IndustryStandard/Pci.h> #include <Library/ArmGenericTimerCounterLib.h> #include <Library/BaseLib.h> +#include <Library/BaseMemoryLib.h> #include <Library/BoardPcieLib.h> #include <Library/DebugLib.h> #include <Library/HobLib.h> @@ -22,6 +24,25 @@ #include "PcieCore.h" +VOID +EnableDbiAccess ( + AC01_ROOT_COMPLEX *RootComplex, + UINT32 PcieIndex, + BOOLEAN EnableDbi + ); + +BOOLEAN +EndpointCfgReady ( + IN AC01_ROOT_COMPLEX *RootComplex, + IN UINT8 PcieIndex, + IN UINT32 Timeout + ); + +BOOLEAN +PcieLinkUpCheck ( + IN AC01_PCIE_CONTROLLER *Pcie + ); + /** Return the next extended capability base address @@ -41,14 +62,38 @@ GetCapabilityBase ( { BOOLEAN IsExtCapability = FALSE; PHYSICAL_ADDRESS CfgBase; + PHYSICAL_ADDRESS Ret = 0; + PHYSICAL_ADDRESS RootComplexCfgBase; UINT32 CapabilityId; UINT32 NextCapabilityPtr; UINT32 Val; + UINT32 RestoreVal; - if (IsRootComplex) { - CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT); - } else { + RootComplexCfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << DEV_SHIFT); + if (!IsRootComplex) { + // Allow programming to config space + EnableDbiAccess (RootComplex, PcieIndex, TRUE); + + Val = MmioRead32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG); + RestoreVal = Val; + Val = SUB_BUS_SET (Val, DEFAULT_SUB_BUS); + Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum); + Val = PRIM_BUS_SET (Val, 0x0); + MmioWrite32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, Val); CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT); + + if (!EndpointCfgReady (RootComplex, PcieIndex, EP_LINKUP_TIMEOUT)) { + goto _CheckCapEnd; + } + } else { + CfgBase = RootComplexCfgBase; + } + + // Check if device provide capability + Val = MmioRead32 (CfgBase + PCI_COMMAND_OFFSET); + Val = GET_HIGH_16_BITS (Val); /* Status */ + if (!(Val & EFI_PCI_STATUS_CAPABILITY)) { + goto _CheckCapEnd; } Val = MmioRead32 (CfgBase + TYPE1_CAP_PTR_REG); @@ -58,7 +103,8 @@ GetCapabilityBase ( while (1) { if ((NextCapabilityPtr & WORD_ALIGN_MASK) != 0) { // Not alignment, just return - return 0; + Ret = 0; + goto _CheckCapEnd; } Val = MmioRead32 (CfgBase + NextCapabilityPtr); @@ -69,7 +115,8 @@ GetCapabilityBase ( } if (CapabilityId == ExtCapabilityId) { - return (CfgBase + NextCapabilityPtr); + Ret = (CfgBase + NextCapabilityPtr); + goto _CheckCapEnd; } if (NextCapabilityPtr < EXT_CAPABILITY_START_BASE) { @@ -84,9 +131,20 @@ GetCapabilityBase ( } if ((NextCapabilityPtr == 0) && IsExtCapability) { - return 0; + Ret = 0; + goto _CheckCapEnd; } } + +_CheckCapEnd: + if (!IsRootComplex) { + MmioWrite32 (RootComplexCfgBase + SEC_LAT_TIMER_SUB_BUS_SEC_BUS_PRI_BUS_REG, RestoreVal); + + // Disable programming to config space + EnableDbiAccess (RootComplex, PcieIndex, FALSE); + } + + return Ret; } /** @@ -677,6 +735,14 @@ Ac01PcieCoreSetupRC ( // Hold link training StartLinkTraining (RootComplex, PcieIndex, FALSE); + // Clear BUSCTRL.CfgUrMask to set CRS (Configuration Request Retry Status) to 0xFFFF.FFFF + // rather than 0xFFFF.0001 as per PCIe specification requirement. Otherwise, this causes + // device drivers respond incorrectly on timeout due to long device operations. + TargetAddress = CsrBase + AC01_PCIE_CORE_BUS_CONTROL_REG; + Val = MmioRead32 (TargetAddress); + Val &= ~BUS_CTL_CFG_UR_MASK; + MmioWrite32 (TargetAddress, Val); + if (!EnableAxiPipeClock (RootComplex, PcieIndex)) { DEBUG ((DEBUG_ERROR, "- Pcie[%d] - PIPE clock is not stable\n", PcieIndex)); return RETURN_DEVICE_ERROR; @@ -1067,21 +1133,20 @@ Ac01PFACommand ( return Ret; } -UINT32 +BOOLEAN EndpointCfgReady ( - IN AC01_ROOT_COMPLEX *RootComplex, - IN UINT8 PcieIndex + IN AC01_ROOT_COMPLEX *RootComplex, + IN UINT8 PcieIndex, + IN UINT32 TimeOut ) { PHYSICAL_ADDRESS CfgBase; - UINT32 TimeOut; UINT32 Val; CfgBase = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT); // Loop read CfgBase value until got valid value or - // reach to timeout EP_LINKUP_TIMEOUT (or more depend on card) - TimeOut = EP_LINKUP_TIMEOUT; + // reach to Timeout (or more depend on card) do { Val = MmioRead32 (CfgBase); if (Val != 0xFFFF0001 && Val != 0xFFFFFFFF) { @@ -1112,6 +1177,7 @@ Ac01PcieCoreGetEndpointInfo ( ) { PHYSICAL_ADDRESS CfgBase; + PHYSICAL_ADDRESS EpCfgAddr; PHYSICAL_ADDRESS PcieCapBase; PHYSICAL_ADDRESS SecLatTimerAddr; PHYSICAL_ADDRESS TargetAddress; @@ -1133,8 +1199,23 @@ Ac01PcieCoreGetEndpointInfo ( Val = SEC_BUS_SET (Val, RootComplex->Pcie[PcieIndex].DevNum); Val = PRIM_BUS_SET (Val, DEFAULT_PRIM_BUS); MmioWrite32 (SecLatTimerAddr, Val); + EpCfgAddr = RootComplex->MmcfgBase + (RootComplex->Pcie[PcieIndex].DevNum << BUS_SHIFT); - if (EndpointCfgReady (RootComplex, PcieIndex)) { + if (!EndpointCfgReady (RootComplex, PcieIndex, EP_LINKUP_EXTRA_TIMEOUT)) { + goto Exit; + } + + Val = MmioRead32 (EpCfgAddr); + // Check whether EP config space is accessible or not + if (Val == 0xFFFFFFFF) { + *EpMaxWidth = 0; // Invalid Width + *EpMaxGen = 0; // Invalid Speed + DEBUG ((DEBUG_ERROR, "PCIE%d.%d Cannot access EP config space!\n", RootComplex->ID, PcieIndex)); + } else if (Val == 0xFFFF0001) { + *EpMaxWidth = 0; // Invalid Width + *EpMaxGen = 0; // Invalid Speed + DEBUG ((DEBUG_ERROR, "PCIE%d.%d EP config space still not ready to access, need poll more time!!!\n", RootComplex->ID, PcieIndex)); + } else { PcieCapBase = GetCapabilityBase (RootComplex, PcieIndex, FALSE, PCIE_CAPABILITY_ID); if (PcieCapBase == 0) { DEBUG (( @@ -1164,6 +1245,7 @@ Ac01PcieCoreGetEndpointInfo ( } } +Exit: // Restore value in order to not affect enumeration process MmioWrite32 (SecLatTimerAddr, RestoreVal); @@ -1280,6 +1362,30 @@ Ac01PcieCoreQoSLinkCheckRecovery ( return LINK_CHECK_SUCCESS; } +BOOLEAN +Ac01PcieCoreCheckCardPresent ( + IN AC01_PCIE_CONTROLLER *PcieController + ) +{ + EFI_PHYSICAL_ADDRESS TargetAddress; + UINT32 ControlValue; + + ControlValue = 0; + + TargetAddress = PcieController->CsrBase; + + ControlValue = MmioRead32 (TargetAddress + AC01_PCIE_CORE_LINK_CTRL_REG); + + if (0 == LTSSMENB_GET (ControlValue)) { + // + // LTSSMENB is clear to 0x00 by Hardware -> link partner is connected. + // + return TRUE; + } + + return FALSE; +} + VOID Ac01PcieCoreUpdateLink ( IN AC01_ROOT_COMPLEX *RootComplex, @@ -1314,30 +1420,16 @@ Ac01PcieCoreUpdateLink ( Pcie->LinkUp = TRUE; Val = MmioRead32 (CfgBase + PCIE_CAPABILITY_BASE + LINK_CONTROL_LINK_STATUS_REG); - DEBUG (( - DEBUG_INFO, - "%a Socket%d RootComplex%d RP%d NEGO_LINK_WIDTH: 0x%x LINK_SPEED: 0x%x\n", - __FUNCTION__, - RootComplex->Socket, - RootComplex->ID, - PcieIndex, - CAP_NEGO_LINK_WIDTH_GET (Val), - CAP_LINK_SPEED_GET (Val) - )); - // Doing link checking and recovery if needed Ac01PcieCoreQoSLinkCheckRecovery (RootComplex, PcieIndex); - // Link timeout after 32ms - SetLinkTimeout (RootComplex, PcieIndex, 32); - // Un-mask Completion Timeout DisableCompletionTimeOut (RootComplex, PcieIndex, FALSE); } else { - *IsNextRoundNeeded = FALSE; FailedPciePtr[*FailedPcieCount] = PcieIndex; *FailedPcieCount += 1; + *IsNextRoundNeeded = !(*IsNextRoundNeeded) ? Ac01PcieCoreCheckCardPresent (Pcie) : TRUE; } } } -- 2.25.1 -=-=-=-=-=-=-=-=-=-=-=- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#102091): https://edk2.groups.io/g/devel/message/102091 Mute This Topic: https://groups.io/mt/97922251/21656 Group Owner: devel+ow...@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com] -=-=-=-=-=-=-=-=-=-=-=-