xref: /linux-6.15/rust/kernel/device_id.rs (revision 9b90864b)
1*9b90864bSDanilo Krummrich // SPDX-License-Identifier: GPL-2.0
2*9b90864bSDanilo Krummrich 
3*9b90864bSDanilo Krummrich //! Generic implementation of device IDs.
4*9b90864bSDanilo Krummrich //!
5*9b90864bSDanilo Krummrich //! Each bus / subsystem that matches device and driver through a bus / subsystem specific ID is
6*9b90864bSDanilo Krummrich //! expected to implement [`RawDeviceId`].
7*9b90864bSDanilo Krummrich 
8*9b90864bSDanilo Krummrich use core::mem::MaybeUninit;
9*9b90864bSDanilo Krummrich 
10*9b90864bSDanilo Krummrich /// Marker trait to indicate a Rust device ID type represents a corresponding C device ID type.
11*9b90864bSDanilo Krummrich ///
12*9b90864bSDanilo Krummrich /// This is meant to be implemented by buses/subsystems so that they can use [`IdTable`] to
13*9b90864bSDanilo Krummrich /// guarantee (at compile-time) zero-termination of device id tables provided by drivers.
14*9b90864bSDanilo Krummrich ///
15*9b90864bSDanilo Krummrich /// # Safety
16*9b90864bSDanilo Krummrich ///
17*9b90864bSDanilo Krummrich /// Implementers must ensure that:
18*9b90864bSDanilo Krummrich ///   - `Self` is layout-compatible with [`RawDeviceId::RawType`]; i.e. it's safe to transmute to
19*9b90864bSDanilo Krummrich ///     `RawDeviceId`.
20*9b90864bSDanilo Krummrich ///
21*9b90864bSDanilo Krummrich ///     This requirement is needed so `IdArray::new` can convert `Self` to `RawType` when building
22*9b90864bSDanilo Krummrich ///     the ID table.
23*9b90864bSDanilo Krummrich ///
24*9b90864bSDanilo Krummrich ///     Ideally, this should be achieved using a const function that does conversion instead of
25*9b90864bSDanilo Krummrich ///     transmute; however, const trait functions relies on `const_trait_impl` unstable feature,
26*9b90864bSDanilo Krummrich ///     which is broken/gone in Rust 1.73.
27*9b90864bSDanilo Krummrich ///
28*9b90864bSDanilo Krummrich ///   - `DRIVER_DATA_OFFSET` is the offset of context/data field of the device ID (usually named
29*9b90864bSDanilo Krummrich ///     `driver_data`) of the device ID, the field is suitable sized to write a `usize` value.
30*9b90864bSDanilo Krummrich ///
31*9b90864bSDanilo Krummrich ///     Similar to the previous requirement, the data should ideally be added during `Self` to
32*9b90864bSDanilo Krummrich ///     `RawType` conversion, but there's currently no way to do it when using traits in const.
33*9b90864bSDanilo Krummrich pub unsafe trait RawDeviceId {
34*9b90864bSDanilo Krummrich     /// The raw type that holds the device id.
35*9b90864bSDanilo Krummrich     ///
36*9b90864bSDanilo Krummrich     /// Id tables created from [`Self`] are going to hold this type in its zero-terminated array.
37*9b90864bSDanilo Krummrich     type RawType: Copy;
38*9b90864bSDanilo Krummrich 
39*9b90864bSDanilo Krummrich     /// The offset to the context/data field.
40*9b90864bSDanilo Krummrich     const DRIVER_DATA_OFFSET: usize;
41*9b90864bSDanilo Krummrich 
42*9b90864bSDanilo Krummrich     /// The index stored at `DRIVER_DATA_OFFSET` of the implementor of the [`RawDeviceId`] trait.
index(&self) -> usize43*9b90864bSDanilo Krummrich     fn index(&self) -> usize;
44*9b90864bSDanilo Krummrich }
45*9b90864bSDanilo Krummrich 
46*9b90864bSDanilo Krummrich /// A zero-terminated device id array.
47*9b90864bSDanilo Krummrich #[repr(C)]
48*9b90864bSDanilo Krummrich pub struct RawIdArray<T: RawDeviceId, const N: usize> {
49*9b90864bSDanilo Krummrich     ids: [T::RawType; N],
50*9b90864bSDanilo Krummrich     sentinel: MaybeUninit<T::RawType>,
51*9b90864bSDanilo Krummrich }
52*9b90864bSDanilo Krummrich 
53*9b90864bSDanilo Krummrich impl<T: RawDeviceId, const N: usize> RawIdArray<T, N> {
54*9b90864bSDanilo Krummrich     #[doc(hidden)]
size(&self) -> usize55*9b90864bSDanilo Krummrich     pub const fn size(&self) -> usize {
56*9b90864bSDanilo Krummrich         core::mem::size_of::<Self>()
57*9b90864bSDanilo Krummrich     }
58*9b90864bSDanilo Krummrich }
59*9b90864bSDanilo Krummrich 
60*9b90864bSDanilo Krummrich /// A zero-terminated device id array, followed by context data.
61*9b90864bSDanilo Krummrich #[repr(C)]
62*9b90864bSDanilo Krummrich pub struct IdArray<T: RawDeviceId, U, const N: usize> {
63*9b90864bSDanilo Krummrich     raw_ids: RawIdArray<T, N>,
64*9b90864bSDanilo Krummrich     id_infos: [U; N],
65*9b90864bSDanilo Krummrich }
66*9b90864bSDanilo Krummrich 
67*9b90864bSDanilo Krummrich impl<T: RawDeviceId, U, const N: usize> IdArray<T, U, N> {
68*9b90864bSDanilo Krummrich     /// Creates a new instance of the array.
69*9b90864bSDanilo Krummrich     ///
70*9b90864bSDanilo Krummrich     /// The contents are derived from the given identifiers and context information.
new(ids: [(T, U); N]) -> Self71*9b90864bSDanilo Krummrich     pub const fn new(ids: [(T, U); N]) -> Self {
72*9b90864bSDanilo Krummrich         let mut raw_ids = [const { MaybeUninit::<T::RawType>::uninit() }; N];
73*9b90864bSDanilo Krummrich         let mut infos = [const { MaybeUninit::uninit() }; N];
74*9b90864bSDanilo Krummrich 
75*9b90864bSDanilo Krummrich         let mut i = 0usize;
76*9b90864bSDanilo Krummrich         while i < N {
77*9b90864bSDanilo Krummrich             // SAFETY: by the safety requirement of `RawDeviceId`, we're guaranteed that `T` is
78*9b90864bSDanilo Krummrich             // layout-wise compatible with `RawType`.
79*9b90864bSDanilo Krummrich             raw_ids[i] = unsafe { core::mem::transmute_copy(&ids[i].0) };
80*9b90864bSDanilo Krummrich             // SAFETY: by the safety requirement of `RawDeviceId`, this would be effectively
81*9b90864bSDanilo Krummrich             // `raw_ids[i].driver_data = i;`.
82*9b90864bSDanilo Krummrich             unsafe {
83*9b90864bSDanilo Krummrich                 raw_ids[i]
84*9b90864bSDanilo Krummrich                     .as_mut_ptr()
85*9b90864bSDanilo Krummrich                     .byte_offset(T::DRIVER_DATA_OFFSET as _)
86*9b90864bSDanilo Krummrich                     .cast::<usize>()
87*9b90864bSDanilo Krummrich                     .write(i);
88*9b90864bSDanilo Krummrich             }
89*9b90864bSDanilo Krummrich 
90*9b90864bSDanilo Krummrich             // SAFETY: this is effectively a move: `infos[i] = ids[i].1`. We make a copy here but
91*9b90864bSDanilo Krummrich             // later forget `ids`.
92*9b90864bSDanilo Krummrich             infos[i] = MaybeUninit::new(unsafe { core::ptr::read(&ids[i].1) });
93*9b90864bSDanilo Krummrich             i += 1;
94*9b90864bSDanilo Krummrich         }
95*9b90864bSDanilo Krummrich 
96*9b90864bSDanilo Krummrich         core::mem::forget(ids);
97*9b90864bSDanilo Krummrich 
98*9b90864bSDanilo Krummrich         Self {
99*9b90864bSDanilo Krummrich             raw_ids: RawIdArray {
100*9b90864bSDanilo Krummrich                 // SAFETY: this is effectively `array_assume_init`, which is unstable, so we use
101*9b90864bSDanilo Krummrich                 // `transmute_copy` instead. We have initialized all elements of `raw_ids` so this
102*9b90864bSDanilo Krummrich                 // `array_assume_init` is safe.
103*9b90864bSDanilo Krummrich                 ids: unsafe { core::mem::transmute_copy(&raw_ids) },
104*9b90864bSDanilo Krummrich                 sentinel: MaybeUninit::zeroed(),
105*9b90864bSDanilo Krummrich             },
106*9b90864bSDanilo Krummrich             // SAFETY: We have initialized all elements of `infos` so this `array_assume_init` is
107*9b90864bSDanilo Krummrich             // safe.
108*9b90864bSDanilo Krummrich             id_infos: unsafe { core::mem::transmute_copy(&infos) },
109*9b90864bSDanilo Krummrich         }
110*9b90864bSDanilo Krummrich     }
111*9b90864bSDanilo Krummrich 
112*9b90864bSDanilo Krummrich     /// Reference to the contained [`RawIdArray`].
raw_ids(&self) -> &RawIdArray<T, N>113*9b90864bSDanilo Krummrich     pub const fn raw_ids(&self) -> &RawIdArray<T, N> {
114*9b90864bSDanilo Krummrich         &self.raw_ids
115*9b90864bSDanilo Krummrich     }
116*9b90864bSDanilo Krummrich }
117*9b90864bSDanilo Krummrich 
118*9b90864bSDanilo Krummrich /// A device id table.
119*9b90864bSDanilo Krummrich ///
120*9b90864bSDanilo Krummrich /// This trait is only implemented by `IdArray`.
121*9b90864bSDanilo Krummrich ///
122*9b90864bSDanilo Krummrich /// The purpose of this trait is to allow `&'static dyn IdArray<T, U>` to be in context when `N` in
123*9b90864bSDanilo Krummrich /// `IdArray` doesn't matter.
124*9b90864bSDanilo Krummrich pub trait IdTable<T: RawDeviceId, U> {
125*9b90864bSDanilo Krummrich     /// Obtain the pointer to the ID table.
as_ptr(&self) -> *const T::RawType126*9b90864bSDanilo Krummrich     fn as_ptr(&self) -> *const T::RawType;
127*9b90864bSDanilo Krummrich 
128*9b90864bSDanilo Krummrich     /// Obtain the pointer to the bus specific device ID from an index.
id(&self, index: usize) -> &T::RawType129*9b90864bSDanilo Krummrich     fn id(&self, index: usize) -> &T::RawType;
130*9b90864bSDanilo Krummrich 
131*9b90864bSDanilo Krummrich     /// Obtain the pointer to the driver-specific information from an index.
info(&self, index: usize) -> &U132*9b90864bSDanilo Krummrich     fn info(&self, index: usize) -> &U;
133*9b90864bSDanilo Krummrich }
134*9b90864bSDanilo Krummrich 
135*9b90864bSDanilo Krummrich impl<T: RawDeviceId, U, const N: usize> IdTable<T, U> for IdArray<T, U, N> {
as_ptr(&self) -> *const T::RawType136*9b90864bSDanilo Krummrich     fn as_ptr(&self) -> *const T::RawType {
137*9b90864bSDanilo Krummrich         // This cannot be `self.ids.as_ptr()`, as the return pointer must have correct provenance
138*9b90864bSDanilo Krummrich         // to access the sentinel.
139*9b90864bSDanilo Krummrich         (self as *const Self).cast()
140*9b90864bSDanilo Krummrich     }
141*9b90864bSDanilo Krummrich 
id(&self, index: usize) -> &T::RawType142*9b90864bSDanilo Krummrich     fn id(&self, index: usize) -> &T::RawType {
143*9b90864bSDanilo Krummrich         &self.raw_ids.ids[index]
144*9b90864bSDanilo Krummrich     }
145*9b90864bSDanilo Krummrich 
info(&self, index: usize) -> &U146*9b90864bSDanilo Krummrich     fn info(&self, index: usize) -> &U {
147*9b90864bSDanilo Krummrich         &self.id_infos[index]
148*9b90864bSDanilo Krummrich     }
149*9b90864bSDanilo Krummrich }
150*9b90864bSDanilo Krummrich 
151*9b90864bSDanilo Krummrich /// Create device table alias for modpost.
152*9b90864bSDanilo Krummrich #[macro_export]
153*9b90864bSDanilo Krummrich macro_rules! module_device_table {
154*9b90864bSDanilo Krummrich     ($table_type: literal, $module_table_name:ident, $table_name:ident) => {
155*9b90864bSDanilo Krummrich         #[rustfmt::skip]
156*9b90864bSDanilo Krummrich         #[export_name =
157*9b90864bSDanilo Krummrich             concat!("__mod_device_table__", $table_type,
158*9b90864bSDanilo Krummrich                     "__", module_path!(),
159*9b90864bSDanilo Krummrich                     "_", line!(),
160*9b90864bSDanilo Krummrich                     "_", stringify!($table_name))
161*9b90864bSDanilo Krummrich         ]
162*9b90864bSDanilo Krummrich         static $module_table_name: [core::mem::MaybeUninit<u8>; $table_name.raw_ids().size()] =
163*9b90864bSDanilo Krummrich             unsafe { core::mem::transmute_copy($table_name.raw_ids()) };
164*9b90864bSDanilo Krummrich     };
165*9b90864bSDanilo Krummrich }
166