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.
Set the flag managed_sriov to always disable SR-IOV when a Rust PCI driver is unbound from a PF device. 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 <[email protected]> Signed-off-by: Peter Colberg <[email protected]> --- Changes in v2: - Set flag managed_sriov to disable SR-IOV on remove(). - Use to_result() to handle error in enable_sriov(). - Note Bound device context in SAFETY comments. --- rust/kernel/pci.rs | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index af74ddff6114db3c2ce8e228c5a953cd0769e8a5..e1cab1574a3d309d25bf5267c0b0d8da8fb66d44 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -82,6 +82,7 @@ unsafe fn register( (*pdrv.get()).probe = Some(Self::probe_callback); (*pdrv.get()).remove = Some(Self::remove_callback); (*pdrv.get()).id_table = T::ID_TABLE.as_ptr(); + (*pdrv.get()).managed_sriov = true; } // SAFETY: `pdrv` is guaranteed to be a valid `DriverType`. @@ -458,6 +459,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.52.0
