Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

rust: auxiliary: add auxiliary device / driver abstractions

Implement the basic auxiliary abstractions required to implement a
driver matching an auxiliary device.

The design and implementation is analogous to PCI and platform and is
based on the generic device / driver abstractions.

Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Link: https://lore.kernel.org/r/20250414131934.28418-4-dakr@kernel.org
[ Fix typos, `let _ =` => `drop()`, use `kernel::ffi`. - Danilo ]
Signed-off-by: Danilo Krummrich <dakr@kernel.org>

+303 -1
+2
MAINTAINERS
··· 3872 3872 F: Documentation/driver-api/auxiliary_bus.rst 3873 3873 F: drivers/base/auxiliary.c 3874 3874 F: include/linux/auxiliary_bus.h 3875 + F: rust/helpers/auxiliary.c 3876 + F: rust/kernel/auxiliary.rs 3875 3877 3876 3878 AUXILIARY DISPLAY DRIVERS 3877 3879 M: Andy Shevchenko <andy@kernel.org>
+1
rust/bindings/bindings_helper.h
··· 7 7 */ 8 8 9 9 #include <kunit/test.h> 10 + #include <linux/auxiliary_bus.h> 10 11 #include <linux/blk-mq.h> 11 12 #include <linux/blk_types.h> 12 13 #include <linux/blkdev.h>
+23
rust/helpers/auxiliary.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + #include <linux/auxiliary_bus.h> 4 + 5 + void rust_helper_auxiliary_set_drvdata(struct auxiliary_device *adev, void *data) 6 + { 7 + auxiliary_set_drvdata(adev, data); 8 + } 9 + 10 + void *rust_helper_auxiliary_get_drvdata(struct auxiliary_device *adev) 11 + { 12 + return auxiliary_get_drvdata(adev); 13 + } 14 + 15 + void rust_helper_auxiliary_device_uninit(struct auxiliary_device *adev) 16 + { 17 + return auxiliary_device_uninit(adev); 18 + } 19 + 20 + void rust_helper_auxiliary_device_delete(struct auxiliary_device *adev) 21 + { 22 + return auxiliary_device_delete(adev); 23 + }
+1
rust/helpers/helpers.c
··· 7 7 * Sorted alphabetically. 8 8 */ 9 9 10 + #include "auxiliary.c" 10 11 #include "blk.c" 11 12 #include "bug.c" 12 13 #include "build_assert.c"
+274
rust/kernel/auxiliary.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Abstractions for the auxiliary bus. 4 + //! 5 + //! C header: [`include/linux/auxiliary_bus.h`](srctree/include/linux/auxiliary_bus.h) 6 + 7 + use crate::{ 8 + bindings, device, 9 + device_id::RawDeviceId, 10 + driver, 11 + error::{to_result, Result}, 12 + prelude::*, 13 + str::CStr, 14 + types::{ForeignOwnable, Opaque}, 15 + ThisModule, 16 + }; 17 + use core::{ 18 + marker::PhantomData, 19 + ptr::{addr_of_mut, NonNull}, 20 + }; 21 + 22 + /// An adapter for the registration of auxiliary drivers. 23 + pub struct Adapter<T: Driver>(T); 24 + 25 + // SAFETY: A call to `unregister` for a given instance of `RegType` is guaranteed to be valid if 26 + // a preceding call to `register` has been successful. 27 + unsafe impl<T: Driver + 'static> driver::RegistrationOps for Adapter<T> { 28 + type RegType = bindings::auxiliary_driver; 29 + 30 + unsafe fn register( 31 + adrv: &Opaque<Self::RegType>, 32 + name: &'static CStr, 33 + module: &'static ThisModule, 34 + ) -> Result { 35 + // SAFETY: It's safe to set the fields of `struct auxiliary_driver` on initialization. 36 + unsafe { 37 + (*adrv.get()).name = name.as_char_ptr(); 38 + (*adrv.get()).probe = Some(Self::probe_callback); 39 + (*adrv.get()).remove = Some(Self::remove_callback); 40 + (*adrv.get()).id_table = T::ID_TABLE.as_ptr(); 41 + } 42 + 43 + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. 44 + to_result(unsafe { 45 + bindings::__auxiliary_driver_register(adrv.get(), module.0, name.as_char_ptr()) 46 + }) 47 + } 48 + 49 + unsafe fn unregister(adrv: &Opaque<Self::RegType>) { 50 + // SAFETY: `adrv` is guaranteed to be a valid `RegType`. 51 + unsafe { bindings::auxiliary_driver_unregister(adrv.get()) } 52 + } 53 + } 54 + 55 + impl<T: Driver + 'static> Adapter<T> { 56 + extern "C" fn probe_callback( 57 + adev: *mut bindings::auxiliary_device, 58 + id: *const bindings::auxiliary_device_id, 59 + ) -> kernel::ffi::c_int { 60 + // SAFETY: The auxiliary bus only ever calls the probe callback with a valid pointer to a 61 + // `struct auxiliary_device`. 62 + // 63 + // INVARIANT: `adev` is valid for the duration of `probe_callback()`. 64 + let adev = unsafe { &*adev.cast::<Device<device::Core>>() }; 65 + 66 + // SAFETY: `DeviceId` is a `#[repr(transparent)`] wrapper of `struct auxiliary_device_id` 67 + // and does not add additional invariants, so it's safe to transmute. 68 + let id = unsafe { &*id.cast::<DeviceId>() }; 69 + let info = T::ID_TABLE.info(id.index()); 70 + 71 + match T::probe(adev, info) { 72 + Ok(data) => { 73 + // Let the `struct auxiliary_device` own a reference of the driver's private data. 74 + // SAFETY: By the type invariant `adev.as_raw` returns a valid pointer to a 75 + // `struct auxiliary_device`. 76 + unsafe { bindings::auxiliary_set_drvdata(adev.as_raw(), data.into_foreign()) }; 77 + } 78 + Err(err) => return Error::to_errno(err), 79 + } 80 + 81 + 0 82 + } 83 + 84 + extern "C" fn remove_callback(adev: *mut bindings::auxiliary_device) { 85 + // SAFETY: The auxiliary bus only ever calls the remove callback with a valid pointer to a 86 + // `struct auxiliary_device`. 87 + let ptr = unsafe { bindings::auxiliary_get_drvdata(adev) }; 88 + 89 + // SAFETY: `remove_callback` is only ever called after a successful call to 90 + // `probe_callback`, hence it's guaranteed that `ptr` points to a valid and initialized 91 + // `KBox<T>` pointer created through `KBox::into_foreign`. 92 + drop(unsafe { KBox::<T>::from_foreign(ptr) }); 93 + } 94 + } 95 + 96 + /// Declares a kernel module that exposes a single auxiliary driver. 97 + #[macro_export] 98 + macro_rules! module_auxiliary_driver { 99 + ($($f:tt)*) => { 100 + $crate::module_driver!(<T>, $crate::auxiliary::Adapter<T>, { $($f)* }); 101 + }; 102 + } 103 + 104 + /// Abstraction for `bindings::auxiliary_device_id`. 105 + #[repr(transparent)] 106 + #[derive(Clone, Copy)] 107 + pub struct DeviceId(bindings::auxiliary_device_id); 108 + 109 + impl DeviceId { 110 + /// Create a new [`DeviceId`] from name. 111 + pub const fn new(modname: &'static CStr, name: &'static CStr) -> Self { 112 + let name = name.as_bytes_with_nul(); 113 + let modname = modname.as_bytes_with_nul(); 114 + 115 + // TODO: Replace with `bindings::auxiliary_device_id::default()` once stabilized for 116 + // `const`. 117 + // 118 + // SAFETY: FFI type is valid to be zero-initialized. 119 + let mut id: bindings::auxiliary_device_id = unsafe { core::mem::zeroed() }; 120 + 121 + let mut i = 0; 122 + while i < modname.len() { 123 + id.name[i] = modname[i]; 124 + i += 1; 125 + } 126 + 127 + // Reuse the space of the NULL terminator. 128 + id.name[i - 1] = b'.'; 129 + 130 + let mut j = 0; 131 + while j < name.len() { 132 + id.name[i] = name[j]; 133 + i += 1; 134 + j += 1; 135 + } 136 + 137 + Self(id) 138 + } 139 + } 140 + 141 + // SAFETY: 142 + // * `DeviceId` is a `#[repr(transparent)`] wrapper of `auxiliary_device_id` and does not add 143 + // additional invariants, so it's safe to transmute to `RawType`. 144 + // * `DRIVER_DATA_OFFSET` is the offset to the `driver_data` field. 145 + unsafe impl RawDeviceId for DeviceId { 146 + type RawType = bindings::auxiliary_device_id; 147 + 148 + const DRIVER_DATA_OFFSET: usize = 149 + core::mem::offset_of!(bindings::auxiliary_device_id, driver_data); 150 + 151 + fn index(&self) -> usize { 152 + self.0.driver_data 153 + } 154 + } 155 + 156 + /// IdTable type for auxiliary drivers. 157 + pub type IdTable<T> = &'static dyn kernel::device_id::IdTable<DeviceId, T>; 158 + 159 + /// Create a auxiliary `IdTable` with its alias for modpost. 160 + #[macro_export] 161 + macro_rules! auxiliary_device_table { 162 + ($table_name:ident, $module_table_name:ident, $id_info_type: ty, $table_data: expr) => { 163 + const $table_name: $crate::device_id::IdArray< 164 + $crate::auxiliary::DeviceId, 165 + $id_info_type, 166 + { $table_data.len() }, 167 + > = $crate::device_id::IdArray::new($table_data); 168 + 169 + $crate::module_device_table!("auxiliary", $module_table_name, $table_name); 170 + }; 171 + } 172 + 173 + /// The auxiliary driver trait. 174 + /// 175 + /// Drivers must implement this trait in order to get an auxiliary driver registered. 176 + pub trait Driver { 177 + /// The type holding information about each device id supported by the driver. 178 + /// 179 + /// TODO: Use associated_type_defaults once stabilized: 180 + /// 181 + /// type IdInfo: 'static = (); 182 + type IdInfo: 'static; 183 + 184 + /// The table of device ids supported by the driver. 185 + const ID_TABLE: IdTable<Self::IdInfo>; 186 + 187 + /// Auxiliary driver probe. 188 + /// 189 + /// Called when an auxiliary device is matches a corresponding driver. 190 + fn probe(dev: &Device<device::Core>, id_info: &Self::IdInfo) -> Result<Pin<KBox<Self>>>; 191 + } 192 + 193 + /// The auxiliary device representation. 194 + /// 195 + /// This structure represents the Rust abstraction for a C `struct auxiliary_device`. The 196 + /// implementation abstracts the usage of an already existing C `struct auxiliary_device` within 197 + /// Rust code that we get passed from the C side. 198 + /// 199 + /// # Invariants 200 + /// 201 + /// A [`Device`] instance represents a valid `struct auxiliary_device` created by the C portion of 202 + /// the kernel. 203 + #[repr(transparent)] 204 + pub struct Device<Ctx: device::DeviceContext = device::Normal>( 205 + Opaque<bindings::auxiliary_device>, 206 + PhantomData<Ctx>, 207 + ); 208 + 209 + impl<Ctx: device::DeviceContext> Device<Ctx> { 210 + fn as_raw(&self) -> *mut bindings::auxiliary_device { 211 + self.0.get() 212 + } 213 + 214 + /// Returns the auxiliary device' id. 215 + pub fn id(&self) -> u32 { 216 + // SAFETY: By the type invariant `self.as_raw()` is a valid pointer to a 217 + // `struct auxiliary_device`. 218 + unsafe { (*self.as_raw()).id } 219 + } 220 + 221 + /// Returns a reference to the parent [`device::Device`], if any. 222 + pub fn parent(&self) -> Option<&device::Device> { 223 + let ptr: *const Self = self; 224 + // CAST: `Device<Ctx: DeviceContext>` types are transparent to each other. 225 + let ptr: *const Device = ptr.cast(); 226 + // SAFETY: `ptr` was derived from `&self`. 227 + let this = unsafe { &*ptr }; 228 + 229 + this.as_ref().parent() 230 + } 231 + } 232 + 233 + // SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic 234 + // argument. 235 + kernel::impl_device_context_deref!(unsafe { Device }); 236 + kernel::impl_device_context_into_aref!(Device); 237 + 238 + // SAFETY: Instances of `Device` are always reference-counted. 239 + unsafe impl crate::types::AlwaysRefCounted for Device { 240 + fn inc_ref(&self) { 241 + // SAFETY: The existence of a shared reference guarantees that the refcount is non-zero. 242 + unsafe { bindings::get_device(self.as_ref().as_raw()) }; 243 + } 244 + 245 + unsafe fn dec_ref(obj: NonNull<Self>) { 246 + // CAST: `Self` a transparent wrapper of `bindings::auxiliary_device`. 247 + let adev: *mut bindings::auxiliary_device = obj.cast().as_ptr(); 248 + 249 + // SAFETY: By the type invariant of `Self`, `adev` is a pointer to a valid 250 + // `struct auxiliary_device`. 251 + let dev = unsafe { addr_of_mut!((*adev).dev) }; 252 + 253 + // SAFETY: The safety requirements guarantee that the refcount is non-zero. 254 + unsafe { bindings::put_device(dev) } 255 + } 256 + } 257 + 258 + impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> { 259 + fn as_ref(&self) -> &device::Device<Ctx> { 260 + // SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid 261 + // `struct auxiliary_device`. 262 + let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) }; 263 + 264 + // SAFETY: `dev` points to a valid `struct device`. 265 + unsafe { device::Device::as_ref(dev) } 266 + } 267 + } 268 + 269 + // SAFETY: A `Device` is always reference-counted and can be released from any thread. 270 + unsafe impl Send for Device {} 271 + 272 + // SAFETY: `Device` can be shared among threads because all methods of `Device` 273 + // (i.e. `Device<Normal>) are thread safe. 274 + unsafe impl Sync for Device {}
-1
rust/kernel/device.rs
··· 68 68 } 69 69 70 70 /// Returns a reference to the parent device, if any. 71 - #[expect(unused)] 72 71 pub(crate) fn parent(&self) -> Option<&Self> { 73 72 // SAFETY: 74 73 // - By the type invariant `self.as_raw()` is always valid.
+2
rust/kernel/lib.rs
··· 38 38 pub use ffi; 39 39 40 40 pub mod alloc; 41 + #[cfg(CONFIG_AUXILIARY_BUS)] 42 + pub mod auxiliary; 41 43 #[cfg(CONFIG_BLOCK)] 42 44 pub mod block; 43 45 #[doc(hidden)]