summaryrefslogtreecommitdiffstats
path: root/sys/dev/pci/pci.c
diff options
context:
space:
mode:
authorrstone <rstone@FreeBSD.org>2015-03-01 00:40:19 +0000
committerrstone <rstone@FreeBSD.org>2015-03-01 00:40:19 +0000
commit89058c6ddf90ce9df75bd000e86824b6d85b8a20 (patch)
tree45cae5e69af2feffd051e89c1c6b49eda8838b84 /sys/dev/pci/pci.c
parente40d09375f3eaf15c6f9b6d563c7371512c76d51 (diff)
downloadFreeBSD-src-89058c6ddf90ce9df75bd000e86824b6d85b8a20.zip
FreeBSD-src-89058c6ddf90ce9df75bd000e86824b6d85b8a20.tar.gz
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.
Diffstat (limited to 'sys/dev/pci/pci.c')
-rw-r--r--sys/dev/pci/pci.c31
1 files changed, 31 insertions, 0 deletions
diff --git a/sys/dev/pci/pci.c b/sys/dev/pci/pci.c
index 517e91e..e103f04 100644
--- a/sys/dev/pci/pci.c
+++ b/sys/dev/pci/pci.c
@@ -4880,6 +4880,37 @@ pci_read_config_method(device_t dev, device_t child, int reg, int width)
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));
}
OpenPOWER on IntegriCloud