Merge tag 'cxl-for-6.0' of git://git.kernel.org/pub/scm/linux/kernel/git/cxl/cxl
[linux-2.6-microblaze.git] / drivers / pci / probe.c
index 6280e78..c5286b0 100644 (file)
@@ -1890,6 +1890,9 @@ int pci_setup_device(struct pci_dev *dev)
 
        dev->broken_intx_masking = pci_intx_mask_broken(dev);
 
+       /* Clear errors left from system firmware */
+       pci_write_config_word(dev, PCI_STATUS, 0xffff);
+
        switch (dev->hdr_type) {                    /* header type */
        case PCI_HEADER_TYPE_NORMAL:                /* standard header */
                if (class == PCI_CLASS_BRIDGE_PCI)
@@ -2579,33 +2582,39 @@ struct pci_dev *pci_scan_single_device(struct pci_bus *bus, int devfn)
 }
 EXPORT_SYMBOL(pci_scan_single_device);
 
-static unsigned int next_fn(struct pci_bus *bus, struct pci_dev *dev,
-                           unsigned int fn)
+static int next_ari_fn(struct pci_bus *bus, struct pci_dev *dev, int fn)
 {
        int pos;
        u16 cap = 0;
        unsigned int next_fn;
 
-       if (pci_ari_enabled(bus)) {
-               if (!dev)
-                       return 0;
-               pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
-               if (!pos)
-                       return 0;
+       if (!dev)
+               return -ENODEV;
 
-               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 */
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
+       if (!pos)
+               return -ENODEV;
 
-               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 -ENODEV; /* protect against malformed list */
 
-       /* dev may be NULL for non-contiguous multifunction devices */
-       if (!dev || dev->multifunction)
-               return (fn + 1) % 8;
+       return next_fn;
+}
 
-       return 0;
+static int next_fn(struct pci_bus *bus, struct pci_dev *dev, int fn)
+{
+       if (pci_ari_enabled(bus))
+               return next_ari_fn(bus, dev, fn);
+
+       if (fn >= 7)
+               return -ENODEV;
+       /* only multifunction devices may have more functions */
+       if (dev && !dev->multifunction)
+               return -ENODEV;
+
+       return fn + 1;
 }
 
 static int only_one_child(struct pci_bus *bus)
@@ -2643,26 +2652,30 @@ static int only_one_child(struct pci_bus *bus)
  */
 int pci_scan_slot(struct pci_bus *bus, int devfn)
 {
-       unsigned int fn, nr = 0;
        struct pci_dev *dev;
+       int fn = 0, nr = 0;
 
        if (only_one_child(bus) && (devfn > 0))
                return 0; /* Already scanned the entire slot */
 
-       dev = pci_scan_single_device(bus, devfn);
-       if (!dev)
-               return 0;
-       if (!pci_dev_is_added(dev))
-               nr++;
-
-       for (fn = next_fn(bus, dev, 0); fn > 0; fn = next_fn(bus, dev, fn)) {
+       do {
                dev = pci_scan_single_device(bus, devfn + fn);
                if (dev) {
                        if (!pci_dev_is_added(dev))
                                nr++;
-                       dev->multifunction = 1;
+                       if (fn > 0)
+                               dev->multifunction = 1;
+               } else if (fn == 0) {
+                       /*
+                        * Function 0 is required unless we are running on
+                        * a hypervisor that passes through individual PCI
+                        * functions.
+                        */
+                       if (!hypervisor_isolated_pci_functions())
+                               break;
                }
-       }
+               fn = next_fn(bus, dev, fn);
+       } while (fn >= 0);
 
        /* Only one slot has PCIe device */
        if (bus->self && nr)
@@ -2858,29 +2871,14 @@ static unsigned int pci_scan_child_bus_extend(struct pci_bus *bus,
 {
        unsigned int used_buses, normal_bridges = 0, hotplug_bridges = 0;
        unsigned int start = bus->busn_res.start;
-       unsigned int devfn, fn, cmax, max = start;
+       unsigned int devfn, cmax, max = start;
        struct pci_dev *dev;
-       int nr_devs;
 
        dev_dbg(&bus->dev, "scanning bus\n");
 
        /* Go find them, Rover! */
-       for (devfn = 0; devfn < 256; devfn += 8) {
-               nr_devs = pci_scan_slot(bus, devfn);
-
-               /*
-                * The Jailhouse hypervisor may pass individual functions of a
-                * multi-function device to a guest without passing function 0.
-                * Look for them as well.
-                */
-               if (jailhouse_paravirt() && nr_devs == 0) {
-                       for (fn = 1; fn < 8; fn++) {
-                               dev = pci_scan_single_device(bus, devfn + fn);
-                               if (dev)
-                                       dev->multifunction = 1;
-                       }
-               }
-       }
+       for (devfn = 0; devfn < 256; devfn += 8)
+               pci_scan_slot(bus, devfn);
 
        /* Reserve buses for SR-IOV capability */
        used_buses = pci_iov_bus_range(bus);