[PATCH 1/7] rust: pci: pass driver data by value to `unbind`

Alexandre Courbot
2025-12-16T05:13:45Z

When unbinding a PCI driver, the `T::unbind` callback is invoked by the
driver framework, passing the driver data as a `Pin<&T>`.

This artificially restricts what the driver can do, as it cannot mutate
any state on the data. This becomes a problem in e.g. Nova, which needs
to invoke mutable methods when unbinding.

`remove_callback` retrieves the driver data by value, and drops it right
after the call to `T::unbind`, meaning it is the only reference to the
driver data by the time `T::unbind` is called.

There is thus no reason for not granting full ownership of the data to
`T::unbind`, so do it. This allows the driver mutate the state of its
data while unbinding, and also makes the API more symmetric as the
framework grants back to the driver the data it created in the first
place.

Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpu/nova-core/driver.rs | 2 +-
rust/kernel/pci.rs | 4 ++--
samples/rust/rust_driver_pci.rs | 2 +-
3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/nova-core/driver.rs b/drivers/gpu/nova-core/driver.rs
index b8b0cc0f2d93..b0e3e41ae9d8 100644
--- a/drivers/gpu/nova-core/driver.rs
+++ b/drivers/gpu/nova-core/driver.rs
@@ -98,7 +98,7 @@ fn probe(pdev: &pci::Device<Core>, _info: &Self::IdInfo) -> impl PinInit<Self, E
})
}

- fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
+ fn unbind(pdev: &pci::Device<Core>, this: Pin<KBox<Self>>) {
this.gpu.unbind(pdev.as_ref());
}
}
diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs
index 82e128431f08..39e70adde484 100644
--- a/rust/kernel/pci.rs
+++ b/rust/kernel/pci.rs
@@ -116,7 +116,7 @@ extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) {
// and stored a `Pin<KBox<T>>`.
let data = unsafe { pdev.as_ref().drvdata_obtain::<T>() };

- T::unbind(pdev, data.as_ref());
+ T::unbind(pdev, data);
}
}

@@ -303,7 +303,7 @@ pub trait Driver: Send {
/// operations to gracefully tear down the device.
///
/// Otherwise, release operations for driver resources should be performed in `Self::drop`.
- fn unbind(dev: &Device<device::Core>, this: Pin<&Self>) {
+ fn unbind(dev: &Device<device::Core>, this: Pin<KBox<Self>>) {
let _ = (dev, this);
}
}
diff --git a/samples/rust/rust_driver_pci.rs b/samples/rust/rust_driver_pci.rs
index 5823787bea8e..ee8fc8d48ff3 100644
--- a/samples/rust/rust_driver_pci.rs
+++ b/samples/rust/rust_driver_pci.rs
@@ -95,7 +95,7 @@ fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> impl PinInit<Self, Er
})
}

- fn unbind(pdev: &pci::Device<Core>, this: Pin<&Self>) {
+ fn unbind(pdev: &pci::Device<Core>, this: Pin<KBox<Self>>) {
if let Ok(bar) = this.bar.access(pdev.as_ref()) {
// Reset pci-testdev by writing a new test index.
bar.write8(this.index.0, Regs::TEST);

--
2.52.0