The branch main has been updated by jhb:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=f44ff2aba2d64d1d9312cb55008dc90275ccdc04

commit f44ff2aba2d64d1d9312cb55008dc90275ccdc04
Author:     John Baldwin <j...@freebsd.org>
AuthorDate: 2024-07-31 14:50:33 +0000
Commit:     John Baldwin <j...@freebsd.org>
CommitDate: 2024-07-31 14:50:33 +0000

    bhyve: Treat the COMMAND register for PCI passthru devices as emulated
    
    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
---
 usr.sbin/bhyve/pci_passthru.c | 46 +++++++++++++++++++------------------------
 1 file changed, 20 insertions(+), 26 deletions(-)

diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
index 13d422eaa59c..b8ac782bd7be 100644
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -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;
@@ -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);
 
@@ -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) {
@@ -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;
 
@@ -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);
 }
 

Reply via email to