PCI: Add generic pci_bus_claim_resources()
authorLorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Wed, 8 Jun 2016 11:04:47 +0000 (12:04 +0100)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 23 Jun 2016 16:48:59 +0000 (11:48 -0500)
All PCI resources (bridge windows and BARs) should be inserted in the
iomem_resource and ioport_resource trees so we know what space is occupied
and what is available for other devices.  There's nothing arch-specific
about this, but it is currently done by arch-specific code.

Add a generic pci_bus_claim_resources() interface so we can migrate away
from the arch-specific code.

[bhelgaas: changelog]
Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
CC: Arnd Bergmann <arnd@arndb.de>
CC: Yinghai Lu <yinghai@kernel.org>
drivers/pci/setup-bus.c
include/linux/pci.h

index 55641a39a3e94f3eab29a5494d943afc9614d3e6..1d1a2c952c351e308cc2aefe7ffd4de82d528488 100644 (file)
@@ -1423,6 +1423,74 @@ void pci_bus_assign_resources(const struct pci_bus *bus)
 }
 EXPORT_SYMBOL(pci_bus_assign_resources);
 
+static void pci_claim_device_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = 0; i < PCI_BRIDGE_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_resource(dev, i);
+       }
+}
+
+static void pci_claim_bridge_resources(struct pci_dev *dev)
+{
+       int i;
+
+       for (i = PCI_BRIDGE_RESOURCES; i < PCI_NUM_RESOURCES; i++) {
+               struct resource *r = &dev->resource[i];
+
+               if (!r->flags || r->parent)
+                       continue;
+
+               pci_claim_bridge_resource(dev, i);
+       }
+}
+
+static void pci_bus_allocate_dev_resources(struct pci_bus *b)
+{
+       struct pci_dev *dev;
+       struct pci_bus *child;
+
+       list_for_each_entry(dev, &b->devices, bus_list) {
+               pci_claim_device_resources(dev);
+
+               child = dev->subordinate;
+               if (child)
+                       pci_bus_allocate_dev_resources(child);
+       }
+}
+
+static void pci_bus_allocate_resources(struct pci_bus *b)
+{
+       struct pci_bus *child;
+
+       /*
+        * Carry out a depth-first search on the PCI bus
+        * tree to allocate bridge apertures. Read the
+        * programmed bridge bases and recursively claim
+        * the respective bridge resources.
+        */
+       if (b->self) {
+               pci_read_bridge_bases(b);
+               pci_claim_bridge_resources(b->self);
+       }
+
+       list_for_each_entry(child, &b->children, node)
+               pci_bus_allocate_resources(child);
+}
+
+void pci_bus_claim_resources(struct pci_bus *b)
+{
+       pci_bus_allocate_resources(b);
+       pci_bus_allocate_dev_resources(b);
+}
+EXPORT_SYMBOL(pci_bus_claim_resources);
+
 static void __pci_bridge_assign_resources(const struct pci_dev *bridge,
                                          struct list_head *add_head,
                                          struct list_head *fail_head)
index 6af3b93f07105b74e97b4aaeea654a6c097ad139..d6cfecfee864fdea9f1173c53a5f0141b339efb9 100644 (file)
@@ -1114,6 +1114,7 @@ int pci_set_vpd_size(struct pci_dev *dev, size_t len);
 /* Helper functions for low-level code (drivers/pci/setup-[bus,res].c) */
 resource_size_t pcibios_retrieve_fw_addr(struct pci_dev *dev, int idx);
 void pci_bus_assign_resources(const struct pci_bus *bus);
+void pci_bus_claim_resources(struct pci_bus *bus);
 void pci_bus_size_bridges(struct pci_bus *bus);
 int pci_claim_resource(struct pci_dev *, int);
 int pci_claim_bridge_resource(struct pci_dev *bridge, int i);