git: 3b90096cf9bc - main - bhyve: Keep passthrough PCI power state virtual
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Thu, 20 Aug 2026 22:14:43 UTC
The branch main has been updated by kbowling:
URL: https://cgit.FreeBSD.org/src/commit/?id=3b90096cf9bcaec70b717e9ff0a9e23d14b600b6
commit 3b90096cf9bcaec70b717e9ff0a9e23d14b600b6
Author: Kevin Bowling <kbowling@FreeBSD.org>
AuthorDate: 2026-08-17 17:09:23 +0000
Commit: Kevin Bowling <kbowling@FreeBSD.org>
CommitDate: 2026-08-20 22:13:36 +0000
bhyve: Keep passthrough PCI power state virtual
The passthrough Command register is emulated, but PMCSR writes were
sent directly to the physical function. A guest D3hot-to-D0 transition
can perform an internal reset and clear physical Command while its
emulated copy remains enabled.
Cache the Power Management capability and keep the physical D-state
host-owned. Emulate the guest D-state and advertise No_Soft_Reset so
the guest is not promised a function reset by a virtual power cycle.
Restore the assignment-time virtual state after a managed FLR.
Reviewed by: markj
MFC after: 2 weeks
Sponsored by: BBOX.io
---
usr.sbin/bhyve/pci_passthru.c | 53 +++++++++++++++++++++++++++++++++++++++++--
1 file changed, 51 insertions(+), 2 deletions(-)
diff --git a/usr.sbin/bhyve/pci_passthru.c b/usr.sbin/bhyve/pci_passthru.c
index a78ca06c9d83..24d96764964d 100644
--- a/usr.sbin/bhyve/pci_passthru.c
+++ b/usr.sbin/bhyve/pci_passthru.c
@@ -100,6 +100,11 @@ struct passthru_softc {
struct {
int capoff;
} psc_msix;
+ struct {
+ int capoff;
+ uint16_t pmcsr;
+ uint16_t reset_pmcsr;
+ } psc_pm;
struct {
int capoff;
uint16_t devctl;
@@ -331,6 +336,8 @@ cfginitcaps(struct passthru_softc *sc)
capptr += 4;
msixcap_ptr += 4;
}
+ } else if (cap == PCIY_PMG) {
+ sc->psc_pm.capoff = ptr;
} else if (cap == PCIY_EXPRESS) {
sc->psc_pcie.capoff = ptr;
}
@@ -338,6 +345,13 @@ cfginitcaps(struct passthru_softc *sc)
1);
}
}
+ if (sc->psc_pm.capoff != 0) {
+ sc->psc_pm.pmcsr = passthru_read_config(&sel,
+ sc->psc_pm.capoff + PCIR_POWER_STATUS, 2);
+ /* The physical function remains in its host-owned power state. */
+ sc->psc_pm.pmcsr |= PCIM_PSTAT_NOSOFTRESET;
+ sc->psc_pm.reset_pmcsr = sc->psc_pm.pmcsr;
+ }
if (sc->psc_pcie.capoff != 0) {
sc->psc_pcie.devctl = passthru_read_config(&sel,
sc->psc_pcie.capoff + PCIER_DEVICE_CTL, 2);
@@ -1120,6 +1134,8 @@ msixcap_access(struct passthru_softc *sc, int coff)
#define PASSTHRU_DEVCTL_NO_WRITE PCIEM_CTL_PHANTHOM_FUNCS
#define PASSTHRU_DEVCTL2_VIRT (PCIEM_CTL2_COMP_TIMO_VAL | \
PCIEM_CTL2_COMP_TIMO_DISABLE)
+#define PASSTHRU_PMCSR_VIRT (PCIM_PSTAT_DMASK | \
+ PCIM_PSTAT_NOSOFTRESET)
static uint32_t
passthru_cfg_field_mask(int coff, int bytes, int fieldoff, uint16_t mask)
@@ -1243,6 +1259,8 @@ passthru_reset_capability_state(struct passthru_softc *sc)
(sc->psc_pcie.reset_devctl & ~PCIEM_CTL_MAX_PAYLOAD) | guest_mps;
if (sc->psc_pcie.has_devctl2)
sc->psc_pcie.devctl2 = sc->psc_pcie.reset_devctl2;
+ if (sc->psc_pm.capoff != 0)
+ sc->psc_pm.pmcsr = sc->psc_pm.reset_pmcsr;
}
static int
@@ -1320,6 +1338,13 @@ passthru_cfgread_default(struct passthru_softc *sc,
/* Everything else just read from the device's config space. */
*rv = passthru_read_config(&sc->psc_sel, coff, bytes);
+ if (sc->psc_pm.capoff != 0) {
+ int pmcsr;
+
+ pmcsr = sc->psc_pm.capoff + PCIR_POWER_STATUS;
+ *rv = passthru_cfg_overlay_field(coff, bytes, *rv, pmcsr,
+ sc->psc_pm.pmcsr, PASSTHRU_PMCSR_VIRT);
+ }
if (sc->psc_pcie.capoff != 0) {
int devctl;
@@ -1362,8 +1387,8 @@ passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi,
int coff, int bytes, uint32_t val)
{
uint32_t flr_mask, transport_mask;
- uint16_t physical_devctl;
- int devctl, devctl2, host_mps, guest_mrrs;
+ uint16_t physical_devctl, physical_pmcsr;
+ int devctl, devctl2, host_mps, guest_mrrs, pmcsr;
int error, msix_table_entries, i;
uint16_t cmd_old;
@@ -1408,6 +1433,30 @@ passthru_cfgwrite_default(struct passthru_softc *sc, struct pci_devinst *pi,
return (0);
}
+ /*
+ * A physical D3hot-to-D0 transition may reset the function and clear
+ * Command behind bhyve's emulated copy. Keep the physical D-state
+ * host-owned, emulate the guest D-state, and advertise No_Soft_Reset so
+ * the guest does not rely on this cycle as a function reset.
+ */
+ pmcsr = sc->psc_pm.capoff + PCIR_POWER_STATUS;
+ if (sc->psc_pm.capoff != 0 && coff < pmcsr + 2 &&
+ coff + bytes > pmcsr) {
+ physical_pmcsr = passthru_read_config(&sc->psc_sel, pmcsr, 2);
+ if (physical_pmcsr == 0xffff) {
+ warnx("configuration space unavailable for passthru "
+ "device %d/%d/%d", sc->psc_sel.pc_bus,
+ sc->psc_sel.pc_dev, sc->psc_sel.pc_func);
+ return (0);
+ }
+ passthru_cfg_update_field(coff, bytes, val, pmcsr,
+ PCIM_PSTAT_DMASK, &sc->psc_pm.pmcsr);
+ val = passthru_cfg_overlay_field(coff, bytes, val, pmcsr,
+ physical_pmcsr, PASSTHRU_PMCSR_VIRT);
+ passthru_write_config(&sc->psc_sel, coff, bytes, val);
+ return (0);
+ }
+
/*
* A direct FLR would clear physical Command while the guest sees its
* emulated copy remain enabled. Route FLR through ppt so it restores