Message ID | 1491046162-53797-5-git-send-email-chenhui.sun@linaro.org |
---|---|
State | Superseded |
Headers | show |
Series | D03/D05 platforms bug fix | expand |
On Sat, Apr 01, 2017 at 07:29:09PM +0800, Chenhui Sun wrote: > In some cases, the PCIe device may close part of lanes in > config state of LTSSM, the hip06 RC should reconfig lane number > and try to linkup again. > > Contributed-under: TianoCore Contribution Agreement 1.0 > Signed-off-by: Chenhui Sun <sunchenhui@huawei.com> > Signed-off-by: Heyi Guo <heyi.guo@linaro.org> > Signed-off-by: Yi Li <phoenix.liyi@huawei.com> Reviewed-by: Leif Lindholm <leif.lindholm@linaro.org> > --- > .../Hi1610/Drivers/PcieInit1610/PcieInitLib.c | 136 ++++++++++++++++++++- > Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h | 5 + > 2 files changed, 139 insertions(+), 2 deletions(-) > > diff --git a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c > index 8ec094f..bd91ca4 100644 > --- a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c > +++ b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c > @@ -39,6 +39,14 @@ extern PCIE_DRIVER_CFG gastr_pcie_driver_cfg; > extern PCIE_IATU gastr_pcie_iatu_cfg; > extern PCIE_IATU_VA mPcieIatuTable; > > +EFI_STATUS > +EFIAPI > +PciePortInit ( > + IN UINT32 soctype, > + IN UINT32 HostBridgeNum, > + IN PCIE_DRIVER_CFG *PcieCfg > + ); > + > VOID PcieRegWrite(UINT32 Port, UINTN Offset, UINT32 Value) > { > RegWrite((UINT64)mPcieIntCfg.RegResource[Port] + Offset, Value); > @@ -149,8 +157,131 @@ VOID PcieRxValidCtrl(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port, BOOLEAN > } > } > } > +/* > + * The ltssm register is assigned in an asynchronous way, the value > + * of register may not right in metastable state. > + * Read the register twice to get stable value. > + */ > +VOID PcieGetLtssmValue ( > + IN UINT32 HostBridgeNum, > + IN UINT32 Port, > + IN UINT32 *Value > + ) > +{ > + UINT32 ValueA; > + UINT32 ValueB = 0; > + UINT32 Count; > + > + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueA); > + ValueA = ValueA & PCIE_LTSSM_STATE_MASK; > + > + Count = 0; > + while (Count < 2) { > + > + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueB); > + ValueB = ValueB & PCIE_LTSSM_STATE_MASK; > + > + /* Get the same state in continuous two times*/ > + if (ValueA == ValueB) { > + break; > + } > + > + //If the second value not equal to the first, we return the second one as the stable > + ValueA = ValueB; > + Count++; > + } > + > + *Value = ValueB; > + > + return; > + > +} > + > +/* > + * In some cases, the PCIe device may close part of lanes in > + * config state of LTSSM, the hip06 RC should reconfig lane num > + * and try to linkup again. > + */ > +VOID PcieReconfigLaneNum ( > + IN UINT32 soctype, > + IN UINT32 HostBridgeNum, > + IN UINT32 Port, > + IN PCIE_DRIVER_CFG *PcieCfg > + ) > +{ > + EFI_STATUS Status; > + UINT32 LtssmStatus; > + UINT32 RegVal; > + UINT32 LoopCnt = 0; > + UINT32 LaneNumCnt = 0; > + PCIE_PORT_WIDTH PortWidth = PcieCfg->PortInfo.PortWidth; > + > + // 500 * 200us = 100ms, so it takes 100 ms must to reconfig lane numbers > + while (LoopCnt < 500) { > + > + /* > + * The minimum lanenum is 1, no need to try any more. > + */ > + if (PortWidth <= 1) { > + DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum PortWidth <= 1 !\n")); > + return; > + } > + > + /* > + * Check the lane num config state is normal or not. > + */ > + PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus); > + if ((LtssmStatus == PCIE_LTSSM_CFG_LANENUM_ACPT) || (LtssmStatus == PCIE_LTSSM_CFG_COMPLETE)) { > + LaneNumCnt++; > + } else if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) { > + PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus); > + if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) { > + break; > + } > + } else { > + LaneNumCnt = 0; > + } > + > + /* > + * The lane num config state is abnormal, need to reconfig > + * the lane num and try to establish link again. > + */ > + if (LaneNumCnt > MAX_TRY_LINK_NUM) { > + /* Disable LTSSM */ > + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal); > + RegVal &= ~(LTSSM_ENABLE); > + RegWrite (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal); > + /* > + * Decrease the PortWidth and try to link again, > + * the value of PortWidth 0xf (X8), 0x7(x4), 0x3(X2), 0x1(X1) > + */ > + PcieCfg->PortInfo.PortWidth = (PCIE_PORT_WIDTH)((UINT8)PcieCfg->PortInfo.PortWidth >> 1); > + > + Status = PciePortInit (soctype, HostBridgeNum, PcieCfg); > + if (EFI_ERROR(Status)) { > + DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum HostBridge %d, Pcie Port %d Init Failed! \n", HostBridgeNum, Port)); > + } > + return; > + } > + > + LoopCnt++; > + /* Pcie 3.0 Spec,part 4.2.6.3.4.1: the Upstream Lanes are permitted > + * delay up to 1 ms before transitioning to Configuration.Lanenum.Accept. > + * So the delay time 200 us * 5(LanNumCnt) = 1ms, not beyond the reasonable range. > + */ > + MicroSecondDelay (200); > + } > + > + return ; > +} > > -EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port) > +EFI_STATUS > +PcieEnableItssm ( > + IN UINT32 soctype, > + IN UINT32 HostBridgeNum, > + IN UINT32 Port, > + IN PCIE_DRIVER_CFG *PcieCfg > + ) > { > PCIE_CTRL_7_U pcie_ctrl7; > UINT32 Value = 0; > @@ -165,6 +296,7 @@ EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port) > Value |= BIT11|BIT30|BIT31; > RegWrite(PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + 0x1114, Value); > (VOID)PcieRxValidCtrl(soctype, HostBridgeNum, Port, 1); > + PcieReconfigLaneNum (soctype, HostBridgeNum, Port, PcieCfg); > return EFI_SUCCESS; > } > else > @@ -1008,7 +1140,7 @@ PciePortInit ( > /* Disable RC Option Rom */ > DisableRcOptionRom (soctype, HostBridgeNum, PortIndex, PcieCfg->PortInfo.PortType); > /* assert LTSSM enable */ > - (VOID)PcieEnableItssm(soctype, HostBridgeNum, PortIndex); > + (VOID)PcieEnableItssm (soctype, HostBridgeNum, PortIndex, PcieCfg); > if (FeaturePcdGet(PcdIsPciPerfTuningEnable)) { > //PCIe will still work even if performance tuning fails, > //and there is warning message inside the function to print > diff --git a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h > index 539d567..bf57652 100644 > --- a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h > +++ b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h > @@ -8982,6 +8982,7 @@ typedef union tagIepMsiCtrlIntStatus > #define PCIE_SYS_CTRL28_REG (PCI_SYS_BASE + 0x1c4) > #define PCIE_SYS_CTRL29_REG (PCI_SYS_BASE + 0x1c8) > #define PCIE_SYS_CTRL54_REG (PCI_SYS_BASE + 0x274) > +#define PCIE_SYS_STATE4_REG (PCI_SYS_BASE + 0x31C) > #define PCIE_SYS_STATE5_REG (PCI_SYS_BASE + 0x30) > #define PCIE_SYS_STATE6_REG (PCI_SYS_BASE + 0x34) > #define PCIE_SYS_STATE7_REG (PCI_SYS_BASE + 0x38) > @@ -12694,7 +12695,11 @@ typedef union tagPortlogic93 > #define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE3_REG (PCIE_SUBCTRL_BASE + 0x6814) > #define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE4_REG (PCIE_SUBCTRL_BASE + 0x6818) > #define PCIE_LTSSM_STATE_MASK (0x3f) > +#define PCIE_LTSSM_CFG_LANENUM_ACPT 0x0a > +#define PCIE_LTSSM_CFG_COMPLETE 0x0b > #define PCIE_LTSSM_LINKUP_STATE (0x11) > +#define LTSSM_ENABLE BIT11 > +#define MAX_TRY_LINK_NUM 5 > #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS0_REG (PCIE_SUBCTRL_BASE + 0x6880) > #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS1_REG (PCIE_SUBCTRL_BASE + 0x6884) > #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_RD_STS0_REG (PCIE_SUBCTRL_BASE + 0x6890) > -- > 1.9.1 >
diff --git a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c index 8ec094f..bd91ca4 100644 --- a/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c +++ b/Chips/Hisilicon/Hi1610/Drivers/PcieInit1610/PcieInitLib.c @@ -39,6 +39,14 @@ extern PCIE_DRIVER_CFG gastr_pcie_driver_cfg; extern PCIE_IATU gastr_pcie_iatu_cfg; extern PCIE_IATU_VA mPcieIatuTable; +EFI_STATUS +EFIAPI +PciePortInit ( + IN UINT32 soctype, + IN UINT32 HostBridgeNum, + IN PCIE_DRIVER_CFG *PcieCfg + ); + VOID PcieRegWrite(UINT32 Port, UINTN Offset, UINT32 Value) { RegWrite((UINT64)mPcieIntCfg.RegResource[Port] + Offset, Value); @@ -149,8 +157,131 @@ VOID PcieRxValidCtrl(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port, BOOLEAN } } } +/* + * The ltssm register is assigned in an asynchronous way, the value + * of register may not right in metastable state. + * Read the register twice to get stable value. + */ +VOID PcieGetLtssmValue ( + IN UINT32 HostBridgeNum, + IN UINT32 Port, + IN UINT32 *Value + ) +{ + UINT32 ValueA; + UINT32 ValueB = 0; + UINT32 Count; + + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueA); + ValueA = ValueA & PCIE_LTSSM_STATE_MASK; + + Count = 0; + while (Count < 2) { + + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_SYS_REG_OFFSET + PCIE_SYS_STATE4_REG, ValueB); + ValueB = ValueB & PCIE_LTSSM_STATE_MASK; + + /* Get the same state in continuous two times*/ + if (ValueA == ValueB) { + break; + } + + //If the second value not equal to the first, we return the second one as the stable + ValueA = ValueB; + Count++; + } + + *Value = ValueB; + + return; + +} + +/* + * In some cases, the PCIe device may close part of lanes in + * config state of LTSSM, the hip06 RC should reconfig lane num + * and try to linkup again. + */ +VOID PcieReconfigLaneNum ( + IN UINT32 soctype, + IN UINT32 HostBridgeNum, + IN UINT32 Port, + IN PCIE_DRIVER_CFG *PcieCfg + ) +{ + EFI_STATUS Status; + UINT32 LtssmStatus; + UINT32 RegVal; + UINT32 LoopCnt = 0; + UINT32 LaneNumCnt = 0; + PCIE_PORT_WIDTH PortWidth = PcieCfg->PortInfo.PortWidth; + + // 500 * 200us = 100ms, so it takes 100 ms must to reconfig lane numbers + while (LoopCnt < 500) { + + /* + * The minimum lanenum is 1, no need to try any more. + */ + if (PortWidth <= 1) { + DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum PortWidth <= 1 !\n")); + return; + } + + /* + * Check the lane num config state is normal or not. + */ + PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus); + if ((LtssmStatus == PCIE_LTSSM_CFG_LANENUM_ACPT) || (LtssmStatus == PCIE_LTSSM_CFG_COMPLETE)) { + LaneNumCnt++; + } else if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) { + PcieGetLtssmValue (HostBridgeNum, Port, &LtssmStatus); + if (LtssmStatus == PCIE_LTSSM_LINKUP_STATE) { + break; + } + } else { + LaneNumCnt = 0; + } + + /* + * The lane num config state is abnormal, need to reconfig + * the lane num and try to establish link again. + */ + if (LaneNumCnt > MAX_TRY_LINK_NUM) { + /* Disable LTSSM */ + RegRead (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal); + RegVal &= ~(LTSSM_ENABLE); + RegWrite (PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + PCIE_CTRL_7_REG, RegVal); + /* + * Decrease the PortWidth and try to link again, + * the value of PortWidth 0xf (X8), 0x7(x4), 0x3(X2), 0x1(X1) + */ + PcieCfg->PortInfo.PortWidth = (PCIE_PORT_WIDTH)((UINT8)PcieCfg->PortInfo.PortWidth >> 1); + + Status = PciePortInit (soctype, HostBridgeNum, PcieCfg); + if (EFI_ERROR(Status)) { + DEBUG ((DEBUG_ERROR, "PcieReconfigLanenum HostBridge %d, Pcie Port %d Init Failed! \n", HostBridgeNum, Port)); + } + return; + } + + LoopCnt++; + /* Pcie 3.0 Spec,part 4.2.6.3.4.1: the Upstream Lanes are permitted + * delay up to 1 ms before transitioning to Configuration.Lanenum.Accept. + * So the delay time 200 us * 5(LanNumCnt) = 1ms, not beyond the reasonable range. + */ + MicroSecondDelay (200); + } + + return ; +} -EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port) +EFI_STATUS +PcieEnableItssm ( + IN UINT32 soctype, + IN UINT32 HostBridgeNum, + IN UINT32 Port, + IN PCIE_DRIVER_CFG *PcieCfg + ) { PCIE_CTRL_7_U pcie_ctrl7; UINT32 Value = 0; @@ -165,6 +296,7 @@ EFI_STATUS PcieEnableItssm(UINT32 soctype, UINT32 HostBridgeNum, UINT32 Port) Value |= BIT11|BIT30|BIT31; RegWrite(PCIE_APB_SLAVE_BASE_1610[HostBridgeNum][Port] + 0x1114, Value); (VOID)PcieRxValidCtrl(soctype, HostBridgeNum, Port, 1); + PcieReconfigLaneNum (soctype, HostBridgeNum, Port, PcieCfg); return EFI_SUCCESS; } else @@ -1008,7 +1140,7 @@ PciePortInit ( /* Disable RC Option Rom */ DisableRcOptionRom (soctype, HostBridgeNum, PortIndex, PcieCfg->PortInfo.PortType); /* assert LTSSM enable */ - (VOID)PcieEnableItssm(soctype, HostBridgeNum, PortIndex); + (VOID)PcieEnableItssm (soctype, HostBridgeNum, PortIndex, PcieCfg); if (FeaturePcdGet(PcdIsPciPerfTuningEnable)) { //PCIe will still work even if performance tuning fails, //and there is warning message inside the function to print diff --git a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h index 539d567..bf57652 100644 --- a/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h +++ b/Chips/Hisilicon/Include/Regs/HisiPcieV1RegOffset.h @@ -8982,6 +8982,7 @@ typedef union tagIepMsiCtrlIntStatus #define PCIE_SYS_CTRL28_REG (PCI_SYS_BASE + 0x1c4) #define PCIE_SYS_CTRL29_REG (PCI_SYS_BASE + 0x1c8) #define PCIE_SYS_CTRL54_REG (PCI_SYS_BASE + 0x274) +#define PCIE_SYS_STATE4_REG (PCI_SYS_BASE + 0x31C) #define PCIE_SYS_STATE5_REG (PCI_SYS_BASE + 0x30) #define PCIE_SYS_STATE6_REG (PCI_SYS_BASE + 0x34) #define PCIE_SYS_STATE7_REG (PCI_SYS_BASE + 0x38) @@ -12694,7 +12695,11 @@ typedef union tagPortlogic93 #define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE3_REG (PCIE_SUBCTRL_BASE + 0x6814) #define PCIE_SUBCTRL_SC_PCIE0_SYS_STATE4_REG (PCIE_SUBCTRL_BASE + 0x6818) #define PCIE_LTSSM_STATE_MASK (0x3f) +#define PCIE_LTSSM_CFG_LANENUM_ACPT 0x0a +#define PCIE_LTSSM_CFG_COMPLETE 0x0b #define PCIE_LTSSM_LINKUP_STATE (0x11) +#define LTSSM_ENABLE BIT11 +#define MAX_TRY_LINK_NUM 5 #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS0_REG (PCIE_SUBCTRL_BASE + 0x6880) #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_WR_STS1_REG (PCIE_SUBCTRL_BASE + 0x6884) #define PCIE_SUBCTRL_SC_PCIE0_AXI_MSTR_OOO_RD_STS0_REG (PCIE_SUBCTRL_BASE + 0x6890)