diff --git a/usr.sbin/bhyve/pci_emul.c b/usr.sbin/bhyve/pci_emul.c index 0502cde9c053..a8fc53e0496e 100644 --- a/usr.sbin/bhyve/pci_emul.c +++ b/usr.sbin/bhyve/pci_emul.c @@ -1679,11 +1679,64 @@ pci_emul_hdrtype_fixup(int bus, int slot, int off, int bytes, uint32_t *rv) } } +/* + * Update device state in response to changes to the PCI command + * register. + */ +void +pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old) +{ + int i; + uint16_t changed, new; + + new = pci_get_cfgdata16(pi, PCIR_COMMAND); + changed = old ^ new; + + /* + * If the MMIO or I/O address space decoding has changed then + * register/unregister all BARs that decode that address space. + */ + for (i = 0; i <= PCI_BARMAX; i++) { + switch (pi->pi_bar[i].type) { + case PCIBAR_NONE: + case PCIBAR_MEMHI64: + break; + case PCIBAR_IO: + /* I/O address space decoding changed? */ + if (changed & PCIM_CMD_PORTEN) { + if (new & PCIM_CMD_PORTEN) + register_bar(pi, i); + else + unregister_bar(pi, i); + } + break; + case PCIBAR_MEM32: + case PCIBAR_MEM64: + /* MMIO address space decoding changed? */ + if (changed & PCIM_CMD_MEMEN) { + if (new & PCIM_CMD_MEMEN) + register_bar(pi, i); + else + unregister_bar(pi, i); + } + break; + default: + assert(0); + } + } + + /* + * If INTx has been unmasked and is pending, assert the + * interrupt. + */ + pci_lintr_update(pi); +} + static void pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes) { - int i, rshift; - uint32_t cmd, cmd2, changed, old, readonly; + int rshift; + uint32_t cmd, old, readonly; cmd = pci_get_cfgdata16(pi, PCIR_COMMAND); /* stash old value */ @@ -1702,47 +1755,7 @@ pci_emul_cmdsts_write(struct pci_devinst *pi, int coff, uint32_t new, int bytes) new |= (old & readonly); CFGWRITE(pi, coff, new, bytes); /* update config */ - cmd2 = pci_get_cfgdata16(pi, PCIR_COMMAND); /* get updated value */ - changed = cmd ^ cmd2; - - /* - * If the MMIO or I/O address space decoding has changed then - * register/unregister all BARs that decode that address space. - */ - for (i = 0; i <= PCI_BARMAX; i++) { - switch (pi->pi_bar[i].type) { - case PCIBAR_NONE: - case PCIBAR_MEMHI64: - break; - case PCIBAR_IO: - /* I/O address space decoding changed? */ - if (changed & PCIM_CMD_PORTEN) { - if (porten(pi)) - register_bar(pi, i); - else - unregister_bar(pi, i); - } - break; - case PCIBAR_MEM32: - case PCIBAR_MEM64: - /* MMIO address space decoding changed? */ - if (changed & PCIM_CMD_MEMEN) { - if (memen(pi)) - register_bar(pi, i); - else - unregister_bar(pi, i); - } - break; - default: - assert(0); - } - } - - /* - * If INTx has been unmasked and is pending, assert the - * interrupt. - */ - pci_lintr_update(pi); + pci_emul_cmd_changed(pi, cmd); } static void diff --git a/usr.sbin/bhyve/pci_emul.h b/usr.sbin/bhyve/pci_emul.h index 853badaadbe6..fba2e8845af8 100644 --- a/usr.sbin/bhyve/pci_emul.h +++ b/usr.sbin/bhyve/pci_emul.h @@ -223,6 +223,7 @@ int pci_emul_alloc_pbar(struct pci_devinst *pdi, int idx, uint64_t hostbase, enum pcibar_type type, uint64_t size); int pci_emul_add_msicap(struct pci_devinst *pi, int msgnum); int pci_emul_add_pciecap(struct pci_devinst *pi, int pcie_device_type); +void pci_emul_cmd_changed(struct pci_devinst *pi, uint16_t old); void pci_generate_msi(struct pci_devinst *pi, int msgnum); void pci_generate_msix(struct pci_devinst *pi, int msgnum); void pci_lintr_assert(struct pci_devinst *pi); diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c index 785da84244df..852643e9d779 100644 --- a/usr.sbin/bhyve/pci_passthru.c +++ b/usr.sbin/bhyve/pci_passthru.c @@ -639,6 +639,9 @@ cfginit(struct vmctx *ctx, struct pci_devinst *pi, int bus, int slot, int func) goto done; } + pci_set_cfgdata16(pi, PCIR_COMMAND, read_config(&sc->psc_sel, + PCIR_COMMAND, 2)); + error = 0; /* success */ done: return (error); @@ -815,6 +818,7 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, { int error, msix_table_entries, i; struct passthru_softc *sc; + uint16_t cmd_old; sc = pi->pi_arg; @@ -871,6 +875,14 @@ passthru_cfgwrite(struct vmctx *ctx, int vcpu, struct pci_devinst *pi, #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); }