diff options
author | rstone <rstone@FreeBSD.org> | 2015-03-01 00:40:19 +0000 |
---|---|---|
committer | rstone <rstone@FreeBSD.org> | 2015-03-01 00:40:19 +0000 |
commit | 89058c6ddf90ce9df75bd000e86824b6d85b8a20 (patch) | |
tree | 45cae5e69af2feffd051e89c1c6b49eda8838b84 /sys/dev/pci/pci.c | |
parent | e40d09375f3eaf15c6f9b6d563c7371512c76d51 (diff) | |
download | FreeBSD-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.c | 31 |
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)); } |