From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.133]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id A517EC531D0 for ; Mon, 27 Jul 2026 17:27:16 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20210309; h=Sender: Content-Transfer-Encoding:Content-Type:List-Subscribe:List-Help:List-Post: List-Archive:List-Unsubscribe:List-Id:MIME-Version:References:In-Reply-To: Message-ID:Date:Subject:Cc:To:From:Reply-To:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: List-Owner; bh=7lq3q2M+g0SrqI/VgzWeeOTVTgzsgXNaNwHisLjV67I=; b=hRZk3VuCPqLBZ0 lsnl/D2ANOQvRVth3U6p+DWBD7FU+GB1E/Memjf/5gNnvzPI4myCJXIBDD28BFAxr0jTfK9azdX+q uskInJAjGV84WKHSYZmKPt0kjvHBBPSBVay/VcapM9AIOKOZxF8I/qkBcmCJUJPvj9nf/KmXhj8A9 mi8wwaQ3XVTNBrVbXII01ARfGWXoXDD0hTZyBgzIFukKvsktZ5c147uNISLtctrNpzciDnP/rLsql pVp2Rm++hVlnycTRQ0iUFuW2udaJDs4fTrj8T+AoQGQRKDgktnVfE2fjihgcRnstkcno0ngYOYvmv 9FxQ6q2oKcsD/FCtHScw==; Received: from localhost ([::1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.99.1 #2 (Red Hat Linux)) id 1woP6f-00000003W1i-3eAC; Mon, 27 Jul 2026 17:27:13 +0000 Received: from tor.source.kernel.org ([172.105.4.254]) by bombadil.infradead.org with esmtps (Exim 4.99.1 #2 (Red Hat Linux)) id 1woP6e-00000003W0Y-06qm for linux-rockchip@lists.infradead.org; Mon, 27 Jul 2026 17:27:12 +0000 Received: from smtp.kernel.org (quasi.space.kernel.org [100.103.45.18]) by tor.source.kernel.org (Postfix) with ESMTP id 1E72D6013A; Mon, 27 Jul 2026 17:27:10 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2E77B1F00A3A; Mon, 27 Jul 2026 17:27:07 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1785173229; bh=mC5SnK7bd9ACNq5Ehz9E0+93QnTC6sx/Xv4on/acEGk=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=N9N3iTSnWapi0gqcFigXP8ZwzG5gj272Zmeir/5i+RvYoImQSxti+QH+dhWkppoxe 0qgAMiXp14PvWze5ndhV+i8nyV3BbTeMcsqEbqipo2zvR9z+O+cVXTaf6U81WIG2FQ 1Fz10BtZuQt7cxBTQnVwB344oscnpu+dFoiDpynkJ5oKf8p26VUe7n/FmJF8iy/plC Ti+1Szm2fR5BrMhVEOx9n5KXu/gKQbrv1COsmyPZjpnc6WTALGW6BQetLGdUel4o0c O02x+vnkx33G0DU7zv7TvzwTcVzxs4Ja0V/uVJWscgsUhF8qPpVKqAXuooji+VlEG1 ulVDcPIogXP/w== From: Niklas Cassel To: Manivannan Sadhasivam , Lorenzo Pieralisi , Rob Herring , Heiko Stuebner , =?UTF-8?q?Krzysztof=20Wilczy=C5=84ski?= , Bjorn Helgaas , Philipp Zabel Cc: linux-pci@vger.kernel.org, linux-rockchip@lists.infradead.org, Wilfred Mallawa , Shin'ichiro Kawasaki , Damien Le Moal , Niklas Cassel Subject: [PATCH 1/1] PCI: dw-rockchip: Add support to reset Root Port upon link down event Date: Mon, 27 Jul 2026 19:26:56 +0200 Message-ID: <20260727172654.605988-4-cassel@kernel.org> X-Mailer: git-send-email 2.55.0 In-Reply-To: <20260727172654.605988-3-cassel@kernel.org> References: <20260727172654.605988-3-cassel@kernel.org> MIME-Version: 1.0 X-Developer-Signature: v=1; a=openpgp-sha256; l=7802; i=cassel@kernel.org; h=from:subject; bh=z5Wd2J4+V2Zw6SSBcGR92TwVeSVDFtRgKDJnMK+9PP0=; b=owGbwMvMwCV2MsVw8cxjvkWMp9WSGLLSp9z70tj9MC49Yk+jwwSu26bbH5ppnglefDB9s38h5 5WsJNMtHaUsDGJcDLJiiiy+P1z2F3e7TzmueMcGZg4rE8gQBi5OAZhIcAbD/5JnYrEBqzRM3dbv jv6/6mvUa0eLJ8+dRSa9/i0rd835JQ8jw9Xd6rPSXj3c0/k149mvCo5Hez9nSu5K8Dz3ZabOtnp rEWYA X-Developer-Key: i=cassel@kernel.org; a=openpgp; fpr=5ADE635C0E631CBBD5BE065A352FE6582ED9B5DA X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.34 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+linux-rockchip=archiver.kernel.org@lists.infradead.org From: Wilfred Mallawa The PCIe link may go down in cases like firmware crashes or unstable connections. When this occurs, the PCIe Root Port must be reset to restore the functionality. However, the current driver lacks link down handling, forcing users to reboot the system to recover. This patch implements the `reset_root_port` callback for link down handling for Rockchip DWC PCIe host controller. In which, the RC is reset, reconfigured and link training initiated to recover from the link down event. This also by extension fixes issues with sysfs initiated bus resets. In that, currently, when a sysfs initiated bus reset is issued, the endpoint device is non-functional after (may link up with downgraded link status). With the link down handling support, a sysfs initiated bus reset works as intended. Testing conducted on a ROCK5B board with an M.2 NVMe drive. Signed-off-by: Wilfred Mallawa Signed-off-by: Niklas Cassel --- drivers/pci/controller/dwc/Kconfig | 1 + drivers/pci/controller/dwc/pcie-dw-rockchip.c | 134 +++++++++++++++++- 2 files changed, 132 insertions(+), 3 deletions(-) diff --git a/drivers/pci/controller/dwc/Kconfig b/drivers/pci/controller/dwc/Kconfig index f2fde13107f2..70947544c6a3 100644 --- a/drivers/pci/controller/dwc/Kconfig +++ b/drivers/pci/controller/dwc/Kconfig @@ -373,6 +373,7 @@ config PCIE_ROCKCHIP_DW_HOST depends on OF select PCIE_DW_HOST select PCIE_ROCKCHIP_DW + select PCI_HOST_COMMON help Enables support for the DesignWare PCIe controller in the Rockchip SoC (except RK3399) to work in host mode. diff --git a/drivers/pci/controller/dwc/pcie-dw-rockchip.c b/drivers/pci/controller/dwc/pcie-dw-rockchip.c index 731d93663cca..f9efe2d44957 100644 --- a/drivers/pci/controller/dwc/pcie-dw-rockchip.c +++ b/drivers/pci/controller/dwc/pcie-dw-rockchip.c @@ -26,6 +26,7 @@ #include #include "../../pci.h" +#include "../pci-host-common.h" #include "pcie-designware.h" /* @@ -122,6 +123,9 @@ struct rockchip_pcie_of_data { const struct pci_epc_features *epc_features; }; +static int rockchip_pcie_rc_reset_root_port(struct pci_host_bridge *bridge, + struct pci_dev *pdev); + static int rockchip_pcie_readl_apb(struct rockchip_pcie *rockchip, u32 reg) { return readl_relaxed(rockchip->apb_base + reg); @@ -436,6 +440,7 @@ static int rockchip_pcie_host_init(struct dw_pcie_rp *pp) rockchip_pcie_configure_l1ss(pci); rockchip_pcie_enable_l0s(pci); + pp->bridge->reset_root_port = rockchip_pcie_rc_reset_root_port; /* Disable Root Ports BAR0 and BAR1 as they report bogus size */ dw_pcie_writel_dbi2(pci, PCI_BASE_ADDRESS_0, 0x0); @@ -634,6 +639,32 @@ static const struct dw_pcie_ops dw_pcie_ops = { .get_ltssm = rockchip_pcie_get_ltssm, }; +static irqreturn_t rockchip_pcie_rc_sys_irq_thread(int irq, void *arg) +{ + struct rockchip_pcie *rockchip = arg; + struct dw_pcie *pci = &rockchip->pci; + struct dw_pcie_rp *pp = &pci->pp; + struct device *dev = pci->dev; + struct pci_dev *port; + u32 reg; + + reg = rockchip_pcie_readl_apb(rockchip, PCIE_CLIENT_INTR_STATUS_MISC); + rockchip_pcie_writel_apb(rockchip, reg, PCIE_CLIENT_INTR_STATUS_MISC); + + dev_dbg(dev, "PCIE_CLIENT_INTR_STATUS_MISC: %#x\n", reg); + dev_dbg(dev, "LTSSM_STATUS: %#x\n", rockchip_pcie_get_ltssm_reg(rockchip)); + + if (reg & PCIE_LINK_REQ_RST_NOT_INT) { + dev_dbg(dev, "hot reset or link-down reset\n"); + for_each_pci_bridge(port, pp->bridge->bus) { + if (pci_pcie_type(port) == PCI_EXP_TYPE_ROOT_PORT) + pci_host_handle_link_down(port); + } + } + + return IRQ_HANDLED; +} + static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) { struct rockchip_pcie *rockchip = arg; @@ -666,14 +697,29 @@ static irqreturn_t rockchip_pcie_ep_sys_irq_thread(int irq, void *arg) return IRQ_HANDLED; } -static int rockchip_pcie_configure_rc(struct rockchip_pcie *rockchip) +static int rockchip_pcie_configure_rc(struct platform_device *pdev, + struct rockchip_pcie *rockchip) { + struct device *dev = &pdev->dev; struct dw_pcie_rp *pp; + int irq, ret; u32 val; if (!IS_ENABLED(CONFIG_PCIE_ROCKCHIP_DW_HOST)) return -ENODEV; + irq = platform_get_irq_byname(pdev, "sys"); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(dev, irq, NULL, + rockchip_pcie_rc_sys_irq_thread, + IRQF_ONESHOT, "pcie-sys-rc", rockchip); + if (ret) { + dev_err(dev, "failed to request PCIe sys IRQ\n"); + return ret; + } + /* LTSSM enable control mode */ val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1); rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); @@ -685,7 +731,17 @@ static int rockchip_pcie_configure_rc(struct rockchip_pcie *rockchip) pp = &rockchip->pci.pp; pp->ops = &rockchip_pcie_host_ops; - return dw_pcie_host_init(pp); + ret = dw_pcie_host_init(pp); + if (ret) { + dev_err(dev, "failed to initialize host\n"); + return ret; + } + + /* unmask hot reset/link-down reset */ + val = FIELD_PREP_WM16(PCIE_LINK_REQ_RST_NOT_INT, 0); + rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC); + + return ret; } static int rockchip_pcie_configure_ep(struct platform_device *pdev, @@ -804,7 +860,7 @@ static int rockchip_pcie_probe(struct platform_device *pdev) switch (data->mode) { case DW_PCIE_RC_TYPE: - ret = rockchip_pcie_configure_rc(rockchip); + ret = rockchip_pcie_configure_rc(pdev, rockchip); if (ret) goto deinit_clk; break; @@ -829,6 +885,78 @@ static int rockchip_pcie_probe(struct platform_device *pdev) return ret; } +static int rockchip_pcie_rc_reset_root_port(struct pci_host_bridge *bridge, + struct pci_dev *pdev) +{ + struct pci_bus *bus = bridge->bus; + struct dw_pcie_rp *pp = bus->sysdata; + struct dw_pcie *pci = to_dw_pcie_from_pp(pp); + struct rockchip_pcie *rockchip = to_rockchip_pcie(pci); + struct device *dev = rockchip->pci.dev; + u32 val; + int ret; + + dw_pcie_stop_link(pci); + clk_bulk_disable_unprepare(rockchip->clk_cnt, rockchip->clks); + rockchip_pcie_phy_deinit(rockchip); + + ret = reset_control_assert(rockchip->rst); + if (ret) + return ret; + + ret = rockchip_pcie_phy_init(rockchip); + if (ret) + return ret; + + ret = reset_control_deassert(rockchip->rst); + if (ret) + goto deinit_phy; + + ret = rockchip_pcie_clk_init(rockchip); + if (ret) + goto deinit_phy; + + ret = pp->ops->init(pp); + if (ret) { + dev_err(dev, "Host init failed: %d\n", ret); + goto deinit_clk; + } + + /* LTSSM enable control mode */ + val = FIELD_PREP_WM16(PCIE_LTSSM_ENABLE_ENHANCE, 1); + rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_HOT_RESET_CTRL); + + rockchip_pcie_writel_apb(rockchip, + PCIE_CLIENT_SET_MODE(PCIE_CLIENT_MODE_RC), + PCIE_CLIENT_GENERAL_CON); + + ret = dw_pcie_setup_rc(pp); + if (ret) { + dev_err(dev, "Failed to setup RC: %d\n", ret); + goto deinit_clk; + } + + /* unmask hot reset/link-down reset */ + val = FIELD_PREP_WM16(PCIE_LINK_REQ_RST_NOT_INT, 0); + rockchip_pcie_writel_apb(rockchip, val, PCIE_CLIENT_INTR_MASK_MISC); + + ret = dw_pcie_start_link(pci); + if (ret) + goto deinit_clk; + + /* Ignore errors, the link may come up later */ + dw_pcie_wait_for_link(pci); + dev_dbg(dev, "Root Port reset completed\n"); + return ret; + +deinit_clk: + clk_bulk_disable_unprepare(rockchip->clk_cnt, rockchip->clks); +deinit_phy: + rockchip_pcie_phy_deinit(rockchip); + + return ret; +} + static const struct rockchip_pcie_of_data rockchip_pcie_rc_of_data_rk3568 = { .mode = DW_PCIE_RC_TYPE, }; -- 2.55.0 _______________________________________________ Linux-rockchip mailing list Linux-rockchip@lists.infradead.org http://lists.infradead.org/mailman/listinfo/linux-rockchip