Skip to content

Commit 101d668

Browse files
author
Danilo Krummrich
committed
rust: dma: add DMA addressing capabilities
Implement `dma_set_mask()`, `dma_set_coherent_mask()` and `dma_set_mask_and_coherent()` in the `dma::Device` trait. Those methods are used to set up the device's DMA addressing capabilities. Reviewed-by: Abdiel Janulgue <abdiel.janulgue@gmail.com> Reviewed-by: Daniel Almeida <daniel.almeida@collabora.com> Reviewed-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Link: https://lore.kernel.org/r/20250716150354.51081-3-dakr@kernel.org [ Add DmaMask::try_new(). - Danilo ] Signed-off-by: Danilo Krummrich <dakr@kernel.org>
1 parent d06d5f6 commit 101d668

2 files changed

Lines changed: 144 additions & 4 deletions

File tree

rust/helpers/dma.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ void rust_helper_dma_free_attrs(struct device *dev, size_t size, void *cpu_addr,
1414
{
1515
dma_free_attrs(dev, size, cpu_addr, dma_handle, attrs);
1616
}
17+
18+
int rust_helper_dma_set_mask_and_coherent(struct device *dev, u64 mask)
19+
{
20+
return dma_set_mask_and_coherent(dev, mask);
21+
}

rust/kernel/dma.rs

Lines changed: 139 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,9 @@
66
77
use crate::{
88
bindings, build_assert, device,
9-
device::Bound,
10-
error::code::*,
11-
error::Result,
9+
device::{Bound, Core},
10+
error::{to_result, Result},
11+
prelude::*,
1212
transmute::{AsBytes, FromBytes},
1313
types::ARef,
1414
};
@@ -18,7 +18,142 @@ use crate::{
1818
/// The [`dma::Device`](Device) trait should be implemented by bus specific device representations,
1919
/// where the underlying bus is DMA capable, such as [`pci::Device`](::kernel::pci::Device) or
2020
/// [`platform::Device`](::kernel::platform::Device).
21-
pub trait Device: AsRef<device::Device<Core>> {}
21+
pub trait Device: AsRef<device::Device<Core>> {
22+
/// Set up the device's DMA streaming addressing capabilities.
23+
///
24+
/// This method is usually called once from `probe()` as soon as the device capabilities are
25+
/// known.
26+
///
27+
/// # Safety
28+
///
29+
/// This method must not be called concurrently with any DMA allocation or mapping primitives,
30+
/// such as [`CoherentAllocation::alloc_attrs`].
31+
unsafe fn dma_set_mask(&self, mask: DmaMask) -> Result {
32+
// SAFETY:
33+
// - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
34+
// - The safety requirement of this function guarantees that there are no concurrent calls
35+
// to DMA allocation and mapping primitives using this mask.
36+
to_result(unsafe { bindings::dma_set_mask(self.as_ref().as_raw(), mask.value()) })
37+
}
38+
39+
/// Set up the device's DMA coherent addressing capabilities.
40+
///
41+
/// This method is usually called once from `probe()` as soon as the device capabilities are
42+
/// known.
43+
///
44+
/// # Safety
45+
///
46+
/// This method must not be called concurrently with any DMA allocation or mapping primitives,
47+
/// such as [`CoherentAllocation::alloc_attrs`].
48+
unsafe fn dma_set_coherent_mask(&self, mask: DmaMask) -> Result {
49+
// SAFETY:
50+
// - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
51+
// - The safety requirement of this function guarantees that there are no concurrent calls
52+
// to DMA allocation and mapping primitives using this mask.
53+
to_result(unsafe { bindings::dma_set_coherent_mask(self.as_ref().as_raw(), mask.value()) })
54+
}
55+
56+
/// Set up the device's DMA addressing capabilities.
57+
///
58+
/// This is a combination of [`Device::dma_set_mask`] and [`Device::dma_set_coherent_mask`].
59+
///
60+
/// This method is usually called once from `probe()` as soon as the device capabilities are
61+
/// known.
62+
///
63+
/// # Safety
64+
///
65+
/// This method must not be called concurrently with any DMA allocation or mapping primitives,
66+
/// such as [`CoherentAllocation::alloc_attrs`].
67+
unsafe fn dma_set_mask_and_coherent(&self, mask: DmaMask) -> Result {
68+
// SAFETY:
69+
// - By the type invariant of `device::Device`, `self.as_ref().as_raw()` is valid.
70+
// - The safety requirement of this function guarantees that there are no concurrent calls
71+
// to DMA allocation and mapping primitives using this mask.
72+
to_result(unsafe {
73+
bindings::dma_set_mask_and_coherent(self.as_ref().as_raw(), mask.value())
74+
})
75+
}
76+
}
77+
78+
/// A DMA mask that holds a bitmask with the lowest `n` bits set.
79+
///
80+
/// Use [`DmaMask::new`] or [`DmaMask::try_new`] to construct a value. Values
81+
/// are guaranteed to never exceed the bit width of `u64`.
82+
///
83+
/// This is the Rust equivalent of the C macro `DMA_BIT_MASK()`.
84+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85+
pub struct DmaMask(u64);
86+
87+
impl DmaMask {
88+
/// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
89+
///
90+
/// For `n <= 64`, sets exactly the lowest `n` bits.
91+
/// For `n > 64`, results in a build error.
92+
///
93+
/// # Examples
94+
///
95+
/// ```
96+
/// use kernel::dma::DmaMask;
97+
///
98+
/// let mask0 = DmaMask::new::<0>();
99+
/// assert_eq!(mask0.value(), 0);
100+
///
101+
/// let mask1 = DmaMask::new::<1>();
102+
/// assert_eq!(mask1.value(), 0b1);
103+
///
104+
/// let mask64 = DmaMask::new::<64>();
105+
/// assert_eq!(mask64.value(), u64::MAX);
106+
///
107+
/// // Build failure.
108+
/// // let mask_overflow = DmaMask::new::<100>();
109+
/// ```
110+
#[inline]
111+
pub const fn new<const N: u32>() -> Self {
112+
let Ok(mask) = Self::try_new(N) else {
113+
build_error!("Invalid DMA Mask.");
114+
};
115+
116+
mask
117+
}
118+
119+
/// Constructs a `DmaMask` with the lowest `n` bits set to `1`.
120+
///
121+
/// For `n <= 64`, sets exactly the lowest `n` bits.
122+
/// For `n > 64`, returns [`EINVAL`].
123+
///
124+
/// # Examples
125+
///
126+
/// ```
127+
/// use kernel::dma::DmaMask;
128+
///
129+
/// let mask0 = DmaMask::try_new(0)?;
130+
/// assert_eq!(mask0.value(), 0);
131+
///
132+
/// let mask1 = DmaMask::try_new(1)?;
133+
/// assert_eq!(mask1.value(), 0b1);
134+
///
135+
/// let mask64 = DmaMask::try_new(64)?;
136+
/// assert_eq!(mask64.value(), u64::MAX);
137+
///
138+
/// let mask_overflow = DmaMask::try_new(100);
139+
/// assert!(mask_overflow.is_err());
140+
/// # Ok::<(), Error>(())
141+
/// ```
142+
#[inline]
143+
pub const fn try_new(n: u32) -> Result<Self> {
144+
Ok(Self(match n {
145+
0 => 0,
146+
1..=64 => u64::MAX >> (64 - n),
147+
_ => return Err(EINVAL),
148+
}))
149+
}
150+
151+
/// Returns the underlying `u64` bitmask value.
152+
#[inline]
153+
pub const fn value(&self) -> u64 {
154+
self.0
155+
}
156+
}
22157

23158
/// Possible attributes associated with a DMA mapping.
24159
///

0 commit comments

Comments
 (0)