summaryrefslogtreecommitdiff
path: root/src/device
diff options
context:
space:
mode:
Diffstat (limited to 'src/device')
-rw-r--r--src/device/pci_device.c27
1 files changed, 27 insertions, 0 deletions
diff --git a/src/device/pci_device.c b/src/device/pci_device.c
index 4b5e73b806..1075ef7e0e 100644
--- a/src/device/pci_device.c
+++ b/src/device/pci_device.c
@@ -1204,6 +1204,30 @@ static void pci_scan_hidden_device(struct device *dev)
}
/**
+ * A PCIe Downstream Port normally leads to a Link with only Device 0 on it
+ * (PCIe spec r5.0, sec 7.3.1). As an optimization, scan only for Device 0 in
+ * that situation.
+ *
+ * @param bus Pointer to the bus structure.
+ */
+static bool pci_bus_only_one_child(struct bus *bus)
+{
+ struct device *bridge = bus->dev;
+ u16 pcie_pos, pcie_flags_reg;
+ int pcie_type;
+
+ pcie_pos = pci_find_capability(bridge, PCI_CAP_ID_PCIE);
+ if (!pcie_pos)
+ return false;
+
+ pcie_flags_reg = pci_read_config16(bridge, pcie_pos + PCI_EXP_FLAGS);
+
+ pcie_type = (pcie_flags_reg & PCI_EXP_FLAGS_TYPE) >> 4;
+
+ return pciexp_is_downstream_port(pcie_type);
+}
+
+/**
* Scan a PCI bus.
*
* Determine the existence of devices and bridges on a PCI bus. If there are
@@ -1232,6 +1256,9 @@ void pci_scan_bus(struct bus *bus, unsigned int min_devfn,
post_code(0x24);
+ if (pci_bus_only_one_child(bus))
+ max_devfn = MIN(max_devfn, 0x07);
+
/*
* Probe all devices/functions on this bus with some optimization for
* non-existence and single function devices.