The branch main has been updated by corvink: URL: https://cgit.FreeBSD.org/src/commit/?id=1bc515184d875964c95c7732738fd8d8ae0511cb
commit 1bc515184d875964c95c7732738fd8d8ae0511cb Author: Corvin Köhne <corv...@freebsd.org> AuthorDate: 2025-06-12 07:56:57 +0000 Commit: Corvin Köhne <corv...@freebsd.org> CommitDate: 2025-08-05 13:49:28 +0000 bhyve: scan PCI device ID to properly set BDSM address The address and size of the BDSM register has changed in recent Intel GPUs. To account for that change, we have to detect the GPU generation. We've recently added all known PCI IDs of Intel GPUs from Linux. Make use of this header to scan the device ID and properly set the BDSM address. Note that even though a bunch of devices is listed in our device array, not all device will work properly. Especially some old devices may not support VT-d, required for passthrough in general, at all. Reviewed by: jhb MFC after: 1 week Sponsored by: Beckhoff Automation GmbH & Co. KG Differential Revision: https://reviews.freebsd.org/D50807 --- usr.sbin/bhyve/amd64/pci_gvt-d.c | 98 +++++++++++++++++++++++++++++++++++++--- 1 file changed, 92 insertions(+), 6 deletions(-) diff --git a/usr.sbin/bhyve/amd64/pci_gvt-d.c b/usr.sbin/bhyve/amd64/pci_gvt-d.c index 60bf460d71ed..e506b75e77fe 100644 --- a/usr.sbin/bhyve/amd64/pci_gvt-d.c +++ b/usr.sbin/bhyve/amd64/pci_gvt-d.c @@ -20,6 +20,7 @@ #include "amd64/e820.h" #include "pci_gvt-d-opregion.h" #include "pci_passthru.h" +#include "pciids_intel_gpus.h" #define KB (1024UL) #define MB (1024 * KB) @@ -41,6 +42,89 @@ #define GVT_D_MAP_OPREGION 1 #define GVT_D_MAP_VBT 2 +static int +set_bdsm_gen3(struct pci_devinst *const pi, vm_paddr_t bdsm_gpa) +{ + struct passthru_softc *sc = pi->pi_arg; + uint32_t bdsm; + int error; + + bdsm = pci_host_read_config(passthru_get_sel(sc), PCIR_BDSM, 4); + + /* Protect the BDSM register in PCI space. */ + pci_set_cfgdata32(pi, PCIR_BDSM, + bdsm_gpa | (bdsm & (PCIM_BDSM_GSM_ALIGNMENT - 1))); + error = set_pcir_handler(sc, PCIR_BDSM, 4, passthru_cfgread_emulate, + passthru_cfgwrite_emulate); + if (error) { + warnx("%s: Failed to setup handler for BDSM register!", __func__); + return (error); + } + + return (0); +} + +struct igd_ops { + int (*set_bdsm)(struct pci_devinst *const pi, vm_paddr_t bdsm_gpa); +}; + +static const struct igd_ops igd_ops_gen3 = { .set_bdsm = set_bdsm_gen3 }; + +struct igd_device { + uint32_t device_id; + const struct igd_ops *ops; +}; + +#define IGD_DEVICE(_device_id, _ops) \ + { \ + .device_id = (_device_id), \ + .ops = (_ops), \ + } + +static const struct igd_device igd_devices[] = { + INTEL_I915G_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_I915GM_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_I945G_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_I945GM_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_VLV_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_PNV_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_I965GM_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_GM45_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_G45_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_ILK_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_SNB_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_IVB_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_HSW_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_BDW_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_CHV_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_SKL_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_BXT_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_KBL_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_CFL_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_WHL_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_CML_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_GLK_IDS(IGD_DEVICE, &igd_ops_gen3), + INTEL_CNL_IDS(IGD_DEVICE, &igd_ops_gen3), +}; + +static const struct igd_ops * +get_igd_ops(struct pci_devinst *const pi) +{ + struct passthru_softc *sc = pi->pi_arg; + uint16_t device_id; + + device_id = pci_host_read_config(passthru_get_sel(sc), PCIR_DEVICE, + 0x02); + for (size_t i = 0; i < nitems(igd_devices); i++) { + if (igd_devices[i].device_id != device_id) + continue; + + return (igd_devices[i].ops); + } + + return (NULL); +} + static int gvt_d_probe(struct pci_devinst *const pi) { @@ -108,8 +192,8 @@ gvt_d_setup_gsm(struct pci_devinst *const pi) { struct passthru_softc *sc; struct passthru_mmio_mapping *gsm; + const struct igd_ops *igd_ops; size_t sysctl_len; - uint32_t bdsm; int error; sc = pi->pi_arg; @@ -170,12 +254,14 @@ gvt_d_setup_gsm(struct pci_devinst *const pi) "Warning: Unable to reuse host address of Graphics Stolen Memory. GPU passthrough might not work properly."); } - bdsm = pci_host_read_config(passthru_get_sel(sc), PCIR_BDSM, 4); - pci_set_cfgdata32(pi, PCIR_BDSM, - gsm->gpa | (bdsm & (PCIM_BDSM_GSM_ALIGNMENT - 1))); + igd_ops = get_igd_ops(pi); + if (igd_ops == NULL) { + warn("%s: Unknown IGD device. It's not supported yet!", + __func__); + return (-1); + } - return (set_pcir_handler(sc, PCIR_BDSM, 4, passthru_cfgread_emulate, - passthru_cfgwrite_emulate)); + return (igd_ops->set_bdsm(pi, gsm->gpa)); } static int