[PATCH 2/4] rust: pci: add managed Device::enable_device()
From: Maurice Hieronymus
Date: Sun Jun 14 2026 - 12:01:19 EST
Add a managed counterpart to Device::enable_device_mem() that wraps
pcim_enable_device(). In addition to enabling the device, it registers a
pci_disable_device() cleanup that runs automatically when the device is
unbound from its driver, keeping the device's enable count balanced
across unbind/rebind cycles.
The existing enable_device_mem() wraps the unmanaged
pci_enable_device_mem() and has no disable counterpart, so the enable
count is leaked on unbind. On the next probe pci_enable_device_flags()
sees a non-zero enable count and returns early, skipping the power-state
transition back to D0. For a device without a PCI power management
capability the power state cannot be re-read from hardware and stays
PCI_UNKNOWN, which makes __pci_enable_msi_range() reject the subsequent
MSI allocation with -EINVAL.
Signed-off-by: Maurice Hieronymus <mhi@xxxxxxxxxxx>
---
rust/kernel/pci.rs | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index af74ddff6114..ca04548c82c3 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -452,6 +452,22 @@ pub fn enable_device_mem(&self) -> Result {
to_result(unsafe { bindings::pci_enable_device_mem(self.as_raw()) })
}
+ /// Enable I/O and memory resources for this device, with automatic cleanup.
+ ///
+ /// This is the managed version of `pci_enable_device()`: it enables the device's I/O and
+ /// memory resources and registers a `pci_disable_device()` call that runs automatically
+ /// when the device is unbound from its driver. In contrast, [`Device::enable_device_mem`]
+ /// is unmanaged and only enables memory resources.
+ ///
+ /// The automatic cleanup keeps the device's enable count balanced across driver
+ /// unbind/rebind cycles. With an unbalanced (leaked) enable count, a re-probe skips the
+ /// power-state transition back to `D0`, which makes subsequent MSI allocation fail with
+ /// `EINVAL`.
+ pub fn enable_device(&self) -> Result {
+ // SAFETY: `self.as_raw` is guaranteed to be a pointer to a valid `struct pci_dev`.
+ to_result(unsafe { bindings::pcim_enable_device(self.as_raw()) })
+ }
+
/// Enable bus-mastering for this device.
#[inline]
pub fn set_master(&self) {
--
2.51.2