Author: rstone
Date: Sun Mar  1 00:40:34 2015
New Revision: 279450
URL: https://svnweb.freebsd.org/changeset/base/279450

Log:
  Add interface to destroy SR-IOV VFs
  
  Differential Revision:        https://reviews.freebsd.org/D79
  Reviewed by:          jhb
  MFC after:            1 month
  Sponsored by:         Sandvine Inc.

Modified:
  head/sys/dev/pci/pci_iov.c
  head/sys/dev/pci/pci_iov_private.h
  head/sys/sys/iov.h

Modified: head/sys/dev/pci/pci_iov.c
==============================================================================
--- head/sys/dev/pci/pci_iov.c  Sun Mar  1 00:40:26 2015        (r279449)
+++ head/sys/dev/pci/pci_iov.c  Sun Mar  1 00:40:34 2015        (r279450)
@@ -143,7 +143,7 @@ pci_iov_detach_method(device_t bus, devi
                return (0);
        }
 
-       if (iov->iov_num_vfs != 0) {
+       if (iov->iov_num_vfs != 0 || iov->iov_flags & IOV_BUSY) {
                mtx_unlock(&Giant);
                return (EBUSY);
        }
@@ -405,10 +405,11 @@ pci_iov_config(struct cdev *cdev, struct
        bus = device_get_parent(dev);
        iov_inited = 0;
 
-       if (iov->iov_num_vfs != 0) {
+       if ((iov->iov_flags & IOV_BUSY) || iov->iov_num_vfs != 0) {
                mtx_unlock(&Giant);
                return (EBUSY);
        }
+       iov->iov_flags |= IOV_BUSY;
 
        total_vfs = IOV_READ(dinfo, PCIR_SRIOV_TOTAL_VFS, 2);
 
@@ -498,10 +499,113 @@ out:
                iov->iov_flags &= ~IOV_RMAN_INITED;
        }
        iov->iov_num_vfs = 0;
+       iov->iov_flags &= ~IOV_BUSY;
        mtx_unlock(&Giant);
        return (error);
 }
 
+/* Return true if child is a VF of the given PF. */
+static int
+pci_iov_is_child_vf(struct pcicfg_iov *pf, device_t child)
+{
+       struct pci_devinfo *vfinfo;
+
+       vfinfo = device_get_ivars(child);
+
+       if (!(vfinfo->cfg.flags & PCICFG_VF))
+               return (0);
+
+       return (pf == vfinfo->cfg.iov);
+}
+
+static int
+pci_iov_delete(struct cdev *cdev)
+{
+       device_t bus, dev, vf, *devlist;
+       struct pci_devinfo *dinfo;
+       struct pcicfg_iov *iov;
+       int i, error, devcount;
+       uint32_t iov_ctl;
+
+       mtx_lock(&Giant);
+       dinfo = cdev->si_drv1;
+       iov = dinfo->cfg.iov;
+       dev = dinfo->cfg.dev;
+       bus = device_get_parent(dev);
+       devlist = NULL;
+
+       if (iov->iov_flags & IOV_BUSY) {
+               mtx_unlock(&Giant);
+               return (EBUSY);
+       }
+
+       if (iov->iov_num_vfs == 0) {
+               mtx_unlock(&Giant);
+               return (ECHILD);
+       }
+
+       iov->iov_flags |= IOV_BUSY;
+
+       error = device_get_children(bus, &devlist, &devcount);
+
+       if (error != 0)
+               goto out;
+
+       for (i = 0; i < devcount; i++) {
+               vf = devlist[i];
+
+               if (!pci_iov_is_child_vf(iov, vf))
+                       continue;
+
+               error = device_detach(vf);
+               if (error != 0) {
+                       device_printf(dev,
+                          "Could not disable SR-IOV: failed to detach VF %s\n",
+                           device_get_nameunit(vf));
+                       goto out;
+               }
+       }
+
+       for (i = 0; i < devcount; i++) {
+               vf = devlist[i];
+
+               if (pci_iov_is_child_vf(iov, vf))
+                       pci_delete_child(bus, vf);
+       }
+       PCI_UNINIT_IOV(dev);
+
+       iov_ctl = IOV_READ(dinfo, PCIR_SRIOV_CTL, 2);
+       iov_ctl &= ~(PCIM_SRIOV_VF_EN | PCIM_SRIOV_VF_MSE);
+       IOV_WRITE(dinfo, PCIR_SRIOV_CTL, iov_ctl, 2);
+       IOV_WRITE(dinfo, PCIR_SRIOV_NUM_VFS, 0, 2);
+
+       iov->iov_num_vfs = 0;
+
+       for (i = 0; i <= PCIR_MAX_BAR_0; i++) {
+               if (iov->iov_bar[i].res != NULL) {
+                       pci_release_resource(bus, dev, SYS_RES_MEMORY,
+                           iov->iov_pos + PCIR_SRIOV_BAR(i),
+                           iov->iov_bar[i].res);
+                       pci_delete_resource(bus, dev, SYS_RES_MEMORY,
+                           iov->iov_pos + PCIR_SRIOV_BAR(i));
+                       iov->iov_bar[i].res = NULL;
+               }
+       }
+
+       if (iov->iov_flags & IOV_RMAN_INITED) {
+               rman_fini(&iov->rman);
+               iov->iov_flags &= ~IOV_RMAN_INITED;
+       }
+
+       error = 0;
+out:
+       free(devlist, M_TEMP);
+       iov->iov_flags &= ~IOV_BUSY;
+       mtx_unlock(&Giant);
+       return (error);
+}
+
+
 static int
 pci_iov_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
     struct thread *td)
@@ -510,6 +614,8 @@ pci_iov_ioctl(struct cdev *dev, u_long c
        switch (cmd) {
        case IOV_CONFIG:
                return (pci_iov_config(dev, (struct pci_iov_arg *)data));
+       case IOV_DELETE:
+               return (pci_iov_delete(dev));
        default:
                return (EINVAL);
        }

Modified: head/sys/dev/pci/pci_iov_private.h
==============================================================================
--- head/sys/dev/pci/pci_iov_private.h  Sun Mar  1 00:40:26 2015        
(r279449)
+++ head/sys/dev/pci/pci_iov_private.h  Sun Mar  1 00:40:34 2015        
(r279450)
@@ -49,6 +49,7 @@ struct pcicfg_iov {
 };
 
 #define        IOV_RMAN_INITED         0x0001
+#define        IOV_BUSY                0x0002
 
 #endif
 

Modified: head/sys/sys/iov.h
==============================================================================
--- head/sys/sys/iov.h  Sun Mar  1 00:40:26 2015        (r279449)
+++ head/sys/sys/iov.h  Sun Mar  1 00:40:34 2015        (r279450)
@@ -38,6 +38,7 @@ struct pci_iov_arg
 };
 
 #define        IOV_CONFIG      _IOWR('p', 10, struct pci_iov_arg)
+#define        IOV_DELETE      _IO('p', 11)
 
 #endif
 
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to