Skip to content

Commit 5ddcb70

Browse files
author
Danilo Krummrich
committed
rust: implement generic driver registration
Implement the generic `Registration` type and the `RegistrationOps` 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 `RegistrationOps` trait is provided to subsystems, which have to implement `RegistrationOps::register` and `RegistrationOps::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 `RegistrationOps::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 edd21fa commit 5ddcb70

File tree

3 files changed

+119
-0
lines changed

3 files changed

+119
-0
lines changed

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7033,6 +7033,7 @@ F: include/linux/kobj*
70337033
F: include/linux/property.h
70347034
F: lib/kobj*
70357035
F: rust/kernel/device.rs
7036+
F: rust/kernel/driver.rs
70367037

70377038
DRIVERS FOR OMAP ADAPTIVE VOLTAGE SCALING (AVS)
70387039
M: Nishanth Menon <[email protected]>

rust/kernel/driver.rs

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
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 provide 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: &Opaque<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: &Opaque<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
42+
/// `T::unregister` 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 { &*(ptr as *const Opaque<T::RegType>) };
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+
T::unregister(&self.reg);
81+
}
82+
}
83+
84+
/// Declares a kernel module that exposes a single driver.
85+
///
86+
/// It is meant to be used as a helper by other subsystems so they can more easily expose their own
87+
/// macros.
88+
#[macro_export]
89+
macro_rules! module_driver {
90+
(<$gen_type:ident>, $driver_ops:ty, { type: $type:ty, $($f:tt)* }) => {
91+
type Ops<$gen_type> = $driver_ops;
92+
93+
#[$crate::prelude::pin_data]
94+
struct DriverModule {
95+
#[pin]
96+
_driver: $crate::driver::Registration<Ops<$type>>,
97+
}
98+
99+
impl $crate::InPlaceModule for DriverModule {
100+
fn init(
101+
module: &'static $crate::ThisModule
102+
) -> impl $crate::init::PinInit<Self, $crate::error::Error> {
103+
$crate::try_pin_init!(Self {
104+
_driver <- $crate::driver::Registration::new(
105+
<Self as $crate::ModuleMetadata>::NAME,
106+
module,
107+
),
108+
})
109+
}
110+
}
111+
112+
$crate::prelude::module! {
113+
type: DriverModule,
114+
$($f)*
115+
}
116+
}
117+
}

rust/kernel/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ pub mod block;
3737
pub mod build_assert;
3838
pub mod cred;
3939
pub mod device;
40+
pub mod driver;
4041
pub mod error;
4142
#[cfg(CONFIG_RUST_FW_LOADER_ABSTRACTIONS)]
4243
pub mod firmware;

0 commit comments

Comments
 (0)