svn commit: r279448 - head/sys/dev/pci

Ryan Stone rstone at FreeBSD.org
Sun Mar 1 00:40:21 UTC 2015


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

Log:
  Emulate the Device ID and Vendor ID registers for VFs
  
  The SR-IOV standard requires VFs to read all-ones when the VID
  and DID registers are read.  The VMM (hypervisor) is required to
  emulate them instead.  Make pci_read_config() do this emulation.
  
  Change pci_user.c to use pci_read_config() to read config space
  registers instead of going directly to the pcib so that the
  emulated VID/DID registers work correctly on VFs.  This is
  required both for pciconf and bhyve PCI passthrough.
  
  Differential Revision:	https://reviews.freebsd.org/D77
  Reviewed by:		jhb
  MFC after: 		1 month
  Sponsored by:		Sandvine Inc.

Modified:
  head/sys/dev/pci/pci.c
  head/sys/dev/pci/pci_user.c

Modified: head/sys/dev/pci/pci.c
==============================================================================
--- head/sys/dev/pci/pci.c	Sun Mar  1 00:40:09 2015	(r279447)
+++ head/sys/dev/pci/pci.c	Sun Mar  1 00:40:19 2015	(r279448)
@@ -4880,6 +4880,37 @@ pci_read_config_method(device_t dev, dev
 	struct pci_devinfo *dinfo = device_get_ivars(child);
 	pcicfgregs *cfg = &dinfo->cfg;
 
+#ifdef PCI_IOV
+	/*
+	 * SR-IOV VFs don't implement the VID or DID registers, so we have to
+	 * emulate them here.
+	 */
+	if (cfg->flags & PCICFG_VF) {
+		if (reg == PCIR_VENDOR) {
+			switch (width) {
+			case 4:
+				return (cfg->device << 16 | cfg->vendor);
+			case 2:
+				return (cfg->vendor);
+			case 1:
+				return (cfg->vendor & 0xff);
+			default:
+				return (0xffffffff);
+			}
+		} else if (reg == PCIR_DEVICE) {
+			switch (width) {
+			/* Note that an unaligned 4-byte read is an error. */
+			case 2:
+				return (cfg->device);
+			case 1:
+				return (cfg->device & 0xff);
+			default:
+				return (0xffffffff);
+			}
+		}
+	}
+#endif
+
 	return (PCIB_READ_CONFIG(device_get_parent(dev),
 	    cfg->bus, cfg->slot, cfg->func, reg, width));
 }

Modified: head/sys/dev/pci/pci_user.c
==============================================================================
--- head/sys/dev/pci/pci_user.c	Sun Mar  1 00:40:09 2015	(r279447)
+++ head/sys/dev/pci/pci_user.c	Sun Mar  1 00:40:19 2015	(r279448)
@@ -492,7 +492,7 @@ pci_list_vpd(device_t dev, struct pci_li
 static int
 pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
 {
-	device_t pcidev, brdev;
+	device_t pcidev;
 	void *confdata;
 	const char *name;
 	struct devlist *devlist_head;
@@ -922,37 +922,25 @@ getconfexit:
 			    io->pi_sel.pc_bus, io->pi_sel.pc_dev,
 			    io->pi_sel.pc_func);
 			if (pcidev) {
-				brdev = device_get_parent(
-				    device_get_parent(pcidev));
-
 #ifdef PRE7_COMPAT
 				if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
 #else
 				if (cmd == PCIOCWRITE)
 #endif
-					PCIB_WRITE_CONFIG(brdev,
-							  io->pi_sel.pc_bus,
-							  io->pi_sel.pc_dev,
-							  io->pi_sel.pc_func,
+					pci_write_config(pcidev,
 							  io->pi_reg,
 							  io->pi_data,
 							  io->pi_width);
 #ifdef PRE7_COMPAT
 				else if (cmd == PCIOCREAD_OLD)
 					io_old->pi_data =
-						PCIB_READ_CONFIG(brdev,
-							  io->pi_sel.pc_bus,
-							  io->pi_sel.pc_dev,
-							  io->pi_sel.pc_func,
+						pci_read_config(pcidev,
 							  io->pi_reg,
 							  io->pi_width);
 #endif
 				else
 					io->pi_data =
-						PCIB_READ_CONFIG(brdev,
-							  io->pi_sel.pc_bus,
-							  io->pi_sel.pc_dev,
-							  io->pi_sel.pc_func,
+						pci_read_config(pcidev,
 							  io->pi_reg,
 							  io->pi_width);
 				error = 0;


More information about the svn-src-head mailing list