PCI: Add sysfs sriov_drivers_autoprobe to control VF driver binding
authorBodong Wang <bodong@mellanox.com>
Wed, 12 Apr 2017 22:51:40 +0000 (01:51 +0300)
committerBjorn Helgaas <bhelgaas@google.com>
Thu, 20 Apr 2017 13:53:51 +0000 (08:53 -0500)
Sometimes it is not desirable to bind SR-IOV VFs to drivers.  This can save
host side resource usage by VF instances that will be assigned to VMs.

Add a new PCI sysfs interface "sriov_drivers_autoprobe" to control that
from the PF.  To modify it, echo 0/n/N (disable probe) or 1/y/Y (enable
probe) to:

  /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe

Note that this must be done before enabling VFs.  The change will not take
effect if VFs are already enabled.  Simply, one can disable VFs by setting
sriov_numvfs to 0, choose whether to probe or not, and then re-enable the
VFs by restoring sriov_numvfs.

[bhelgaas: changelog, ABI doc]
Signed-off-by: Bodong Wang <bodong@mellanox.com>
Signed-off-by: Eli Cohen <eli@mellanox.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Gavin Shan <gwshan@linux.vnet.ibm.com>
Reviewed-by: Alex Williamson <alex.williamson@redhat.com>
Documentation/ABI/testing/sysfs-bus-pci
Documentation/PCI/pci-iov-howto.txt
drivers/pci/iov.c
drivers/pci/pci-driver.c
drivers/pci/pci-sysfs.c
drivers/pci/pci.h

index 5a1732b787071ce1495982f125759f15926e581f..b728f700340d0021c2f3a562e49dacdeac5fb02b 100644 (file)
@@ -301,3 +301,25 @@ Contact:   Emil Velikov <emil.l.velikov@gmail.com>
 Description:
                This file contains the revision field of the the PCI device.
                The value comes from device config space. The file is read only.
+
+What:          /sys/bus/pci/devices/.../sriov_drivers_autoprobe
+Date:          April 2017
+Contact:       Bodong Wang<bodong@mellanox.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.  It initially contains
+               1, which means the kernel automatically binds VFs to a
+               compatible driver immediately after they are enabled.  If
+               an application writes 0 to the file before enabling VFs,
+               the kernel will not bind VFs to a driver.
+
+               A typical use case is to write 0 to this file, then enable
+               VFs, then assign the newly-created VFs to virtual machines.
+               Note that changing this file does not affect already-
+               enabled VFs.  In this scenario, the user must first disable
+               the VFs, write 0 to sriov_drivers_autoprobe, then re-enable
+               the VFs.
+
+               This is similar to /sys/bus/pci/drivers_autoprobe, but
+               affects only the VFs associated with a specific PF.
index 2d91ae25198295dc8559d2ef8d00cae1b5314989..d2a84151e99c0a37242d5dd754a3e571ab58ac53 100644 (file)
@@ -68,6 +68,18 @@ To disable SR-IOV capability:
        echo  0 > \
         /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_numvfs
 
+To enable auto probing VFs by a compatible driver on the host, run
+command below before enabling SR-IOV capabilities. This is the
+default behavior.
+       echo 1 > \
+        /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe
+
+To disable auto probing VFs by a compatible driver on the host, run
+command below before enabling SR-IOV capabilities. Updating this
+entry will not affect VFs which are already probed.
+       echo  0 > \
+        /sys/bus/pci/devices/<DOMAIN:BUS:DEVICE.FUNCTION>/sriov_drivers_autoprobe
+
 3.2 Usage example
 
 Following piece of code illustrates the usage of the SR-IOV API.
index 2479ae8764826575825ded382b48d96491296ecf..d9dc7363ac77def7cd81f06646ae76774d92f743 100644 (file)
@@ -450,6 +450,7 @@ found:
        iov->total_VFs = total;
        iov->pgsz = pgsz;
        iov->self = dev;
+       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);
        if (pci_pcie_type(dev) == PCI_EXP_TYPE_RC_END)
index afa72717a97937cdb5d222dbb292a993fdf5d436..f99f7fe749b8abe9112993029a56b7c9bf86e2e7 100644 (file)
@@ -394,6 +394,18 @@ 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);
+}
+#else
+static inline bool pci_device_can_probe(struct pci_dev *pdev)
+{
+       return true;
+}
+#endif
+
 static int pci_device_probe(struct device *dev)
 {
        int error;
@@ -405,10 +417,12 @@ static int pci_device_probe(struct device *dev)
                return error;
 
        pci_dev_get(pci_dev);
-       error = __pci_device_probe(drv, pci_dev);
-       if (error) {
-               pcibios_free_irq(pci_dev);
-               pci_dev_put(pci_dev);
+       if (pci_device_can_probe(pci_dev)) {
+               error = __pci_device_probe(drv, pci_dev);
+               if (error) {
+                       pcibios_free_irq(pci_dev);
+                       pci_dev_put(pci_dev);
+               }
        }
 
        return error;
index 25d010d449a31408fe3058783eec32f0be92e3e4..369c999683ca3e89e968489d7a5cbeeed7fe56fe 100644 (file)
@@ -526,10 +526,37 @@ exit:
        return count;
 }
 
+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 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),
                       sriov_numvfs_show, sriov_numvfs_store);
+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);
 #endif /* CONFIG_PCI_IOV */
 
 static ssize_t driver_override_store(struct device *dev,
@@ -1549,6 +1576,7 @@ static struct attribute_group pci_dev_hp_attr_group = {
 static struct attribute *sriov_dev_attrs[] = {
        &sriov_totalvfs_attr.attr,
        &sriov_numvfs_attr.attr,
+       &sriov_drivers_autoprobe_attr.attr,
        NULL,
 };
 
index 8dd38e69d6f2a8ae4f4b7d6801f3f321abb5ac1a..3ba7d586f5225f98f01891dcf6b80c56ec6bb6e9 100644 (file)
@@ -272,6 +272,7 @@ struct pci_sriov {
        struct pci_dev *self;   /* this PF */
        struct mutex lock;      /* lock for setting sriov_numvfs in sysfs */
        resource_size_t barsz[PCI_SRIOV_NUM_BARS];      /* VF BAR size */
+       bool drivers_autoprobe; /* auto probing of VFs by driver */
 };
 
 #ifdef CONFIG_PCI_ATS