Index: usr.sbin/bhyve/pci_passthru.c =================================================================== --- usr.sbin/bhyve/pci_passthru.c +++ usr.sbin/bhyve/pci_passthru.c @@ -618,6 +618,7 @@ { int error; struct passthru_softc *sc; + uint16_t cmd, orig_cmd; error = 1; sc = pi->pi_arg; @@ -627,6 +628,17 @@ sc->psc_sel.pc_dev = slot; sc->psc_sel.pc_func = func; + /* + * To initialize the command register, start with the value in + * the PCI device, always enable busmastering and INTx + * interrupts, and let pci_emul_alloc_pbar() enable I/O and + * memory decoding as needed. + */ + orig_cmd = read_config(&sc->psc_sel, PCIR_COMMAND, 2); + cmd = orig_cmd | PCIM_CMD_BUSMASTEREN; + cmd &= ~(PCIM_CMD_INTxDIS | PCIM_CMD_PORTEN | PCIM_CMD_MEMEN); + pci_set_cfgdata16(pi, PCIR_COMMAND, cmd); + if (cfginitmsi(sc) != 0) { warnx("failed to initialize MSI for PCI %d/%d/%d", bus, slot, func); @@ -639,8 +651,13 @@ goto done; } - pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel, - PCIR_COMMAND, 2)); + /* + * Fetch the updated virtual command register and write it to + * the device if needed. + */ + cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); + if (cmd != orig_cmd) + write_config(&sc->psc_sel, PCIR_COMMAND, 2, cmd); error = 0; /* success */ done: @@ -802,6 +819,19 @@ return (-1); } #endif + + /* + * Emulate the command register. If a single read reads both the + * command and status registers, read the status register from the + * device's config space. + */ + if (coff == PCIR_COMMAND) { + if (bytes <= 2) + return (-1); + *rv = pci_get_cfgdata16(pi, PCIR_COMMAND) << 16 | + read_config(&sc->psc_sel, PCIR_STATUS, 2); + return (0); + } /* Everything else just read from the device's config space */ *rv = read_config(&sc->psc_sel, coff, bytes);