summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Hindborg <a.hindborg@samsung.com>2023-09-04 13:27:31 +0200
committerDanilo Krummrich <dakr@redhat.com>2023-11-22 22:01:11 +0100
commit4f54e936ee9e784db8b82dff7169230de55e4231 (patch)
treeaf9a25c53843b3cfe309ca28793a7aa0fa10db68
parent4f3fb034dc1b1c599fa9a86d99dc4810bafa7c4a (diff)
rust: add device::Data
Based on https://github.com/Rust-for-Linux/linux/commit/9d7d4827356cc4c17e1e546175204b12f1becff9
-rw-r--r--rust/kernel/device.rs124
1 files changed, 122 insertions, 2 deletions
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index b591afd3d7be..b342d623ba88 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -5,8 +5,25 @@
//!
//! C header: [`include/linux/device.h`](../../../../include/linux/device.h)
-use crate::{bindings, error::code::*, error::Error, error::Result, str::CStr};
-use core::fmt;
+use macros::pin_data;
+
+use crate::{
+ bindings,
+ error::code::*,
+ error::Error,
+ error::Result,
+ init::InPlaceInit,
+ init::PinInit,
+ pin_init,
+ revocable::{Revocable, RevocableGuard},
+ str::CStr,
+ sync::{LockClassKey, RevocableMutex, UniqueArc},
+};
+use core::{
+ fmt,
+ ops::{Deref, DerefMut},
+ pin::Pin,
+};
/// A raw device.
///
@@ -257,3 +274,106 @@ impl Clone for Device {
Self::from_dev(self)
}
}
+
+/// Device data.
+///
+/// When a device is removed (for whatever reason, for example, because the device was unplugged or
+/// because the user decided to unbind the driver), the driver is given a chance to clean its state
+/// up, and all io resources should ideally not be used anymore.
+///
+/// However, the device data is reference-counted because other subsystems hold pointers to it. So
+/// some device state must be freed and not used anymore, while others must remain accessible.
+///
+/// This struct separates the device data into three categories:
+/// 1. Registrations: are destroyed when the device is removed, but before the io resources
+/// become inaccessible.
+/// 2. Io resources: are available until the device is removed.
+/// 3. General data: remain available as long as the ref count is nonzero.
+///
+/// This struct implements the `DeviceRemoval` trait so that it can clean resources up even if not
+/// explicitly called by the device drivers.
+#[pin_data]
+pub struct Data<T, U, V> {
+ #[pin]
+ registrations: RevocableMutex<T>,
+ #[pin]
+ resources: Revocable<U>,
+ #[pin]
+ general: V,
+}
+
+/// Safely creates an new reference-counted instance of [`Data`].
+#[doc(hidden)]
+#[macro_export]
+macro_rules! new_device_data {
+ ($reg:expr, $res:expr, $gen:expr, $name:literal) => {{
+ static CLASS1: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+ let regs = $reg;
+ let res = $res;
+ let gen = $gen;
+ let name = $crate::c_str!($name);
+ $crate::device::Data::try_new(regs, res, gen, name, &CLASS1)
+ }};
+}
+
+impl<T, U, V> Data<T, U, V> {
+ /// Creates a new instance of `Data`.
+ ///
+ /// It is recommended that the [`new_device_data`] macro be used as it automatically creates
+ /// the lock classes.
+ pub fn try_new(
+ registrations: T,
+ resources: impl PinInit<U>,
+ general: impl PinInit<V>,
+ name: &'static CStr,
+ key1: &'static LockClassKey,
+ ) -> Result<Pin<UniqueArc<Self>>> {
+ let mut ret = UniqueArc::pin_init(pin_init!(Self {
+ registrations <- RevocableMutex::new(
+ registrations,
+ name,
+ key1,
+ ),
+ resources <- Revocable::new(resources),
+ general <- general,
+ }))?;
+
+ Ok(ret)
+ }
+
+ /// Returns the resources if they're still available.
+ pub fn resources(&self) -> Option<RevocableGuard<'_, U>> {
+ self.resources.try_access()
+ }
+
+ /// Returns the locked registrations if they're still available.
+ #[cfg(disabled)]
+ pub fn registrations(&self) -> Option<RevocableMutexGuard<'_, T>> {
+ self.registrations.try_write()
+ }
+}
+
+impl<T, U, V> crate::driver::DeviceRemoval for Data<T, U, V> {
+ fn device_remove(&self) {
+ // We revoke the registrations first so that resources are still available to them during
+ // unregistration.
+ self.registrations.revoke();
+
+ // Release resources now. General data remains available.
+ self.resources.revoke();
+ }
+}
+
+impl<T, U, V> Deref for Data<T, U, V> {
+ type Target = V;
+
+ fn deref(&self) -> &V {
+ &self.general
+ }
+}
+
+impl<T, U, V> DerefMut for Data<T, U, V> {
+ fn deref_mut(&mut self) -> &mut V {
+ &mut self.general
+ }
+}