Bind a single PCI device to `vfio-pci`. Skips devices already bound.
(sysfs: &SysfsRoot, bdf: &str)
| 139 | |
| 140 | /// Bind a single PCI device to `vfio-pci`. Skips devices already bound. |
| 141 | pub(crate) fn bind_device_to_vfio(sysfs: &SysfsRoot, bdf: &str) -> Result<bool, VfioError> { |
| 142 | if let Some(drv) = current_driver_name(sysfs, bdf) { |
| 143 | if drv == "vfio-pci" { |
| 144 | return Ok(false); |
| 145 | } |
| 146 | let unbind_path = sysfs.pci_device_ref(bdf).driver_unbind_path(); |
| 147 | write_sysfs(&unbind_path, bdf).map_err(|e| VfioError::BindFailed { |
| 148 | bdf: bdf.to_string(), |
| 149 | reason: format!("unbind from {drv}: {e}"), |
| 150 | })?; |
| 151 | tracing::info!(bdf, driver = %drv, "unbound device from current driver"); |
| 152 | } |
| 153 | |
| 154 | register_vfio_new_id(sysfs, bdf); |
| 155 | |
| 156 | let override_path = sysfs.pci_device_ref(bdf).driver_override_path(); |
| 157 | if let Err(e) = write_sysfs(&override_path, "vfio-pci") { |
| 158 | deregister_vfio_new_id(sysfs, bdf); |
| 159 | return Err(VfioError::BindFailed { |
| 160 | bdf: bdf.to_string(), |
| 161 | reason: format!("driver_override: {e}"), |
| 162 | }); |
| 163 | } |
| 164 | |
| 165 | if let Err(e) = write_sysfs(&sysfs.drivers_probe(), bdf) { |
| 166 | deregister_vfio_new_id(sysfs, bdf); |
| 167 | cleanup_partial_bind(sysfs, bdf); |
| 168 | return Err(VfioError::BindFailed { |
| 169 | bdf: bdf.to_string(), |
| 170 | reason: format!("drivers_probe: {e}"), |
| 171 | }); |
| 172 | } |
| 173 | |
| 174 | if matches!(current_driver_name(sysfs, bdf).as_deref(), Some("vfio-pci")) { |
| 175 | return Ok(true); |
| 176 | } |
| 177 | |
| 178 | // The kernel processes drivers_probe asynchronously on some systems; poll |
| 179 | // briefly to let the driver attach before declaring failure. |
| 180 | for _ in 0..VFIO_BIND_MAX_POLL_ATTEMPTS { |
| 181 | std::thread::sleep(VFIO_BIND_POLL_INTERVAL); |
| 182 | if matches!(current_driver_name(sysfs, bdf).as_deref(), Some("vfio-pci")) { |
| 183 | tracing::debug!(bdf, "vfio-pci binding confirmed after polling"); |
| 184 | return Ok(true); |
| 185 | } |
| 186 | } |
| 187 | |
| 188 | deregister_vfio_new_id(sysfs, bdf); |
| 189 | cleanup_partial_bind(sysfs, bdf); |
| 190 | Err(VfioError::BindFailed { |
| 191 | bdf: bdf.to_string(), |
| 192 | reason: format!( |
| 193 | "after drivers_probe with {}ms polling, driver is {:?} instead of vfio-pci", |
| 194 | u64::from(VFIO_BIND_MAX_POLL_ATTEMPTS) |
| 195 | * u64::try_from(VFIO_BIND_POLL_INTERVAL.as_millis()).unwrap_or(u64::MAX), |
| 196 | current_driver_name(sysfs, bdf) |
| 197 | .as_deref() |
| 198 | .unwrap_or("<none>") |