Skip to content

Commit

Permalink
bhyve: Treat the COMMAND register for PCI passthru devices as emulated
Browse files Browse the repository at this point in the history
Don't pass through writes of the command register through to the
physical device.  These registers do not need to be in sync, and in
some cases (e.g. when the guest is sizing the BAR and temporarily
disables decoding), the states need to diverge.

PR:		205549
Reviewed by:	corvink
Sponsored by:	Chelsio Communications
Differential Revision:	https://reviews.freebsd.org/D46179
  • Loading branch information
bsdjhb committed Jul 31, 2024
1 parent b4e4512 commit f44ff2a
Showing 1 changed file with 20 additions and 26 deletions.
46 changes: 20 additions & 26 deletions usr.sbin/bhyve/pci_passthru.c
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,7 @@ cfginit(struct pci_devinst *pi, int bus, int slot, int func)
{
int error;
struct passthru_softc *sc;
uint16_t cmd;
uint8_t intline, intpin;

error = 1;
Expand All @@ -618,16 +619,18 @@ cfginit(struct pci_devinst *pi, int bus, int slot, int func)
sc->psc_sel.pc_func = func;

/*
* Copy physical PCI header to virtual config space. INTLINE and INTPIN
* shouldn't be aligned with their physical value and they are already set by
* pci_emul_init().
* Copy physical PCI header to virtual config space. COMMAND,
* INTLINE, and INTPIN shouldn't be aligned with their
* physical value and they are already set by pci_emul_init().
*/
cmd = pci_get_cfgdata16(pi, PCIR_COMMAND);
intline = pci_get_cfgdata8(pi, PCIR_INTLINE);
intpin = pci_get_cfgdata8(pi, PCIR_INTPIN);
for (int i = 0; i <= PCIR_MAXLAT; i += 4) {
pci_set_cfgdata32(pi, i,
pci_host_read_config(&sc->psc_sel, i, 4));
}
pci_set_cfgdata16(pi, PCIR_COMMAND, cmd);
pci_set_cfgdata8(pi, PCIR_INTLINE, intline);
pci_set_cfgdata8(pi, PCIR_INTPIN, intpin);

Expand All @@ -643,13 +646,6 @@ cfginit(struct pci_devinst *pi, int bus, int slot, int func)
goto done;
}

pci_host_write_config(&sc->psc_sel, PCIR_COMMAND, 2,
pci_get_cfgdata16(pi, PCIR_COMMAND));

/*
* We need to do this after PCIR_COMMAND got possibly updated, e.g.,
* a BAR was enabled, as otherwise the PCIOCBARMMAP might fail on us.
*/
if (pci_msix_table_bar(pi) >= 0) {
error = init_msix_table(sc);
if (error != 0) {
Expand Down Expand Up @@ -919,7 +915,7 @@ passthru_init(struct pci_devinst *pi, nvlist_t *nvl)
passthru_cfgread_emulate, passthru_cfgwrite_emulate)) != 0)
goto done;

/* Allow access to the physical command and status register. */
/* Allow access to the physical status register. */
if ((error = set_pcir_handler(sc, PCIR_COMMAND, 0x04, NULL, NULL)) != 0)
goto done;

Expand Down Expand Up @@ -1073,28 +1069,26 @@ passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi,
return (0);
}

#ifdef LEGACY_SUPPORT
/*
* If this device does not support MSI natively then we cannot let
* the guest disable legacy interrupts from the device. It is the
* legacy interrupt that is triggering the virtual MSI to the guest.
* The command register is emulated, but the status register
* is passed through.
*/
if (sc->psc_msi.emulated && pci_msi_enabled(pi)) {
if (coff == PCIR_COMMAND && bytes == 2)
val &= ~PCIM_CMD_INTxDIS;
}
#endif

pci_host_write_config(&sc->psc_sel, coff, bytes, val);
if (coff == PCIR_COMMAND) {
if (bytes <= 2)
return (-1);

/* Update the physical status register. */
pci_host_write_config(&sc->psc_sel, PCIR_STATUS, val >> 16, 2);

/* Update the virtual command register. */
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_set_cfgdata16(pi, PCIR_COMMAND, val & 0xffff);
pci_emul_cmd_changed(pi, cmd_old);
return (0);
}

pci_host_write_config(&sc->psc_sel, coff, bytes, val);

return (0);
}

Expand Down

0 comments on commit f44ff2a

Please sign in to comment.