Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 1 Mar 2015 00:40:35 +0000 (UTC)
From:      Ryan Stone <rstone@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r279450 - in head/sys: dev/pci sys
Message-ID:  <201503010040.t210eZWY093070@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201503010040.t210eZWY093070>