From 33026ad7c540512bd18dbc7ca7c58e12cba47e54 Mon Sep 17 00:00:00 2001 From: Danilo Krummrich Date: Wed, 21 Aug 2024 04:48:16 +0200 Subject: rust: driver: generalize `Registration` structure Generalize the `Registration` structure to be used commonly by subsystems / busses. Signed-off-by: Danilo Krummrich --- rust/kernel/driver.rs | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 2 files changed, 90 insertions(+) create mode 100644 rust/kernel/driver.rs 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 { + driver: Pin>>, + _p: PhantomData, +} + +impl Registration +where + T: RegistrationOps, +{ + /// Register a new driver from `T::RegType`. + pub fn new(name: &'static CStr, module: &'static ThisModule) -> Result { + 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::, + }) + } +} + +impl Drop for Registration +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 Sync for Registration 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 Send for Registration 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; -- cgit v1.2.3-58-ga151