[PATCH v4 2/7] rust: pci: rework device enabling API

From: Maurice Hieronymus

Date: Wed Nov 04 2026 - 19:14:50 EST


`enable_device_mem()` wraps the unmanaged `pci_enable_device_mem()` and
has no disable counterpart, so the enable count is leaked on driver
unbind and the device does not come back up on a subsequent probe.

Replace it with `enable_device()`, which wraps `pci_enable_device()`
and returns a `DeviceEnableGuard<'a>`: dropping the guard runs
`pci_disable_device()`. The guard borrows the device's bound scope
(`&'a Device<Bound>`), so it cannot outlive the driver binding, and
since it is the only way to enable the device from safe code, the
enable count always stays balanced.

Obtaining the guard still requires a `&Device<Core>`, i.e. a bus
callback. Unlike `pci_enable_device_mem()`, `pci_enable_device()`
enables I/O and memory resources.

Convert nova-core, the only user of `enable_device_mem()`, storing the
guard as the last field of `NovaCore` so the device is disabled only
after the GPU teardown.

Link: https://lore.kernel.org/rust-for-linux/DJOEYVBS17MJ.1YD3TNGQBWHNK@xxxxxxxxxx
Suggested-by: Danilo Krummrich <dakr@xxxxxxxxxx>
Signed-off-by: Maurice Hieronymus <mhi@xxxxxxxxxxx>
---
drivers/gpu/nova-core/driver.rs | 7 +++++--
rust/kernel/pci.rs | 33 ++++++++++++++++++++++++++++++---
2 files changed, 35 insertions(+), 5 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index 560a70c4f5a7..f0aebfe705ba 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -38,6 +38,8 @@ pub(crate) struct NovaCore<'bound> {
pub(crate) gpu: Gpu<'bound>,
bar: pci::Bar<'bound, BAR0_SIZE>,
bar1: pci::Bar<'bound>,
+ // Declared last so the device stays enabled until everything above is torn down.
+ _enable: pci::DeviceEnableGuard<'bound>,
}

pub(crate) struct NovaCoreDriver;
@@ -103,9 +105,10 @@ fn probe<'bound>(
dev_dbg!(pdev, "Probe Nova Core GPU driver.\n");

try_pin_init!(NovaCore {
- _: {
- pdev.enable_device_mem()?;
+ _enable: {
+ let enable = pdev.enable_device()?;
pdev.set_master();
+ enable
},

bar: pdev.iomap_region_sized::<BAR0_SIZE>(0, c"nova-core/bar0")?,
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 769d01d23429..75efd5c5ee97 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -469,6 +469,25 @@ pub fn pci_class(&self) -> Class {
}
}

+/// A guard that keeps the device's I/O and memory resources enabled.
+///
+/// # Invariants
+///
+/// The device's enable count was incremented once for this guard; dropping the guard decrements
+/// it again.
+#[must_use = "if unused, the device will be immediately disabled"]
+pub struct DeviceEnableGuard<'a> {
+ dev: &'a Device<device::Bound>,
+}
+
+impl Drop for DeviceEnableGuard<'_> {
+ fn drop(&mut self) {
+ // SAFETY: `self.dev.as_raw()` is a valid pointer to a `struct pci_dev`, and by the type
+ // invariant this guard holds one increment of the device's enable count.
+ unsafe { bindings::pci_disable_device(self.dev.as_raw()) };
+ }
+}
+
impl<'a> Device<device::Core<'a>> {
/// Returns the total number of VFs, or [`None`] if SR-IOV is not available.
#[inline]
@@ -482,10 +501,18 @@ pub fn sriov_get_totalvfs(&self) -> Option<NonZero<u16>> {
NonZero::new(total_vfs as u16)
}

- /// Enable memory resources for this device.
- pub fn enable_device_mem(&self) -> Result {
+ /// Enable I/O and memory resources for this device.
+ ///
+ /// The device stays enabled for the lifetime of the returned guard; dropping the guard
+ /// disables the device again. The guard borrows the device's bound scope, so it cannot
+ /// outlive the driver binding.
+ #[inline]
+ pub fn enable_device(&self) -> Result<DeviceEnableGuard<'_>> {
// SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
- to_result(unsafe { bindings::pci_enable_device_mem(self.as_raw()) })
+ to_result(unsafe { bindings::pci_enable_device(self.as_raw()) })?;
+
+ // INVARIANT: `pci_enable_device()` succeeded, so the enable count was incremented once.
+ Ok(DeviceEnableGuard { dev: self })
}

/// Enable bus-mastering for this device.

--
2.54.0