[PATCH v2 2/2] PCI: Set RCB only when the Root Port has it set
From: Stefan Roese
Date: Fri Oct 02 2026 - 05:16:41 EST
pci_configure_rcb() read-modify-writes Link Control of every endpoint
at enumeration, also when RCB is clear in the Root Port and there is
nothing to set. Not writing a register that has nothing to change is
justified on its own, but the write-back of the other Link Control bits
also has side effects on some devices: the Renesas uPD720201 xHCI
(1912:0014) comes out of reset with ASPM L0s and L1 enabled and stops
clearing them itself once Link Control has been written. On a link
whose Root Port supports no ASPM, the previous patch clears them, but
it does not run with pcie_aspm=off or CONFIG_PCIEASPM=n. There the
first access to the xHCI BAR runs into completion timeouts that hang
the system.
RCB may only be set in an endpoint if it is set in the Root Port, so
there is no need to ever clear it here; an endpoint with RCB set
below a Root Port without it is a firmware configuration error. Only
set RCB, and only when the Root Port has it set.
Fixes: 1a6845aaa6de ("PCI: Initialize RCB from pci_configure_device()")
Cc: stable@xxxxxxxxxxxxxxx
Suggested-by: Bjorn Helgaas <bhelgaas@xxxxxxxxxx>
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Stefan Roese <stefan.roese@xxxxxxxxxxx>
---
Changes in v2:
- Replace "PCI: Write RCB only when it changes" (v1 1/2) with the
set-only variant suggested by Bjorn: never clear RCB, set it only
when the Root Port has it set
- Now patch 2/2, still with Fixes: and stable, because with
pcie_aspm=off or CONFIG_PCIEASPM=n patch 1 never runs and only
avoiding the Link Control write prevents the hang
---
drivers/pci/probe.c | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 721daf5c5184..0d05536216fb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -2448,10 +2448,9 @@ static void pci_configure_rcb(struct pci_dev *dev)
return;
pcie_capability_read_word(rp, PCI_EXP_LNKCTL, &rp_lnkctl);
- pcie_capability_clear_and_set_word(dev, PCI_EXP_LNKCTL,
- PCI_EXP_LNKCTL_RCB,
- (rp_lnkctl & PCI_EXP_LNKCTL_RCB) ?
- PCI_EXP_LNKCTL_RCB : 0);
+ if (rp_lnkctl & PCI_EXP_LNKCTL_RCB)
+ pcie_capability_set_word(dev, PCI_EXP_LNKCTL,
+ PCI_EXP_LNKCTL_RCB);
}
static void pci_configure_device(struct pci_dev *dev)
--
2.56.0