Devicetree
 help / color / mirror / Atom feed
From: Koichiro Den <den@valinux.co.jp>
To: "Marek Vasut" <marek.vasut+renesas@mailbox.org>,
	"Yoshihiro Shimoda" <yoshihiro.shimoda.uh@renesas.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>,
	"Geert Uytterhoeven" <geert+renesas@glider.be>,
	"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 06/11] PCI: rcar-gen4: Add Root Port reset support
Date: Fri, 18 Sep 2026 12:20:33 +0900	[thread overview]
Message-ID: <20260918032038.2216471-7-den@valinux.co.jp> (raw)
In-Reply-To: <20260918032038.2216471-1-den@valinux.co.jp>

Secondary Bus Reset is a hot reset signalled over the link, so it is of
no use for recovering from a link down, and it does not reset the
controller either. Implement the host bridge reset_root_port() callback
instead: it re-runs the hardware initialization probe uses, redoes the
DesignWare Root Port setup and restarts link training. The PCI core
routes every Secondary Bus Reset of the Root Port through it, including
AER recovery and the link-down handling added later.

Rather than tracking which APP interrupt enables survive the power
reset, derive them from software state through a single helper. A state
bit keeps the sources masked while the controller is being
reinitialized.

Serialize the reset with a mutex, as not all callers hold the Root
Port's device lock: pci_try_reset_function() on a downstream device only
locks that device before falling back to a parent bus reset.

Signed-off-by: Koichiro Den <den@valinux.co.jp>
---
For reviewers:
  - scoped_guard() is used deliberately in rcar_gen4_pcie_quiesce_irqs()
    and rcar_gen4_pcie_resume_irqs(): the next patch adds code after the
    locked section, and keeping that shape here makes the diff easier to
    read.

 drivers/pci/controller/dwc/pcie-rcar-gen4.c | 118 ++++++++++++++++++--
 1 file changed, 111 insertions(+), 7 deletions(-)

diff --git a/drivers/pci/controller/dwc/pcie-rcar-gen4.c b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
index 8a85f5f45cda..5b983ef6dc47 100644
--- a/drivers/pci/controller/dwc/pcie-rcar-gen4.c
+++ b/drivers/pci/controller/dwc/pcie-rcar-gen4.c
@@ -15,6 +15,7 @@
 #include <linux/iopoll.h>
 #include <linux/irqchip/arm-gic-v3.h>
 #include <linux/module.h>
+#include <linux/mutex.h>
 #include <linux/of.h>
 #include <linux/of_address.h>
 #include <linux/of_irq.h>
@@ -90,12 +91,22 @@ struct rcar_gen4_pcie_drvdata {
 	enum dw_pcie_device_mode mode;
 };
 
+enum rcar_gen4_pcie_state {
+	/* The controller is being reset and reinitialized */
+	RCAR_PCIE_RESETTING,
+};
+
 struct rcar_gen4_pcie {
 	struct dw_pcie dw;
 	void __iomem *base;
 	void __iomem *phy_base;
 	struct platform_device *pdev;
 	const struct rcar_gen4_pcie_drvdata *drvdata;
+	unsigned long state;
+	/* Protects APP interrupt enable registers and their software state. */
+	raw_spinlock_t app_lock;
+	/* Serializes Root Port hardware reinitialization. */
+	struct mutex reset_lock;
 };
 #define to_rcar_gen4_pcie(_dw)	container_of(_dw, struct rcar_gen4_pcie, dw)
 
@@ -344,6 +355,33 @@ static int rcar_gen4_pcie_host_msi_addr(struct dw_pcie_rp *pp, u32 *msi_addr)
 	return 0;
 }
 
+/* Whether the APP interrupt sources may currently be enabled. */
+static bool rcar_gen4_pcie_irqs_blocked(struct rcar_gen4_pcie *rcar)
+{
+	return !!rcar->state;
+}
+
+static void rcar_gen4_pcie_app_irq_sync_locked(struct rcar_gen4_pcie *rcar)
+{
+	bool armed = !rcar_gen4_pcie_irqs_blocked(rcar);
+	u32 val;
+
+	lockdep_assert_held(&rcar->app_lock);
+
+	val = readl(rcar->base + PCIEINTSTS0EN);
+	val &= ~MSI_CTRL_INT;
+	if (armed && 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);
@@ -374,12 +412,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;
 
@@ -394,6 +427,7 @@ static int rcar_gen4_pcie_host_msi_init(struct dw_pcie_rp *pp)
 	writel(0, rcar->base + AXIINTCCONT);
 
 	/* Deconfigure MSI interrupt signal */
+	guard(raw_spinlock_irqsave)(&rcar->app_lock);
 	val = readl(rcar->base + PCIEINTSTS0EN);
 	val &= ~MSI_CTRL_INT;
 	writel(val, rcar->base + PCIEINTSTS0EN);
@@ -484,14 +518,77 @@ static int rcar_gen4_pcie_host_hw_init(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) {
+		set_bit(RCAR_PCIE_RESETTING, &rcar->state);
+		rcar_gen4_pcie_app_irq_sync_locked(rcar);
+	}
+}
+
+static void rcar_gen4_pcie_resume_irqs(struct rcar_gen4_pcie *rcar)
+{
+	scoped_guard(raw_spinlock_irqsave, &rcar->app_lock) {
+		clear_bit(RCAR_PCIE_RESETTING, &rcar->state);
+		rcar_gen4_pcie_app_irq_sync_locked(rcar);
+	}
+}
+
+/*
+ * R-Car Gen4 controllers have a single Root Port per instance, so the
+ * 'pci_dev' is ignored and the whole controller is reset.
+ */
+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;
+
+	guard(mutex)(&rcar->reset_lock);
+
+	rcar_gen4_pcie_quiesce_irqs(rcar);
+
+	dw_pcie_stop_link(dw);
+
+	ret = rcar_gen4_pcie_host_hw_init(pp);
+	if (ret) {
+		dev_err(dev, "Host init failed: %d\n", ret);
+		goto out;
+	}
+
+	ret = dw_pcie_setup_rc(pp);
+	if (ret) {
+		dev_err(dev, "Failed to setup RC: %d\n", 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);
+
+	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;
+	}
 
 	ret = rcar_gen4_pcie_clk_enable(rcar);
 	if (ret)
@@ -525,10 +622,17 @@ static const struct dw_pcie_host_ops rcar_gen4_pcie_host_ops = {
 static int rcar_gen4_add_dw_pcie_rp(struct rcar_gen4_pcie *rcar)
 {
 	struct dw_pcie_rp *pp = &rcar->dw.pp;
+	int ret;
 
 	if (!IS_ENABLED(CONFIG_PCIE_RCAR_GEN4_HOST))
 		return -ENODEV;
 
+	ret = devm_mutex_init(rcar->dw.dev, &rcar->reset_lock);
+	if (ret)
+		return ret;
+
+	raw_spin_lock_init(&rcar->app_lock);
+
 	pp->num_vectors = MAX_MSI_IRQS;
 	pp->ops = &rcar_gen4_pcie_host_ops;
 
-- 
2.51.0


  parent reply	other threads:[~2026-09-18  3:20 UTC|newest]

Thread overview: 45+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-18  3:20 [PATCH 00/11] PCI: rcar-gen4: Recover from link down and route Root Port interrupts Koichiro Den
2026-09-18  3:20 ` [PATCH 01/11] PCI: dwc: Add Renesas to the RAS DES VSEC list Koichiro Den
2026-09-18  3:24   ` sashiko-bot
2026-09-22 19:40   ` Marek Vasut
2026-09-18  3:20 ` [PATCH 02/11] PCI: rcar-gen4: Drop the APP-based link_up check Koichiro Den
2026-09-18  3:25   ` sashiko-bot
2026-09-22 20:56   ` Marek Vasut
2026-09-23 14:56     ` Koichiro Den
2026-09-27 19:59       ` Marek Vasut
2026-09-28  4:20         ` Koichiro Den
2026-09-28 15:07           ` Marek Vasut
2026-09-18  3:20 ` [PATCH 03/11] dt-bindings: PCI: rcar-gen4: Add optional "aer" interrupt Koichiro Den
2026-09-18  3:25   ` sashiko-bot
2026-09-22 20:59   ` Marek Vasut
2026-09-28 18:32   ` Rob Herring (Arm)
2026-09-18  3:20 ` [PATCH 04/11] PCI: dwc: Add a host op to run before iMSI-RX status is read Koichiro Den
2026-09-18  3:32   ` sashiko-bot
2026-09-18  3:20 ` [PATCH 05/11] PCI: rcar-gen4: Split reusable hardware initialization Koichiro Den
2026-09-18  3:27   ` sashiko-bot
2026-09-22 21:15   ` Marek Vasut
2026-09-23 15:24     ` Koichiro Den
2026-09-27 20:43       ` Marek Vasut
2026-09-18  3:20 ` Koichiro Den [this message]
2026-09-18  3:29   ` [PATCH 06/11] PCI: rcar-gen4: Add Root Port reset support sashiko-bot
2026-09-22 21:22   ` Marek Vasut
2026-09-23 16:12     ` Koichiro Den
2026-09-27 22:25       ` Marek Vasut
2026-09-28  3:50         ` Koichiro Den
2026-09-28 17:47           ` Marek Vasut
2026-09-18  3:20 ` [PATCH 07/11] PCI: rcar-gen4: Recover the Root Port on link down Koichiro Den
2026-09-18  3:33   ` sashiko-bot
2026-09-22 21:44   ` Marek Vasut
2026-09-24 16:15     ` Koichiro Den
2026-09-27 22:37       ` Marek Vasut
2026-09-28  4:06         ` Koichiro Den
2026-09-28 17:36           ` Marek Vasut
2026-09-18  3:20 ` [PATCH 08/11] PCI: dwc: Let glue drivers hide the Root Port MSI capabilities Koichiro Den
2026-09-18  3:24   ` sashiko-bot
2026-09-18  3:20 ` [PATCH 09/11] PCI: rcar-gen4: Route Root Port AER to a virtual Root Port IRQ Koichiro Den
2026-09-18  3:32   ` sashiko-bot
2026-09-18  3:20 ` [PATCH 10/11] PCI: rcar-gen4: Route Root Port PME and bandwidth notifications Koichiro Den
2026-09-18  3:30   ` sashiko-bot
2026-09-18  3:20 ` [PATCH 11/11] arm64: dts: renesas: r8a779f0: Describe the PCIe AER interrupts Koichiro Den
2026-09-18  3:27   ` sashiko-bot
2026-09-22 21:31   ` Marek Vasut

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=20260918032038.2216471-7-den@valinux.co.jp \
    --to=den@valinux.co.jp \
    --cc=Frank.Li@nxp.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