From: Koichiro Den <den@valinux.co.jp>
To: "Marek Vasut" <marek.vasut+renesas@mailbox.org>,
"Geert Uytterhoeven" <geert+renesas@glider.be>,
"Yoshihiro Shimoda" <yoshihiro.shimoda.uh@renesas.com>,
"Shawn Lin" <Shawn.lin@rock-chips.com>,
"Lorenzo Pieralisi" <lpieralisi@kernel.org>,
"Krzysztof Wilczyński" <kwilczynski@kernel.org>,
"Manivannan Sadhasivam" <mani@kernel.org>,
"Rob Herring" <robh@kernel.org>,
"Bjorn Helgaas" <bhelgaas@google.com>,
"Krzysztof Kozlowski" <krzk+dt@kernel.org>,
"Conor Dooley" <conor+dt@kernel.org>,
"Magnus Damm" <magnus.damm@gmail.com>,
"Jingoo Han" <jingoohan1@gmail.com>
Cc: Philipp Zabel <p.zabel@pengutronix.de>,
Frank Li <Frank.Li@nxp.com>, Niklas Cassel <cassel@kernel.org>,
Wilfred Mallawa <wilfred.mallawa@wdc.com>,
Serge Semin <fancer.lancer@gmail.com>,
linux-pci@vger.kernel.org, linux-renesas-soc@vger.kernel.org,
devicetree@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH v5 09/17] PCI: rcar-gen4: Add Root Port reset support
Date: Tue, 20 Oct 2026 12:10:41 +0900 [thread overview]
Message-ID: <20261020031049.969895-10-den@valinux.co.jp> (raw)
In-Reply-To: <20261020031049.969895-1-den@valinux.co.jp>
Implement the host bridge reset_root_port() callback so PCI error
recovery can reset and reinitialize the R-Car controller. This also
provides the reset operation for the link-down handling added later.
Reinitialize without going through .deinit() and .init(), which would
release and re-acquire the clocks and the R-Car Gen5 SoC PHY: split the
SoC-specific register setup that the power reset wipes out into a
.configure callback and repeat only that, then restore the Root Port
registers and restart link training.
Rather than tracking which APP interrupt enables survive the power
reset, derive them from software state through a single helper. A flag
keeps the sources masked from the start of a reset until one succeeds,
so a failed reinitialization does not re-enable them against an
uninitialized controller.
Reject a reset while the controller is suspended, as a failed resume may
have left it powered down.
Track whether the R-Car Gen5 SoC PHY power-on has been requested so a
reset retry, or teardown after a failed reset, does not call
phy_power_off() twice. Continue to ignore the PHY power operation return
values.
Reviewed-by: Marek Vasut <marek.vasut+renesas@mailbox.org>
Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
Changes since v4:
- Use scoped_guard() in the MSI setup error path. (Marek)
https://lore.kernel.org/r/0fece6ed-e91a-4d35-99ab-ce3f4fd789a9@mailbox.org/
drivers/pci/controller/dwc/pcie-rcar-gen4.c | 146 ++++++++++++++++++--
1 file changed, 136 insertions(+), 10 deletions(-)
diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index cbd22e6bb44b..420392ace349 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -99,6 +99,8 @@ struct rcar_gen4_pcie;
struct rcar_gen4_pcie_drvdata {
int (*init)(struct rcar_gen4_pcie *rcar);
void (*deinit)(struct rcar_gen4_pcie *rcar);
+ /* SoC-specific register setup, repeated after a power reset */
+ void (*configure)(struct rcar_gen4_pcie *rcar);
int (*ltssm_control)(struct rcar_gen4_pcie *rcar, bool enable);
int (*speed_control)(struct rcar_gen4_pcie *rcar);
enum dw_pcie_device_mode mode;
@@ -109,9 +111,17 @@ struct rcar_gen4_pcie {
void __iomem *base;
void __iomem *phy_base;
struct phy *phy;
+ bool phy_powered;
struct platform_device *pdev;
struct reset_control *perst;
const struct rcar_gen4_pcie_drvdata *drvdata;
+ /*
+ * The controller needs reinitializing; the APP interrupt sources
+ * stay masked until a reset succeeds.
+ */
+ bool reinit_pending;
+ /* Protects APP interrupt enable registers and their software state. */
+ raw_spinlock_t app_lock;
};
#define to_rcar_gen4_pcie(_dw) container_of(_dw, struct rcar_gen4_pcie, dw)
@@ -322,6 +332,21 @@ static void rcar_gen4_pcie_common_deinit(struct rcar_gen4_pcie *rcar)
clk_bulk_disable_unprepare(DW_PCIE_NUM_CORE_CLKS, dw->core_clks);
}
+/* Reset and restore registers while clocks and PHY remain initialized. */
+static int rcar_gen4_pcie_common_reinit(struct rcar_gen4_pcie *rcar)
+{
+ int ret;
+
+ ret = rcar_gen4_pcie_reset(rcar);
+ if (ret)
+ return ret;
+
+ if (rcar->drvdata->configure)
+ rcar->drvdata->configure(rcar);
+
+ return 0;
+}
+
static void rcar_gen4_v4h_v4m_pcie_configure(struct rcar_gen4_pcie *rcar)
{
struct dw_pcie *dw = &rcar->dw;
@@ -513,6 +538,26 @@ static int rcar_gen4_pcie_host_msi_addr(struct dw_pcie_rp *pp, u32 *msi_addr)
return 0;
}
+static void rcar_gen4_pcie_app_irq_sync_locked(struct rcar_gen4_pcie *rcar)
+{
+ u32 val;
+
+ lockdep_assert_held(&rcar->app_lock);
+
+ val = readl(rcar->base + PCIEINTSTS0EN);
+ val &= ~MSI_CTRL_INT;
+ if (!rcar->reinit_pending && pci_msi_enabled())
+ val |= MSI_CTRL_INT;
+ writel(val, rcar->base + PCIEINTSTS0EN);
+}
+
+static void rcar_gen4_pcie_app_irq_sync(struct rcar_gen4_pcie *rcar)
+{
+ guard(raw_spinlock_irqsave)(&rcar->app_lock);
+
+ rcar_gen4_pcie_app_irq_sync_locked(rcar);
+}
+
static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
@@ -543,12 +588,7 @@ static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
}
/* Configure MSI interrupt signal */
- val = readl(rcar->base + PCIEINTSTS0EN);
- if (pci_msi_enabled())
- val |= MSI_CTRL_INT;
- else
- val &= ~MSI_CTRL_INT;
- writel(val, rcar->base + PCIEINTSTS0EN);
+ rcar_gen4_pcie_app_irq_sync(rcar);
return 0;
@@ -563,9 +603,11 @@ static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
writel(0, rcar->base + AXIINTCCONT);
/* Deconfigure MSI interrupt signal */
- val = readl(rcar->base + PCIEINTSTS0EN);
- val &= ~MSI_CTRL_INT;
- writel(val, rcar->base + PCIEINTSTS0EN);
+ scoped_guard(raw_spinlock_irqsave, &rcar->app_lock) {
+ val = readl(rcar->base + PCIEINTSTS0EN);
+ val &= ~MSI_CTRL_INT;
+ writel(val, rcar->base + PCIEINTSTS0EN);
+ }
return ret;
}
@@ -661,14 +703,87 @@ static int rcar_gen4_pcie_host_setup(struct dw_pcie_rp *pp)
return 0;
}
+static void rcar_gen4_pcie_quiesce_irqs(struct rcar_gen4_pcie *rcar)
+{
+ scoped_guard(raw_spinlock_irqsave, &rcar->app_lock) {
+ rcar->reinit_pending = true;
+ rcar_gen4_pcie_app_irq_sync_locked(rcar);
+ }
+}
+
+static void rcar_gen4_pcie_resume_irqs(struct rcar_gen4_pcie *rcar,
+ bool recovered)
+{
+ scoped_guard(raw_spinlock_irqsave, &rcar->app_lock) {
+ rcar->reinit_pending = !recovered;
+ rcar_gen4_pcie_app_irq_sync_locked(rcar);
+ }
+}
+
+/*
+ * R-Car Gen4 SoC PCIe controllers and R-Car Gen5 SoC PCIe4 controller have
+ * a single Root Port per instance, so the 'pci_dev' is ignored and the whole
+ * controller is reset. The PCI core serializes the callers through its
+ * device locks.
+ */
+static int rcar_gen4_pcie_reset_root_port(struct pci_host_bridge *bridge,
+ struct pci_dev *pdev)
+{
+ struct rcar_gen4_pcie *rcar = dev_get_drvdata(bridge->dev.parent);
+ struct dw_pcie *dw = &rcar->dw;
+ struct dw_pcie_rp *pp = &dw->pp;
+ struct device *dev = dw->dev;
+ int ret;
+
+ /* A failed resume may have left the controller powered down. */
+ if (dw->suspended)
+ return -EBUSY;
+
+ rcar_gen4_pcie_quiesce_irqs(rcar);
+
+ dw_pcie_stop_link(dw);
+
+ rcar_gen4_pcie_host_perst_assert(pp, true);
+
+ ret = rcar_gen4_pcie_common_reinit(rcar);
+ if (ret)
+ goto out;
+
+ ret = rcar_gen4_pcie_host_setup(pp);
+ if (ret)
+ goto out;
+
+ ret = dw_pcie_setup_rc(pp);
+ if (ret)
+ goto out;
+
+ ret = dw_pcie_start_link(dw);
+ if (ret)
+ goto out;
+
+ /* Ignore errors, the link may come up later */
+ dw_pcie_wait_for_link(dw);
+ dev_dbg(dev, "Root Port reset completed\n");
+
+out:
+ rcar_gen4_pcie_resume_irqs(rcar, !ret);
+ if (ret)
+ dev_err(dev, "Root Port reset failed (%d); interrupts stay masked until a reset succeeds\n",
+ ret);
+
+ return ret;
+}
+
static int rcar_gen4_pcie_host_init(struct dw_pcie_rp *pp)
{
struct dw_pcie *dw = to_dw_pcie_from_pp(pp);
struct rcar_gen4_pcie *rcar = to_rcar_gen4_pcie(dw);
int ret;
- if (pp->bridge)
+ if (pp->bridge) {
pp->bridge->enable_device = rcar_gen4_pcie_enable_device;
+ pp->bridge->reset_root_port = rcar_gen4_pcie_reset_root_port;
+ }
rcar_gen4_pcie_host_perst_assert(pp, true);
@@ -708,6 +823,8 @@ static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_HOST))
return -ENODEV;
+ raw_spin_lock_init(&rcar->app_lock);
+
pp->num_vectors = MAX_MSI_IRQS;
/* Reserve an iATU window for the generic PME_Turn_Off implementation. */
pp->use_atu_msg = true;
@@ -944,11 +1061,17 @@ static int rcar_gen5_pcie_ltssm_control(struct rcar_gen4_pcie *rcar, bool enable
}
writel(val, rcar->base + PCIERSTCTRL1);
+ /* A reset retry may find the PHY already powered off. */
+ if (enable == rcar->phy_powered)
+ return 0;
+
if (enable)
phy_power_on(rcar->phy);
else
phy_power_off(rcar->phy);
+ rcar->phy_powered = enable;
+
return 0;
}
@@ -1141,6 +1264,7 @@ static struct rcar_gen4_pcie_drvdata drvdata_r8a779f0_pcie_ep = {
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie = {
.init = rcar_gen4_v4h_v4m_pcie_init,
.deinit = rcar_gen4_pcie_common_deinit,
+ .configure = rcar_gen4_v4h_v4m_pcie_configure,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
.speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_RC_TYPE,
@@ -1149,6 +1273,7 @@ static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie = {
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie_ep = {
.init = rcar_gen4_v4h_v4m_pcie_init,
.deinit = rcar_gen4_pcie_common_deinit,
+ .configure = rcar_gen4_v4h_v4m_pcie_configure,
.ltssm_control = rcar_gen4_pcie_ltssm_control,
.speed_control = rcar_gen4_pcie_speed_control,
.mode = DW_PCIE_EP_TYPE,
@@ -1157,6 +1282,7 @@ static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen4_pcie_ep = {
static struct rcar_gen4_pcie_drvdata drvdata_rcar_gen5_pcie = {
.init = rcar_gen5_pcie_init,
.deinit = rcar_gen5_pcie_deinit,
+ .configure = rcar_gen5_pcie_configure,
.ltssm_control = rcar_gen5_pcie_ltssm_control,
.speed_control = rcar_gen5_pcie_speed_control,
.mode = DW_PCIE_RC_TYPE,
--
2.54.0
next prev parent reply other threads:[~2026-10-20 3:11 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-20 3:10 [PATCH v5 00/17] PCI: rcar-gen4: Recover from link down and route Root Port interrupts Koichiro Den
2026-10-20 3:10 ` [PATCH v5 01/17] PCI: dwc: Add Renesas to the RAS DES VSEC list Koichiro Den
2026-10-20 3:10 ` [PATCH v5 02/17] PCI: dwc: Factor out the PORT_LINK_DEBUG1 link-up check Koichiro Den
2026-10-20 3:10 ` [PATCH v5 03/17] PCI: rcar-gen4: Check live link status in link_up() Koichiro Den
2026-10-20 3:10 ` [PATCH v5 04/17] dt-bindings: PCI: rcar-gen4: Add optional "aer" interrupt for R-Car Gen4 SoCs Koichiro Den
2026-10-20 12:45 ` Marek Vasut
2026-10-20 3:10 ` [PATCH v5 05/17] PCI: dwc: Export dw_handle_msi_irq() Koichiro Den
2026-10-20 3:10 ` [PATCH v5 06/17] PCI: rcar-gen4: Move deinitialization helpers before SoC initialization Koichiro Den
2026-10-20 3:10 ` [PATCH v5 07/17] PCI: rcar-gen4: Assert resets when Gen5 SoC PHY initialization fails Koichiro Den
2026-10-20 3:10 ` [PATCH v5 08/17] PCI: rcar-gen4: Separate hardware setup from resource acquisition Koichiro Den
2026-10-20 3:10 ` Koichiro Den [this message]
2026-10-20 3:10 ` [PATCH v5 10/17] PCI: dwc: Free the MSI domain after the host .deinit() callback Koichiro Den
2026-10-20 3:54 ` Shawn Lin
2026-10-20 6:41 ` Koichiro Den
2026-10-20 7:00 ` Shawn Lin
2026-10-20 7:21 ` Koichiro Den
2026-10-20 11:47 ` Geert Uytterhoeven
2026-10-20 13:45 ` Koichiro Den
2026-10-20 3:10 ` [PATCH v5 11/17] PCI: rcar-gen4: Take over the iMSI-RX interrupt Koichiro Den
2026-10-20 3:10 ` [PATCH v5 12/17] PCI: rcar-gen4: Recover the Root Port on link down Koichiro Den
2026-10-20 3:10 ` [PATCH v5 13/17] PCI: rcar-gen4: Route Root Port AER to a virtual Root Port IRQ Koichiro Den
2026-10-21 0:19 ` Marek Vasut
2026-10-20 3:10 ` [PATCH v5 14/17] PCI: rcar-gen4: Route Root Port PME and bandwidth notifications Koichiro Den
2026-10-20 3:10 ` [PATCH v5 15/17] arm64: dts: renesas: r8a779f0: Describe the PCIe AER interrupts Koichiro Den
2026-10-20 3:10 ` [PATCH v5 16/17] arm64: dts: renesas: r8a779g0: " Koichiro Den
2026-10-20 3:10 ` [PATCH v5 17/17] arm64: dts: renesas: r8a779h0: Describe the PCIe AER interrupt Koichiro Den
2026-10-20 8:03 ` [PATCH v5 00/17] PCI: rcar-gen4: Recover from link down and route Root Port interrupts Geert Uytterhoeven
2026-10-20 8:45 ` Koichiro Den
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261020031049.969895-10-den@valinux.co.jp \
--to=den@valinux.co.jp \
--cc=Frank.Li@nxp.com \
--cc=Shawn.lin@rock-chips.com \
--cc=bhelgaas@google.com \
--cc=cassel@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=fancer.lancer@gmail.com \
--cc=geert+renesas@glider.be \
--cc=jingoohan1@gmail.com \
--cc=krzk+dt@kernel.org \
--cc=kwilczynski@kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=linux-renesas-soc@vger.kernel.org \
--cc=lpieralisi@kernel.org \
--cc=magnus.damm@gmail.com \
--cc=mani@kernel.org \
--cc=marek.vasut+renesas@mailbox.org \
--cc=p.zabel@pengutronix.de \
--cc=robh@kernel.org \
--cc=wilfred.mallawa@wdc.com \
--cc=yoshihiro.shimoda.uh@renesas.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®