diff options
Diffstat (limited to 'drivers/pci/iov.c')
| -rw-r--r-- | drivers/pci/iov.c | 171 | 
1 files changed, 169 insertions, 2 deletions
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 525fd3f272b3..b3f972e8cfed 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -240,6 +240,173 @@ void pci_iov_remove_virtfn(struct pci_dev *dev, int id)  	pci_dev_put(dev);  } +static ssize_t sriov_totalvfs_show(struct device *dev, +				   struct device_attribute *attr, +				   char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%u\n", pci_sriov_get_totalvfs(pdev)); +} + +static ssize_t sriov_numvfs_show(struct device *dev, +				 struct device_attribute *attr, +				 char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%u\n", pdev->sriov->num_VFs); +} + +/* + * num_vfs > 0; number of VFs to enable + * num_vfs = 0; disable all VFs + * + * Note: SRIOV spec does not allow partial VF + *	 disable, so it's all or none. + */ +static ssize_t sriov_numvfs_store(struct device *dev, +				  struct device_attribute *attr, +				  const char *buf, size_t count) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	int ret; +	u16 num_vfs; + +	ret = kstrtou16(buf, 0, &num_vfs); +	if (ret < 0) +		return ret; + +	if (num_vfs > pci_sriov_get_totalvfs(pdev)) +		return -ERANGE; + +	device_lock(&pdev->dev); + +	if (num_vfs == pdev->sriov->num_VFs) +		goto exit; + +	/* is PF driver loaded w/callback */ +	if (!pdev->driver || !pdev->driver->sriov_configure) { +		pci_info(pdev, "Driver does not support SRIOV configuration via sysfs\n"); +		ret = -ENOENT; +		goto exit; +	} + +	if (num_vfs == 0) { +		/* disable VFs */ +		ret = pdev->driver->sriov_configure(pdev, 0); +		goto exit; +	} + +	/* enable VFs */ +	if (pdev->sriov->num_VFs) { +		pci_warn(pdev, "%d VFs already enabled. Disable before enabling %d VFs\n", +			 pdev->sriov->num_VFs, num_vfs); +		ret = -EBUSY; +		goto exit; +	} + +	ret = pdev->driver->sriov_configure(pdev, num_vfs); +	if (ret < 0) +		goto exit; + +	if (ret != num_vfs) +		pci_warn(pdev, "%d VFs requested; only %d enabled\n", +			 num_vfs, ret); + +exit: +	device_unlock(&pdev->dev); + +	if (ret < 0) +		return ret; + +	return count; +} + +static ssize_t sriov_offset_show(struct device *dev, +				 struct device_attribute *attr, +				 char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%u\n", pdev->sriov->offset); +} + +static ssize_t sriov_stride_show(struct device *dev, +				 struct device_attribute *attr, +				 char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%u\n", pdev->sriov->stride); +} + +static ssize_t sriov_vf_device_show(struct device *dev, +				    struct device_attribute *attr, +				    char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%x\n", pdev->sriov->vf_device); +} + +static ssize_t sriov_drivers_autoprobe_show(struct device *dev, +					    struct device_attribute *attr, +					    char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); + +	return sprintf(buf, "%u\n", pdev->sriov->drivers_autoprobe); +} + +static ssize_t sriov_drivers_autoprobe_store(struct device *dev, +					     struct device_attribute *attr, +					     const char *buf, size_t count) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	bool drivers_autoprobe; + +	if (kstrtobool(buf, &drivers_autoprobe) < 0) +		return -EINVAL; + +	pdev->sriov->drivers_autoprobe = drivers_autoprobe; + +	return count; +} + +static DEVICE_ATTR_RO(sriov_totalvfs); +static DEVICE_ATTR_RW(sriov_numvfs); +static DEVICE_ATTR_RO(sriov_offset); +static DEVICE_ATTR_RO(sriov_stride); +static DEVICE_ATTR_RO(sriov_vf_device); +static DEVICE_ATTR_RW(sriov_drivers_autoprobe); + +static struct attribute *sriov_dev_attrs[] = { +	&dev_attr_sriov_totalvfs.attr, +	&dev_attr_sriov_numvfs.attr, +	&dev_attr_sriov_offset.attr, +	&dev_attr_sriov_stride.attr, +	&dev_attr_sriov_vf_device.attr, +	&dev_attr_sriov_drivers_autoprobe.attr, +	NULL, +}; + +static umode_t sriov_attrs_are_visible(struct kobject *kobj, +				       struct attribute *a, int n) +{ +	struct device *dev = kobj_to_dev(kobj); + +	if (!dev_is_pf(dev)) +		return 0; + +	return a->mode; +} + +const struct attribute_group sriov_dev_attr_group = { +	.attrs = sriov_dev_attrs, +	.is_visible = sriov_attrs_are_visible, +}; +  int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs)  {  	return 0; @@ -557,8 +724,8 @@ static void sriov_restore_state(struct pci_dev *dev)  	ctrl |= iov->ctrl & PCI_SRIOV_CTRL_ARI;  	pci_write_config_word(dev, iov->pos + PCI_SRIOV_CTRL, ctrl); -	for (i = PCI_IOV_RESOURCES; i <= PCI_IOV_RESOURCE_END; i++) -		pci_update_resource(dev, i); +	for (i = 0; i < PCI_SRIOV_NUM_BARS; i++) +		pci_update_resource(dev, i + PCI_IOV_RESOURCES);  	pci_write_config_dword(dev, iov->pos + PCI_SRIOV_SYS_PGSIZE, iov->pgsz);  	pci_iov_set_numvfs(dev, iov->num_VFs);  |