--- zzzz-none-000/linux-3.10.107/drivers/pci/iov.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/pci/iov.c 2021-02-04 17:41:59.000000000 +0000 @@ -19,16 +19,64 @@ #define VIRTFN_ID_LEN 16 -static inline u8 virtfn_bus(struct pci_dev *dev, int id) +int pci_iov_virtfn_bus(struct pci_dev *dev, int vf_id) { + if (!dev->is_physfn) + return -EINVAL; return dev->bus->number + ((dev->devfn + dev->sriov->offset + - dev->sriov->stride * id) >> 8); + dev->sriov->stride * vf_id) >> 8); } -static inline u8 virtfn_devfn(struct pci_dev *dev, int id) +int pci_iov_virtfn_devfn(struct pci_dev *dev, int vf_id) { + if (!dev->is_physfn) + return -EINVAL; return (dev->devfn + dev->sriov->offset + - dev->sriov->stride * id) & 0xff; + dev->sriov->stride * vf_id) & 0xff; +} + +/* + * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may + * change when NumVFs changes. + * + * Update iov->offset and iov->stride when NumVFs is written. + */ +static inline void pci_iov_set_numvfs(struct pci_dev *dev, int nr_virtfn) +{ + struct pci_sriov *iov = dev->sriov; + + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); + pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &iov->offset); + pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &iov->stride); +} + +/* + * The PF consumes one bus number. NumVFs, First VF Offset, and VF Stride + * determine how many additional bus numbers will be consumed by VFs. + * + * Iterate over all valid NumVFs, validate offset and stride, and calculate + * the maximum number of bus numbers that could ever be required. + */ +static int compute_max_vf_buses(struct pci_dev *dev) +{ + struct pci_sriov *iov = dev->sriov; + int nr_virtfn, busnr, rc = 0; + + for (nr_virtfn = iov->total_VFs; nr_virtfn; nr_virtfn--) { + pci_iov_set_numvfs(dev, nr_virtfn); + if (!iov->offset || (nr_virtfn > 1 && !iov->stride)) { + rc = -EIO; + goto out; + } + + busnr = pci_iov_virtfn_bus(dev, nr_virtfn - 1); + if (busnr > iov->max_VF_buses) + iov->max_VF_buses = busnr; + } + +out: + pci_iov_set_numvfs(dev, 0); + return rc; } static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) @@ -47,62 +95,60 @@ return NULL; pci_bus_insert_busn_res(child, busnr, busnr); - bus->is_added = 1; return child; } -static void virtfn_remove_bus(struct pci_bus *bus, int busnr) +static void virtfn_remove_bus(struct pci_bus *physbus, struct pci_bus *virtbus) { - struct pci_bus *child; - - if (bus->number == busnr) - return; + if (physbus != virtbus && list_empty(&virtbus->devices)) + pci_remove_bus(virtbus); +} - child = pci_find_bus(pci_domain_nr(bus), busnr); - BUG_ON(!child); +resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno) +{ + if (!dev->is_physfn) + return 0; - if (list_empty(&child->devices)) - pci_remove_bus(child); + return dev->sriov->barsz[resno - PCI_IOV_RESOURCES]; } static int virtfn_add(struct pci_dev *dev, int id, int reset) { int i; - int rc; + int rc = -ENOMEM; u64 size; char buf[VIRTFN_ID_LEN]; struct pci_dev *virtfn; struct resource *res; struct pci_sriov *iov = dev->sriov; + struct pci_bus *bus; - virtfn = alloc_pci_dev(); + mutex_lock(&iov->dev->sriov->lock); + bus = virtfn_add_bus(dev->bus, pci_iov_virtfn_bus(dev, id)); + if (!bus) + goto failed; + + virtfn = pci_alloc_dev(bus); if (!virtfn) - return -ENOMEM; + goto failed0; - mutex_lock(&iov->dev->sriov->lock); - virtfn->bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); - if (!virtfn->bus) { - kfree(virtfn); - mutex_unlock(&iov->dev->sriov->lock); - return -ENOMEM; - } - virtfn->devfn = virtfn_devfn(dev, id); + virtfn->devfn = pci_iov_virtfn_devfn(dev, id); virtfn->vendor = dev->vendor; pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device); pci_setup_device(virtfn); virtfn->dev.parent = dev->dev.parent; virtfn->physfn = pci_dev_get(dev); virtfn->is_virtfn = 1; + virtfn->multifunction = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { - res = dev->resource + PCI_IOV_RESOURCES + i; + res = &dev->resource[i + PCI_IOV_RESOURCES]; if (!res->parent) continue; virtfn->resource[i].name = pci_name(virtfn); virtfn->resource[i].flags = res->flags; - size = resource_size(res); - do_div(size, iov->total_VFs); + size = pci_iov_resource_size(dev, i + PCI_IOV_RESOURCES); virtfn->resource[i].start = res->start + size * id; virtfn->resource[i].end = virtfn->resource[i].start + size - 1; rc = request_resource(res, &virtfn->resource[i]); @@ -115,7 +161,7 @@ pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - rc = pci_bus_add_device(virtfn); + pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); if (rc) @@ -134,7 +180,9 @@ pci_dev_put(dev); mutex_lock(&iov->dev->sriov->lock); pci_stop_and_remove_bus_device(virtfn); - virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); +failed0: + virtfn_remove_bus(dev->bus, bus); +failed: mutex_unlock(&iov->dev->sriov->lock); return rc; @@ -143,20 +191,15 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) { char buf[VIRTFN_ID_LEN]; - struct pci_bus *bus; struct pci_dev *virtfn; struct pci_sriov *iov = dev->sriov; - bus = pci_find_bus(pci_domain_nr(dev->bus), virtfn_bus(dev, id)); - if (!bus) - return; - - virtfn = pci_get_slot(bus, virtfn_devfn(dev, id)); + virtfn = pci_get_domain_bus_and_slot(pci_domain_nr(dev->bus), + pci_iov_virtfn_bus(dev, id), + pci_iov_virtfn_devfn(dev, id)); if (!virtfn) return; - pci_dev_put(virtfn); - if (reset) { device_release_driver(&virtfn->dev); __pci_reset_function(virtfn); @@ -174,113 +217,35 @@ mutex_lock(&iov->dev->sriov->lock); pci_stop_and_remove_bus_device(virtfn); - virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); + virtfn_remove_bus(dev->bus, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); + /* balance pci_get_domain_bus_and_slot() */ + pci_dev_put(virtfn); pci_dev_put(dev); } -static int sriov_migration(struct pci_dev *dev) -{ - u16 status; - struct pci_sriov *iov = dev->sriov; - - if (!iov->num_VFs) - return 0; - - if (!(iov->cap & PCI_SRIOV_CAP_VFM)) - return 0; - - pci_read_config_word(dev, iov->pos + PCI_SRIOV_STATUS, &status); - if (!(status & PCI_SRIOV_STATUS_VFM)) - return 0; - - schedule_work(&iov->mtask); - - return 1; -} - -static void sriov_migration_task(struct work_struct *work) +int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs) { - int i; - u8 state; - u16 status; - struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask); - - for (i = iov->initial_VFs; i < iov->num_VFs; i++) { - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_MI) { - writeb(PCI_SRIOV_VFM_AV, iov->mstate + i); - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_AV) - virtfn_add(iov->self, i, 1); - } else if (state == PCI_SRIOV_VFM_MO) { - virtfn_remove(iov->self, i, 1); - writeb(PCI_SRIOV_VFM_UA, iov->mstate + i); - state = readb(iov->mstate + i); - if (state == PCI_SRIOV_VFM_AV) - virtfn_add(iov->self, i, 0); - } - } - - pci_read_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, &status); - status &= ~PCI_SRIOV_STATUS_VFM; - pci_write_config_word(iov->self, iov->pos + PCI_SRIOV_STATUS, status); -} - -static int sriov_enable_migration(struct pci_dev *dev, int nr_virtfn) -{ - int bir; - u32 table; - resource_size_t pa; - struct pci_sriov *iov = dev->sriov; - - if (nr_virtfn <= iov->initial_VFs) - return 0; - - pci_read_config_dword(dev, iov->pos + PCI_SRIOV_VFM, &table); - bir = PCI_SRIOV_VFM_BIR(table); - if (bir > PCI_STD_RESOURCE_END) - return -EIO; - - table = PCI_SRIOV_VFM_OFFSET(table); - if (table + nr_virtfn > pci_resource_len(dev, bir)) - return -EIO; - - pa = pci_resource_start(dev, bir) + table; - iov->mstate = ioremap(pa, nr_virtfn); - if (!iov->mstate) - return -ENOMEM; - - INIT_WORK(&iov->mtask, sriov_migration_task); - - iov->ctrl |= PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR; - pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); - return 0; } -static void sriov_disable_migration(struct pci_dev *dev) +int __weak pcibios_sriov_disable(struct pci_dev *pdev) { - struct pci_sriov *iov = dev->sriov; - - iov->ctrl &= ~(PCI_SRIOV_CTRL_VFM | PCI_SRIOV_CTRL_INTR); - pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); - - cancel_work_sync(&iov->mtask); - iounmap(iov->mstate); + return 0; } static int sriov_enable(struct pci_dev *dev, int nr_virtfn) { int rc; - int i, j; + int i; int nres; - u16 offset, stride, initial; + u16 initial; struct resource *res; struct pci_dev *pdev; struct pci_sriov *iov = dev->sriov; int bars = 0; + int bus; if (!nr_virtfn) return 0; @@ -297,16 +262,10 @@ (!(iov->cap & PCI_SRIOV_CAP_VFM) && (nr_virtfn > initial))) return -EINVAL; - pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, nr_virtfn); - pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_OFFSET, &offset); - pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_STRIDE, &stride); - if (!offset || (nr_virtfn > 1 && !stride)) - return -EIO; - nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { bars |= (1 << (i + PCI_IOV_RESOURCES)); - res = dev->resource + PCI_IOV_RESOURCES + i; + res = &dev->resource[i + PCI_IOV_RESOURCES]; if (res->parent) nres++; } @@ -315,11 +274,10 @@ return -ENOMEM; } - iov->offset = offset; - iov->stride = stride; - - if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->busn_res.end) { - dev_err(&dev->dev, "SR-IOV: bus number out of range\n"); + bus = pci_iov_virtfn_bus(dev, nr_virtfn - 1); + if (bus > dev->bus->busn_res.end) { + dev_err(&dev->dev, "can't enable %d VFs (bus %02x out of range of %pR)\n", + nr_virtfn, bus, &dev->bus->busn_res); return -ENOMEM; } @@ -333,48 +291,52 @@ if (!pdev) return -ENODEV; - pci_dev_put(pdev); - - if (!pdev->is_physfn) - return -ENODEV; + if (!pdev->is_physfn) { + pci_dev_put(pdev); + return -ENOSYS; + } rc = sysfs_create_link(&dev->dev.kobj, &pdev->dev.kobj, "dep_link"); + pci_dev_put(pdev); if (rc) return rc; } + iov->initial_VFs = initial; + if (nr_virtfn < initial) + initial = nr_virtfn; + + rc = pcibios_sriov_enable(dev, initial); + if (rc) { + dev_err(&dev->dev, "failure %d from pcibios_sriov_enable()\n", rc); + goto err_pcibios; + } + + pci_iov_set_numvfs(dev, nr_virtfn); iov->ctrl |= PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE; pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); msleep(100); pci_cfg_access_unlock(dev); - iov->initial_VFs = initial; - if (nr_virtfn < initial) - initial = nr_virtfn; - for (i = 0; i < initial; i++) { rc = virtfn_add(dev, i, 0); if (rc) goto failed; } - if (iov->cap & PCI_SRIOV_CAP_VFM) { - rc = sriov_enable_migration(dev, nr_virtfn); - if (rc) - goto failed; - } - kobject_uevent(&dev->dev.kobj, KOBJ_CHANGE); iov->num_VFs = nr_virtfn; return 0; failed: - for (j = 0; j < i; j++) - virtfn_remove(dev, j, 0); + while (i--) + virtfn_remove(dev, i, 0); + pcibios_sriov_disable(dev); +err_pcibios: iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); @@ -384,6 +346,7 @@ if (iov->link != dev->devfn) sysfs_remove_link(&dev->dev.kobj, "dep_link"); + pci_iov_set_numvfs(dev, 0); return rc; } @@ -395,12 +358,11 @@ if (!iov->num_VFs) return; - if (iov->cap & PCI_SRIOV_CAP_VFM) - sriov_disable_migration(dev); - for (i = 0; i < iov->num_VFs; i++) virtfn_remove(dev, i, 0); + pcibios_sriov_disable(dev); + iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); pci_cfg_access_lock(dev); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); @@ -411,15 +373,16 @@ sysfs_remove_link(&dev->dev.kobj, "dep_link"); iov->num_VFs = 0; + pci_iov_set_numvfs(dev, 0); } static int sriov_init(struct pci_dev *dev, int pos) { - int i; + int i, bar64; int rc; int nres; u32 pgsz; - u16 ctrl, total, offset, stride; + u16 ctrl, total; struct pci_sriov *iov; struct resource *res; struct pci_dev *pdev; @@ -434,10 +397,6 @@ ssleep(1); } - pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); - if (!total) - return 0; - ctrl = 0; list_for_each_entry(pdev, &dev->bus->devices, bus_list) if (pdev->is_physfn) @@ -449,10 +408,10 @@ found: pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); - pci_read_config_word(dev, pos + PCI_SRIOV_VF_OFFSET, &offset); - pci_read_config_word(dev, pos + PCI_SRIOV_VF_STRIDE, &stride); - if (!offset || (total > 1 && !stride)) - return -EIO; + + pci_read_config_word(dev, pos + PCI_SRIOV_TOTAL_VF, &total); + if (!total) + return 0; pci_read_config_dword(dev, pos + PCI_SRIOV_SUP_PGSIZE, &pgsz); i = PAGE_SHIFT > 12 ? PAGE_SHIFT - 12 : 0; @@ -463,33 +422,40 @@ pgsz &= ~(pgsz - 1); pci_write_config_dword(dev, pos + PCI_SRIOV_SYS_PGSIZE, pgsz); + iov = kzalloc(sizeof(*iov), GFP_KERNEL); + if (!iov) + return -ENOMEM; + nres = 0; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { - res = dev->resource + PCI_IOV_RESOURCES + i; - i += __pci_read_base(dev, pci_bar_unknown, res, - pos + PCI_SRIOV_BAR + i * 4); + res = &dev->resource[i + PCI_IOV_RESOURCES]; + /* + * If it is already FIXED, don't change it, something + * (perhaps EA or header fixups) wants it this way. + */ + if (res->flags & IORESOURCE_PCI_FIXED) + bar64 = (res->flags & IORESOURCE_MEM_64) ? 1 : 0; + else + bar64 = __pci_read_base(dev, pci_bar_unknown, res, + pos + PCI_SRIOV_BAR + i * 4); if (!res->flags) continue; if (resource_size(res) & (PAGE_SIZE - 1)) { rc = -EIO; goto failed; } + iov->barsz[i] = resource_size(res); res->end = res->start + resource_size(res) * total - 1; + dev_info(&dev->dev, "VF(n) BAR%d space: %pR (contains BAR%d for %d VFs)\n", + i, res, i, total); + i += bar64; nres++; } - iov = kzalloc(sizeof(*iov), GFP_KERNEL); - if (!iov) { - rc = -ENOMEM; - goto failed; - } - iov->pos = pos; iov->nres = nres; iov->ctrl = ctrl; iov->total_VFs = total; - iov->offset = offset; - iov->stride = stride; iov->pgsz = pgsz; iov->self = dev; pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap); @@ -506,15 +472,22 @@ dev->sriov = iov; dev->is_physfn = 1; + rc = compute_max_vf_buses(dev); + if (rc) + goto fail_max_buses; return 0; +fail_max_buses: + dev->sriov = NULL; + dev->is_physfn = 0; failed: for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { - res = dev->resource + PCI_IOV_RESOURCES + i; + res = &dev->resource[i + PCI_IOV_RESOURCES]; res->flags = 0; } + kfree(iov); return rc; } @@ -545,7 +518,7 @@ pci_update_resource(dev, i); pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz); - pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->num_VFs); + pci_iov_set_numvfs(dev, iov->num_VFs); pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl); if (iov->ctrl & PCI_SRIOV_CTRL_VFE) msleep(100); @@ -582,25 +555,67 @@ } /** - * pci_iov_resource_bar - get position of the SR-IOV BAR + * pci_iov_update_resource - update a VF BAR * @dev: the PCI device * @resno: the resource number - * @type: the BAR type to be filled in * - * Returns position of the BAR encapsulated in the SR-IOV capability. + * Update a VF BAR in the SR-IOV capability of a PF. */ -int pci_iov_resource_bar(struct pci_dev *dev, int resno, - enum pci_bar_type *type) +void pci_iov_update_resource(struct pci_dev *dev, int resno) { - if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END) - return 0; + struct pci_sriov *iov = dev->is_physfn ? dev->sriov : NULL; + struct resource *res = dev->resource + resno; + int vf_bar = resno - PCI_IOV_RESOURCES; + struct pci_bus_region region; + u16 cmd; + u32 new; + int reg; + + /* + * The generic pci_restore_bars() path calls this for all devices, + * including VFs and non-SR-IOV devices. If this is not a PF, we + * have nothing to do. + */ + if (!iov) + return; - BUG_ON(!dev->is_physfn); + pci_read_config_word(dev, iov->pos + PCI_SRIOV_CTRL, &cmd); + if ((cmd & PCI_SRIOV_CTRL_VFE) && (cmd & PCI_SRIOV_CTRL_MSE)) { + dev_WARN(&dev->dev, "can't update enabled VF BAR%d %pR\n", + vf_bar, res); + return; + } - *type = pci_bar_unknown; + /* + * Ignore unimplemented BARs, unused resource slots for 64-bit + * BARs, and non-movable resources, e.g., those described via + * Enhanced Allocation. + */ + if (!res->flags) + return; + + if (res->flags & IORESOURCE_UNSET) + return; + + if (res->flags & IORESOURCE_PCI_FIXED) + return; - return dev->sriov->pos + PCI_SRIOV_BAR + - 4 * (resno - PCI_IOV_RESOURCES); + pcibios_resource_to_bus(dev->bus, ®ion, res); + new = region.start; + new |= res->flags & ~PCI_BASE_ADDRESS_MEM_MASK; + + reg = iov->pos + PCI_SRIOV_BAR + 4 * vf_bar; + pci_write_config_dword(dev, reg, new); + if (res->flags & IORESOURCE_MEM_64) { + new = region.start >> 16 >> 16; + pci_write_config_dword(dev, reg + 4, new); + } +} + +resource_size_t __weak pcibios_iov_resource_alignment(struct pci_dev *dev, + int resno) +{ + return pci_iov_resource_size(dev, resno); } /** @@ -615,15 +630,7 @@ */ resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno) { - struct resource tmp; - enum pci_bar_type type; - int reg = pci_iov_resource_bar(dev, resno, &type); - - if (!reg) - return 0; - - __pci_read_base(dev, type, &tmp, reg); - return resource_alignment(&tmp); + return pcibios_iov_resource_alignment(dev, resno); } /** @@ -646,15 +653,13 @@ int pci_iov_bus_range(struct pci_bus *bus) { int max = 0; - u8 busnr; struct pci_dev *dev; list_for_each_entry(dev, &bus->devices, bus_list) { if (!dev->is_physfn) continue; - busnr = virtfn_bus(dev, dev->sriov->total_VFs - 1); - if (busnr > max) - max = busnr; + if (dev->sriov->max_VF_buses > max) + max = dev->sriov->max_VF_buses; } return max ? max - bus->number : 0; @@ -672,7 +677,7 @@ might_sleep(); if (!dev->is_physfn) - return -ENODEV; + return -ENOSYS; return sriov_enable(dev, nr_virtfn); } @@ -694,25 +699,6 @@ EXPORT_SYMBOL_GPL(pci_disable_sriov); /** - * pci_sriov_migration - notify SR-IOV core of Virtual Function Migration - * @dev: the PCI device - * - * Returns IRQ_HANDLED if the IRQ is handled, or IRQ_NONE if not. - * - * Physical Function driver is responsible to register IRQ handler using - * VF Migration Interrupt Message Number, and call this function when the - * interrupt is generated by the hardware. - */ -irqreturn_t pci_sriov_migration(struct pci_dev *dev) -{ - if (!dev->is_physfn) - return IRQ_NONE; - - return sriov_migration(dev) ? IRQ_HANDLED : IRQ_NONE; -} -EXPORT_SYMBOL_GPL(pci_sriov_migration); - -/** * pci_num_vf - return number of VFs associated with a PF device_release_driver * @dev: the PCI device * @@ -732,7 +718,7 @@ * @dev: the PCI device * * Returns number of VFs belonging to this device that are assigned to a guest. - * If device is not a physical function returns -ENODEV. + * If device is not a physical function returns 0. */ int pci_vfs_assigned(struct pci_dev *dev) { @@ -758,7 +744,7 @@ * our dev as the physical function and the assigned bit is set */ if (vfdev->is_virtfn && (vfdev->physfn == dev) && - (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)) + pci_is_dev_assigned(vfdev)) vfs_assigned++; vfdev = pci_get_device(dev->vendor, dev_id, vfdev); @@ -777,12 +763,15 @@ * device's mutex held. * * Returns 0 if PF is an SRIOV-capable device and - * value of numvfs valid. If not a PF with VFS, return -EINVAL; + * value of numvfs valid. If not a PF return -ENOSYS; + * if numvfs is invalid return -EINVAL; * if VFs already enabled, return -EBUSY. */ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) { - if (!dev->is_physfn || (numvfs > dev->sriov->total_VFs)) + if (!dev->is_physfn) + return -ENOSYS; + if (numvfs > dev->sriov->total_VFs) return -EINVAL; /* Shouldn't change if VFs already enabled */ @@ -796,17 +785,17 @@ EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs); /** - * pci_sriov_get_totalvfs -- get total VFs supported on this devic3 + * pci_sriov_get_totalvfs -- get total VFs supported on this device * @dev: the PCI PF device * * For a PCIe device with SRIOV support, return the PCIe * SRIOV capability value of TotalVFs or the value of driver_max_VFs - * if the driver reduced it. Otherwise, -EINVAL. + * if the driver reduced it. Otherwise 0. */ int pci_sriov_get_totalvfs(struct pci_dev *dev) { if (!dev->is_physfn) - return -EINVAL; + return 0; if (dev->sriov->driver_max_VFs) return dev->sriov->driver_max_VFs;