]> Pileus Git - ~andy/linux/blobdiff - drivers/pci/probe.c
Merge tag 'pci-v3.9-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
[~andy/linux] / drivers / pci / probe.c
index 2dcd22d9c816f98c681f572a2f48fbba7da5680b..b494066ef32f5f08e3f5d4f4b3d88acf9257d710 100644 (file)
@@ -623,6 +623,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
 {
        struct pci_bus *child;
        int i;
+       int ret;
 
        /*
         * Allocate a new bus, and inherit stuff from the parent..
@@ -637,8 +638,7 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
        child->bus_flags = parent->bus_flags;
 
        /* initialize some portions of the bus device, but don't register it
-        * now as the parent is not properly set up yet.  This device will get
-        * registered later in pci_bus_add_devices()
+        * now as the parent is not properly set up yet.
         */
        child->dev.class = &pcibus_class;
        dev_set_name(&child->dev, "%04x:%02x", pci_domain_nr(child), busnr);
@@ -651,11 +651,14 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
        child->primary = parent->busn_res.start;
        child->busn_res.end = 0xff;
 
-       if (!bridge)
-               return child;
+       if (!bridge) {
+               child->dev.parent = parent->bridge;
+               goto add_dev;
+       }
 
        child->self = bridge;
        child->bridge = get_device(&bridge->dev);
+       child->dev.parent = child->bridge;
        pci_set_bus_of_node(child);
        pci_set_bus_speed(child);
 
@@ -666,6 +669,13 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
        }
        bridge->subordinate = child;
 
+add_dev:
+       ret = device_register(&child->dev);
+       WARN_ON(ret < 0);
+
+       /* Create legacy_io and legacy_mem files for this bus */
+       pci_create_legacy_files(child);
+
        return child;
 }
 
@@ -1285,7 +1295,7 @@ static void pci_init_capabilities(struct pci_dev *dev)
        pci_vpd_pci22_init(dev);
 
        /* Alternative Routing-ID Forwarding */
-       pci_enable_ari(dev);
+       pci_configure_ari(dev);
 
        /* Single Root I/O Virtualization */
        pci_iov_init(dev);
@@ -1296,10 +1306,12 @@ static void pci_init_capabilities(struct pci_dev *dev)
 
 void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
 {
+       int ret;
+
        device_initialize(&dev->dev);
        dev->dev.release = pci_release_dev;
-       pci_dev_get(dev);
 
+       set_dev_node(&dev->dev, pcibus_to_node(bus));
        dev->dev.dma_mask = &dev->dma_mask;
        dev->dev.dma_parms = &dev->dma_parms;
        dev->dev.coherent_dma_mask = 0xffffffffull;
@@ -1326,6 +1338,17 @@ void pci_device_add(struct pci_dev *dev, struct pci_bus *bus)
        down_write(&pci_bus_sem);
        list_add_tail(&dev->bus_list, &bus->devices);
        up_write(&pci_bus_sem);
+
+       pci_fixup_device(pci_fixup_final, dev);
+       ret = pcibios_add_device(dev);
+       WARN_ON(ret < 0);
+
+       /* Notifier could use PCI capabilities */
+       dev->match_driver = false;
+       ret = device_add(&dev->dev);
+       WARN_ON(ret < 0);
+
+       pci_proc_attach_device(dev);
 }
 
 struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
@@ -1348,31 +1371,31 @@ struct pci_dev *__ref pci_scan_single_device(struct pci_bus *bus, int devfn)
 }
 EXPORT_SYMBOL(pci_scan_single_device);
 
-static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
+static unsigned next_fn(struct pci_bus *bus, struct pci_dev *dev, unsigned fn)
 {
-       u16 cap;
-       unsigned pos, next_fn;
+       int pos;
+       u16 cap = 0;
+       unsigned next_fn;
 
-       if (!dev)
-               return 0;
+       if (pci_ari_enabled(bus)) {
+               if (!dev)
+                       return 0;
+               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
+               if (!pos)
+                       return 0;
 
-       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
-       if (!pos)
-               return 0;
-       pci_read_config_word(dev, pos + 4, &cap);
-       next_fn = cap >> 8;
-       if (next_fn <= fn)
-               return 0;
-       return next_fn;
-}
+               pci_read_config_word(dev, pos + PCI_ARI_CAP, &cap);
+               next_fn = PCI_ARI_CAP_NFN(cap);
+               if (next_fn <= fn)
+                       return 0;       /* protect against malformed list */
 
-static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
-{
-       return (fn + 1) % 8;
-}
+               return next_fn;
+       }
+
+       /* dev may be NULL for non-contiguous multifunction devices */
+       if (!dev || dev->multifunction)
+               return (fn + 1) % 8;
 
-static unsigned no_next_fn(struct pci_dev *dev, unsigned fn)
-{
        return 0;
 }
 
@@ -1405,7 +1428,6 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
        unsigned fn, nr = 0;
        struct pci_dev *dev;
-       unsigned (*next_fn)(struct pci_dev *, unsigned) = no_next_fn;
 
        if (only_one_child(bus) && (devfn > 0))
                return 0; /* Already scanned the entire slot */
@@ -1416,12 +1438,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
        if (!dev->is_added)
                nr++;
 
-       if (pci_ari_enabled(bus))
-               next_fn = next_ari_fn;
-       else if (dev->multifunction)
-               next_fn = next_trad_fn;
-
-       for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
+       for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
                dev = pci_scan_single_device(bus, devfn + fn);
                if (dev) {
                        if (!dev->is_added)
@@ -1632,6 +1649,18 @@ unsigned int pci_scan_child_bus(struct pci_bus *bus)
        return max;
 }
 
+/**
+ * pcibios_root_bridge_prepare - Platform-specific host bridge setup.
+ * @bridge: Host bridge to set up.
+ *
+ * Default empty implementation.  Replace with an architecture-specific setup
+ * routine, if necessary.
+ */
+int __weak pcibios_root_bridge_prepare(struct pci_host_bridge *bridge)
+{
+       return 0;
+}
+
 struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
                struct pci_ops *ops, void *sysdata, struct list_head *resources)
 {
@@ -1644,13 +1673,13 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        char bus_addr[64];
        char *fmt;
 
-
        b = pci_alloc_bus();
        if (!b)
                return NULL;
 
        b->sysdata = sysdata;
        b->ops = ops;
+       b->number = b->busn_res.start = bus;
        b2 = pci_find_bus(pci_domain_nr(b), bus);
        if (b2) {
                /* If we already got to this bus through a different bridge, ignore it */
@@ -1665,6 +1694,10 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        bridge->dev.parent = parent;
        bridge->dev.release = pci_release_bus_bridge_dev;
        dev_set_name(&bridge->dev, "pci%04x:%02x", pci_domain_nr(b), bus);
+       error = pcibios_root_bridge_prepare(bridge);
+       if (error)
+               goto bridge_dev_reg_err;
+
        error = device_register(&bridge->dev);
        if (error)
                goto bridge_dev_reg_err;
@@ -1685,8 +1718,6 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
        /* Create legacy_io and legacy_mem files for this bus */
        pci_create_legacy_files(b);
 
-       b->number = b->busn_res.start = bus;
-
        if (parent)
                dev_info(parent, "PCI host bridge to bus %s\n", dev_name(&b->dev));
        else