diff options
Diffstat (limited to 'drivers/pci/iov.c')
| -rw-r--r-- | drivers/pci/iov.c | 102 | 
1 files changed, 96 insertions, 6 deletions
| diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c index 4afd4ee4f7f0..afc06e6ce115 100644 --- a/drivers/pci/iov.c +++ b/drivers/pci/iov.c @@ -31,6 +31,7 @@ int pci_iov_virtfn_devfn(struct pci_dev *dev, int vf_id)  	return (dev->devfn + dev->sriov->offset +  		dev->sriov->stride * vf_id) & 0xff;  } +EXPORT_SYMBOL_GPL(pci_iov_virtfn_devfn);  /*   * Per SR-IOV spec sec 3.3.10 and 3.3.11, First VF Offset and VF Stride may @@ -157,6 +158,92 @@ failed:  	return rc;  } +#ifdef CONFIG_PCI_MSI +static ssize_t sriov_vf_total_msix_show(struct device *dev, +					struct device_attribute *attr, +					char *buf) +{ +	struct pci_dev *pdev = to_pci_dev(dev); +	u32 vf_total_msix = 0; + +	device_lock(dev); +	if (!pdev->driver || !pdev->driver->sriov_get_vf_total_msix) +		goto unlock; + +	vf_total_msix = pdev->driver->sriov_get_vf_total_msix(pdev); +unlock: +	device_unlock(dev); +	return sysfs_emit(buf, "%u\n", vf_total_msix); +} +static DEVICE_ATTR_RO(sriov_vf_total_msix); + +static ssize_t sriov_vf_msix_count_store(struct device *dev, +					 struct device_attribute *attr, +					 const char *buf, size_t count) +{ +	struct pci_dev *vf_dev = to_pci_dev(dev); +	struct pci_dev *pdev = pci_physfn(vf_dev); +	int val, ret; + +	ret = kstrtoint(buf, 0, &val); +	if (ret) +		return ret; + +	if (val < 0) +		return -EINVAL; + +	device_lock(&pdev->dev); +	if (!pdev->driver || !pdev->driver->sriov_set_msix_vec_count) { +		ret = -EOPNOTSUPP; +		goto err_pdev; +	} + +	device_lock(&vf_dev->dev); +	if (vf_dev->driver) { +		/* +		 * A driver is already attached to this VF and has configured +		 * itself based on the current MSI-X vector count. Changing +		 * the vector size could mess up the driver, so block it. +		 */ +		ret = -EBUSY; +		goto err_dev; +	} + +	ret = pdev->driver->sriov_set_msix_vec_count(vf_dev, val); + +err_dev: +	device_unlock(&vf_dev->dev); +err_pdev: +	device_unlock(&pdev->dev); +	return ret ? : count; +} +static DEVICE_ATTR_WO(sriov_vf_msix_count); +#endif + +static struct attribute *sriov_vf_dev_attrs[] = { +#ifdef CONFIG_PCI_MSI +	&dev_attr_sriov_vf_msix_count.attr, +#endif +	NULL, +}; + +static umode_t sriov_vf_attrs_are_visible(struct kobject *kobj, +					  struct attribute *a, int n) +{ +	struct device *dev = kobj_to_dev(kobj); +	struct pci_dev *pdev = to_pci_dev(dev); + +	if (!pdev->is_virtfn) +		return 0; + +	return a->mode; +} + +const struct attribute_group sriov_vf_dev_attr_group = { +	.attrs = sriov_vf_dev_attrs, +	.is_visible = sriov_vf_attrs_are_visible, +}; +  int pci_iov_add_virtfn(struct pci_dev *dev, int id)  {  	int i; @@ -400,18 +487,21 @@ 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[] = { +static struct attribute *sriov_pf_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, +#ifdef CONFIG_PCI_MSI +	&dev_attr_sriov_vf_total_msix.attr, +#endif  	NULL,  }; -static umode_t sriov_attrs_are_visible(struct kobject *kobj, -				       struct attribute *a, int n) +static umode_t sriov_pf_attrs_are_visible(struct kobject *kobj, +					  struct attribute *a, int n)  {  	struct device *dev = kobj_to_dev(kobj); @@ -421,9 +511,9 @@ static umode_t sriov_attrs_are_visible(struct kobject *kobj,  	return a->mode;  } -const struct attribute_group sriov_dev_attr_group = { -	.attrs = sriov_dev_attrs, -	.is_visible = sriov_attrs_are_visible, +const struct attribute_group sriov_pf_dev_attr_group = { +	.attrs = sriov_pf_dev_attrs, +	.is_visible = sriov_pf_attrs_are_visible,  };  int __weak pcibios_sriov_enable(struct pci_dev *pdev, u16 num_vfs) | 
