[PATCH v2 1/8] rust: pci: add {enable,disable}_sriov(), to control SR-IOV capability

From: Zhi Wang

Date: Thu Sep 24 2026 - 15:07:45 EST


From: Peter Colberg <pcolberg@xxxxxxxxxx>

Add methods to enable and disable the Single Root I/O Virtualization
(SR-IOV) capability for a PCI device. The wrapped C methods take care
of validating whether the device is a Physical Function (PF), whether
SR-IOV is currently disabled (or enabled), and whether the number of
requested VFs does not exceed the total number of supported VFs.

Synchronously disable SR-IOV in the Rust PCI remove callback before
unbinding the PF driver. This ensures that when a Virtual
Function (VF) is bound to a driver, the corresponding Physical Function
(PF) is bound to a driver, too, which is a prerequisite for exposing a
safe Rust API that allows a VF driver to obtain the PF device for a VF
device and subsequently access the private data of the PF driver.

Suggested-by: Danilo Krummrich <dakr@xxxxxxxxxx>
Signed-off-by: Peter Colberg <pcolberg@xxxxxxxxxx>
Signed-off-by: Zhi Wang <zhiw@xxxxxxxxxx>
---
rust/kernel/pci.rs | 36 ++++++++++++++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 3ec897709e89..e6dac919f02d 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -133,6 +133,10 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
// INVARIANT: `pdev` is valid for the duration of `remove_callback()`.
let pdev = unsafe { &*pdev.cast::<Device<device::CoreInternal<'_>>>() };

+ // Keep PF data installed until all VF remove callbacks have completed.
+ #[cfg(CONFIG_PCI_IOV)]
+ pdev.disable_sriov();
+
// SAFETY: `remove_callback` is only ever called after a successful call to
// `probe_callback`, hence it's guaranteed that `Device::set_drvdata()` has been called
// and stored a `Pin<KBox<T::Data<'_>>>`.
@@ -472,6 +476,38 @@ pub fn set_master(&self) {
// SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
unsafe { bindings::pci_set_master(self.as_raw()) };
}
+
+ /// Enable the Single Root I/O Virtualization (SR-IOV) capability for this device,
+ /// where `nr_virtfn` is number of Virtual Functions (VF) to enable.
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn enable_sriov(&self, nr_virtfn: i32) -> Result {
+ // SAFETY:
+ // `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ //
+ // `pci_enable_sriov()` checks that the enable operation is valid:
+ // - the device is a Physical Function (PF),
+ // - SR-IOV is currently disabled, and
+ // - `nr_virtfn` does not exceed the total number of supported VFs.
+ //
+ // The Core device context inherits from the Bound device context,
+ // which guarantees that the PF device is bound to a driver.
+ to_result(unsafe { bindings::pci_enable_sriov(self.as_raw(), nr_virtfn) })
+ }
+
+ /// Disable the Single Root I/O Virtualization (SR-IOV) capability for this device.
+ #[cfg(CONFIG_PCI_IOV)]
+ pub fn disable_sriov(&self) {
+ // SAFETY:
+ // `self.as_raw` returns a valid pointer to a `struct pci_dev`.
+ //
+ // `pci_disable_sriov()` checks that the disable operation is valid:
+ // - the device is a Physical Function (PF), and
+ // - SR-IOV is currently enabled.
+ //
+ // The Core device context inherits from the Bound device context,
+ // which guarantees that the PF device is bound to a driver.
+ unsafe { bindings::pci_disable_sriov(self.as_raw()) };
+ }
}

// SAFETY: `pci::Device` is a transparent wrapper of `struct pci_dev`.
--
2.53.0