* [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode @ 2025-06-13 10:19 Niklas Cassel 2025-06-13 11:22 ` Manivannan Sadhasivam 2025-06-17 22:01 ` Bjorn Helgaas 0 siblings, 2 replies; 10+ messages in thread From: Niklas Cassel @ 2025-06-13 10:19 UTC (permalink / raw) To: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner Cc: Wilfred Mallawa, Niklas Cassel, linux-pci, linux-arm-kernel, linux-rockchip From: Wilfred Mallawa <wilfred.mallawa@wdc.com> RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: """ If you want to delay link re-establishment (after reset) so that you can reprogram some registers through DBI, you must set app_ltssm_enable =0 immediately after core_rst_n as shown in above. This can be achieved by enable the app_dly2_en, and end-up the delay by assert app_dly2_done. """ I.e. setting app_dly2_en will automatically deassert app_ltssm_enable on a hot reset, and setting app_dly2_done will re-assert app_ltssm_enable, re-enabling link training. When receiving a hot reset/link-down IRQ when running in EP mode, we will call dw_pcie_ep_linkdown(), which will call the .link_down() callback in the currently bound endpoint function (EPF) drivers. The callback in an EPF driver can theoretically take a long time to complete, so make sure that the link is not re-established until after dw_pcie_ep_linkdown() (which calls the .link_down() callback(s) synchronously). Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> Co-developed-by: Niklas Cassel <cassel@kernel.org> Signed-off-by: Niklas Cassel <cassel@kernel.org> --- Changes since v1: -Rebased on v6.16-rc1 drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 93171a392879..cd1e9352b21f 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -58,6 +58,8 @@ /* Hot Reset Control Register */ #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 +#define PCIE_LTSSM_APP_DLY2_EN BIT(1) +#define PCIE_LTSSM_APP_DLY2_DONE BIT(3) #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) /* LTSSM Status Register */ @@ -474,7 +476,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) struct rockchip_pcie *rockchip = arg; struct dw_pcie *pci = &rockchip->pci; struct device *dev = pci->dev; - u32 reg; + u32 reg, val; reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); @@ -485,6 +487,10 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) if (reg & PCIE_LINK_REQ_RST_NOT_INT) { dev_dbg(dev, "hot reset or link-down reset\n"); dw_pcie_ep_linkdown(&pci->ep); + /* Stop delaying link training. */ + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); + rockchip_pcie_writel_apb(rockchip, val, + PCIE_CLIENT_HOT_RESET_CTRL); } if (reg & PCIE_RDLH_LINK_UP_CHGED) { @@ -566,8 +572,11 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, return ret; } - /* LTSSM enable control mode */ - val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); + /* + * LTSSM enable control mode, and automatically delay link training on + * hot reset/link-down reset. + */ + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN); rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, -- 2.49.0 ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-13 10:19 [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode Niklas Cassel @ 2025-06-13 11:22 ` Manivannan Sadhasivam 2025-06-17 22:01 ` Bjorn Helgaas 1 sibling, 0 replies; 10+ messages in thread From: Manivannan Sadhasivam @ 2025-06-13 11:22 UTC (permalink / raw) To: Lorenzo Pieralisi, Krzysztof Wilczyński, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Niklas Cassel Cc: Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Fri, 13 Jun 2025 12:19:09 +0200, Niklas Cassel wrote: > RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: > """ > If you want to delay link re-establishment (after reset) so that you can > reprogram some registers through DBI, you must set app_ltssm_enable =0 > immediately after core_rst_n as shown in above. This can be achieved by > enable the app_dly2_en, and end-up the delay by assert app_dly2_done. > """ > > [...] Applied, thanks! [1/1] PCI: dw-rockchip: Delay link training after hot reset in EP mode commit: dcca6051a220484f0c1a5cb018f3012735067254 Best regards, -- Manivannan Sadhasivam <mani@kernel.org> ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-13 10:19 [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode Niklas Cassel 2025-06-13 11:22 ` Manivannan Sadhasivam @ 2025-06-17 22:01 ` Bjorn Helgaas 2025-06-17 22:05 ` Bjorn Helgaas 2025-06-18 14:04 ` Niklas Cassel 1 sibling, 2 replies; 10+ messages in thread From: Bjorn Helgaas @ 2025-06-17 22:01 UTC (permalink / raw) To: Niklas Cassel Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > From: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: > """ > If you want to delay link re-establishment (after reset) so that you can > reprogram some registers through DBI, you must set app_ltssm_enable =0 > immediately after core_rst_n as shown in above. This can be achieved by > enable the app_dly2_en, and end-up the delay by assert app_dly2_done. > """ Ugh. Is """ some sort of markup? There's a nice English convention of indenting block quotes a couple spaces with no quote marks at all that would work nicely here. > I.e. setting app_dly2_en will automatically deassert app_ltssm_enable on > a hot reset, and setting app_dly2_done will re-assert app_ltssm_enable, > re-enabling link training. > > When receiving a hot reset/link-down IRQ when running in EP mode, we will > call dw_pcie_ep_linkdown(), which will call the .link_down() callback in > the currently bound endpoint function (EPF) drivers. > > The callback in an EPF driver can theoretically take a long time to > complete, so make sure that the link is not re-established until after > dw_pcie_ep_linkdown() (which calls the .link_down() callback(s) > synchronously). I don't know why we care *how long* EPF callbacks might take. From the TRM quote, it sounds like the important thing is that you don't want the link to train before dw_pcie_ep_linkdown() calls dw_pcie_ep_init_non_sticky_registers(), which looks like it programs registers through DBI. Maybe you also want to allow the EFP ->link_down() callbacks to also program things via DBI before link training? But I don't think the amount of time they take is relevant. If you need to do *anything* via DBI before the link trains, you have to prevent training until you're finished with DBI. > Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> > Co-developed-by: Niklas Cassel <cassel@kernel.org> > Signed-off-by: Niklas Cassel <cassel@kernel.org> > --- > Changes since v1: > -Rebased on v6.16-rc1 > > drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 ++++++++++++--- > 1 file changed, 12 insertions(+), 3 deletions(-) > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > index 93171a392879..cd1e9352b21f 100644 > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > @@ -58,6 +58,8 @@ > > /* Hot Reset Control Register */ > #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 > +#define PCIE_LTSSM_APP_DLY2_EN BIT(1) > +#define PCIE_LTSSM_APP_DLY2_DONE BIT(3) > #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) > > /* LTSSM Status Register */ > @@ -474,7 +476,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > struct rockchip_pcie *rockchip = arg; > struct dw_pcie *pci = &rockchip->pci; > struct device *dev = pci->dev; > - u32 reg; > + u32 reg, val; > > reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); > rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); > @@ -485,6 +487,10 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > dev_dbg(dev, "hot reset or link-down reset\n"); > dw_pcie_ep_linkdown(&pci->ep); > + /* Stop delaying link training. */ > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > + rockchip_pcie_writel_apb(rockchip, val, > + PCIE_CLIENT_HOT_RESET_CTRL); > } > > if (reg & PCIE_RDLH_LINK_UP_CHGED) { > @@ -566,8 +572,11 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, > return ret; > } > > - /* LTSSM enable control mode */ > - val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); > + /* > + * LTSSM enable control mode, and automatically delay link training on > + * hot reset/link-down reset. > + */ > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN); > rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); > > rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, > -- > 2.49.0 > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-17 22:01 ` Bjorn Helgaas @ 2025-06-17 22:05 ` Bjorn Helgaas 2025-06-18 14:23 ` Niklas Cassel 2025-06-18 14:04 ` Niklas Cassel 1 sibling, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2025-06-17 22:05 UTC (permalink / raw) To: Niklas Cassel Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Tue, Jun 17, 2025 at 05:01:16PM -0500, Bjorn Helgaas wrote: > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > From: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > > > RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: > > """ > > If you want to delay link re-establishment (after reset) so that you can > > reprogram some registers through DBI, you must set app_ltssm_enable =0 > > immediately after core_rst_n as shown in above. This can be achieved by > > enable the app_dly2_en, and end-up the delay by assert app_dly2_done. > > """ > > Ugh. Is """ some sort of markup? There's a nice English convention > of indenting block quotes a couple spaces with no quote marks at all > that would work nicely here. > > > I.e. setting app_dly2_en will automatically deassert app_ltssm_enable on > > a hot reset, and setting app_dly2_done will re-assert app_ltssm_enable, > > re-enabling link training. > > > > When receiving a hot reset/link-down IRQ when running in EP mode, we will > > call dw_pcie_ep_linkdown(), which will call the .link_down() callback in > > the currently bound endpoint function (EPF) drivers. > > > > The callback in an EPF driver can theoretically take a long time to > > complete, so make sure that the link is not re-established until after > > dw_pcie_ep_linkdown() (which calls the .link_down() callback(s) > > synchronously). > > I don't know why we care *how long* EPF callbacks might take. > > From the TRM quote, it sounds like the important thing is that you > don't want the link to train before dw_pcie_ep_linkdown() calls > dw_pcie_ep_init_non_sticky_registers(), which looks like it programs > registers through DBI. > > Maybe you also want to allow the EFP ->link_down() callbacks to also > program things via DBI before link training? But I don't think the > amount of time they take is relevant. If you need to do *anything* > via DBI before the link trains, you have to prevent training until > you're finished with DBI. Oh, and this sets PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN once at probe-time, but what about after a link-down/link-up cycle? Don't we need to set PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN again when the link comes up so we don't have the same race when the link goes down again? > > Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > Co-developed-by: Niklas Cassel <cassel@kernel.org> > > Signed-off-by: Niklas Cassel <cassel@kernel.org> > > --- > > Changes since v1: > > -Rebased on v6.16-rc1 > > > > drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 ++++++++++++--- > > 1 file changed, 12 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > index 93171a392879..cd1e9352b21f 100644 > > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > @@ -58,6 +58,8 @@ > > > > /* Hot Reset Control Register */ > > #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 > > +#define PCIE_LTSSM_APP_DLY2_EN BIT(1) > > +#define PCIE_LTSSM_APP_DLY2_DONE BIT(3) > > #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) > > > > /* LTSSM Status Register */ > > @@ -474,7 +476,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > struct rockchip_pcie *rockchip = arg; > > struct dw_pcie *pci = &rockchip->pci; > > struct device *dev = pci->dev; > > - u32 reg; > > + u32 reg, val; > > > > reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); > > rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); > > @@ -485,6 +487,10 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > > dev_dbg(dev, "hot reset or link-down reset\n"); > > dw_pcie_ep_linkdown(&pci->ep); > > + /* Stop delaying link training. */ > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > > + rockchip_pcie_writel_apb(rockchip, val, > > + PCIE_CLIENT_HOT_RESET_CTRL); > > } > > > > if (reg & PCIE_RDLH_LINK_UP_CHGED) { > > @@ -566,8 +572,11 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, > > return ret; > > } > > > > - /* LTSSM enable control mode */ > > - val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); > > + /* > > + * LTSSM enable control mode, and automatically delay link training on > > + * hot reset/link-down reset. > > + */ > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN); > > rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); > > > > rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, > > -- > > 2.49.0 > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-17 22:05 ` Bjorn Helgaas @ 2025-06-18 14:23 ` Niklas Cassel 2025-06-18 14:40 ` Niklas Cassel 0 siblings, 1 reply; 10+ messages in thread From: Niklas Cassel @ 2025-06-18 14:23 UTC (permalink / raw) To: Bjorn Helgaas Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Tue, Jun 17, 2025 at 05:05:23PM -0500, Bjorn Helgaas wrote: > On Tue, Jun 17, 2025 at 05:01:16PM -0500, Bjorn Helgaas wrote: > > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > Oh, and this sets PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN > once at probe-time, but what about after a link-down/link-up cycle? > > Don't we need to set PCIE_LTSSM_ENABLE_ENHANCE | > PCIE_LTSSM_APP_DLY2_EN again when the link comes up so we don't have > the same race when the link goes down again? Nope, we don't. To verify I used this patch: diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index be239254aacd..e79add5412b8 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -506,6 +506,8 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) if (reg & PCIE_LINK_REQ_RST_NOT_INT) { dev_dbg(dev, "hot reset or link-down reset\n"); dw_pcie_ep_linkdown(&pci->ep); + pr_info("PCIE_CLIENT_HOT_RESET_CTRL after reset: %#x\n", + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL)); /* Stop delaying link training. */ val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); rockchip_pcie_writel_apb(rockchip, val, [ 85.979567] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset [ 85.980210] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 [ 93.720413] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset [ 93.721074] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 0x12 == bit 1 and bit 4 are set. bit 1: app_dly2_en bit 4: app_ltssm_enable_enhance I also looked at the downstream driver and they also only set it once during probe(). When running the controller EP mode, we (the Linux driver) currently never reset the whole core after probe(), and as we can see above, the hardware itself also does not reset the app_dly2_en bit during a hot reset signal. Kind regards, Niklas ^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-18 14:23 ` Niklas Cassel @ 2025-06-18 14:40 ` Niklas Cassel 2025-06-18 19:54 ` Bjorn Helgaas 0 siblings, 1 reply; 10+ messages in thread From: Niklas Cassel @ 2025-06-18 14:40 UTC (permalink / raw) To: Bjorn Helgaas Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Wed, Jun 18, 2025 at 04:23:19PM +0200, Niklas Cassel wrote: > On Tue, Jun 17, 2025 at 05:05:23PM -0500, Bjorn Helgaas wrote: > > On Tue, Jun 17, 2025 at 05:01:16PM -0500, Bjorn Helgaas wrote: > > > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > > > Oh, and this sets PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN > > once at probe-time, but what about after a link-down/link-up cycle? > > > > Don't we need to set PCIE_LTSSM_ENABLE_ENHANCE | > > PCIE_LTSSM_APP_DLY2_EN again when the link comes up so we don't have > > the same race when the link goes down again? > > Nope, we don't. > > To verify I used this patch: > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > index be239254aacd..e79add5412b8 100644 > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > @@ -506,6 +506,8 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > dev_dbg(dev, "hot reset or link-down reset\n"); > dw_pcie_ep_linkdown(&pci->ep); > + pr_info("PCIE_CLIENT_HOT_RESET_CTRL after reset: %#x\n", > + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL)); > /* Stop delaying link training. */ > val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > rockchip_pcie_writel_apb(rockchip, val, > > > > > [ 85.979567] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset > [ 85.980210] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 > [ 93.720413] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset > [ 93.721074] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 > > 0x12 == bit 1 and bit 4 are set. > > bit 1: app_dly2_en > bit 4: app_ltssm_enable_enhance Oh, and just to verify that the hardware does not clear the app_dly2_en bit when we write the app_dly2_done bit, I ran the same test, but with the prints in rockchip_pcie_ep_sys_irq_thread(), just after calling dw_pcie_ep_linkup(&pci->ep); and got the same result: [ 57.176862] rockchip-dw-pcie a40000000.pcie-ep: link up [ 57.177338] PCIE_CLIENT_HOT_RESET_CTRL after linkup: 0x12 [ 72.448052] rockchip-dw-pcie a40000000.pcie-ep: link up [ 72.448527] PCIE_CLIENT_HOT_RESET_CTRL after linkup: 0x12 So I think this patch is good as is. (Except for the citation style in the commit message which you didn't like :)) Kind regards, Niklas ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-18 14:40 ` Niklas Cassel @ 2025-06-18 19:54 ` Bjorn Helgaas 0 siblings, 0 replies; 10+ messages in thread From: Bjorn Helgaas @ 2025-06-18 19:54 UTC (permalink / raw) To: Niklas Cassel Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Wed, Jun 18, 2025 at 04:40:11PM +0200, Niklas Cassel wrote: > On Wed, Jun 18, 2025 at 04:23:19PM +0200, Niklas Cassel wrote: > > On Tue, Jun 17, 2025 at 05:05:23PM -0500, Bjorn Helgaas wrote: > > > On Tue, Jun 17, 2025 at 05:01:16PM -0500, Bjorn Helgaas wrote: > > > > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > > > > > Oh, and this sets PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN > > > once at probe-time, but what about after a link-down/link-up cycle? > > > > > > Don't we need to set PCIE_LTSSM_ENABLE_ENHANCE | > > > PCIE_LTSSM_APP_DLY2_EN again when the link comes up so we don't have > > > the same race when the link goes down again? > > > > Nope, we don't. > > > > To verify I used this patch: > > > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > index be239254aacd..e79add5412b8 100644 > > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > @@ -506,6 +506,8 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > > dev_dbg(dev, "hot reset or link-down reset\n"); > > dw_pcie_ep_linkdown(&pci->ep); > > + pr_info("PCIE_CLIENT_HOT_RESET_CTRL after reset: %#x\n", > > + rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_HOT_RESET_CTRL)); > > /* Stop delaying link training. */ > > val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > > rockchip_pcie_writel_apb(rockchip, val, > > > > > > > > > > [ 85.979567] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset > > [ 85.980210] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 > > [ 93.720413] rockchip-dw-pcie a40000000.pcie-ep: hot reset or link-down reset > > [ 93.721074] PCIE_CLIENT_HOT_RESET_CTRL after reset: 0x12 > > > > 0x12 == bit 1 and bit 4 are set. > > > > bit 1: app_dly2_en > > bit 4: app_ltssm_enable_enhance > > Oh, and just to verify that the hardware does not clear the app_dly2_en bit > when we write the app_dly2_done bit, I ran the same test, but with the > prints in rockchip_pcie_ep_sys_irq_thread(), just after calling > dw_pcie_ep_linkup(&pci->ep); and got the same result: > > [ 57.176862] rockchip-dw-pcie a40000000.pcie-ep: link up > [ 57.177338] PCIE_CLIENT_HOT_RESET_CTRL after linkup: 0x12 > [ 72.448052] rockchip-dw-pcie a40000000.pcie-ep: link up > [ 72.448527] PCIE_CLIENT_HOT_RESET_CTRL after linkup: 0x12 Thanks, I had missed the difference between PCIE_LTSSM_APP_DLY2_EN and PCIE_LTSSM_APP_DLY2_DONE. ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-17 22:01 ` Bjorn Helgaas 2025-06-17 22:05 ` Bjorn Helgaas @ 2025-06-18 14:04 ` Niklas Cassel 2025-06-18 19:59 ` Bjorn Helgaas 1 sibling, 1 reply; 10+ messages in thread From: Niklas Cassel @ 2025-06-18 14:04 UTC (permalink / raw) To: Bjorn Helgaas Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip Hello Bjorn, On Tue, Jun 17, 2025 at 05:01:14PM -0500, Bjorn Helgaas wrote: > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > From: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > > > RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: > > """ > > If you want to delay link re-establishment (after reset) so that you can > > reprogram some registers through DBI, you must set app_ltssm_enable =0 > > immediately after core_rst_n as shown in above. This can be achieved by > > enable the app_dly2_en, and end-up the delay by assert app_dly2_done. > > """ > > Ugh. Is """ some sort of markup? There's a nice English convention > of indenting block quotes a couple spaces with no quote marks at all > that would work nicely here. """ is not any markup, just to highlight that it is a direct quote from the TRM. Since the patch is already queued, could you please fix it up? > > > I.e. setting app_dly2_en will automatically deassert app_ltssm_enable on > > a hot reset, and setting app_dly2_done will re-assert app_ltssm_enable, > > re-enabling link training. > > > > When receiving a hot reset/link-down IRQ when running in EP mode, we will > > call dw_pcie_ep_linkdown(), which will call the .link_down() callback in > > the currently bound endpoint function (EPF) drivers. > > > > The callback in an EPF driver can theoretically take a long time to > > complete, so make sure that the link is not re-established until after > > dw_pcie_ep_linkdown() (which calls the .link_down() callback(s) > > synchronously). > > I don't know why we care *how long* EPF callbacks might take. Well, because currently, we do NOT delay link training, and everything works as expected. Most likely we are just lucky, because dw_pcie_ep_linkdown() calls dw_pcie_ep_init_non_sticky_registers(), which is quite a short function. During a hot reset, the BARs get resized to 1 GB (yes, that is the default/reset value on rk3588), so the fact that the host sees a smaller BAR size means that dw_pcie_ep_init_non_sticky_registers() must have had time to run before link training completed. But we do not want to rely on luck for these DBI writes to finish before link training is complete, hence this patch. The .link_down() callback in drivers/pci/endpoint/functions/pci-epf-test.c simply does a cancel_delayed_work_sync(). I could imagine an EPF driver doing some more time consuming work in the callback, like allocating memory (which could trigger direct reclaim), and then calling pci_epc_set_bar() which will eventually result in some DBI writes. That most likely would not work without this patch. > > From the TRM quote, it sounds like the important thing is that you > don't want the link to train before dw_pcie_ep_linkdown() calls > dw_pcie_ep_init_non_sticky_registers(), which looks like it programs > registers through DBI. > > Maybe you also want to allow the EFP ->link_down() callbacks to also > program things via DBI before link training? But I don't think the > amount of time they take is relevant. If you need to do *anything* > via DBI before the link trains, you have to prevent training until > you're finished with DBI. > > > Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > Co-developed-by: Niklas Cassel <cassel@kernel.org> > > Signed-off-by: Niklas Cassel <cassel@kernel.org> > > --- > > Changes since v1: > > -Rebased on v6.16-rc1 > > > > drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 ++++++++++++--- > > 1 file changed, 12 insertions(+), 3 deletions(-) > > > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > index 93171a392879..cd1e9352b21f 100644 > > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > @@ -58,6 +58,8 @@ > > > > /* Hot Reset Control Register */ > > #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 > > +#define PCIE_LTSSM_APP_DLY2_EN BIT(1) > > +#define PCIE_LTSSM_APP_DLY2_DONE BIT(3) > > #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) > > > > /* LTSSM Status Register */ > > @@ -474,7 +476,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > struct rockchip_pcie *rockchip = arg; > > struct dw_pcie *pci = &rockchip->pci; > > struct device *dev = pci->dev; > > - u32 reg; > > + u32 reg, val; > > > > reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); > > rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); > > @@ -485,6 +487,10 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > > dev_dbg(dev, "hot reset or link-down reset\n"); > > dw_pcie_ep_linkdown(&pci->ep); > > + /* Stop delaying link training. */ > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > > + rockchip_pcie_writel_apb(rockchip, val, > > + PCIE_CLIENT_HOT_RESET_CTRL); > > } > > > > if (reg & PCIE_RDLH_LINK_UP_CHGED) { > > @@ -566,8 +572,11 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, > > return ret; > > } > > > > - /* LTSSM enable control mode */ > > - val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); > > + /* > > + * LTSSM enable control mode, and automatically delay link training on > > + * hot reset/link-down reset. > > + */ > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN); > > rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); > > > > rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, > > -- > > 2.49.0 > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-18 14:04 ` Niklas Cassel @ 2025-06-18 19:59 ` Bjorn Helgaas 2025-06-19 9:53 ` Niklas Cassel 0 siblings, 1 reply; 10+ messages in thread From: Bjorn Helgaas @ 2025-06-18 19:59 UTC (permalink / raw) To: Niklas Cassel Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Wed, Jun 18, 2025 at 04:04:17PM +0200, Niklas Cassel wrote: > On Tue, Jun 17, 2025 at 05:01:14PM -0500, Bjorn Helgaas wrote: > > On Fri, Jun 13, 2025 at 12:19:09PM +0200, Niklas Cassel wrote: > > > From: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > > > > > RK3588 TRM, section "11.6.1.3.3 Hot Reset and Link-Down Reset" states that: > > > """ > > > If you want to delay link re-establishment (after reset) so that you can > > > reprogram some registers through DBI, you must set app_ltssm_enable =0 > > > immediately after core_rst_n as shown in above. This can be achieved by > > > enable the app_dly2_en, and end-up the delay by assert app_dly2_done. > > > """ > > > > > > I.e. setting app_dly2_en will automatically deassert app_ltssm_enable on > > > a hot reset, and setting app_dly2_done will re-assert app_ltssm_enable, > > > re-enabling link training. > > > > > > When receiving a hot reset/link-down IRQ when running in EP mode, we will > > > call dw_pcie_ep_linkdown(), which will call the .link_down() callback in > > > the currently bound endpoint function (EPF) drivers. > > > > > > The callback in an EPF driver can theoretically take a long time to > > > complete, so make sure that the link is not re-established until after > > > dw_pcie_ep_linkdown() (which calls the .link_down() callback(s) > > > synchronously). > > > > I don't know why we care *how long* EPF callbacks might take. > > Well, because currently, we do NOT delay link training, and everything > works as expected. > > Most likely we are just lucky, because dw_pcie_ep_linkdown() calls > dw_pcie_ep_init_non_sticky_registers(), which is quite a short function. I'm just making the point that IIUC there's a race between link training and any DBI accesses done by dw_pcie_ep_init_non_sticky_registers() and potentially EPF callbacks, and the time those paths take is immaterial. If this is indeed a race and this patch is the fix, I think it's misleading to describe it as "this path might take a long time and lose the race." We have to assume arbitrary delays can be added to either path, so we can never rely on a path being "fast enough" to avoid the race. Is the following basically what we're doing? Set PCIE_LTSSM_APP_DLY2_EN so the controller never automatically trains the link after a link-down interrupt. That way any DBI updates done in the dw_pcie_ep_linkdown() path will happen while the link is still down. Then allow link training by setting PCIE_LTSSM_APP_DLY2_DONE. We don't set PCIE_LTSSM_APP_DLY2_DONE anywhere in the initial probe path. Obviously the link must train in that case, so I guess PCIE_LTSSM_APP_DLY2_EN only applies to the case of link state transition from link-up to link-down? > During a hot reset, the BARs get resized to 1 GB (yes, that is the > default/reset value on rk3588), so the fact that the host sees a smaller > BAR size means that dw_pcie_ep_init_non_sticky_registers() must have had > time to run before link training completed. > > But we do not want to rely on luck for these DBI writes to finish before > link training is complete, hence this patch. > > The .link_down() callback in drivers/pci/endpoint/functions/pci-epf-test.c > simply does a cancel_delayed_work_sync(). > > I could imagine an EPF driver doing some more time consuming work in the > callback, like allocating memory (which could trigger direct reclaim), and > then calling pci_epc_set_bar() which will eventually result in some DBI > writes. That most likely would not work without this patch. > > > From the TRM quote, it sounds like the important thing is that you > > don't want the link to train before dw_pcie_ep_linkdown() calls > > dw_pcie_ep_init_non_sticky_registers(), which looks like it programs > > registers through DBI. > > > > Maybe you also want to allow the EFP ->link_down() callbacks to also > > program things via DBI before link training? But I don't think the > > amount of time they take is relevant. If you need to do *anything* > > via DBI before the link trains, you have to prevent training until > > you're finished with DBI. > > > > > Signed-off-by: Wilfred Mallawa <wilfred.mallawa@wdc.com> > > > Co-developed-by: Niklas Cassel <cassel@kernel.org> > > > Signed-off-by: Niklas Cassel <cassel@kernel.org> > > > --- > > > Changes since v1: > > > -Rebased on v6.16-rc1 > > > > > > drivers/pci/controller/dwc/pcie-dw-rockchip.c | 15 ++++++++++++--- > > > 1 file changed, 12 insertions(+), 3 deletions(-) > > > > > > diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > > index 93171a392879..cd1e9352b21f 100644 > > > --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > > +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c > > > @@ -58,6 +58,8 @@ > > > > > > /* Hot Reset Control Register */ > > > #define PCIE_CLIENT_HOT_RESET_CTRL 0x180 > > > +#define PCIE_LTSSM_APP_DLY2_EN BIT(1) > > > +#define PCIE_LTSSM_APP_DLY2_DONE BIT(3) > > > #define PCIE_LTSSM_ENABLE_ENHANCE BIT(4) > > > > > > /* LTSSM Status Register */ > > > @@ -474,7 +476,7 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > > struct rockchip_pcie *rockchip = arg; > > > struct dw_pcie *pci = &rockchip->pci; > > > struct device *dev = pci->dev; > > > - u32 reg; > > > + u32 reg, val; > > > > > > reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); > > > rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); > > > @@ -485,6 +487,10 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) > > > if (reg & PCIE_LINK_REQ_RST_NOT_INT) { > > > dev_dbg(dev, "hot reset or link-down reset\n"); > > > dw_pcie_ep_linkdown(&pci->ep); > > > + /* Stop delaying link training. */ > > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_APP_DLY2_DONE); > > > + rockchip_pcie_writel_apb(rockchip, val, > > > + PCIE_CLIENT_HOT_RESET_CTRL); > > > } > > > > > > if (reg & PCIE_RDLH_LINK_UP_CHGED) { > > > @@ -566,8 +572,11 @@ static int rockchip_pcie_configure_ep(struct platform_device *pdev, > > > return ret; > > > } > > > > > > - /* LTSSM enable control mode */ > > > - val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE); > > > + /* > > > + * LTSSM enable control mode, and automatically delay link training on > > > + * hot reset/link-down reset. > > > + */ > > > + val = HIWORD_UPDATE_BIT(PCIE_LTSSM_ENABLE_ENHANCE | PCIE_LTSSM_APP_DLY2_EN); > > > rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); > > > > > > rockchip_pcie_writel_apb(rockchip, PCIE_CLIENT_EP_MODE, > > > -- > > > 2.49.0 > > > ^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode 2025-06-18 19:59 ` Bjorn Helgaas @ 2025-06-19 9:53 ` Niklas Cassel 0 siblings, 0 replies; 10+ messages in thread From: Niklas Cassel @ 2025-06-19 9:53 UTC (permalink / raw) To: Bjorn Helgaas Cc: Lorenzo Pieralisi, Krzysztof Wilczyński, Manivannan Sadhasivam, Rob Herring, Bjorn Helgaas, Heiko Stuebner, Wilfred Mallawa, linux-pci, linux-arm-kernel, linux-rockchip On Wed, Jun 18, 2025 at 02:59:59PM -0500, Bjorn Helgaas wrote: > > > > Well, because currently, we do NOT delay link training, and everything > > works as expected. > > > > Most likely we are just lucky, because dw_pcie_ep_linkdown() calls > > dw_pcie_ep_init_non_sticky_registers(), which is quite a short function. > > I'm just making the point that IIUC there's a race between link > training and any DBI accesses done by > dw_pcie_ep_init_non_sticky_registers() and potentially EPF callbacks, > and the time those paths take is immaterial. > > If this is indeed a race and this patch is the fix, I think it's > misleading to describe it as "this path might take a long time and > lose the race." We have to assume arbitrary delays can be added to > either path, so we can never rely on a path being "fast enough" to > avoid the race. I agree 100%. When writing the commit message, we simply wanted to be transparent that we have not observed the problem that this fix (theoretical fix?) is solving. However, from reading the TRM (trust me, a lot of hours...), we are certain that this feature DLY2_EN + DLY2_DONE was implemented such that there would not be a race between link training and reinitializing registers via the DBI. > > Is the following basically what we're doing? > > Set PCIE_LTSSM_APP_DLY2_EN so the controller never automatically > trains the link after a link-down interrupt. That way any DBI > updates done in the dw_pcie_ep_linkdown() path will happen while the > link is still down. Then allow link training by setting > PCIE_LTSSM_APP_DLY2_DONE. Yes. s/link-down interrupt/link-down or hot reset interrupt/ When Hot Reset or Link-down reset occurs, controller will assert smlh_req_rst_not as an early warning. This warning is an interrupt bit in Client Register group(link_req_rst_not_int). (It is the same IRQ, so we can't tell the difference, at least not from only looking at the IRQ status.) > > We don't set PCIE_LTSSM_APP_DLY2_DONE anywhere in the initial probe > path. Obviously the link must train in that case, so I guess > PCIE_LTSSM_APP_DLY2_EN only applies to the case of link state > transition from link-up to link-down? Yes. The register description for dly2_en: Set "1" to enable delaying the link training after Hot Reset. The register description for dly2_done: Set "1" to end the delaying of the link training after Hot Reset. Kind regards, Niklas ^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2025-06-19 15:44 UTC | newest] Thread overview: 10+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2025-06-13 10:19 [PATCH v2] PCI: dw-rockchip: Delay link training after hot reset in EP mode Niklas Cassel 2025-06-13 11:22 ` Manivannan Sadhasivam 2025-06-17 22:01 ` Bjorn Helgaas 2025-06-17 22:05 ` Bjorn Helgaas 2025-06-18 14:23 ` Niklas Cassel 2025-06-18 14:40 ` Niklas Cassel 2025-06-18 19:54 ` Bjorn Helgaas 2025-06-18 14:04 ` Niklas Cassel 2025-06-18 19:59 ` Bjorn Helgaas 2025-06-19 9:53 ` Niklas Cassel
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).