From: Danilo Krummrich <dakr@kernel.org>
To: aliceryhl@google.com, acourbot@nvidia.com, ojeda@kernel.org,
boqun@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com,
lossin@kernel.org, a.hindborg@kernel.org, tmgross@umich.edu,
abdiel.janulgue@gmail.com, daniel.almeida@collabora.com,
robin.murphy@arm.com
Cc: driver-core@lists.linux.dev, nouveau@lists.freedesktop.org,
dri-devel@lists.freedesktop.org, rust-for-linux@vger.kernel.org,
linux-kernel@vger.kernel.org, Danilo Krummrich <dakr@kernel.org>
Subject: [PATCH 4/8] rust: dma: introduce dma::CoherentInit for memory initialization
Date: Tue, 3 Mar 2026 17:22:55 +0100 [thread overview]
Message-ID: <20260303162314.94363-5-dakr@kernel.org> (raw)
In-Reply-To: <20260303162314.94363-1-dakr@kernel.org>
Currently, dma::Coherent cannot safely provide (mutable) access to its
underlying memory because the memory might be concurrently accessed by a
DMA device. This makes it difficult to safely initialize the memory
before handing it over to the hardware.
Introduce dma::CoherentInit, a type that encapsulates a dma::Coherent
before its DMA address is exposed to the device. dma::CoherentInit can
guarantee exclusive access to the inner dma::Coherent and implement
Deref and DerefMut.
Once the memory is properly initialized, dma::CoherentInit can be
converted into a regular dma::Coherent.
Signed-off-by: Danilo Krummrich <dakr@kernel.org>
---
rust/kernel/dma.rs | 153 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 152 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 291fdea3b52b..79dd8717ac47 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -20,7 +20,13 @@
FromBytes, //
}, //
};
-use core::ptr::NonNull;
+use core::{
+ ops::{
+ Deref,
+ DerefMut, //
+ },
+ ptr::NonNull, //
+};
/// DMA address type.
///
@@ -352,6 +358,151 @@ fn from(direction: DataDirection) -> Self {
}
}
+/// Initializer type for [`Coherent`].
+///
+/// A [`Coherent`] object can't provide access to its memory as (mutable) slice safely, since it
+/// can't fulfill the requirements for creating a slice. For instance, it is not valid to have a
+/// (mutable) slice to of the memory of a [`Coherent`] while the memory might be accessed by a
+/// device.
+///
+/// In contrast, this initializer type is able to fulfill the requirements to safely obtain a
+/// (mutable) slice, as it neither provides access to the DMA address of the embedded [`Coherent`],
+/// nor can it be used with the DMA projection accessors.
+///
+/// Once initialized, this type can be converted to a regular [`Coherent`] object.
+///
+/// # Examples
+///
+/// `CoherentInit<T>`:
+///
+/// ```
+/// # use kernel::device::{
+/// # Bound,
+/// # Device,
+/// # };
+/// use kernel::dma::{attrs::*,
+/// Coherent,
+/// CoherentInit,
+/// };
+///
+/// # fn test(dev: &Device<Bound>) -> Result {
+/// let mut dmem: CoherentInit<u64> =
+/// CoherentInit::zeroed_with_attrs(dev, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
+/// *dmem = 42;
+/// let dmem: Coherent<u64> = dmem.into();
+/// # Ok::<(), Error>(()) }
+/// ```
+///
+/// `CoherentInit<[T]>`:
+///
+///
+/// ```
+/// # use kernel::device::{
+/// # Bound,
+/// # Device,
+/// # };
+/// use kernel::dma::{attrs::*,
+/// Coherent,
+/// CoherentInit,
+/// };
+///
+/// # fn test(dev: &Device<Bound>) -> Result {
+/// let mut dmem: CoherentInit<[u64]> =
+/// CoherentInit::zeroed_slice_with_attrs(dev, 4, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
+/// dmem.fill(42);
+/// let dmem: Coherent<[u64]> = dmem.into();
+/// # Ok::<(), Error>(()) }
+/// ```
+pub struct CoherentInit<T: AsBytes + FromBytes + KnownSize + ?Sized>(Coherent<T>);
+
+impl<T: AsBytes + FromBytes> CoherentInit<[T]> {
+ /// Initializer variant of [`Coherent::zeroed_slice_with_attrs`].
+ pub fn zeroed_slice_with_attrs(
+ dev: &device::Device<Bound>,
+ count: usize,
+ gfp_flags: kernel::alloc::Flags,
+ dma_attrs: Attrs,
+ ) -> Result<Self> {
+ Coherent::zeroed_slice_with_attrs(dev, count, gfp_flags, dma_attrs).map(Self)
+ }
+
+ /// Same as [CoherentInit::zeroed_slice_with_attrs], but with `dma::Attrs(0)`.
+ pub fn zeroed_slice(
+ dev: &device::Device<Bound>,
+ count: usize,
+ gfp_flags: kernel::alloc::Flags,
+ ) -> Result<Self> {
+ Self::zeroed_slice_with_attrs(dev, count, gfp_flags, Attrs(0))
+ }
+
+ /// Initializes the element at `i` using the given initializer.
+ ///
+ /// Returns `EINVAL` if `i` is out of bounds.
+ pub fn init_at<E>(&mut self, i: usize, init: impl Init<T, E>) -> Result
+ where
+ Error: From<E>,
+ {
+ if i >= self.0.len() {
+ return Err(EINVAL);
+ }
+
+ let ptr = core::ptr::from_mut(&mut self[i]);
+
+ // SAFETY:
+ // - `ptr` is valid, properly aligned, and within this allocation.
+ // - `T: AsBytes + FromBytes` guarantees all bit patterns are valid, so partial writes on
+ // error cannot leave the element in an invalid state.
+ // - The DMA address has not been exposed yet, so there is no concurrent device access.
+ unsafe { init.__init(ptr)? };
+
+ Ok(())
+ }
+}
+
+impl<T: AsBytes + FromBytes> CoherentInit<T> {
+ /// Same as [`CoherentInit::zeroed_slice_with_attrs`], but for a single element.
+ pub fn zeroed_with_attrs(
+ dev: &device::Device<Bound>,
+ gfp_flags: kernel::alloc::Flags,
+ dma_attrs: Attrs,
+ ) -> Result<Self> {
+ Coherent::zeroed_with_attrs(dev, gfp_flags, dma_attrs).map(Self)
+ }
+
+ /// Same as [`CoherentInit::zeroed_slice`], but for a single element.
+ pub fn zeroed(dev: &device::Device<Bound>, gfp_flags: kernel::alloc::Flags) -> Result<Self> {
+ Self::zeroed_with_attrs(dev, gfp_flags, Attrs(0))
+ }
+}
+
+impl<T: AsBytes + FromBytes + KnownSize + ?Sized> Deref for CoherentInit<T> {
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // SAFETY:
+ // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
+ // device.
+ // - We have exclusive access to `self.0`.
+ unsafe { self.0.as_ref() }
+ }
+}
+
+impl<T: AsBytes + FromBytes + KnownSize + ?Sized> DerefMut for CoherentInit<T> {
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ // SAFETY:
+ // - We have not exposed the DMA address yet, so there can't be any concurrent access by a
+ // device.
+ // - We have exclusive access to `self.0`.
+ unsafe { self.0.as_mut() }
+ }
+}
+
+impl<T: AsBytes + FromBytes + KnownSize + ?Sized> From<CoherentInit<T>> for Coherent<T> {
+ fn from(value: CoherentInit<T>) -> Self {
+ value.0
+ }
+}
+
/// An abstraction of the `dma_alloc_coherent` API.
///
/// This is an abstraction around the `dma_alloc_coherent` API which is used to allocate and map
--
2.53.0
next prev parent reply other threads:[~2026-03-03 16:23 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <9A1gWen63AbJmi06Y_vu_qF1S86nj3fcQEil9RzLAn8QkIYpCOrLMNO7JcgIP0BccPHhzaYaQ_te1S_gKuHRgg==@protonmail.internalid>
2026-03-03 16:22 ` [PATCH 0/8] dma::Coherent & dma::CoherentInit API Danilo Krummrich
2026-03-03 16:22 ` [PATCH 1/8] rust: dma: use "kernel vertical" style for imports Danilo Krummrich
2026-03-03 17:12 ` Gary Guo
2026-03-03 17:12 ` Gary Guo
2026-03-03 16:22 ` [PATCH 2/8] rust: dma: add generalized container for types other than slices Danilo Krummrich
2026-03-17 6:50 ` Alice Ryhl
2026-03-17 12:56 ` Gary Guo
2026-03-17 12:56 ` Gary Guo
2026-03-20 13:58 ` Alexandre Courbot
2026-03-20 13:58 ` Alexandre Courbot
2026-03-03 16:22 ` [PATCH 3/8] rust: dma: add zeroed constructor to `Coherent` Danilo Krummrich
2026-03-17 6:47 ` Alice Ryhl
2026-03-20 14:35 ` Alexandre Courbot
2026-03-20 14:35 ` Alexandre Courbot
2026-03-03 16:22 ` Danilo Krummrich [this message]
2026-03-12 13:51 ` [PATCH 4/8] rust: dma: introduce dma::CoherentInit for memory initialization Gary Guo
2026-03-12 13:51 ` Gary Guo
2026-03-17 6:52 ` Alice Ryhl
2026-03-17 14:40 ` Danilo Krummrich
2026-03-17 14:40 ` Danilo Krummrich
2026-03-17 14:43 ` Alice Ryhl
2026-03-20 14:35 ` Alexandre Courbot
2026-03-20 14:35 ` Alexandre Courbot
2026-03-20 13:51 ` Danilo Krummrich
2026-03-03 16:22 ` [PATCH 5/8] rust: dma: add Coherent:init() and Coherent::init_with_attrs() Danilo Krummrich
2026-03-03 16:22 ` [PATCH 6/8] gpu: nova-core: use Coherent::init to initialize GspFwWprMeta Danilo Krummrich
2026-03-03 17:21 ` Gary Guo
2026-03-03 17:21 ` Gary Guo
2026-03-20 14:36 ` Alexandre Courbot
2026-03-20 14:36 ` Alexandre Courbot
2026-03-03 16:22 ` [PATCH 7/8] gpu: nova-core: convert Gsp::new() to use CoherentInit Danilo Krummrich
2026-03-03 17:33 ` Gary Guo
2026-03-03 17:33 ` Gary Guo
2026-03-03 16:22 ` [PATCH 8/8] gpu: nova-core: convert to new dma::Coherent API Danilo Krummrich
2026-03-20 14:36 ` Alexandre Courbot
2026-03-20 14:36 ` Alexandre Courbot
2026-03-20 15:05 ` Gary Guo
2026-03-20 15:05 ` Gary Guo
2026-03-24 12:33 ` [PATCH 0/8] dma::Coherent & dma::CoherentInit API Andreas Hindborg
2026-03-24 12:36 ` Danilo Krummrich
2026-03-24 12:46 ` Andreas Hindborg
2026-03-24 12:51 ` Danilo Krummrich
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260303162314.94363-5-dakr@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=abdiel.janulgue@gmail.com \
--cc=acourbot@nvidia.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun@kernel.org \
--cc=daniel.almeida@collabora.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=driver-core@lists.linux.dev \
--cc=gary@garyguo.net \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=robin.murphy@arm.com \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.