diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs index 30b8f215e0..123067ea67 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/inner.rs @@ -632,6 +632,25 @@ impl QemuInner { return Ok(DeviceType::Block(block_device)); } + DeviceType::Vfio(mut vfiodev) => { + // FIXME: the first one might not the true device we want to passthrough. + // The `multifunction=on` is temporarily unsupported. + // Tracking issue #11292 has been created to monitor progress towards full multifunction support. + let primary_device = vfiodev.devices.first_mut().unwrap(); + info!( + sl!(), + "qmp hotplug vfio primary_device {:?}", &primary_device + ); + + primary_device.guest_pci_path = qmp.hotplug_vfio_device( + &primary_device.hostdev_id, + &primary_device.bus_slot_func, + &vfiodev.driver_type, + &vfiodev.bus, + )?; + + return Ok(DeviceType::Vfio(vfiodev)); + } _ => info!(sl!(), "hotplugging of {:#?} is unsupported", device), } Ok(device) diff --git a/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs index 8b823d8161..10dcd57a7e 100644 --- a/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs +++ b/src/runtime-rs/crates/hypervisor/src/qemu/qmp.rs @@ -596,6 +596,42 @@ impl Qmp { Ok(Some(pci_path)) } + + pub fn hotplug_vfio_device( + &mut self, + hostdev_id: &str, + bus_slot_func: &str, + driver: &str, + bus: &str, + ) -> Result> { + let mut vfio_args = Dictionary::new(); + let bdf = if !bus_slot_func.starts_with("0000") { + format!("0000:{}", bus_slot_func) + } else { + bus_slot_func.to_owned() + }; + vfio_args.insert("addr".to_owned(), "0x0".into()); + vfio_args.insert("host".to_owned(), bdf.into()); + vfio_args.insert("multifunction".to_owned(), "off".into()); + + let vfio_device_add = qmp::device_add { + driver: driver.to_string(), + bus: Some(bus.to_string()), + id: Some(hostdev_id.to_string()), + arguments: vfio_args, + }; + info!(sl!(), "vfio_device_add: {:?}", vfio_device_add.clone()); + + self.qmp + .execute(&vfio_device_add) + .map_err(|e| anyhow!("device_add vfio device failed {:?}", e))?; + + let pci_path = self + .get_device_by_qdev_id(hostdev_id) + .context("get device by qdev_id failed")?; + + Ok(Some(pci_path)) + } } fn vcpu_id_from_core_id(core_id: i64) -> String {