Skip to content

Commit 55443b4

Browse files
dakrDanilo Krummrich
authored andcommitted
rust: implement generic driver registration
Implement the generic `Registration` type and the `DriverOps` trait. The `Registration` structure is the common type that represents a driver registration and is typically bound to the lifetime of a module. However, it doesn't implement actual calls to the kernel's driver core to register drivers itself. Instead the `DriverOps` trait is provided to subsystems, which have to implement `DriverOps::register` and `DrvierOps::unregister`. Subsystems have to provide an implementation for both of those methods where the subsystem specific variants to register / unregister a driver have to implemented. For instance, the PCI subsystem would call __pci_register_driver() from `DriverOps::register` and pci_unregister_driver() from `DrvierOps::unregister`. This patch is based on previous work from Wedson Almeida Filho. Co-developed-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Wedson Almeida Filho <[email protected]> Signed-off-by: Danilo Krummrich <[email protected]>
1 parent acde67c commit 55443b4

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

rust/kernel/driver.rs

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
//! Generic support for drivers of different buses (e.g., PCI, Platform, Amba, etc.).
4+
//!
5+
//! Each bus / subsystem is expected to implement [`DriverOps`], which allows drivers to register
6+
//! using the [`Registration`] class.
7+
8+
use crate::error::{Error, Result};
9+
use crate::{init::PinInit, str::CStr, try_pin_init, types::Opaque, ThisModule};
10+
use core::pin::Pin;
11+
use macros::{pin_data, pinned_drop};
12+
13+
/// The [`DriverOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform, Amba,
14+
/// etc.) to privide the corresponding subsystem specific implementation to register / unregister a
15+
/// driver of the particular type (`RegType`).
16+
///
17+
/// For instance, the PCI subsystem would set `RegType` to `bindings::pci_driver` and call
18+
/// `bindings::__pci_register_driver` from `DriverOps::register` and
19+
/// `bindings::pci_unregister_driver` from `DriverOps::unregister`.
20+
pub trait DriverOps {
21+
/// The type that holds information about the registration. This is typically a struct defined
22+
/// by the C portion of the kernel.
23+
type RegType: Default;
24+
25+
/// Registers a driver.
26+
///
27+
/// # Safety
28+
///
29+
/// `reg` must point to valid, initialised, and writable memory. It may be modified by this
30+
/// function to hold registration state.
31+
///
32+
/// On success, `reg` must remain pinned and valid until the matching call to
33+
/// [`DriverOps::unregister`].
34+
fn register(
35+
reg: &mut Self::RegType,
36+
name: &'static CStr,
37+
module: &'static ThisModule,
38+
) -> Result;
39+
40+
/// Unregisters a driver previously registered with [`DriverOps::register`].
41+
///
42+
/// # Safety
43+
///
44+
/// `reg` must point to valid writable memory, initialised by a previous successful call to
45+
/// [`DriverOps::register`].
46+
fn unregister(reg: &mut Self::RegType);
47+
}
48+
49+
/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g.
50+
/// `bindings::pci_driver`). Therefore a [`Registration`] is initialized with some type that
51+
/// implements the [`DriverOps`] trait, such that the generic `T::register` and `T::unregister`
52+
/// calls result in the subsystem specific registration calls.
53+
///
54+
///Once the `Registration` structure is dropped, the driver is unregistered.
55+
#[pin_data(PinnedDrop)]
56+
pub struct Registration<T: DriverOps> {
57+
#[pin]
58+
reg: Opaque<T::RegType>,
59+
}
60+
61+
// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
62+
// share references to it with multiple threads as nothing can be done.
63+
unsafe impl<T: DriverOps> Sync for Registration<T> {}
64+
65+
// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from
66+
// any thread, so `Registration` is `Send`.
67+
unsafe impl<T: DriverOps> Send for Registration<T> {}
68+
69+
impl<T: DriverOps> Registration<T> {
70+
/// Creates a new instance of the registration object.
71+
pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> {
72+
try_pin_init!(Self {
73+
reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| {
74+
// SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write.
75+
unsafe { ptr.write(T::RegType::default()) };
76+
77+
// SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has
78+
// just been initialised above, so it's also valid for read.
79+
let drv = unsafe { &mut *ptr };
80+
81+
T::register(drv, name, module)
82+
}),
83+
})
84+
}
85+
}
86+
87+
#[pinned_drop]
88+
impl<T: DriverOps> PinnedDrop for Registration<T> {
89+
fn drop(self: Pin<&mut Self>) {
90+
let drv = unsafe { &mut *self.reg.get() };
91+
92+
T::unregister(drv);
93+
}
94+
}
95+
96+
/// A kernel module that only registers the given driver on init.
97+
///
98+
/// This is a helper struct to make it easier to define single-functionality modules, in this case,
99+
/// modules that offer a single driver.
100+
#[pin_data]
101+
pub struct Module<T: DriverOps> {
102+
#[pin]
103+
_driver: Registration<T>,
104+
}
105+
106+
impl<T: DriverOps + Sync + Send> crate::InPlaceModule for Module<T> {
107+
fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> {
108+
try_pin_init!(Self {
109+
_driver <- Registration::<T>::new(name, module),
110+
})
111+
}
112+
}
113+
114+
/// Declares a kernel module that exposes a single driver.
115+
///
116+
/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
117+
/// macros.
118+
#[macro_export]
119+
macro_rules! module_driver {
120+
(<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
121+
type Ops<$gen_type> = $driver_ops;
122+
type ModuleType = $crate::driver::Module<Ops<$type>>;
123+
$crate::prelude::module! {
124+
type: ModuleType,
125+
$($f)*
126+
}
127+
}
128+
}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub mod alloc;
3131
pub mod block;
3232
mod build_assert;
3333
pub mod device;
34+
pub mod driver;
3435
pub mod error;
3536
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
3637
pub mod firmware;

0 commit comments

Comments
 (0)