Skip to content

Commit cffb910

Browse files
committed
rust: convert platform to use driver
A platform driver is now defined by implementing a trait, very much like `amba`. There is also a module macro used that can used if a module is just a platform driver. Lastly, drivers can specify additional data with each supported id (to be passed back to them on `probe`). Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
1 parent 3e62840 commit cffb910

File tree

4 files changed

+253
-217
lines changed

4 files changed

+253
-217
lines changed

drivers/char/hw_random/bcm2835_rng_rust.rs

Lines changed: 27 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@
66
#![feature(allocator_api, global_asm)]
77

88
use kernel::{
9-
c_str, file::File, file_operations::FileOperations, io_buffer::IoBufferWriter, miscdev,
10-
of::ConstOfMatchTable, platform, platform::PlatformDriver, prelude::*,
9+
c_str, device, file::File, file_operations::FileOperations, io_buffer::IoBufferWriter, miscdev,
10+
module_platform_driver, of, platform, prelude::*, sync::Ref,
1111
};
1212

13-
module! {
14-
type: RngModule,
13+
module_platform_driver! {
14+
type: RngDriver,
1515
name: b"bcm2835_rng_rust",
1616
author: b"Rust for Linux Contributors",
1717
description: b"BCM2835 Random Number Generator (RNG) driver",
@@ -38,35 +38,29 @@ impl FileOperations for RngDevice {
3838
}
3939
}
4040

41-
struct RngDriver;
42-
43-
impl PlatformDriver for RngDriver {
44-
type DrvData = Pin<Box<miscdev::Registration<RngDevice>>>;
45-
46-
fn probe(device_id: i32) -> Result<Self::DrvData> {
47-
pr_info!("probing discovered hwrng with id {}\n", device_id);
48-
let drv_data = miscdev::Registration::new_pinned(c_str!("rust_hwrng"), None, ())?;
49-
Ok(drv_data)
50-
}
41+
type DeviceData = device::Data<miscdev::Registration<RngDevice>, (), ()>;
5142

52-
fn remove(device_id: i32, _drv_data: Self::DrvData) -> Result {
53-
pr_info!("removing hwrng with id {}\n", device_id);
54-
Ok(())
55-
}
56-
}
57-
58-
struct RngModule {
59-
_pdev: Pin<Box<platform::Registration>>,
60-
}
61-
62-
impl KernelModule for RngModule {
63-
fn init(name: &'static CStr, module: &'static ThisModule) -> Result<Self> {
64-
const OF_MATCH_TBL: ConstOfMatchTable<1> =
65-
ConstOfMatchTable::new_const([c_str!("brcm,bcm2835-rng")]);
66-
67-
let pdev =
68-
platform::Registration::new_pinned::<RngDriver>(name, Some(&OF_MATCH_TBL), module)?;
69-
70-
Ok(RngModule { _pdev: pdev })
43+
struct RngDriver;
44+
impl platform::Driver for RngDriver {
45+
type Data = Ref<DeviceData>;
46+
47+
kernel::define_of_id_table! {(), [
48+
(of::DeviceId::Compatible(b"brcm,bcm2835-rng"), None),
49+
]}
50+
51+
fn probe(dev: &mut platform::Device, _id_info: Option<&Self::IdInfo>) -> Result<Self::Data> {
52+
pr_info!("probing discovered hwrng with id {}\n", dev.id());
53+
let data = kernel::new_device_data!(
54+
miscdev::Registration::new(),
55+
(),
56+
(),
57+
"BCM2835::Registrations"
58+
)?;
59+
60+
data.registrations()
61+
.ok_or(Error::ENXIO)?
62+
.as_pinned_mut()
63+
.register(c_str!("rust_hwrng"), None, ())?;
64+
Ok(data.into())
7165
}
7266
}

rust/helpers.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <linux/irqchip/chained_irq.h>
1818
#include <linux/irqdomain.h>
1919
#include <linux/amba/bus.h>
20+
#include <linux/of_device.h>
2021

2122
__noreturn void rust_helper_BUG(void)
2223
{
@@ -477,6 +478,13 @@ void rust_helper_put_cred(const struct cred *cred) {
477478
}
478479
EXPORT_SYMBOL_GPL(rust_helper_put_cred);
479480

481+
const struct of_device_id *rust_helper_of_match_device(
482+
const struct of_device_id *matches, const struct device *dev)
483+
{
484+
return of_match_device(matches, dev);
485+
}
486+
EXPORT_SYMBOL_GPL(rust_helper_of_match_device);
487+
480488
/* We use bindgen's --size_t-is-usize option to bind the C size_t type
481489
* as the Rust usize type, so we can use it in contexts where Rust
482490
* expects a usize like slice (array) indices. usize is defined to be

rust/kernel/of.rs

Lines changed: 42 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -4,98 +4,60 @@
44
//!
55
//! C header: [`include/linux/of_*.h`](../../../../include/linux/of_*.h)
66
7-
use crate::{bindings, c_types, str::CStr};
7+
use crate::{bindings, driver, str::BStr};
88

9-
use core::ops::Deref;
10-
use core::ptr;
9+
/// An open firmware device id.
10+
#[derive(Clone, Copy)]
11+
pub enum DeviceId {
12+
/// An open firmware device id where only a compatible string is specified.
13+
Compatible(&'static BStr),
14+
}
1115

12-
/// A kernel Open Firmware / devicetree match table.
13-
///
14-
/// Can only exist as an `&OfMatchTable` reference (akin to `&str` or
15-
/// `&Path` in Rust std).
16+
/// Defines a const open firmware device id table that also carries per-entry data/context/info.
1617
///
17-
/// # Invariants
18+
/// The name of the const is `OF_DEVICE_ID_TABLE`, which is what buses are expected to name their
19+
/// open firmware tables.
1820
///
19-
/// The inner reference points to a sentinel-terminated C array.
20-
#[repr(transparent)]
21-
pub struct OfMatchTable(bindings::of_device_id);
22-
23-
impl OfMatchTable {
24-
/// Returns the table as a reference to a static lifetime, sentinel-terminated C array.
25-
///
26-
/// This is suitable to be coerced into the kernel's `of_match_table` field.
27-
pub fn as_ptr(&'static self) -> &'static bindings::of_device_id {
28-
// The inner reference points to a sentinel-terminated C array, as per
29-
// the type invariant.
30-
&self.0
31-
}
32-
}
33-
34-
/// An Open Firmware Match Table that can be constructed at build time.
21+
/// # Examples
3522
///
36-
/// # Invariants
23+
/// ```
24+
/// # use kernel::define_of_id_table;
25+
/// use kernel::of;
3726
///
38-
/// `sentinel` always contains zeroes.
39-
#[repr(C)]
40-
pub struct ConstOfMatchTable<const N: usize> {
41-
table: [bindings::of_device_id; N],
42-
sentinel: bindings::of_device_id,
27+
/// define_of_id_table! {u32, [
28+
/// (of::DeviceId::Compatible(b"test-device1,test-device2"), Some(0xff)),
29+
/// (of::DeviceId::Compatible(b"test-device3"), None),
30+
/// ]};
31+
/// ```
32+
#[macro_export]
33+
macro_rules! define_of_id_table {
34+
($data_type:ty, $($t:tt)*) => {
35+
$crate::define_id_table!(OF_DEVICE_ID_TABLE, $crate::of::DeviceId, $data_type, $($t)*);
36+
};
4337
}
4438

45-
impl<const N: usize> ConstOfMatchTable<N> {
46-
/// Creates a new Open Firmware Match Table from a list of compatible strings.
47-
pub const fn new_const(compatibles: [&'static CStr; N]) -> Self {
48-
let mut table = [Self::zeroed_of_device_id(); N];
49-
let mut i = 0;
50-
while i < N {
51-
table[i] = Self::new_of_device_id(compatibles[i]);
52-
i += 1;
53-
}
54-
Self {
55-
table,
56-
// INVARIANTS: we zero the sentinel here, and never change it
57-
// anywhere. Therefore it always contains zeroes.
58-
sentinel: Self::zeroed_of_device_id(),
59-
}
60-
}
61-
62-
const fn zeroed_of_device_id() -> bindings::of_device_id {
63-
bindings::of_device_id {
64-
name: [0; 32],
65-
type_: [0; 32],
66-
compatible: [0; 128],
67-
data: ptr::null(),
68-
}
69-
}
70-
71-
const fn new_of_device_id(compatible: &'static CStr) -> bindings::of_device_id {
72-
let mut id = Self::zeroed_of_device_id();
73-
let compatible = compatible.as_bytes_with_nul();
39+
// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `of_device_id::data`.
40+
unsafe impl const driver::RawDeviceId for DeviceId {
41+
type RawType = bindings::of_device_id;
42+
const ZERO: Self::RawType = bindings::of_device_id {
43+
name: [0; 32],
44+
type_: [0; 32],
45+
compatible: [0; 128],
46+
data: core::ptr::null(),
47+
};
48+
49+
fn to_rawid(&self, offset: isize) -> Self::RawType {
50+
let DeviceId::Compatible(compatible) = self;
51+
let mut id = Self::ZERO;
7452
let mut i = 0;
7553
while i < compatible.len() {
76-
// If `compatible` does not fit in `id.compatible`, an
77-
// "index out of bounds" build time error will be triggered.
78-
id.compatible[i] = compatible[i] as c_types::c_char;
54+
// If `compatible` does not fit in `id.compatible`, an "index out of bounds" build time
55+
// error will be triggered.
56+
id.compatible[i] = compatible[i] as _;
7957
i += 1;
8058
}
59+
id.compatible[i] = b'\0' as _;
60+
id.data = offset as _;
8161
id
8262
}
8363
}
84-
85-
impl<const N: usize> Deref for ConstOfMatchTable<N> {
86-
type Target = OfMatchTable;
87-
88-
fn deref(&self) -> &OfMatchTable {
89-
// INVARIANTS: `head` points to a sentinel-terminated C array,
90-
// as per the `ConstOfMatchTable` type invariant, therefore
91-
// `&OfMatchTable`'s inner reference will point to a sentinel-terminated C array.
92-
let head = &self.table[0] as *const bindings::of_device_id as *const OfMatchTable;
93-
94-
// SAFETY: The returned reference must remain valid for the lifetime of `self`.
95-
// The raw pointer `head` points to memory inside `self`. So the reference created
96-
// from this raw pointer has the same lifetime as `self`.
97-
// Therefore this reference remains valid for the lifetime of `self`, and
98-
// is safe to return.
99-
unsafe { &*head }
100-
}
101-
}

0 commit comments

Comments
 (0)