Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dc087f2f authored by Jiang Liu's avatar Jiang Liu Committed by Bjorn Helgaas
Browse files

PCI: Simplify IOV implementation and fix reference count races



Trivial changes to IOV:

  1) use new PCI interfaces to simplify IOV implementation
  2) fix some reference count related race windows

[bhelgaas: fix virtfn_add() add bus/alloc dev error paths]
Signed-off-by: default avatarJiang Liu <jiang.liu@huawei.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Cc: Donald Dutile <ddutile@redhat.com>
Cc: Yinghai Lu <yinghai@kernel.org>
Cc: Ram Pai <linuxram@us.ibm.com>
parent d35329d9
Loading
Loading
Loading
Loading
+24 −35
Original line number Diff line number Diff line
@@ -51,24 +51,16 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)
	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;
@@ -76,18 +68,15 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
	struct pci_sriov *iov = dev->sriov;
	struct pci_bus *bus;

	virtfn = pci_alloc_dev(NULL);
	if (!virtfn)
		return -ENOMEM;

	mutex_lock(&iov->dev->sriov->lock);
	bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id));
	if (!bus) {
		kfree(virtfn);
		mutex_unlock(&iov->dev->sriov->lock);
		return -ENOMEM;
	}
	virtfn->bus = pci_bus_get(bus);
	if (!bus)
		goto failed;

	virtfn = pci_alloc_dev(bus);
	if (!virtfn)
		goto failed0;

	virtfn->devfn = virtfn_devfn(dev, id);
	virtfn->vendor = dev->vendor;
	pci_read_config_word(dev, iov->pos + PCI_SRIOV_VF_DID, &virtfn->device);
@@ -136,7 +125,9 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
	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;
@@ -145,20 +136,15 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)
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);
@@ -176,9 +162,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);
}

@@ -335,13 +323,14 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)
		if (!pdev)
			return -ENODEV;

		if (!pdev->is_physfn) {
			pci_dev_put(pdev);

		if (!pdev->is_physfn)
			return -ENODEV;
		}

		rc = sysfs_create_link(&dev->dev.kobj,
					&pdev->dev.kobj, "dep_link");
		pci_dev_put(pdev);
		if (rc)
			return rc;
	}