Bind a GPU to `vfio-pci`, returning an RAII guard that restores it on drop. Also binds all companion devices in the same IOMMU group (e.g. the HD Audio function on consumer GPUs). All bound companions are tracked and restored when the guard is dropped.
(
sysfs: &SysfsRoot,
bdf: &str,
)
| 82 | /// function on consumer GPUs). All bound companions are tracked and restored |
| 83 | /// when the guard is dropped. |
| 84 | pub fn prepare_gpu_for_passthrough( |
| 85 | sysfs: &SysfsRoot, |
| 86 | bdf: &str, |
| 87 | ) -> Result<PciBindGuard, VfioError> { |
| 88 | validate_bdf(bdf)?; |
| 89 | |
| 90 | let device = sysfs.pci_device_ref(bdf); |
| 91 | if !device.exists() { |
| 92 | return Err(VfioError::GpuNotFound { |
| 93 | bdf: bdf.to_string(), |
| 94 | }); |
| 95 | } |
| 96 | |
| 97 | let class = device.class()?; |
| 98 | if !is_gpu_class(&class) { |
| 99 | return Err(VfioError::NotGpu { |
| 100 | bdf: bdf.to_string(), |
| 101 | class, |
| 102 | }); |
| 103 | } |
| 104 | |
| 105 | let iommu_group = device.iommu_group()?; |
| 106 | let group_devices = sysfs.iommu_group_devices(iommu_group)?; |
| 107 | let peers: Vec<String> = group_devices.into_iter().filter(|d| d != bdf).collect(); |
| 108 | |
| 109 | let mut bound_companions = Vec::new(); |
| 110 | for peer in &peers { |
| 111 | if !sysfs.pci_device_ref(peer).exists() { |
| 112 | continue; |
| 113 | } |
| 114 | match crate::bind::bind_device_to_vfio(sysfs, peer) { |
| 115 | Ok(was_bound) => { |
| 116 | if was_bound { |
| 117 | tracing::info!(bdf = %peer, iommu_group, "bound IOMMU group companion to vfio-pci"); |
| 118 | bound_companions.push(peer.clone()); |
| 119 | } |
| 120 | } |
| 121 | Err(err) => { |
| 122 | for already_bound in bound_companions.iter().rev() { |
| 123 | if let Err(restore_err) = |
| 124 | crate::bind::restore_to_host_driver(sysfs, already_bound) |
| 125 | { |
| 126 | tracing::error!(bdf = %already_bound, error = %restore_err, "failed to restore companion during rollback"); |
| 127 | } |
| 128 | } |
| 129 | return Err(VfioError::BindFailed { |
| 130 | bdf: peer.clone(), |
| 131 | reason: format!("IOMMU group {iommu_group} companion bind failed: {err}"), |
| 132 | }); |
| 133 | } |
| 134 | } |
| 135 | } |
| 136 | |
| 137 | match crate::bind::bind_device_to_vfio(sysfs, bdf) { |
| 138 | Ok(was_bound) => { |
| 139 | if was_bound { |
| 140 | tracing::info!(bdf, "GPU bound to vfio-pci"); |
| 141 | } else { |