]> git.ipfire.org Git - thirdparty/u-boot.git/commitdiff
pci: skip unnecessary PCIe scanning
authorGeorge McCollister <george.mccollister@konsulko.com>
Fri, 30 Jan 2026 15:38:01 +0000 (09:38 -0600)
committerTom Rini <trini@konsulko.com>
Wed, 4 Feb 2026 16:40:28 +0000 (10:40 -0600)
Use the same mechanism as the Linux kernel to skip unnecessary (and in
the case of the J722S, errant) scanning of direct children of root
ports, downstream ports or bridges.

Based on Linux PCI code in the following files as of b927546677c8:
  drivers/pci/probe.c
  drivers/pci/pci.h
  include/linux/pci.h

Signed-off-by: George McCollister <george.mccollister@konsulko.com>
Tested-by: Bryan Brattlof <bb@ti.com>
drivers/pci/pci-uclass.c

index c370f8c6400dbfdcacafa51bb4bdae78c3ec545c..83b76d01f24a68d0bfa330669875bbef8dcdbe77 100644 (file)
@@ -872,6 +872,38 @@ __weak extern void board_pci_fixup_dev(struct udevice *bus, struct udevice *dev)
 {
 }
 
+static int only_one_child(struct udevice *bus)
+{
+       int pos;
+
+       if (!dev_get_parent_plat(bus))
+               return 0;
+
+       /*
+        * A PCIe Downstream Port normally leads to a Link with only Device
+        * 0 on it (PCIe spec r3.1, sec 7.3.1).  As an optimization, scan
+        * only for Device 0 in that situation.
+        */
+       pos = dm_pci_find_capability(bus, PCI_CAP_ID_EXP);
+       if (pos) {
+               ulong reg;
+               ulong pcie_type;
+
+               dm_pci_read_config(bus, pos + PCI_EXP_FLAGS,
+                                  &reg, PCI_SIZE_16);
+
+               pcie_type = (reg & PCI_EXP_FLAGS_TYPE) >> 4;
+
+               if (pcie_type == PCI_EXP_TYPE_ROOT_PORT ||
+                   pcie_type == PCI_EXP_TYPE_DOWNSTREAM ||
+                   pcie_type == PCI_EXP_TYPE_PCIE_BRIDGE) {
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
 int pci_bind_bus_devices(struct udevice *bus)
 {
        ulong vendor, device;
@@ -895,6 +927,9 @@ int pci_bind_bus_devices(struct udevice *bus)
                if (PCI_FUNC(bdf) && !found_multi)
                        continue;
 
+               if (only_one_child(bus) && (PCI_MASK_BUS(bdf) > 0))
+                       continue;
+
                /* Check only the first access, we don't expect problems */
                ret = pci_bus_read_config(bus, bdf, PCI_VENDOR_ID, &vendor,
                                          PCI_SIZE_16);