]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Initialize RCB from pci_configure_device()
authorHåkon Bugge <haakon.bugge@oracle.com>
Thu, 29 Jan 2026 17:52:32 +0000 (18:52 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 30 Jan 2026 17:52:09 +0000 (11:52 -0600)
Commit e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root
Port supports it (_HPX)") worked around a bogus _HPX type 2 record, which
caused program_hpx_type2() to set the RCB in an endpoint even though the
Root Port did not have the RCB bit set.

e42010d8207f fixed that by setting the RCB in the endpoint only when it was
set in the Root Port.

In retrospect, program_hpx_type2() is intended for AER-related settings,
and the RCB should be configured elsewhere so it doesn't depend on the
presence or contents of an _HPX record.

Explicitly program the RCB from pci_configure_device() so it matches the
Root Port's RCB.  The Root Port may not be visible to virtualized guests;
in that case, leave RCB alone.

Fixes: e42010d8207f ("PCI: Set Read Completion Boundary to 128 iff Root Port supports it (_HPX)")
Signed-off-by: Håkon Bugge <haakon.bugge@oracle.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260129175237.727059-2-haakon.bugge@oracle.com
drivers/pci/probe.c

index 86665658d70477eab149bf951ee898cf1df2221b..c791bca2891f635b854afd4f80ddffd497952921 100644 (file)
@@ -2411,6 +2411,37 @@ static void pci_configure_serr(struct pci_dev *dev)
        }
 }
 
+static void pci_configure_rcb(struct pci_dev *dev)
+{
+       struct pci_dev *rp;
+       u16 rp_lnkctl;
+
+       /*
+        * Per PCIe r7.0, sec 7.5.3.7, RCB is only meaningful in Root Ports
+        * (where it is read-only), Endpoints, and Bridges.  It may only be
+        * set for Endpoints and Bridges if it is set in the Root Port. For
+        * Endpoints, it is 'RsvdP' for Virtual Functions.
+        */
+       if (!pci_is_pcie(dev) ||
+           pci_pcie_type(dev) == PCI_EXP_TYPE_ROOT_PORT ||
+           pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM ||
+           pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM ||
+           pci_pcie_type(dev) == PCI_EXP_TYPE_RC_EC ||
+           dev->is_virtfn)
+               return;
+
+       /* Root Port often not visible to virtualized guests */
+       rp = pcie_find_root_port(dev);
+       if (!rp)
+               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);
+}
+
 static void pci_configure_device(struct pci_dev *dev)
 {
        pci_configure_mps(dev);
@@ -2420,6 +2451,7 @@ static void pci_configure_device(struct pci_dev *dev)
        pci_configure_aspm_l1ss(dev);
        pci_configure_eetlp_prefix(dev);
        pci_configure_serr(dev);
+       pci_configure_rcb(dev);
 
        pci_acpi_program_hp_params(dev);
 }