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);
|
struct pci_devinfo *dinfo = device_get_ivars(child);
|
||||||
pcicfgregs *cfg = &dinfo->cfg;
|
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),
|
return (PCIB_READ_CONFIG(device_get_parent(dev),
|
||||||
cfg->bus, cfg->slot, cfg->func, reg, width));
|
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
|
static int
|
||||||
pci_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
|
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;
|
void *confdata;
|
||||||
const char *name;
|
const char *name;
|
||||||
struct devlist *devlist_head;
|
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_bus, io->pi_sel.pc_dev,
|
||||||
io->pi_sel.pc_func);
|
io->pi_sel.pc_func);
|
||||||
if (pcidev) {
|
if (pcidev) {
|
||||||
brdev = device_get_parent(
|
|
||||||
device_get_parent(pcidev));
|
|
||||||
|
|
||||||
#ifdef PRE7_COMPAT
|
#ifdef PRE7_COMPAT
|
||||||
if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
|
if (cmd == PCIOCWRITE || cmd == PCIOCWRITE_OLD)
|
||||||
#else
|
#else
|
||||||
if (cmd == PCIOCWRITE)
|
if (cmd == PCIOCWRITE)
|
||||||
#endif
|
#endif
|
||||||
PCIB_WRITE_CONFIG(brdev,
|
pci_write_config(pcidev,
|
||||||
io->pi_sel.pc_bus,
|
|
||||||
io->pi_sel.pc_dev,
|
|
||||||
io->pi_sel.pc_func,
|
|
||||||
io->pi_reg,
|
io->pi_reg,
|
||||||
io->pi_data,
|
io->pi_data,
|
||||||
io->pi_width);
|
io->pi_width);
|
||||||
#ifdef PRE7_COMPAT
|
#ifdef PRE7_COMPAT
|
||||||
else if (cmd == PCIOCREAD_OLD)
|
else if (cmd == PCIOCREAD_OLD)
|
||||||
io_old->pi_data =
|
io_old->pi_data =
|
||||||
PCIB_READ_CONFIG(brdev,
|
pci_read_config(pcidev,
|
||||||
io->pi_sel.pc_bus,
|
|
||||||
io->pi_sel.pc_dev,
|
|
||||||
io->pi_sel.pc_func,
|
|
||||||
io->pi_reg,
|
io->pi_reg,
|
||||||
io->pi_width);
|
io->pi_width);
|
||||||
#endif
|
#endif
|
||||||
else
|
else
|
||||||
io->pi_data =
|
io->pi_data =
|
||||||
PCIB_READ_CONFIG(brdev,
|
pci_read_config(pcidev,
|
||||||
io->pi_sel.pc_bus,
|
|
||||||
io->pi_sel.pc_dev,
|
|
||||||
io->pi_sel.pc_func,
|
|
||||||
io->pi_reg,
|
io->pi_reg,
|
||||||
io->pi_width);
|
io->pi_width);
|
||||||
error = 0;
|
error = 0;
|
||||||
|
Loading…
Reference in New Issue
Block a user