[PATCH RFC v2 1/3] PCI: rockchip-host: Skip downstream config access while link is down
From: Matt Thompson via B4 Relay
Date: Fri Nov 13 2026 - 19:52:38 EST
From: Matt Thompson <matt@xxxxxxxxxxxxx>
On a RockPro64, a PCI bus rescan with the downstream FPGA unavailable
faulted in rockchip_pcie_rd_conf() during a vendor ID read. The rescan
task exited with interrupts disabled and the watchdog reported a lockup.
Check the controller's link-up and link-training status before issuing
downstream config requests. Return PCIBIOS_DEVICE_NOT_FOUND while the
link is unavailable. Root port config access still uses the local
controller registers.
This check cannot prevent the link from dropping during the transaction.
Signed-off-by: Matt Thompson <matt@xxxxxxxxxxxxx>
---
drivers/pci/controller/pcie-rockchip-host.c | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/drivers/pci/controller/pcie-rockchip-host.c b/drivers/pci/controller/pcie-rockchip-host.c
index 5b071bd..35105c1 100644
--- a/drivers/pci/controller/pcie-rockchip-host.c
+++ b/drivers/pci/controller/pcie-rockchip-host.c
@@ -143,12 +143,23 @@ static int rockchip_pcie_wr_own_conf(struct rockchip_pcie *rockchip,
return PCIBIOS_SUCCESSFUL;
}
+static bool rockchip_pcie_downstream_ready(struct rockchip_pcie *rockchip)
+{
+ return PCIE_LINK_UP(rockchip_pcie_read(rockchip, PCIE_CLIENT_BASIC_STATUS1)) &&
+ PCIE_LINK_TRAINING_DONE(rockchip_pcie_read(rockchip, PCIE_CORE_CTRL));
+}
+
static int rockchip_pcie_rd_other_conf(struct rockchip_pcie *rockchip,
struct pci_bus *bus, u32 devfn,
int where, int size, u32 *val)
{
void __iomem *addr;
+ if (!rockchip_pcie_downstream_ready(rockchip)) {
+ *val = ~0U;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
if (!IS_ALIGNED((uintptr_t)addr, size)) {
@@ -182,6 +193,9 @@ static int rockchip_pcie_wr_other_conf(struct rockchip_pcie *rockchip,
{
void __iomem *addr;
+ if (!rockchip_pcie_downstream_ready(rockchip))
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
addr = rockchip->reg_base + PCIE_ECAM_OFFSET(bus->number, devfn, where);
if (!IS_ALIGNED((uintptr_t)addr, size))
--
Git-155)