diff options
Diffstat (limited to 'drivers/pci/iov.c')
| -rw-r--r-- | drivers/pci/iov.c | 463 | 
1 files changed, 146 insertions, 317 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 553d8ee55c1..cb6f24740ee 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -11,8 +11,10 @@  #include <linux/pci.h>  #include <linux/slab.h>  #include <linux/mutex.h> +#include <linux/export.h>  #include <linux/string.h>  #include <linux/delay.h> +#include <linux/pci-ats.h>  #include "pci.h"  #define VIRTFN_ID_LEN	16 @@ -31,7 +33,6 @@ static inline u8 virtfn_devfn(struct pci_dev *dev, int id)  static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)  { -	int rc;  	struct pci_bus *child;  	if (bus->number == busnr) @@ -45,57 +46,45 @@ static struct pci_bus *virtfn_add_bus(struct pci_bus *bus, int busnr)  	if (!child)  		return NULL; -	child->subordinate = busnr; -	child->dev.parent = bus->bridge; -	rc = pci_bus_add_child(child); -	if (rc) { -		pci_remove_bus(child); -		return NULL; -	} +	pci_bus_insert_busn_res(child, busnr, 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;  	struct resource *res;  	struct pci_sriov *iov = dev->sriov; +	struct pci_bus *bus; + +	mutex_lock(&iov->dev->sriov->lock); +	bus = virtfn_add_bus(dev->bus, virtfn_bus(dev, id)); +	if (!bus) +		goto failed; -	virtfn = alloc_pci_dev(); +	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; +	virtfn->multifunction = 0;  	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) {  		res = dev->resource + PCI_IOV_RESOURCES + i; @@ -104,7 +93,7 @@ static int virtfn_add(struct pci_dev *dev, int id, int reset)  		virtfn->resource[i].name = pci_name(virtfn);  		virtfn->resource[i].flags = res->flags;  		size = resource_size(res); -		do_div(size, iov->total); +		do_div(size, iov->total_VFs);  		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]); @@ -117,12 +106,7 @@ 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); -	if (rc) -		goto failed1; +	pci_bus_add_device(virtfn);  	sprintf(buf, "virtfn%u", id);  	rc = sysfs_create_link(&dev->dev.kobj, &virtfn->dev.kobj, buf);  	if (rc) @@ -140,8 +124,10 @@ failed2:  failed1:  	pci_dev_put(dev);  	mutex_lock(&iov->dev->sriov->lock); -	pci_remove_bus_device(virtfn); -	virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); +	pci_stop_and_remove_bus_device(virtfn); +failed0: +	virtfn_remove_bus(dev->bus, bus); +failed:  	mutex_unlock(&iov->dev->sriov->lock);  	return rc; @@ -150,20 +136,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); @@ -171,107 +152,24 @@ static void virtfn_remove(struct pci_dev *dev, int id, int reset)  	sprintf(buf, "virtfn%u", id);  	sysfs_remove_link(&dev->dev.kobj, buf); -	sysfs_remove_link(&virtfn->dev.kobj, "physfn"); +	/* +	 * pci_stop_dev() could have been called for this virtfn already, +	 * so the directory for the virtfn may have been removed before. +	 * Double check to avoid spurious sysfs warnings. +	 */ +	if (virtfn->dev.kobj.sd) +		sysfs_remove_link(&virtfn->dev.kobj, "physfn");  	mutex_lock(&iov->dev->sriov->lock); -	pci_remove_bus_device(virtfn); -	virtfn_remove_bus(dev->bus, virtfn_bus(dev, id)); +	pci_stop_and_remove_bus_device(virtfn); +	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->nr_virtfn) -		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 i; -	u8 state; -	u16 status; -	struct pci_sriov *iov = container_of(work, struct pci_sriov, mtask); - -	for (i = iov->initial; i < iov->nr_virtfn; 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) -		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) -{ -	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); -} -  static int sriov_enable(struct pci_dev *dev, int nr_virtfn)  {  	int rc; @@ -281,23 +179,23 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)  	struct resource *res;  	struct pci_dev *pdev;  	struct pci_sriov *iov = dev->sriov; +	int bars = 0;  	if (!nr_virtfn)  		return 0; -	if (iov->nr_virtfn) +	if (iov->num_VFs)  		return -EINVAL;  	pci_read_config_word(dev, iov->pos + PCI_SRIOV_INITIAL_VF, &initial); -	if (initial > iov->total || -	    (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total))) +	if (initial > iov->total_VFs || +	    (!(iov->cap & PCI_SRIOV_CAP_VFM) && (initial != iov->total_VFs)))  		return -EIO; -	if (nr_virtfn < 0 || nr_virtfn > iov->total || +	if (nr_virtfn < 0 || nr_virtfn > iov->total_VFs ||  	    (!(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)) @@ -305,6 +203,7 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)  	nres = 0;  	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) { +		bars |= (1 << (i + PCI_IOV_RESOURCES));  		res = dev->resource + PCI_IOV_RESOURCES + i;  		if (res->parent)  			nres++; @@ -317,34 +216,41 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)  	iov->offset = offset;  	iov->stride = stride; -	if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->subordinate) { +	if (virtfn_bus(dev, nr_virtfn - 1) > dev->bus->busn_res.end) {  		dev_err(&dev->dev, "SR-IOV: bus number out of range\n");  		return -ENOMEM;  	} +	if (pci_enable_resources(dev, bars)) { +		dev_err(&dev->dev, "SR-IOV: IOV BARS not allocated\n"); +		return -ENOMEM; +	} +  	if (iov->link != dev->devfn) {  		pdev = pci_get_slot(dev->bus, iov->link);  		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_block_user_cfg_access(dev); +	pci_cfg_access_lock(dev);  	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);  	msleep(100); -	pci_unblock_user_cfg_access(dev); +	pci_cfg_access_unlock(dev); -	iov->initial = initial; +	iov->initial_VFs = initial;  	if (nr_virtfn < initial)  		initial = nr_virtfn; @@ -354,14 +260,8 @@ static int sriov_enable(struct pci_dev *dev, int nr_virtfn)  			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->nr_virtfn = nr_virtfn; +	iov->num_VFs = nr_virtfn;  	return 0; @@ -370,10 +270,11 @@ failed:  		virtfn_remove(dev, j, 0);  	iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); -	pci_block_user_cfg_access(dev); +	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_unblock_user_cfg_access(dev); +	pci_cfg_access_unlock(dev);  	if (iov->link != dev->devfn)  		sysfs_remove_link(&dev->dev.kobj, "dep_link"); @@ -386,25 +287,23 @@ static void sriov_disable(struct pci_dev *dev)  	int i;  	struct pci_sriov *iov = dev->sriov; -	if (!iov->nr_virtfn) +	if (!iov->num_VFs)  		return; -	if (iov->cap & PCI_SRIOV_CAP_VFM) -		sriov_disable_migration(dev); - -	for (i = 0; i < iov->nr_virtfn; i++) +	for (i = 0; i < iov->num_VFs; i++)  		virtfn_remove(dev, i, 0);  	iov->ctrl &= ~(PCI_SRIOV_CTRL_VFE | PCI_SRIOV_CTRL_MSE); -	pci_block_user_cfg_access(dev); +	pci_cfg_access_lock(dev);  	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);  	ssleep(1); -	pci_unblock_user_cfg_access(dev); +	pci_cfg_access_unlock(dev);  	if (iov->link != dev->devfn)  		sysfs_remove_link(&dev->dev.kobj, "dep_link"); -	iov->nr_virtfn = 0; +	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) @@ -418,8 +317,8 @@ static int sriov_init(struct pci_dev *dev, int pos)  	struct resource *res;  	struct pci_dev *pdev; -	if (dev->pcie_type != PCI_EXP_TYPE_RC_END && -	    dev->pcie_type != PCI_EXP_TYPE_ENDPOINT) +	if (pci_pcie_type(dev) != PCI_EXP_TYPE_RC_END && +	    pci_pcie_type(dev) != PCI_EXP_TYPE_ENDPOINT)  		return -ENODEV;  	pci_read_config_word(dev, pos + PCI_SRIOV_CTRL, &ctrl); @@ -443,7 +342,7 @@ static int sriov_init(struct pci_dev *dev, int pos)  found:  	pci_write_config_word(dev, pos + PCI_SRIOV_CTRL, ctrl); -	pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, total); +	pci_write_config_word(dev, pos + PCI_SRIOV_NUM_VF, 0);  	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)) @@ -482,14 +381,14 @@ found:  	iov->pos = pos;  	iov->nres = nres;  	iov->ctrl = ctrl; -	iov->total = total; +	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);  	pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link); -	if (dev->pcie_type == PCI_EXP_TYPE_RC_END) +	if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)  		iov->link = PCI_DEVFN(PCI_SLOT(dev->devfn), iov->link);  	if (pdev) @@ -515,7 +414,7 @@ failed:  static void sriov_release(struct pci_dev *dev)  { -	BUG_ON(dev->sriov->nr_virtfn); +	BUG_ON(dev->sriov->num_VFs);  	if (dev != dev->sriov->dev)  		pci_dev_put(dev->sriov->dev); @@ -540,7 +439,7 @@ static void sriov_restore_state(struct pci_dev *dev)  		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->nr_virtfn); +	pci_write_config_word(dev, iov->pos + PCI_SRIOV_NUM_VF, iov->num_VFs);  	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, iov->ctrl);  	if (iov->ctrl & PCI_SRIOV_CTRL_VFE)  		msleep(100); @@ -613,7 +512,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; @@ -647,7 +546,7 @@ int pci_iov_bus_range(struct pci_bus *bus)  	list_for_each_entry(dev, &bus->devices, bus_list) {  		if (!dev->is_physfn)  			continue; -		busnr = virtfn_bus(dev, dev->sriov->total - 1); +		busnr = virtfn_bus(dev, dev->sriov->total_VFs - 1);  		if (busnr > max)  			max = busnr;  	} @@ -667,7 +566,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);  } @@ -689,25 +588,6 @@ void pci_disable_sriov(struct pci_dev *dev)  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   * @@ -715,151 +595,100 @@ EXPORT_SYMBOL_GPL(pci_sriov_migration);   */  int pci_num_vf(struct pci_dev *dev)  { -	if (!dev || !dev->is_physfn) +	if (!dev->is_physfn)  		return 0; -	else -		return dev->sriov->nr_virtfn; -} -EXPORT_SYMBOL_GPL(pci_num_vf); - -static int ats_alloc_one(struct pci_dev *dev, int ps) -{ -	int pos; -	u16 cap; -	struct pci_ats *ats; -	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); -	if (!pos) -		return -ENODEV; - -	ats = kzalloc(sizeof(*ats), GFP_KERNEL); -	if (!ats) -		return -ENOMEM; - -	ats->pos = pos; -	ats->stu = ps; -	pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); -	ats->qdep = PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : -					    PCI_ATS_MAX_QDEP; -	dev->ats = ats; - -	return 0; -} - -static void ats_free_one(struct pci_dev *dev) -{ -	kfree(dev->ats); -	dev->ats = NULL; +	return dev->sriov->num_VFs;  } +EXPORT_SYMBOL_GPL(pci_num_vf);  /** - * pci_enable_ats - enable the ATS capability + * pci_vfs_assigned - returns number of VFs are assigned to a guest   * @dev: the PCI device - * @ps: the IOMMU page shift   * - * Returns 0 on success, or negative on failure. + * Returns number of VFs belonging to this device that are assigned to a guest. + * If device is not a physical function returns 0.   */ -int pci_enable_ats(struct pci_dev *dev, int ps) +int pci_vfs_assigned(struct pci_dev *dev)  { -	int rc; -	u16 ctrl; - -	BUG_ON(dev->ats && dev->ats->is_enabled); - -	if (ps < PCI_ATS_MIN_STU) -		return -EINVAL; - -	if (dev->is_physfn || dev->is_virtfn) { -		struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; - -		mutex_lock(&pdev->sriov->lock); -		if (pdev->ats) -			rc = pdev->ats->stu == ps ? 0 : -EINVAL; -		else -			rc = ats_alloc_one(pdev, ps); +	struct pci_dev *vfdev; +	unsigned int vfs_assigned = 0; +	unsigned short dev_id; -		if (!rc) -			pdev->ats->ref_cnt++; -		mutex_unlock(&pdev->sriov->lock); -		if (rc) -			return rc; -	} +	/* only search if we are a PF */ +	if (!dev->is_physfn) +		return 0; -	if (!dev->is_physfn) { -		rc = ats_alloc_one(dev, ps); -		if (rc) -			return rc; +	/* +	 * determine the device ID for the VFs, the vendor ID will be the +	 * same as the PF so there is no need to check for that one +	 */ +	pci_read_config_word(dev, dev->sriov->pos + PCI_SRIOV_VF_DID, &dev_id); + +	/* loop through all the VFs to see if we own any that are assigned */ +	vfdev = pci_get_device(dev->vendor, dev_id, NULL); +	while (vfdev) { +		/* +		 * It is considered assigned if it is a virtual function with +		 * 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)) +			vfs_assigned++; + +		vfdev = pci_get_device(dev->vendor, dev_id, vfdev);  	} -	ctrl = PCI_ATS_CTRL_ENABLE; -	if (!dev->is_virtfn) -		ctrl |= PCI_ATS_CTRL_STU(ps - PCI_ATS_MIN_STU); -	pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); - -	dev->ats->is_enabled = 1; - -	return 0; +	return vfs_assigned;  } +EXPORT_SYMBOL_GPL(pci_vfs_assigned);  /** - * pci_disable_ats - disable the ATS capability - * @dev: the PCI device + * pci_sriov_set_totalvfs -- reduce the TotalVFs available + * @dev: the PCI PF device + * @numvfs: number that should be used for TotalVFs supported + * + * Should be called from PF driver's probe routine with + * device's mutex held. + * + * Returns 0 if PF is an SRIOV-capable device and + * value of numvfs valid. If not a PF return -ENOSYS; + * if numvfs is invalid return -EINVAL; + * if VFs already enabled, return -EBUSY.   */ -void pci_disable_ats(struct pci_dev *dev) +int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs)  { -	u16 ctrl; - -	BUG_ON(!dev->ats || !dev->ats->is_enabled); - -	pci_read_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, &ctrl); -	ctrl &= ~PCI_ATS_CTRL_ENABLE; -	pci_write_config_word(dev, dev->ats->pos + PCI_ATS_CTRL, ctrl); - -	dev->ats->is_enabled = 0; - -	if (dev->is_physfn || dev->is_virtfn) { -		struct pci_dev *pdev = dev->is_physfn ? dev : dev->physfn; +	if (!dev->is_physfn) +		return -ENOSYS; +	if (numvfs > dev->sriov->total_VFs) +		return -EINVAL; -		mutex_lock(&pdev->sriov->lock); -		pdev->ats->ref_cnt--; -		if (!pdev->ats->ref_cnt) -			ats_free_one(pdev); -		mutex_unlock(&pdev->sriov->lock); -	} +	/* Shouldn't change if VFs already enabled */ +	if (dev->sriov->ctrl & PCI_SRIOV_CTRL_VFE) +		return -EBUSY; +	else +		dev->sriov->driver_max_VFs = numvfs; -	if (!dev->is_physfn) -		ats_free_one(dev); +	return 0;  } +EXPORT_SYMBOL_GPL(pci_sriov_set_totalvfs);  /** - * pci_ats_queue_depth - query the ATS Invalidate Queue Depth - * @dev: the PCI device + * pci_sriov_get_totalvfs -- get total VFs supported on this device + * @dev: the PCI PF device   * - * Returns the queue depth on success, or negative on failure. - * - * The ATS spec uses 0 in the Invalidate Queue Depth field to - * indicate that the function can accept 32 Invalidate Request. - * But here we use the `real' values (i.e. 1~32) for the Queue - * Depth; and 0 indicates the function shares the Queue with - * other functions (doesn't exclusively own a Queue). + * 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 0.   */ -int pci_ats_queue_depth(struct pci_dev *dev) +int pci_sriov_get_totalvfs(struct pci_dev *dev)  { -	int pos; -	u16 cap; - -	if (dev->is_virtfn) +	if (!dev->is_physfn)  		return 0; -	if (dev->ats) -		return dev->ats->qdep; - -	pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ATS); -	if (!pos) -		return -ENODEV; - -	pci_read_config_word(dev, pos + PCI_ATS_CAP, &cap); +	if (dev->sriov->driver_max_VFs) +		return dev->sriov->driver_max_VFs; -	return PCI_ATS_CAP_QDEP(cap) ? PCI_ATS_CAP_QDEP(cap) : -				       PCI_ATS_MAX_QDEP; +	return dev->sriov->total_VFs;  } +EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs);  | 
