Skip to content

Commit 8117b01

Browse files
author
Danilo Krummrich
committed
Merge tag 'topic/device-context-2025-04-17' into driver-core-next
Introduce "Bound" device context Introduce the "Bound" device context, such that it can be ensured to only ever pass a bound device to APIs that require this precondition. [1] This tag exists to share the patches from [1] between multiple trees. [1] https://lore.kernel.org/lkml/[email protected]/
2 parents 9bec944 + 7bd1710 commit 8117b01

File tree

5 files changed

+121
-65
lines changed

5 files changed

+121
-65
lines changed

rust/kernel/device.rs

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
str::CStr,
1010
types::{ARef, Opaque},
1111
};
12-
use core::{fmt, ptr};
12+
use core::{fmt, marker::PhantomData, ptr};
1313

1414
#[cfg(CONFIG_PRINTK)]
1515
use crate::c_str;
@@ -42,7 +42,7 @@ use crate::c_str;
4242
/// `bindings::device::release` is valid to be called from any thread, hence `ARef<Device>` can be
4343
/// dropped from any thread.
4444
#[repr(transparent)]
45-
pub struct Device(Opaque<bindings::device>);
45+
pub struct Device<Ctx: DeviceContext = Normal>(Opaque<bindings::device>, PhantomData<Ctx>);
4646

4747
impl Device {
4848
/// Creates a new reference-counted abstraction instance of an existing `struct device` pointer.
@@ -59,7 +59,9 @@ impl Device {
5959
// SAFETY: By the safety requirements ptr is valid
6060
unsafe { Self::as_ref(ptr) }.into()
6161
}
62+
}
6263

64+
impl<Ctx: DeviceContext> Device<Ctx> {
6365
/// Obtain the raw `struct device *`.
6466
pub(crate) fn as_raw(&self) -> *mut bindings::device {
6567
self.0.get()
@@ -189,6 +191,11 @@ impl Device {
189191
}
190192
}
191193

194+
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
195+
// argument.
196+
kernel::impl_device_context_deref!(unsafe { Device });
197+
kernel::impl_device_context_into_aref!(Device);
198+
192199
// SAFETY: Instances of `Device` are always reference-counted.
193200
unsafe impl crate::types::AlwaysRefCounted for Device {
194201
fn inc_ref(&self) {
@@ -225,16 +232,95 @@ pub struct Normal;
225232
/// any of the bus callbacks, such as `probe()`.
226233
pub struct Core;
227234

235+
/// The [`Bound`] context is the context of a bus specific device reference when it is guaranteed to
236+
/// be bound for the duration of its lifetime.
237+
pub struct Bound;
238+
228239
mod private {
229240
pub trait Sealed {}
230241

242+
impl Sealed for super::Bound {}
231243
impl Sealed for super::Core {}
232244
impl Sealed for super::Normal {}
233245
}
234246

247+
impl DeviceContext for Bound {}
235248
impl DeviceContext for Core {}
236249
impl DeviceContext for Normal {}
237250

251+
/// # Safety
252+
///
253+
/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
254+
/// generic argument of `$device`.
255+
#[doc(hidden)]
256+
#[macro_export]
257+
macro_rules! __impl_device_context_deref {
258+
(unsafe { $device:ident, $src:ty => $dst:ty }) => {
259+
impl ::core::ops::Deref for $device<$src> {
260+
type Target = $device<$dst>;
261+
262+
fn deref(&self) -> &Self::Target {
263+
let ptr: *const Self = self;
264+
265+
// CAST: `$device<$src>` and `$device<$dst>` transparently wrap the same type by the
266+
// safety requirement of the macro.
267+
let ptr = ptr.cast::<Self::Target>();
268+
269+
// SAFETY: `ptr` was derived from `&self`.
270+
unsafe { &*ptr }
271+
}
272+
}
273+
};
274+
}
275+
276+
/// Implement [`core::ops::Deref`] traits for allowed [`DeviceContext`] conversions of a (bus
277+
/// specific) device.
278+
///
279+
/// # Safety
280+
///
281+
/// The type given as `$device` must be a transparent wrapper of a type that doesn't depend on the
282+
/// generic argument of `$device`.
283+
#[macro_export]
284+
macro_rules! impl_device_context_deref {
285+
(unsafe { $device:ident }) => {
286+
// SAFETY: This macro has the exact same safety requirement as
287+
// `__impl_device_context_deref!`.
288+
::kernel::__impl_device_context_deref!(unsafe {
289+
$device,
290+
$crate::device::Core => $crate::device::Bound
291+
});
292+
293+
// SAFETY: This macro has the exact same safety requirement as
294+
// `__impl_device_context_deref!`.
295+
::kernel::__impl_device_context_deref!(unsafe {
296+
$device,
297+
$crate::device::Bound => $crate::device::Normal
298+
});
299+
};
300+
}
301+
302+
#[doc(hidden)]
303+
#[macro_export]
304+
macro_rules! __impl_device_context_into_aref {
305+
($src:ty, $device:tt) => {
306+
impl ::core::convert::From<&$device<$src>> for $crate::types::ARef<$device> {
307+
fn from(dev: &$device<$src>) -> Self {
308+
(&**dev).into()
309+
}
310+
}
311+
};
312+
}
313+
314+
/// Implement [`core::convert::From`], such that all `&Device<Ctx>` can be converted to an
315+
/// `ARef<Device>`.
316+
#[macro_export]
317+
macro_rules! impl_device_context_into_aref {
318+
($device:tt) => {
319+
::kernel::__impl_device_context_into_aref!($crate::device::Core, $device);
320+
::kernel::__impl_device_context_into_aref!($crate::device::Bound, $device);
321+
};
322+
}
323+
238324
#[doc(hidden)]
239325
#[macro_export]
240326
macro_rules! dev_printk {

rust/kernel/devres.rs

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use crate::{
99
alloc::Flags,
1010
bindings,
11-
device::Device,
11+
device::{Bound, Device},
1212
error::{Error, Result},
1313
ffi::c_void,
1414
prelude::*,
@@ -45,7 +45,7 @@ struct DevresInner<T> {
4545
/// # Example
4646
///
4747
/// ```no_run
48-
/// # use kernel::{bindings, c_str, device::Device, devres::Devres, io::{Io, IoRaw}};
48+
/// # use kernel::{bindings, c_str, device::{Bound, Device}, devres::Devres, io::{Io, IoRaw}};
4949
/// # use core::ops::Deref;
5050
///
5151
/// // See also [`pci::Bar`] for a real example.
@@ -83,13 +83,10 @@ struct DevresInner<T> {
8383
/// unsafe { Io::from_raw(&self.0) }
8484
/// }
8585
/// }
86-
/// # fn no_run() -> Result<(), Error> {
87-
/// # // SAFETY: Invalid usage; just for the example to get an `ARef<Device>` instance.
88-
/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) };
89-
///
86+
/// # fn no_run(dev: &Device<Bound>) -> Result<(), Error> {
9087
/// // SAFETY: Invalid usage for example purposes.
9188
/// let iomem = unsafe { IoMem::<{ core::mem::size_of::<u32>() }>::new(0xBAAAAAAD)? };
92-
/// let devres = Devres::new(&dev, iomem, GFP_KERNEL)?;
89+
/// let devres = Devres::new(dev, iomem, GFP_KERNEL)?;
9390
///
9491
/// let res = devres.try_access().ok_or(ENXIO)?;
9592
/// res.write8(0x42, 0x0);
@@ -99,7 +96,7 @@ struct DevresInner<T> {
9996
pub struct Devres<T>(Arc<DevresInner<T>>);
10097

10198
impl<T> DevresInner<T> {
102-
fn new(dev: &Device, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {
99+
fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Arc<DevresInner<T>>> {
103100
let inner = Arc::pin_init(
104101
pin_init!( DevresInner {
105102
dev: dev.into(),
@@ -171,15 +168,15 @@ impl<T> DevresInner<T> {
171168
impl<T> Devres<T> {
172169
/// Creates a new [`Devres`] instance of the given `data`. The `data` encapsulated within the
173170
/// returned `Devres` instance' `data` will be revoked once the device is detached.
174-
pub fn new(dev: &Device, data: T, flags: Flags) -> Result<Self> {
171+
pub fn new(dev: &Device<Bound>, data: T, flags: Flags) -> Result<Self> {
175172
let inner = DevresInner::new(dev, data, flags)?;
176173

177174
Ok(Devres(inner))
178175
}
179176

180177
/// Same as [`Devres::new`], but does not return a `Devres` instance. Instead the given `data`
181178
/// is owned by devres and will be revoked / dropped, once the device is detached.
182-
pub fn new_foreign_owned(dev: &Device, data: T, flags: Flags) -> Result {
179+
pub fn new_foreign_owned(dev: &Device<Bound>, data: T, flags: Flags) -> Result {
183180
let _ = DevresInner::new(dev, data, flags)?;
184181

185182
Ok(())

rust/kernel/dma.rs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
77
use crate::{
88
bindings, build_assert,
9-
device::Device,
9+
device::{Bound, Device},
1010
error::code::*,
1111
error::Result,
1212
transmute::{AsBytes, FromBytes},
@@ -22,10 +22,10 @@ use crate::{
2222
/// # Examples
2323
///
2424
/// ```
25-
/// use kernel::device::Device;
25+
/// # use kernel::device::{Bound, Device};
2626
/// use kernel::dma::{attrs::*, CoherentAllocation};
2727
///
28-
/// # fn test(dev: &Device) -> Result {
28+
/// # fn test(dev: &Device<Bound>) -> Result {
2929
/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
3030
/// let c: CoherentAllocation<u64> =
3131
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?;
@@ -143,16 +143,16 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
143143
/// # Examples
144144
///
145145
/// ```
146-
/// use kernel::device::Device;
146+
/// # use kernel::device::{Bound, Device};
147147
/// use kernel::dma::{attrs::*, CoherentAllocation};
148148
///
149-
/// # fn test(dev: &Device) -> Result {
149+
/// # fn test(dev: &Device<Bound>) -> Result {
150150
/// let c: CoherentAllocation<u64> =
151151
/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
152152
/// # Ok::<(), Error>(()) }
153153
/// ```
154154
pub fn alloc_attrs(
155-
dev: &Device,
155+
dev: &Device<Bound>,
156156
count: usize,
157157
gfp_flags: kernel::alloc::Flags,
158158
dma_attrs: Attrs,
@@ -194,7 +194,7 @@ impl<T: AsBytes + FromBytes> CoherentAllocation<T> {
194194
/// Performs the same functionality as [`CoherentAllocation::alloc_attrs`], except the
195195
/// `dma_attrs` is 0 by default.
196196
pub fn alloc_coherent(
197-
dev: &Device,
197+
dev: &Device<Bound>,
198198
count: usize,
199199
gfp_flags: kernel::alloc::Flags,
200200
) -> Result<CoherentAllocation<T>> {

rust/kernel/pci.rs

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -360,11 +360,13 @@ impl<const SIZE: usize> Deref for Bar<SIZE> {
360360
}
361361
}
362362

363-
impl Device {
363+
impl<Ctx: device::DeviceContext> Device<Ctx> {
364364
fn as_raw(&self) -> *mut bindings::pci_dev {
365365
self.0.get()
366366
}
367+
}
367368

369+
impl Device {
368370
/// Returns the PCI vendor ID.
369371
pub fn vendor_id(&self) -> u16 {
370372
// SAFETY: `self.as_raw` is a valid pointer to a `struct pci_dev`.
@@ -388,7 +390,9 @@ impl Device {
388390
// - by its type invariant `self.as_raw` is always a valid pointer to a `struct pci_dev`.
389391
Ok(unsafe { bindings::pci_resource_len(self.as_raw(), bar.try_into()?) })
390392
}
393+
}
391394

395+
impl Device<device::Bound> {
392396
/// Mapps an entire PCI-BAR after performing a region-request on it. I/O operation bound checks
393397
/// can be performed on compile time for offsets (plus the requested type size) < SIZE.
394398
pub fn iomap_region_sized<const SIZE: usize>(
@@ -422,25 +426,10 @@ impl Device<device::Core> {
422426
}
423427
}
424428

425-
impl Deref for Device<device::Core> {
426-
type Target = Device;
427-
428-
fn deref(&self) -> &Self::Target {
429-
let ptr: *const Self = self;
430-
431-
// CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::pci_dev>`.
432-
let ptr = ptr.cast::<Device>();
433-
434-
// SAFETY: `ptr` was derived from `&self`.
435-
unsafe { &*ptr }
436-
}
437-
}
438-
439-
impl From<&Device<device::Core>> for ARef<Device> {
440-
fn from(dev: &Device<device::Core>) -> Self {
441-
(&**dev).into()
442-
}
443-
}
429+
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
430+
// argument.
431+
kernel::impl_device_context_deref!(unsafe { Device });
432+
kernel::impl_device_context_into_aref!(Device);
444433

445434
// SAFETY: Instances of `Device` are always reference-counted.
446435
unsafe impl crate::types::AlwaysRefCounted for Device {
@@ -455,8 +444,8 @@ unsafe impl crate::types::AlwaysRefCounted for Device {
455444
}
456445
}
457446

458-
impl AsRef<device::Device> for Device {
459-
fn as_ref(&self) -> &device::Device {
447+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
448+
fn as_ref(&self) -> &device::Device<Ctx> {
460449
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
461450
// `struct pci_dev`.
462451
let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };

rust/kernel/platform.rs

Lines changed: 8 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@ use crate::{
1010
of,
1111
prelude::*,
1212
str::CStr,
13-
types::{ARef, ForeignOwnable, Opaque},
13+
types::{ForeignOwnable, Opaque},
1414
ThisModule,
1515
};
1616

1717
use core::{
1818
marker::PhantomData,
19-
ops::Deref,
2019
ptr::{addr_of_mut, NonNull},
2120
};
2221

@@ -184,31 +183,16 @@ pub struct Device<Ctx: device::DeviceContext = device::Normal>(
184183
PhantomData<Ctx>,
185184
);
186185

187-
impl Device {
186+
impl<Ctx: device::DeviceContext> Device<Ctx> {
188187
fn as_raw(&self) -> *mut bindings::platform_device {
189188
self.0.get()
190189
}
191190
}
192191

193-
impl Deref for Device<device::Core> {
194-
type Target = Device;
195-
196-
fn deref(&self) -> &Self::Target {
197-
let ptr: *const Self = self;
198-
199-
// CAST: `Device<Ctx>` is a transparent wrapper of `Opaque<bindings::platform_device>`.
200-
let ptr = ptr.cast::<Device>();
201-
202-
// SAFETY: `ptr` was derived from `&self`.
203-
unsafe { &*ptr }
204-
}
205-
}
206-
207-
impl From<&Device<device::Core>> for ARef<Device> {
208-
fn from(dev: &Device<device::Core>) -> Self {
209-
(&**dev).into()
210-
}
211-
}
192+
// SAFETY: `Device` is a transparent wrapper of a type that doesn't depend on `Device`'s generic
193+
// argument.
194+
kernel::impl_device_context_deref!(unsafe { Device });
195+
kernel::impl_device_context_into_aref!(Device);
212196

213197
// SAFETY: Instances of `Device` are always reference-counted.
214198
unsafe impl crate::types::AlwaysRefCounted for Device {
@@ -223,8 +207,8 @@ unsafe impl crate::types::AlwaysRefCounted for Device {
223207
}
224208
}
225209

226-
impl AsRef<device::Device> for Device {
227-
fn as_ref(&self) -> &device::Device {
210+
impl<Ctx: device::DeviceContext> AsRef<device::Device<Ctx>> for Device<Ctx> {
211+
fn as_ref(&self) -> &device::Device<Ctx> {
228212
// SAFETY: By the type invariant of `Self`, `self.as_raw()` is a pointer to a valid
229213
// `struct platform_device`.
230214
let dev = unsafe { addr_of_mut!((*self.as_raw()).dev) };

0 commit comments

Comments
 (0)