diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c --- a/usr.sbin/bhyve/pci_passthru.c +++ b/usr.sbin/bhyve/pci_passthru.c @@ -80,6 +80,11 @@ static int pcifd = -1; +static int passthru_cfgread_command(struct passthru_softc *sc, + struct pci_devinst *pi, int coff, int bytes, uint32_t *rv); +static int passthru_cfgwrite_command(struct passthru_softc *sc, + struct pci_devinst *pi, int coff, int bytes, uint32_t rv); + static int msi_caplen(int msgctrl) { @@ -883,11 +888,16 @@ passthru_cfgread_emulate, passthru_cfgwrite_emulate)) != 0) goto done; - /* Allow access to the physical command and status register. */ - if ((error = set_pcir_handler(sc, PCIR_COMMAND, 0x04, + /* Allow access to the physical status register. */ + if ((error = set_pcir_handler(sc, PCIR_STATUS, 0x02, passthru_cfgread_default, passthru_cfgwrite_default)) != 0) goto done; + /* The command register requires special handling. */ + if ((error = set_pcir_handler(sc, PCIR_COMMAND, 0x02, + passthru_cfgread_command, passthru_cfgwrite_command)) != 0) + goto done; + error = 0; /* success */ done: if (error) { @@ -933,6 +943,24 @@ return (sc->psc_pcir_rhandler[coff](sc, pi, coff, bytes, rv)); } +static int +passthru_cfgread_command(struct passthru_softc *sc, struct pci_devinst *pi, + int coff __unused, int bytes, uint32_t *rv) +{ + /* + * 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 (bytes <= 2) + return (-1); + + *rv = read_config(&sc->psc_sel, PCIR_STATUS, 2) << 16 | + pci_get_cfgdata16(pi, PCIR_COMMAND); + + return (0); +} + int passthru_cfgread_default(struct passthru_softc *sc, struct pci_devinst *pi __unused, int coff, int bytes, uint32_t *rv) @@ -954,19 +982,6 @@ } #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 = read_config(&sc->psc_sel, PCIR_STATUS, 2) << 16 | - pci_get_cfgdata16(pi, PCIR_COMMAND); - return (0); - } - /* Everything else just read from the device's config space */ *rv = read_config(&sc->psc_sel, coff, bytes); @@ -991,12 +1006,29 @@ return (sc->psc_pcir_whandler[coff](sc, pi, coff, bytes, val)); } +static int +passthru_cfgwrite_command(struct passthru_softc *sc, struct pci_devinst *pi, + int coff, int bytes, uint32_t val) +{ + uint16_t cmd_old; + + write_config(&sc->psc_sel, coff, bytes, val); + + cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND); + if (bytes == 1) + pci_set_cfgdata8(pi, coff, val); + else if (bytes == 2) + pci_set_cfgdata16(pi, coff, val); + pci_emul_cmd_changed(pi, cmd_old); + + return (0); +} + int passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi, int coff, int bytes, uint32_t val) { int error, msix_table_entries, i; - uint16_t cmd_old; /* * MSI capability is emulated @@ -1052,14 +1084,6 @@ #endif write_config(&sc->psc_sel, coff, bytes, val); - if (coff == PCIR_COMMAND) { - cmd_old = pci_get_cfgdata16(pi, PCIR_COMMAND); - if (bytes == 1) - pci_set_cfgdata8(pi, PCIR_COMMAND, val); - else if (bytes == 2) - pci_set_cfgdata16(pi, PCIR_COMMAND, val); - pci_emul_cmd_changed(pi, cmd_old); - } return (0); }