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;
_______________________________________________
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