diff options
author | Andreas Hindborg <a.hindborg@samsung.com> | 2023-09-04 13:27:31 +0200 |
---|---|---|
committer | Danilo Krummrich <dakr@redhat.com> | 2023-11-22 22:01:11 +0100 |
commit | 4f54e936ee9e784db8b82dff7169230de55e4231 (patch) | |
tree | af9a25c53843b3cfe309ca28793a7aa0fa10db68 | |
parent | 4f3fb034dc1b1c599fa9a86d99dc4810bafa7c4a (diff) |
rust: add device::Data
Based on
https://github.com/Rust-for-Linux/linux/commit/9d7d4827356cc4c17e1e546175204b12f1becff9
-rw-r--r-- | rust/kernel/device.rs | 124 |
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 + } +} |