Merge branch 'pci/virtualization'
authorBjorn Helgaas <bhelgaas@google.com>
Thu, 4 Aug 2022 16:41:53 +0000 (11:41 -0500)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 4 Aug 2022 16:41:53 +0000 (11:41 -0500)
- Add ACS quirk for Broadcom BCM5750x multifunction NICs that isolate the
  functions but don't advertise an ACS capability (Pavan Chebbi)

* pci/virtualization:
  PCI: Add ACS quirk for Broadcom BCM5750x NICs

17 files changed:
Documentation/PCI/pci-iov-howto.rst
Documentation/PCI/sysfs-pci.rst
arch/s390/pci/pci_bus.c
arch/sparc/include/asm/pci.h
arch/sparc/kernel/pci.c
drivers/pci/endpoint/functions/pci-epf-test.c
drivers/pci/mmap.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer.c
drivers/pci/pcie/aspm.c
drivers/pci/pcie/err.c
drivers/pci/pcie/portdrv_core.c
drivers/pci/probe.c
drivers/pci/proc.c
include/linux/hypervisor.h
include/linux/pci.h

index b9fd003..27d3593 100644 (file)
@@ -125,14 +125,14 @@ Following piece of code illustrates the usage of the SR-IOV API.
                ...
        }
 
-       static int dev_suspend(struct pci_dev *dev, pm_message_t state)
+       static int dev_suspend(struct device *dev)
        {
                ...
 
                return 0;
        }
 
-       static int dev_resume(struct pci_dev *dev)
+       static int dev_resume(struct device *dev)
        {
                ...
 
@@ -165,8 +165,7 @@ Following piece of code illustrates the usage of the SR-IOV API.
                .id_table =     dev_id_table,
                .probe =        dev_probe,
                .remove =       dev_remove,
-               .suspend =      dev_suspend,
-               .resume =       dev_resume,
+               .driver.pm =    &dev_pm_ops,
                .shutdown =     dev_shutdown,
                .sriov_configure = dev_sriov_configure,
        };
index 742fbd2..f495185 100644 (file)
@@ -125,7 +125,7 @@ implementation of that functionality. To support the historical interface of
 mmap() through files in /proc/bus/pci, platforms may also set HAVE_PCI_MMAP.
 
 Alternatively, platforms which set HAVE_PCI_MMAP may provide their own
-implementation of pci_mmap_page_range() instead of defining
+implementation of pci_mmap_resource_range() instead of defining
 ARCH_GENERIC_PCI_MMAP_RESOURCE.
 
 Platforms which support write-combining maps of PCI resources must define
index 5d77acb..6a8da1b 100644 (file)
@@ -145,9 +145,6 @@ int zpci_bus_scan_bus(struct zpci_bus *zbus)
        struct zpci_dev *zdev;
        int devfn, rc, ret = 0;
 
-       if (!zbus->function[0])
-               return 0;
-
        for (devfn = 0; devfn < ZPCI_FUNCTIONS_PER_BUS; devfn++) {
                zdev = zbus->function[devfn];
                if (zdev && zdev->state == ZPCI_FN_STATE_CONFIGURED) {
@@ -184,26 +181,26 @@ void zpci_bus_scan_busses(void)
 
 /* zpci_bus_create_pci_bus - Create the PCI bus associated with this zbus
  * @zbus: the zbus holding the zdevices
- * @f0: function 0 of the bus
+ * @fr: PCI root function that will determine the bus's domain, and bus speeed
  * @ops: the pci operations
  *
- * Function zero is taken as a parameter as this is used to determine the
- * domain, multifunction property and maximum bus speed of the entire bus.
+ * The PCI function @fr determines the domain (its UID), multifunction property
+ * and maximum bus speed of the entire bus.
  *
  * Return: 0 on success, an error code otherwise
  */
-static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *f0, struct pci_ops *ops)
+static int zpci_bus_create_pci_bus(struct zpci_bus *zbus, struct zpci_dev *fr, struct pci_ops *ops)
 {
        struct pci_bus *bus;
        int domain;
 
-       domain = zpci_alloc_domain((u16)f0->uid);
+       domain = zpci_alloc_domain((u16)fr->uid);
        if (domain < 0)
                return domain;
 
        zbus->domain_nr = domain;
-       zbus->multifunction = f0->rid_available;
-       zbus->max_bus_speed = f0->max_bus_speed;
+       zbus->multifunction = fr->rid_available;
+       zbus->max_bus_speed = fr->max_bus_speed;
 
        /*
         * Note that the zbus->resources are taken over and zbus->resources
@@ -303,47 +300,6 @@ void pcibios_bus_add_device(struct pci_dev *pdev)
        }
 }
 
-/* zpci_bus_create_hotplug_slots - Add hotplug slot(s) for device added to bus
- * @zdev: the zPCI device that was newly added
- *
- * Add the hotplug slot(s) for the newly added PCI function. Normally this is
- * simply the slot for the function itself. If however we are adding the
- * function 0 on a zbus, it might be that we already registered functions on
- * that zbus but could not create their hotplug slots yet so add those now too.
- *
- * Return: 0 on success, an error code otherwise
- */
-static int zpci_bus_create_hotplug_slots(struct zpci_dev *zdev)
-{
-       struct zpci_bus *zbus = zdev->zbus;
-       int devfn, rc = 0;
-
-       rc = zpci_init_slot(zdev);
-       if (rc)
-               return rc;
-       zdev->has_hp_slot = 1;
-
-       if (zdev->devfn == 0 && zbus->multifunction) {
-               /* Now that function 0 is there we can finally create the
-                * hotplug slots for those functions with devfn != 0 that have
-                * been parked in zbus->function[] waiting for us to be able to
-                * create the PCI bus.
-                */
-               for  (devfn = 1; devfn < ZPCI_FUNCTIONS_PER_BUS; devfn++) {
-                       zdev = zbus->function[devfn];
-                       if (zdev && !zdev->has_hp_slot) {
-                               rc = zpci_init_slot(zdev);
-                               if (rc)
-                                       return rc;
-                               zdev->has_hp_slot = 1;
-                       }
-               }
-
-       }
-
-       return rc;
-}
-
 static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
 {
        int rc = -EINVAL;
@@ -352,21 +308,19 @@ static int zpci_bus_add_device(struct zpci_bus *zbus, struct zpci_dev *zdev)
                pr_err("devfn %04x is already assigned\n", zdev->devfn);
                return rc;
        }
+
        zdev->zbus = zbus;
        zbus->function[zdev->devfn] = zdev;
        zpci_nb_devices++;
 
-       if (zbus->bus) {
-               if (zbus->multifunction && !zdev->rid_available) {
-                       WARN_ONCE(1, "rid_available not set for multifunction\n");
-                       goto error;
-               }
-
-               zpci_bus_create_hotplug_slots(zdev);
-       } else {
-               /* Hotplug slot will be created once function 0 appears */
-               zbus->multifunction = 1;
+       if (zbus->multifunction && !zdev->rid_available) {
+               WARN_ONCE(1, "rid_available not set for multifunction\n");
+               goto error;
        }
+       rc = zpci_init_slot(zdev);
+       if (rc)
+               goto error;
+       zdev->has_hp_slot = 1;
 
        return 0;
 
@@ -400,7 +354,11 @@ int zpci_bus_device_register(struct zpci_dev *zdev, struct pci_ops *ops)
                        return -ENOMEM;
        }
 
-       if (zdev->devfn == 0) {
+       if (!zbus->bus) {
+               /* The UID of the first PCI function registered with a zpci_bus
+                * is used as the domain number for that bus. Currently there
+                * is exactly one zpci_bus per domain.
+                */
                rc = zpci_bus_create_pci_bus(zbus, zdev, ops);
                if (rc)
                        goto error;
index 4deddf4..dff90dc 100644 (file)
@@ -37,6 +37,7 @@ static inline int pci_proc_domain(struct pci_bus *bus)
 #define HAVE_PCI_MMAP
 #define arch_can_pci_mmap_io() 1
 #define HAVE_ARCH_PCI_GET_UNMAPPED_AREA
+#define ARCH_GENERIC_PCI_MMAP_RESOURCE
 #define get_pci_unmapped_area get_fb_unmapped_area
 #endif /* CONFIG_SPARC64 */
 
index 31b0c19..cb1ef25 100644 (file)
@@ -751,156 +751,15 @@ int pcibios_enable_device(struct pci_dev *dev, int mask)
 }
 
 /* Platform support for /proc/bus/pci/X/Y mmap()s. */
-
-/* If the user uses a host-bridge as the PCI device, he may use
- * this to perform a raw mmap() of the I/O or MEM space behind
- * that controller.
- *
- * This can be useful for execution of x86 PCI bios initialization code
- * on a PCI card, like the xfree86 int10 stuff does.
- */
-static int __pci_mmap_make_offset_bus(struct pci_dev *pdev, struct vm_area_struct *vma,
-                                     enum pci_mmap_state mmap_state)
+int pci_iobar_pfn(struct pci_dev *pdev, int bar, struct vm_area_struct *vma)
 {
        struct pci_pbm_info *pbm = pdev->dev.archdata.host_controller;
-       unsigned long space_size, user_offset, user_size;
-
-       if (mmap_state == pci_mmap_io) {
-               space_size = resource_size(&pbm->io_space);
-       } else {
-               space_size = resource_size(&pbm->mem_space);
-       }
-
-       /* Make sure the request is in range. */
-       user_offset = vma->vm_pgoff << PAGE_SHIFT;
-       user_size = vma->vm_end - vma->vm_start;
-
-       if (user_offset >= space_size ||
-           (user_offset + user_size) > space_size)
-               return -EINVAL;
-
-       if (mmap_state == pci_mmap_io) {
-               vma->vm_pgoff = (pbm->io_space.start +
-                                user_offset) >> PAGE_SHIFT;
-       } else {
-               vma->vm_pgoff = (pbm->mem_space.start +
-                                user_offset) >> PAGE_SHIFT;
-       }
-
-       return 0;
-}
-
-/* Adjust vm_pgoff of VMA such that it is the physical page offset
- * corresponding to the 32-bit pci bus offset for DEV requested by the user.
- *
- * Basically, the user finds the base address for his device which he wishes
- * to mmap.  They read the 32-bit value from the config space base register,
- * add whatever PAGE_SIZE multiple offset they wish, and feed this into the
- * offset parameter of mmap on /proc/bus/pci/XXX for that device.
- *
- * Returns negative error code on failure, zero on success.
- */
-static int __pci_mmap_make_offset(struct pci_dev *pdev,
-                                 struct vm_area_struct *vma,
-                                 enum pci_mmap_state mmap_state)
-{
-       unsigned long user_paddr, user_size;
-       int i, err;
-
-       /* First compute the physical address in vma->vm_pgoff,
-        * making sure the user offset is within range in the
-        * appropriate PCI space.
-        */
-       err = __pci_mmap_make_offset_bus(pdev, vma, mmap_state);
-       if (err)
-               return err;
-
-       /* If this is a mapping on a host bridge, any address
-        * is OK.
-        */
-       if ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
-               return err;
-
-       /* Otherwise make sure it's in the range for one of the
-        * device's resources.
-        */
-       user_paddr = vma->vm_pgoff << PAGE_SHIFT;
-       user_size = vma->vm_end - vma->vm_start;
+       resource_size_t ioaddr = pci_resource_start(pdev, bar);
 
-       for (i = 0; i <= PCI_ROM_RESOURCE; i++) {
-               struct resource *rp = &pdev->resource[i];
-               resource_size_t aligned_end;
-
-               /* Active? */
-               if (!rp->flags)
-                       continue;
-
-               /* Same type? */
-               if (i == PCI_ROM_RESOURCE) {
-                       if (mmap_state != pci_mmap_mem)
-                               continue;
-               } else {
-                       if ((mmap_state == pci_mmap_io &&
-                            (rp->flags & IORESOURCE_IO) == 0) ||
-                           (mmap_state == pci_mmap_mem &&
-                            (rp->flags & IORESOURCE_MEM) == 0))
-                               continue;
-               }
-
-               /* Align the resource end to the next page address.
-                * PAGE_SIZE intentionally added instead of (PAGE_SIZE - 1),
-                * because actually we need the address of the next byte
-                * after rp->end.
-                */
-               aligned_end = (rp->end + PAGE_SIZE) & PAGE_MASK;
-
-               if ((rp->start <= user_paddr) &&
-                   (user_paddr + user_size) <= aligned_end)
-                       break;
-       }
-
-       if (i > PCI_ROM_RESOURCE)
+       if (!pbm)
                return -EINVAL;
 
-       return 0;
-}
-
-/* Set vm_page_prot of VMA, as appropriate for this architecture, for a pci
- * device mapping.
- */
-static void __pci_mmap_set_pgprot(struct pci_dev *dev, struct vm_area_struct *vma,
-                                            enum pci_mmap_state mmap_state)
-{
-       /* Our io_remap_pfn_range takes care of this, do nothing.  */
-}
-
-/* Perform the actual remap of the pages for a PCI device mapping, as appropriate
- * for this architecture.  The region in the process to map is described by vm_start
- * and vm_end members of VMA, the base physical address is found in vm_pgoff.
- * The pci device structure is provided so that architectures may make mapping
- * decisions on a per-device or per-bus basis.
- *
- * Returns a negative error code on failure, zero on success.
- */
-int pci_mmap_page_range(struct pci_dev *dev, int bar,
-                       struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state, int write_combine)
-{
-       int ret;
-
-       ret = __pci_mmap_make_offset(dev, vma, mmap_state);
-       if (ret < 0)
-               return ret;
-
-       __pci_mmap_set_pgprot(dev, vma, mmap_state);
-
-       vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-       ret = io_remap_pfn_range(vma, vma->vm_start,
-                                vma->vm_pgoff,
-                                vma->vm_end - vma->vm_start,
-                                vma->vm_page_prot);
-       if (ret)
-               return ret;
+       vma->vm_pgoff += (ioaddr + pbm->io_space.start) >> PAGE_SHIFT;
 
        return 0;
 }
index 5b833f0..a5ed779 100644 (file)
@@ -627,7 +627,6 @@ static void pci_epf_test_unbind(struct pci_epf *epf)
 
        cancel_delayed_work(&epf_test->cmd_handler);
        pci_epf_test_clean_dma_chan(epf_test);
-       pci_epc_stop(epc);
        for (bar = 0; bar < PCI_STD_NUM_BARS; bar++) {
                epf_bar = &epf->bar[bar];
 
index b8c9011..4504039 100644 (file)
 
 #ifdef ARCH_GENERIC_PCI_MMAP_RESOURCE
 
-/*
- * Modern setup: generic pci_mmap_resource_range(), and implement the legacy
- * pci_mmap_page_range() (if needed) as a wrapper round it.
- */
-
-#ifdef HAVE_PCI_MMAP
-int pci_mmap_page_range(struct pci_dev *pdev, int bar,
-                       struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state, int write_combine)
-{
-       resource_size_t start, end;
-
-       pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end);
-
-       /* Adjust vm_pgoff to be the offset within the resource */
-       vma->vm_pgoff -= start >> PAGE_SHIFT;
-       return pci_mmap_resource_range(pdev, bar, vma, mmap_state,
-                                      write_combine);
-}
-#endif
-
 static const struct vm_operations_struct pci_phys_vm_ops = {
 #ifdef CONFIG_HAVE_IOREMAP_PROT
        .access = generic_access_phys,
@@ -70,27 +49,4 @@ int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
                                  vma->vm_page_prot);
 }
 
-#elif defined(HAVE_PCI_MMAP) /* && !ARCH_GENERIC_PCI_MMAP_RESOURCE */
-
-/*
- * Legacy setup: Implement pci_mmap_resource_range() as a wrapper around
- * the architecture's pci_mmap_page_range(), converting to "user visible"
- * addresses as necessary.
- */
-
-int pci_mmap_resource_range(struct pci_dev *pdev, int bar,
-                           struct vm_area_struct *vma,
-                           enum pci_mmap_state mmap_state, int write_combine)
-{
-       resource_size_t start, end;
-
-       /*
-        * pci_mmap_page_range() expects the same kind of entry as coming
-        * from /proc/bus/pci/ which is a "user visible" value. If this is
-        * different from the resource itself, arch will do necessary fixup.
-        */
-       pci_resource_to_user(pdev, bar, &pdev->resource[bar], &start, &end);
-       vma->vm_pgoff += start >> PAGE_SHIFT;
-       return pci_mmap_page_range(pdev, bar, vma, mmap_state, write_combine);
-}
 #endif
index cfaf40a..093303c 100644 (file)
@@ -1293,9 +1293,6 @@ static int pci_set_full_power_state(struct pci_dev *dev)
                pci_restore_bars(dev);
        }
 
-       if (dev->bus->self)
-               pcie_aspm_pm_state_change(dev->bus->self);
-
        return 0;
 }
 
@@ -1390,9 +1387,6 @@ static int pci_set_low_power_state(struct pci_dev *dev, pci_power_t state)
                                     pci_power_name(dev->current_state),
                                     pci_power_name(state));
 
-       if (dev->bus->self)
-               pcie_aspm_pm_state_change(dev->bus->self);
-
        return 0;
 }
 
index e10cdec..785f310 100644 (file)
@@ -560,12 +560,10 @@ bool pcie_wait_for_link(struct pci_dev *pdev, bool active);
 #ifdef CONFIG_PCIEASPM
 void pcie_aspm_init_link_state(struct pci_dev *pdev);
 void pcie_aspm_exit_link_state(struct pci_dev *pdev);
-void pcie_aspm_pm_state_change(struct pci_dev *pdev);
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev);
 #else
 static inline void pcie_aspm_init_link_state(struct pci_dev *pdev) { }
 static inline void pcie_aspm_exit_link_state(struct pci_dev *pdev) { }
-static inline void pcie_aspm_pm_state_change(struct pci_dev *pdev) { }
 static inline void pcie_aspm_powersave_config_link(struct pci_dev *pdev) { }
 #endif
 
index 7952e5e..e2d8a74 100644 (file)
@@ -392,6 +392,11 @@ void pci_aer_init(struct pci_dev *dev)
        pci_add_ext_cap_save_buffer(dev, PCI_EXT_CAP_ID_ERR, sizeof(u32) * n);
 
        pci_aer_clear_status(dev);
+
+       if (pci_aer_available())
+               pci_enable_pcie_error_reporting(dev);
+
+       pcie_set_ecrc_checking(dev);
 }
 
 void pci_aer_exit(struct pci_dev *dev)
@@ -538,7 +543,7 @@ static const char *aer_agent_string[] = {
        u64 *stats = pdev->aer_stats->stats_array;                      \
        size_t len = 0;                                                 \
                                                                        \
-       for (i = 0; i < ARRAY_SIZE(strings_array); i++) {               \
+       for (i = 0; i < ARRAY_SIZE(pdev->aer_stats->stats_array); i++) {\
                if (strings_array[i])                                   \
                        len += sysfs_emit_at(buf, len, "%s %llu\n",     \
                                             strings_array[i],          \
@@ -1228,9 +1233,6 @@ static int set_device_error_reporting(struct pci_dev *dev, void *data)
                        pci_disable_pcie_error_reporting(dev);
        }
 
-       if (enable)
-               pcie_set_ecrc_checking(dev);
-
        return 0;
 }
 
@@ -1347,6 +1349,11 @@ static int aer_probe(struct pcie_device *dev)
        struct device *device = &dev->device;
        struct pci_dev *port = dev->port;
 
+       BUILD_BUG_ON(ARRAY_SIZE(aer_correctable_error_string) <
+                    AER_MAX_TYPEOF_COR_ERRS);
+       BUILD_BUG_ON(ARRAY_SIZE(aer_uncorrectable_error_string) <
+                    AER_MAX_TYPEOF_UNCOR_ERRS);
+
        /* Limit to Root Ports or Root Complex Event Collectors */
        if ((pci_pcie_type(port) != PCI_EXP_TYPE_RC_EC) &&
            (pci_pcie_type(port) != PCI_EXP_TYPE_ROOT_PORT))
index a96b742..a8aec19 100644 (file)
@@ -1012,25 +1012,6 @@ out:
        up_read(&pci_bus_sem);
 }
 
-/* @pdev: the root port or switch downstream port */
-void pcie_aspm_pm_state_change(struct pci_dev *pdev)
-{
-       struct pcie_link_state *link = pdev->link_state;
-
-       if (aspm_disabled || !link)
-               return;
-       /*
-        * Devices changed PM state, we should recheck if latency
-        * meets all functions' requirement
-        */
-       down_read(&pci_bus_sem);
-       mutex_lock(&aspm_lock);
-       pcie_update_aspm_capable(link->root);
-       pcie_config_aspm_path(link);
-       mutex_unlock(&aspm_lock);
-       up_read(&pci_bus_sem);
-}
-
 void pcie_aspm_powersave_config_link(struct pci_dev *pdev)
 {
        struct pcie_link_state *link = pdev->link_state;
@@ -1366,4 +1347,3 @@ bool pcie_aspm_support_enabled(void)
 {
        return aspm_support_enabled;
 }
-EXPORT_SYMBOL(pcie_aspm_support_enabled);
index 0c5a143..59c90d0 100644 (file)
@@ -55,10 +55,14 @@ static int report_error_detected(struct pci_dev *dev,
 
        device_lock(&dev->dev);
        pdrv = dev->driver;
-       if (!pci_dev_set_io_state(dev, state) ||
-               !pdrv ||
-               !pdrv->err_handler ||
-               !pdrv->err_handler->error_detected) {
+       if (pci_dev_is_disconnected(dev)) {
+               vote = PCI_ERS_RESULT_DISCONNECT;
+       } else if (!pci_dev_set_io_state(dev, state)) {
+               pci_info(dev, "can't recover (state transition %u -> %u invalid)\n",
+                       dev->error_state, state);
+               vote = PCI_ERS_RESULT_NONE;
+       } else if (!pdrv || !pdrv->err_handler ||
+                  !pdrv->err_handler->error_detected) {
                /*
                 * If any device in the subtree does not have an error_detected
                 * callback, PCI_ERS_RESULT_NO_AER_DRIVER prevents subsequent
index 604feeb..1ac7fec 100644 (file)
@@ -222,15 +222,8 @@ static int get_port_device_capability(struct pci_dev *dev)
 
 #ifdef CONFIG_PCIEAER
        if (dev->aer_cap && pci_aer_available() &&
-           (pcie_ports_native || host->native_aer)) {
+           (pcie_ports_native || host->native_aer))
                services |= PCIE_PORT_SERVICE_AER;
-
-               /*
-                * Disable AER on this port in case it's been enabled by the
-                * BIOS (the AER service driver will enable it when necessary).
-                */
-               pci_disable_pcie_error_reporting(dev);
-       }
 #endif
 
        /* Root Ports and Root Complex Event Collectors may generate PMEs */
index 17a9699..9884d8b 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);
index 31b26d8..f967709 100644 (file)
@@ -244,6 +244,7 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
 {
        struct pci_dev *dev = pde_data(file_inode(file));
        struct pci_filp_private *fpriv = file->private_data;
+       resource_size_t start, end;
        int i, ret, write_combine = 0, res_bit = IORESOURCE_MEM;
 
        if (!capable(CAP_SYS_RAWIO) ||
@@ -278,7 +279,11 @@ static int proc_bus_pci_mmap(struct file *file, struct vm_area_struct *vma)
            iomem_is_exclusive(dev->resource[i].start))
                return -EINVAL;
 
-       ret = pci_mmap_page_range(dev, i, vma,
+       pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
+
+       /* Adjust vm_pgoff to be the offset within the resource */
+       vma->vm_pgoff -= start >> PAGE_SHIFT;
+       ret = pci_mmap_resource_range(dev, i, vma,
                                  fpriv->mmap_state, write_combine);
        if (ret < 0)
                return ret;
index fc08b43..9efbc54 100644 (file)
@@ -32,4 +32,12 @@ static inline bool jailhouse_paravirt(void)
 
 #endif /* !CONFIG_X86 */
 
+static inline bool hypervisor_isolated_pci_functions(void)
+{
+       if (IS_ENABLED(CONFIG_S390))
+               return true;
+
+       return jailhouse_paravirt();
+}
+
 #endif /* __LINUX_HYPEVISOR_H */
index 81a57b4..060af91 100644 (file)
@@ -1909,24 +1909,14 @@ pci_alloc_irq_vectors(struct pci_dev *dev, unsigned int min_vecs,
 
 #include <asm/pci.h>
 
-/* These two functions provide almost identical functionality. Depending
- * on the architecture, one will be implemented as a wrapper around the
- * other (in drivers/pci/mmap.c).
- *
+/*
  * pci_mmap_resource_range() maps a specific BAR, and vm->vm_pgoff
  * is expected to be an offset within that region.
  *
- * pci_mmap_page_range() is the legacy architecture-specific interface,
- * which accepts a "user visible" resource address converted by
- * pci_resource_to_user(), as used in the legacy mmap() interface in
- * /proc/bus/pci/.
  */
 int pci_mmap_resource_range(struct pci_dev *dev, int bar,
                            struct vm_area_struct *vma,
                            enum pci_mmap_state mmap_state, int write_combine);
-int pci_mmap_page_range(struct pci_dev *pdev, int bar,
-                       struct vm_area_struct *vma,
-                       enum pci_mmap_state mmap_state, int write_combine);
 
 #ifndef arch_can_pci_mmap_wc
 #define arch_can_pci_mmap_wc()         0