Skip to content

Commit 28f06ce

Browse files
author
Danilo Krummrich
committed
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`. 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 d88dd90 commit 28f06ce

File tree

2 files changed

+121
-0
lines changed

2 files changed

+121
-0
lines changed

rust/kernel/driver.rs

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
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 [`RegistrationOps`], which allows drivers to
6+
//! register 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 [`RegistrationOps`] trait serves as generic interface for subsystems (e.g., PCI, Platform,
14+
/// Amba, etc.) to privide the corresponding subsystem specific implementation to register /
15+
/// unregister a 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 `RegistrationOps::register` and
19+
/// `bindings::pci_unregister_driver` from `RegistrationOps::unregister`.
20+
pub trait RegistrationOps {
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+
/// On success, `reg` must remain pinned and valid until the matching call to
28+
/// [`RegistrationOps::unregister`].
29+
fn register(
30+
reg: &mut Self::RegType,
31+
name: &'static CStr,
32+
module: &'static ThisModule,
33+
) -> Result;
34+
35+
/// Unregisters a driver previously registered with [`RegistrationOps::register`].
36+
fn unregister(reg: &mut Self::RegType);
37+
}
38+
39+
/// A [`Registration`] is a generic type that represents the registration of some driver type (e.g.
40+
/// `bindings::pci_driver`). Therefore a [`Registration`] must be initialized with a type that
41+
/// implements the [`RegistrationOps`] trait, such that the generic `T::register` and `T::unregister`
42+
/// calls result in the subsystem specific registration calls.
43+
///
44+
///Once the `Registration` structure is dropped, the driver is unregistered.
45+
#[pin_data(PinnedDrop)]
46+
pub struct Registration<T: RegistrationOps> {
47+
#[pin]
48+
reg: Opaque<T::RegType>,
49+
}
50+
51+
// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
52+
// share references to it with multiple threads as nothing can be done.
53+
unsafe impl<T: RegistrationOps> Sync for Registration<T> {}
54+
55+
// SAFETY: Both registration and unregistration are implemented in C and safe to be performed from
56+
// any thread, so `Registration` is `Send`.
57+
unsafe impl<T: RegistrationOps> Send for Registration<T> {}
58+
59+
impl<T: RegistrationOps> Registration<T> {
60+
/// Creates a new instance of the registration object.
61+
pub fn new(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> {
62+
try_pin_init!(Self {
63+
reg <- Opaque::try_ffi_init(|ptr: *mut T::RegType| {
64+
// SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write.
65+
unsafe { ptr.write(T::RegType::default()) };
66+
67+
// SAFETY: `try_ffi_init` guarantees that `ptr` is valid for write, and it has
68+
// just been initialised above, so it's also valid for read.
69+
let drv = unsafe { &mut *ptr };
70+
71+
T::register(drv, name, module)
72+
}),
73+
})
74+
}
75+
}
76+
77+
#[pinned_drop]
78+
impl<T: RegistrationOps> PinnedDrop for Registration<T> {
79+
fn drop(self: Pin<&mut Self>) {
80+
// SAFETY: The existance of the `Registration` guarantees that `self.reg.get()` is properly
81+
// aligned and points to a valid value.
82+
let drv = unsafe { &mut *self.reg.get() };
83+
84+
T::unregister(drv);
85+
}
86+
}
87+
88+
/// A kernel module that only registers the given driver on init.
89+
///
90+
/// This is a helper struct to make it easier to define single-functionality modules, in this case,
91+
/// modules that offer a single driver.
92+
#[pin_data]
93+
pub struct Module<T: RegistrationOps> {
94+
#[pin]
95+
_driver: Registration<T>,
96+
}
97+
98+
impl<T: RegistrationOps + Sync + Send> crate::InPlaceModule for Module<T> {
99+
fn init(name: &'static CStr, module: &'static ThisModule) -> impl PinInit<Self, Error> {
100+
try_pin_init!(Self {
101+
_driver <- Registration::<T>::new(name, module),
102+
})
103+
}
104+
}
105+
106+
/// Declares a kernel module that exposes a single driver.
107+
///
108+
/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
109+
/// macros.
110+
#[macro_export]
111+
macro_rules! module_driver {
112+
(<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
113+
type Ops<$gen_type> = $driver_ops;
114+
type ModuleType = $crate::driver::Module<Ops<$type>>;
115+
$crate::prelude::module! {
116+
type: ModuleType,
117+
$($f)*
118+
}
119+
}
120+
}

rust/kernel/lib.rs

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

0 commit comments

Comments
 (0)