diff options
author | Danilo Krummrich <dakr@kernel.org> | 2024-08-21 04:48:16 +0200 |
---|---|---|
committer | Danilo Krummrich <dakr@kernel.org> | 2024-08-21 04:48:16 +0200 |
commit | 33026ad7c540512bd18dbc7ca7c58e12cba47e54 (patch) | |
tree | 04bc7eec7d67553989ea324a0e7e2a8a3a3af27f | |
parent | 14ce3e92cb73161638bedd012c4723eb12a24420 (diff) |
rust: driver: generalize `Registration` structure
Generalize the `Registration` structure to be used commonly by
subsystems / busses.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
-rw-r--r-- | rust/kernel/driver.rs | 89 | ||||
-rw-r--r-- | rust/kernel/lib.rs | 1 |
2 files changed, 90 insertions, 0 deletions
diff --git a/rust/kernel/driver.rs b/rust/kernel/driver.rs new file mode 100644 index 000000000000..4fec6ee1a90d --- /dev/null +++ b/rust/kernel/driver.rs @@ -0,0 +1,89 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Generic driver support + +use core::cell::UnsafeCell; +use core::marker::PhantomData; +use kernel::{alloc::flags::*, prelude::*}; + +/// The [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, +/// Amba, etc.) to privide the corresponding subsystem specific implementation to register / +/// unregister a driver of the particular type (`RegType`). +/// +/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call +/// `bindings::__pci_register_driver` from `RegistrationOps::register` and +/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`. +pub trait RegistrationOps { + /// The type that holds information about the registration. This is typically a struct defined + /// by the C portion of the kernel, e.g. `bindings::pci_driver. + type RegType: Default; + + /// Registers a driver. + /// + /// # Safety + /// + /// `reg` must point to valid, initialised, and writable memory. It may be modified by this + /// function to hold registration state. + /// + /// On success, `reg` must remain pinned and valid until the matching call to + /// [`RegistrationOps::unregister`]. + unsafe fn register( + reg: *mut Self::RegType, + name: &'static CStr, + module: &'static ThisModule, + ) -> Result; + + /// Unregisters a driver previously registered with [`RegistrationOps::register`]. + /// + /// # Safety + /// + /// `reg` must point to valid writable memory, initialised by a previous successful call to + /// [`RegistrationOps::register`]. + unsafe fn unregister(reg: *mut Self::RegType); +} + +/// Registration structure for a driver. +/// +/// The existance of an instance of this structure implies that the corresponding driver is +/// currently registered. +pub struct Registration<T: RegistrationOps> { + driver: Pin<KBox<UnsafeCell<T::RegType>>>, + _p: PhantomData<T>, +} + +impl<T> Registration<T> +where + T: RegistrationOps, +{ + /// Register a new driver from `T::RegType`. + pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result<Self> { + let driver = KBox::pin(UnsafeCell::new(T::RegType::default()), GFP_KERNEL)?; + + // SAFETY: `driver` has just been initialized; it's only freed after `Self::drop`, which + // calls `T::unregister` first. + unsafe { T::register(driver.get(), name, module) }?; + + Ok(Self { + driver, + _p: PhantomData::<T>, + }) + } +} + +impl<T> Drop for Registration<T> +where + T: RegistrationOps, +{ + fn drop(&mut self) { + // SAFETY: Only ever called if the `Registration` was created successfully. + unsafe { T::unregister(self.driver.get()) }; + } +} + +// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to +// share references to it with multiple threads as nothing can be done. +unsafe impl<T> Sync for Registration<T> where T: RegistrationOps {} + +// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from +// any thread, so `Registration` is `Send`. +unsafe impl<T> Send for Registration<T> where T: RegistrationOps {} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index ab8f3cf7fb40..2ef77187c5c7 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -31,6 +31,7 @@ pub mod block; mod build_assert; pub mod cred; pub mod device; +pub mod driver; pub mod error; #[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)] pub mod firmware; |