diff options
Diffstat (limited to 'drivers/pci/iov.c')
| -rw-r--r-- | drivers/pci/iov.c | 88 |
1 files changed, 41 insertions, 47 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index c93071d428f5..21a7182dccd4 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -47,51 +47,43 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr) 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; - - child = pci_find_bus(pci_domain_nr(bus), busnr); - BUG_ON(!child); - - if (list_empty(&child->devices)) - pci_remove_bus(child); + if (physbus != virtbus && list_empty(&virtbus->devices)) + pci_remove_bus(virtbus); } 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, 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->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; for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { res = dev->resource + PCI_IOV_RESOURCES + i; @@ -113,9 +105,6 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset) pci_device_add(virtfn, virtfn->bus); mutex_unlock(&iov->dev->sriov->lock); - virtfn->physfn = pci_dev_get(dev); - virtfn->is_virtfn = 1; - rc = pci_bus_add_device(virtfn); sprintf(buf, "virtfn%u", id); rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf); @@ -135,7 +124,9 @@ failed1: 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; @@ -144,20 +135,15 @@ failed1: 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), + virtfn_bus(dev, id), + virtfn_devfn(dev, id)); if (!virtfn) return; - pci_dev_put(virtfn); - if (reset) { device_release_driver(&virtfn->dev); __pci_reset_function(virtfn); @@ -175,9 +161,11 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset) 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); } @@ -298,7 +286,6 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) (!(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)) @@ -334,17 +321,19 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn) 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; } + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 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); @@ -379,6 +368,7 @@ failed: 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); + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0); ssleep(1); pci_cfg_access_unlock(dev); @@ -412,6 +402,7 @@ static void sriov_disable(struct pci_dev *dev) sysfs_remove_link(&dev->dev.kobj, "dep_link"); iov->num_VFs = 0; + pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, 0); } static int sriov_init(struct pci_dev *dev, int pos) @@ -673,7 +664,7 @@ int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn) might_sleep(); if (!dev->is_physfn) - return -ENODEV; + return -ENOSYS; return sriov_enable(dev, nr_virtfn); } @@ -733,7 +724,7 @@ EXPORT_SYMBOL_GPL(pci_num_vf); * @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) { @@ -778,12 +769,15 @@ EXPORT_SYMBOL_GPL(pci_vfs_assigned); * 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 */ @@ -797,17 +791,17 @@ int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs) 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; |
