@@ -323,3 +323,27 @@ Description:
This is similar to /sys/bus/pci/drivers_autoprobe, but
affects only the VFs associated with a specific PF.
+
+What: /sys/bus/pci/devices/.../sriov_unmanaged_autoprobe
+Date: March 2018
+Contact: Alexander Duyck <alexander.h.duyck@intel.com>
+Description:
+ This file is associated with the PF of a device that
+ supports SR-IOV. It determines whether newly-enabled VFs
+ are immediately bound to a driver when the PF driver does
+ not manage the VFs itself. It initially contains 0, which
+ means the kernel will not automatically bind VFs to a driver.
+ If an application writes 1 to the file before enabling VFs,
+ the kernel will bind VFs to a compatible driver immediately
+ after they are enabled.
+
+ Currently the use of this setting is limited to drivers that
+ make use of pci_sriov_configure_unmanaged. Examples might
+ include drivers such as virtio_net which could expose a PCI
+ function that resembles a VF with the extra SR-IOV related
+ bits, or a PF attached to a vfio interface which is being
+ managed by userspace instead of the kernel directly.
+
+ This overrides /sys/bus/pci/devices/.../sriov_drivers_autoprobe
+ when a PF driver does not provide functionality to manage the
+ VFs when SR-IOV is enabled.
@@ -446,6 +446,7 @@ static int sriov_init(struct pci_dev *dev, int pos)
pci_read_config_word(dev, pos + PCI_SRIOV_VF_DID, &iov->vf_device);
iov->pgsz = pgsz;
iov->self = dev;
+ iov->autoprobe = true;
iov->drivers_autoprobe = true;
pci_read_config_dword(dev, pos + PCI_SRIOV_CAP, &iov->cap);
pci_read_config_byte(dev, pos + PCI_SRIOV_FUNC_LINK, &iov->link);
@@ -683,6 +684,9 @@ int pci_enable_sriov(struct pci_dev *dev, int nr_virtfn)
if (!dev->is_physfn)
return -ENOSYS;
+ /* Update autoprobe setting to reflect managed device */
+ dev->sriov->autoprobe = dev->sriov->drivers_autoprobe;
+
return sriov_enable(dev, nr_virtfn);
}
EXPORT_SYMBOL_GPL(pci_enable_sriov);
@@ -807,3 +811,36 @@ int pci_sriov_get_totalvfs(struct pci_dev *dev)
return dev->sriov->total_VFs;
}
EXPORT_SYMBOL_GPL(pci_sriov_get_totalvfs);
+
+/**
+ * pci_sriov_configure_unmanaged - helper to configure unmanaged SR-IOV
+ * @dev: the PCI device
+ * @nr_virtfn: number of virtual functions to enable, 0 to disable
+ *
+ * Used to provide generic enable/disable SR-IOV option for devices
+ * that do not manage the VFs generated by their driver, or have no
+ * driver present.
+ */
+int pci_sriov_configure_unmanaged(struct pci_dev *dev, int nr_virtfn)
+{
+ int err;
+
+ might_sleep();
+
+ if (!dev->is_physfn)
+ return -ENODEV;
+
+ if (!nr_virtfn) {
+ sriov_disable(dev);
+
+ return 0;
+ }
+
+ /* Update autoprobe setting to reflect unmanaged device */
+ dev->sriov->autoprobe = dev->sriov->unmanaged_autoprobe;
+
+ err = sriov_enable(dev, nr_virtfn);
+
+ return err ? err : nr_virtfn;
+}
+EXPORT_SYMBOL_GPL(pci_sriov_configure_unmanaged);
@@ -398,7 +398,7 @@ void __weak pcibios_free_irq(struct pci_dev *dev)
#ifdef CONFIG_PCI_IOV
static inline bool pci_device_can_probe(struct pci_dev *pdev)
{
- return (!pdev->is_virtfn || pdev->physfn->sriov->drivers_autoprobe);
+ return (!pdev->is_virtfn || pdev->physfn->sriov->autoprobe);
}
#else
static inline bool pci_device_can_probe(struct pci_dev *pdev)
@@ -710,6 +710,30 @@ static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
return count;
}
+static ssize_t sriov_unmanaged_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->unmanaged_autoprobe);
+}
+
+static ssize_t sriov_unmanaged_autoprobe_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ bool unmanaged_autoprobe;
+
+ if (kstrtobool(buf, &unmanaged_autoprobe) < 0)
+ return -EINVAL;
+
+ pdev->sriov->unmanaged_autoprobe = unmanaged_autoprobe;
+
+ return count;
+}
+
static struct device_attribute sriov_totalvfs_attr = __ATTR_RO(sriov_totalvfs);
static struct device_attribute sriov_numvfs_attr =
__ATTR(sriov_numvfs, (S_IRUGO|S_IWUSR|S_IWGRP),
@@ -720,6 +744,10 @@ static ssize_t sriov_drivers_autoprobe_store(struct device *dev,
static struct device_attribute sriov_drivers_autoprobe_attr =
__ATTR(sriov_drivers_autoprobe, (S_IRUGO|S_IWUSR|S_IWGRP),
sriov_drivers_autoprobe_show, sriov_drivers_autoprobe_store);
+static struct device_attribute sriov_unmanaged_autoprobe_attr =
+ __ATTR(sriov_unmanaged_autoprobe, (S_IRUGO|S_IWUSR|S_IWGRP),
+ sriov_unmanaged_autoprobe_show,
+ sriov_unmanaged_autoprobe_store);
#endif /* CONFIG_PCI_IOV */
static ssize_t driver_override_store(struct device *dev,
@@ -1789,6 +1817,7 @@ static umode_t pcie_dev_attrs_are_visible(struct kobject *kobj,
&sriov_stride_attr.attr,
&sriov_vf_device_attr.attr,
&sriov_drivers_autoprobe_attr.attr,
+ &sriov_unmanaged_autoprobe_attr.attr,
NULL,
};
@@ -272,7 +272,9 @@ struct pci_sriov {
struct pci_dev *dev; /* Lowest numbered PF */
struct pci_dev *self; /* This PF */
resource_size_t barsz[PCI_SRIOV_NUM_BARS]; /* VF BAR size */
- bool drivers_autoprobe; /* Auto probing of VFs by driver */
+ bool autoprobe; /* Auto probing of VFs by VF driver */
+ bool drivers_autoprobe; /* "" managed by PF driver */
+ bool unmanaged_autoprobe; /* "" unmanaged by kernel */
};
/* pci_dev priv_flags */
@@ -1953,6 +1953,7 @@ static inline void pci_mmcfg_late_init(void) { }
int pci_vfs_assigned(struct pci_dev *dev);
int pci_sriov_set_totalvfs(struct pci_dev *dev, u16 numvfs);
int pci_sriov_get_totalvfs(struct pci_dev *dev);
+int pci_sriov_configure_unmanaged(struct pci_dev *dev, int nr_virtfn);
resource_size_t pci_iov_resource_size(struct pci_dev *dev, int resno);
void pci_vf_drivers_autoprobe(struct pci_dev *dev, bool probe);
#else