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.
This commit is contained in:
parent
9bfb1e36d9
commit
5060ec97d4
@ -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));
|
||||
}
|
||||
|
@ -492,7 +492,7 @@ pci_list_vpd(device_t dev, struct pci_list_vpd_io *lvio)
|
||||
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 @@ pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *t
|
||||
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;
|
||||
|
Loading…
Reference in New Issue
Block a user