summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDanilo Krummrich <dakr@kernel.org>2025-06-21 21:43:32 +0200
committerDanilo Krummrich <dakr@kernel.org>2025-07-09 00:04:33 +0200
commit4be5f3fff151e49b0e7a82d33d4d12e91840abde (patch)
tree4d583812a972061439055e98f1684b7201a6a03a
parentc46f60246f9ae372ecc1f10976a8af3914b3f79e (diff)
rust: platform: implement Driver::unbind()
Currently, there's really only one core callback for drivers, which is probe(). Now, this isn't entirely true, since there is also the drop() callback of the driver type (serving as the driver's private data), which is returned by probe() and is dropped in remove(). On the C side remove() mainly serves two purposes: (1) Tear down the device that is operated by the driver, e.g. call bus specific functions, write I/O memory to reset the device, etc. (2) Free the resources that have been allocated by a driver for a specific device. The drop() callback mentioned above is intended to cover (2) as the Rust idiomatic way. However, it is partially insufficient and inefficient to cover (1) properly, since drop() can't be called with additional arguments, such as the reference to the corresponding device that has the correct device context, i.e. the Core device context. This makes it inefficient (but not impossible) to access device resources, e.g. to write device registers, and impossible to call device methods, which are only accessible under the Core device context. In order to solve this, add an additional callback for (1), which we call unbind(). The reason for calling it unbind() is that, unlike remove(), it is *only* meant to be used to perform teardown operations on the device (1), but *not* to release resources (2). Link: https://lore.kernel.org/r/20250621195118.124245-7-dakr@kernel.org Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-rw-r--r--rust/kernel/platform.rs18
1 files changed, 17 insertions, 1 deletions
diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs
index e9e95c5bb02b..ced43367d900 100644
--- a/rust/kernel/platform.rs
+++ b/rust/kernel/platform.rs
@@ -87,7 +87,9 @@ impl<T: Driver + 'static> Adapter<T> {
// 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>>`.
- let _ = unsafe { pdev.as_ref().drvdata_obtain::<Pin<KBox<T>>>() };
+ let data = unsafe { pdev.as_ref().drvdata_obtain::<Pin<KBox<T>>>() };
+
+ T::unbind(pdev, data.as_ref());
}
}
@@ -186,6 +188,20 @@ pub trait Driver: Send {
/// Implementers should attempt to initialize the device here.
fn probe(dev: &Device<device::Core>, id_info: Option<&Self::IdInfo>)
-> Result<Pin<KBox<Self>>>;
+
+ /// Platform driver unbind.
+ ///
+ /// Called when a [`Device`] is unbound from its bound [`Driver`]. Implementing this callback
+ /// is optional.
+ ///
+ /// This callback serves as a place for drivers to perform teardown operations that require a
+ /// `&Device<Core>` or `&Device<Bound>` reference. For instance, drivers may try to perform I/O
+ /// 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>) {
+ let _ = (dev, this);
+ }
}
/// The platform device representation.