Skip to content

Commit 3e62840

Browse files
committed
rust: update amba to use the new constant device id table
Also remove the non-const id table processing as `amba` was the only user. Signed-off-by: Wedson Almeida Filho <wedsonaf@google.com>
1 parent efbcb28 commit 3e62840

4 files changed

Lines changed: 67 additions & 117 deletions

File tree

drivers/gpio/gpio_pl061_rust.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#![feature(global_asm, allocator_api)]
99

1010
use kernel::{
11-
amba, bit, bits_iter, declare_amba_id_table, device, gpio,
11+
amba, bit, bits_iter, define_amba_id_table, device, gpio,
1212
io_mem::IoMem,
1313
irq::{self, ExtraResult, IrqData, LockedIrqData},
1414
power,
@@ -261,11 +261,11 @@ impl amba::Driver for PL061Device {
261261
type Data = Ref<DeviceData>;
262262
type PowerOps = Self;
263263

264-
declare_amba_id_table! [
265-
{ id: 0x00041061, mask: 0x000fffff, data: () },
266-
];
264+
define_amba_id_table! {(), [
265+
({id: 0x00041061, mask: 0x000fffff}, None),
266+
]}
267267

268-
fn probe(dev: &mut amba::Device, _id: &amba::DeviceId) -> Result<Ref<DeviceData>> {
268+
fn probe(dev: &mut amba::Device, _data: Option<&Self::IdInfo>) -> Result<Ref<DeviceData>> {
269269
let res = dev.take_resource().ok_or(Error::ENXIO)?;
270270
let irq = dev.irq(0).ok_or(Error::ENXIO)?;
271271

rust/kernel/amba.rs

Lines changed: 54 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,43 @@
11
// SPDX-License-Identifier: GPL-2.0
22

3-
//! Amba devices drivers.
3+
//! Amba devices and drivers.
44
//!
55
//! C header: [`include/linux/amba/bus.h`](../../../../include/linux/amba/bus.h)
66
77
use crate::{
88
bindings, c_types, device, driver, error::from_kernel_result, io_mem::Resource, power,
9-
str::CStr, to_result, types::PointerWrapper, Error, Result, ThisModule,
9+
str::CStr, to_result, types::PointerWrapper, Result, ThisModule,
1010
};
1111

1212
/// A registration of an amba driver.
1313
pub type Registration<T> = driver::Registration<Adapter<T>>;
1414

1515
/// Id of an Amba device.
16-
pub struct DeviceId<T = ()> {
16+
#[derive(Clone, Copy)]
17+
pub struct DeviceId {
1718
/// Device id.
1819
pub id: u32,
1920

2021
/// Mask that identifies which bits are valid in the device id.
2122
pub mask: u32,
23+
}
24+
25+
// SAFETY: `ZERO` is all zeroed-out and `to_rawid` stores `offset` in `amba_id::data`.
26+
unsafe impl const driver::RawDeviceId for DeviceId {
27+
type RawType = bindings::amba_id;
28+
const ZERO: Self::RawType = bindings::amba_id {
29+
id: 0,
30+
mask: 0,
31+
data: core::ptr::null_mut(),
32+
};
2233

23-
/// Context data to be associated with the device id. This is carried over to [`Driver::probe`]
24-
/// so that drivers can encode any information they may need then.
25-
pub data: T,
34+
fn to_rawid(&self, offset: isize) -> Self::RawType {
35+
bindings::amba_id {
36+
id: self.id,
37+
mask: self.mask,
38+
data: offset as _,
39+
}
40+
}
2641
}
2742

2843
/// An amba driver.
@@ -39,11 +54,11 @@ pub trait Driver {
3954
/// The type holding information about each device id supported by the driver.
4055
type IdInfo: 'static = ();
4156

42-
/// The table of device ids supported by the drivers.
43-
const ID_TABLE: &'static [DeviceId<Self::IdInfo>];
57+
/// The table of device ids supported by the driver.
58+
const ID_TABLE: Option<driver::IdTable<'static, DeviceId, Self::IdInfo>> = None;
4459

4560
/// Probes for the device with the given id.
46-
fn probe(dev: &mut Device, id: &DeviceId<Self::IdInfo>) -> Result<Self::Data>;
61+
fn probe(dev: &mut Device, id_info: Option<&Self::IdInfo>) -> Result<Self::Data>;
4762

4863
/// Cleans any resources up that are associated with the device.
4964
///
@@ -56,24 +71,22 @@ pub struct Adapter<T: Driver>(T);
5671

5772
impl<T: Driver> driver::DriverOps for Adapter<T> {
5873
type RegType = bindings::amba_driver;
59-
type RawIdType = bindings::amba_id;
60-
type IdType = DeviceId<T::IdInfo>;
61-
const ID_TABLE: &'static [Self::IdType] = T::ID_TABLE;
6274

6375
unsafe fn register(
6476
reg: *mut bindings::amba_driver,
6577
name: &'static CStr,
6678
module: &'static ThisModule,
67-
id_table: *const bindings::amba_id,
6879
) -> Result {
6980
// SAFETY: By the safety requirements of this function (defined in the trait defintion),
7081
// `reg` is non-null and valid.
7182
let amba = unsafe { &mut *reg };
7283
amba.drv.name = name.as_char_ptr();
7384
amba.drv.owner = module.0;
74-
amba.id_table = id_table;
7585
amba.probe = Some(probe_callback::<T>);
7686
amba.remove = Some(remove_callback::<T>);
87+
if let Some(t) = T::ID_TABLE {
88+
amba.id_table = t.as_ref();
89+
}
7790
if cfg!(CONFIG_PM) {
7891
// SAFETY: `probe_callback` sets the driver data after calling `T::Data::into_pointer`,
7992
// and we guarantee that `T::Data` is the same as `T::PowerOps::Data` by a constraint
@@ -90,14 +103,6 @@ impl<T: Driver> driver::DriverOps for Adapter<T> {
90103
// `reg` was passed (and updated) by a previous successful call to `amba_driver_register`.
91104
unsafe { bindings::amba_driver_unregister(reg) };
92105
}
93-
94-
fn to_raw_id(index: usize, id: &Self::IdType) -> Self::RawIdType {
95-
bindings::amba_id {
96-
id: id.id,
97-
mask: id.mask,
98-
data: index as _,
99-
}
100-
}
101106
}
102107

103108
unsafe extern "C" fn probe_callback<T: Driver>(
@@ -109,11 +114,18 @@ unsafe extern "C" fn probe_callback<T: Driver>(
109114
// duration of this call, so it is guaranteed to remain alive for the lifetime of `dev`.
110115
let mut dev = unsafe { Device::from_ptr(adev) };
111116
// SAFETY: `aid` is valid by the requirements the contract with the C code.
112-
let index = unsafe { (*aid).data } as usize;
113-
if index >= T::ID_TABLE.len() {
114-
return Err(Error::ENXIO);
115-
}
116-
let data = T::probe(&mut dev, &T::ID_TABLE[index])?;
117+
let offset = unsafe { (*aid).data };
118+
let info = if offset.is_null() {
119+
None
120+
} else {
121+
// SAFETY: The offset comes from a previous call to `offset_from` in `IdArray::new`,
122+
// which guarantees that the resulting pointer is within the table.
123+
let ptr = unsafe { aid.cast::<u8>().offset(offset as _).cast::<Option<T::IdInfo>>() };
124+
// SAFETY: The id table has a static lifetime, so `ptr` is guaranteed to be valid for
125+
// read.
126+
unsafe { (&*ptr).as_ref() }
127+
};
128+
let data = T::probe(&mut dev, info)?;
117129
let ptr = T::Data::into_pointer(data);
118130
// SAFETY: `adev` is valid for write by the contract with the C code.
119131
unsafe { bindings::amba_set_drvdata(adev, ptr as _) };
@@ -193,17 +205,17 @@ unsafe impl device::RawDevice for Device {
193205
///
194206
/// ```ignore
195207
/// # use kernel::prelude::*;
196-
/// # use kernel::{amba, declare_amba_id_table, module_amba_driver};
208+
/// # use kernel::{amba, define_amba_id_table, module_amba_driver};
197209
/// #
198210
/// struct MyDriver;
199211
/// impl amba::Driver for MyDriver {
200212
/// // [...]
201-
/// # fn probe(_dev: &mut amba::Device, _id: &amba::DeviceId<Self::IdInfo>) -> Result {
213+
/// # fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
202214
/// # Ok(())
203215
/// # }
204-
/// # declare_amba_id_table! [
205-
/// # { id: 0x00041061, mask: 0x000fffff, data: () },
206-
/// # ];
216+
/// # define_amba_id_table! {(), [
217+
/// # ({ id: 0x00041061, mask: 0x000fffff }, None),
218+
/// # ]}
207219
/// }
208220
///
209221
/// module_amba_driver! {
@@ -220,34 +232,28 @@ macro_rules! module_amba_driver {
220232
};
221233
}
222234

223-
/// Declares the id table for amba devices.
235+
/// Defines the id table for amba devices.
224236
///
225237
/// # Examples
226238
///
227239
/// ```
228240
/// # use kernel::prelude::*;
229-
/// # use kernel::{amba, declare_amba_id_table};
241+
/// # use kernel::{amba, define_amba_id_table};
230242
/// #
231243
/// # struct Sample;
232244
/// # impl kernel::amba::Driver for Sample {
233-
/// # fn probe(_dev: &mut amba::Device, _id: &amba::DeviceId<Self::IdInfo>) -> Result {
245+
/// # fn probe(_dev: &mut amba::Device, _id: Option<&Self::IdInfo>) -> Result {
234246
/// # Ok(())
235247
/// # }
236-
/// declare_amba_id_table! [
237-
/// { id: 0x00041061, mask: 0x000fffff, data: () },
238-
/// ];
248+
/// define_amba_id_table! {(), [
249+
/// ({ id: 0x00041061, mask: 0x000fffff }, None),
250+
/// ]}
239251
/// # }
240252
/// ```
241253
#[macro_export]
242-
macro_rules! declare_amba_id_table {
243-
($({$($entry:tt)*},)*) => {
244-
const ID_TABLE: &'static [$crate::amba::DeviceId<Self::IdInfo>] = &[
245-
$( $crate::amba::DeviceId { $($entry)* },)*
246-
];
254+
macro_rules! define_amba_id_table {
255+
($data_type:ty, $($t:tt)*) => {
256+
type IdInfo = $data_type;
257+
$crate::define_id_table!(ID_TABLE, $crate::amba::DeviceId, $data_type, $($t)*);
247258
};
248-
249-
// Cover case without a trailing comma.
250-
($(($($entry:tt)*)),*) => {
251-
$crate::declare_amba_id_table!{ $({$($entry)*},)*}
252-
}
253259
}

rust/kernel/driver.rs

Lines changed: 8 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -5,47 +5,29 @@
55
//! Each bus/subsystem is expected to implement [`DriverOps`], which allows drivers to register
66
//! using the [`Registration`] class.
77
8-
use crate::{str::CStr, sync::Ref, Error, KernelModule, Result, ScopeGuard, ThisModule};
9-
use alloc::{boxed::Box, vec::Vec};
10-
use core::{cell::UnsafeCell, marker::PhantomData, mem::MaybeUninit, ops::Deref, pin::Pin};
8+
use crate::{str::CStr, sync::Ref, Error, KernelModule, Result, ThisModule};
9+
use alloc::boxed::Box;
10+
use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref, pin::Pin};
1111

1212
/// A subsystem (e.g., PCI, Platform, Amba, etc.) that allows drivers to be written for it.
1313
pub trait DriverOps {
1414
/// The type that holds information about the registration. This is typically a struct defined
1515
/// by the C portion of the kernel.
1616
type RegType: Default;
1717

18-
/// The type that holds identification data for the devices supported by the driver. In
19-
/// addition to the information required by the bus, it may also store device-specific data
20-
/// using Rust types.
21-
type IdType: 'static;
22-
23-
/// The table of ids containing all supported devices.
24-
const ID_TABLE: &'static [Self::IdType];
25-
26-
/// The raw type that holds identification data for the devices supported by the driver. This
27-
/// is typically a struct defined by the C portion of the kernel.
28-
///
29-
/// A zero-terminated array of this type is produced and passed to the C portion during
30-
/// registration.
31-
type RawIdType;
32-
3318
/// Registers a driver.
3419
///
3520
/// # Safety
3621
///
3722
/// `reg` must point to valid, initialised, and writable memory. It may be modified by this
3823
/// function to hold registration state.
3924
///
40-
/// `id_table` must point to a valid for read zero-terminated array of ids.
41-
///
42-
/// On success, `reg` and `id_table` must remain pinned and valid until the matching call to
25+
/// On success, `reg` must remain pinned and valid until the matching call to
4326
/// [`DriverOps::unregister`].
4427
unsafe fn register(
4528
reg: *mut Self::RegType,
4629
name: &'static CStr,
4730
module: &'static ThisModule,
48-
id_table: *const Self::RawIdType,
4931
) -> Result;
5032

5133
/// Unregisters a driver previously registered with [`DriverOps::register`].
@@ -55,18 +37,12 @@ pub trait DriverOps {
5537
/// `reg` must point to valid writable memory, initialised by a previous successful call to
5638
/// [`DriverOps::register`].
5739
unsafe fn unregister(reg: *mut Self::RegType);
58-
59-
/// Converts an id into a raw id.
60-
///
61-
/// This is used when building a zero-terminated array from the Rust array.
62-
fn to_raw_id(index: usize, id: &Self::IdType) -> Self::RawIdType;
6340
}
6441

6542
/// The registration of a driver.
6643
pub struct Registration<T: DriverOps> {
6744
is_registered: bool,
6845
concrete_reg: UnsafeCell<T::RegType>,
69-
id_table: Vec<MaybeUninit<T::RawIdType>>,
7046
}
7147

7248
// SAFETY: `Registration` has no fields or methods accessible via `&Registration`, so it is safe to
@@ -79,7 +55,6 @@ impl<T: DriverOps> Registration<T> {
7955
Self {
8056
is_registered: false,
8157
concrete_reg: UnsafeCell::new(T::RegType::default()),
82-
id_table: Vec::new(),
8358
}
8459
}
8560

@@ -108,42 +83,13 @@ impl<T: DriverOps> Registration<T> {
10883
return Err(Error::EINVAL);
10984
}
11085

111-
if this.id_table.is_empty() {
112-
this.build_table()?;
113-
}
114-
115-
// SAFETY: `concrete_reg` was initialised via its default constructor. `id_table` was just
116-
// initialised above with a zero terminating entry. Both are only freed after `Self::drop`
117-
// is called, which first calls `T::unregister`.
118-
unsafe {
119-
T::register(
120-
this.concrete_reg.get(),
121-
name,
122-
module,
123-
&this.id_table[0] as *const _ as *const _,
124-
)
125-
}?;
86+
// SAFETY: `concrete_reg` was initialised via its default constructor. It is only freed
87+
// after `Self::drop` is called, which first calls `T::unregister`.
88+
unsafe { T::register(this.concrete_reg.get(), name, module) }?;
12689

12790
this.is_registered = true;
12891
Ok(())
12992
}
130-
131-
/// Builds the zero-terminated raw-type array of supported devices.
132-
///
133-
/// This is not ideal because the table is built at runtime. Once Rust fully supports const
134-
/// generics, we can build the table at compile time.
135-
fn build_table(&mut self) -> Result {
136-
// Clear the table on failure, to indicate that the table isn't initialised.
137-
let mut table = ScopeGuard::new_with_data(&mut self.id_table, |t| t.clear());
138-
139-
table.try_reserve_exact(T::ID_TABLE.len() + 1)?;
140-
for (i, id) in T::ID_TABLE.iter().enumerate() {
141-
table.try_push(MaybeUninit::new(T::to_raw_id(i, id)))?;
142-
}
143-
table.try_push(MaybeUninit::zeroed())?;
144-
table.dismiss();
145-
Ok(())
146-
}
14793
}
14894

14995
impl<T: DriverOps> Default for Registration<T> {
@@ -394,15 +340,14 @@ macro_rules! define_id_array {
394340
};
395341
}
396342

397-
// TODO: Remove `ignore` tag from example once we go to 1.58.x.
398343
/// Defines a new constant [`IdTable`] with a concise syntax.
399344
///
400345
/// It is meant to be used by buses and subsystems to create a similar macro with their device id
401346
/// type already specified, i.e., with fewer parameters to the end user.
402347
///
403348
/// # Examples
404349
///
405-
/// ```ignore
350+
/// ```
406351
/// #![feature(const_trait_impl)]
407352
/// # use kernel::{define_id_table, driver::RawDeviceId};
408353
///

rust/kernel/lib.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
concat_idents,
1919
const_fn_trait_bound,
2020
const_mut_refs,
21-
const_precise_live_drops, // TODO: Remove once we go to 1.58.x.
2221
const_ptr_offset_from,
2322
const_refs_to_cell,
2423
const_trait_impl,

0 commit comments

Comments
 (0)