rust: dma: add from-slice constructors for Coherent and CoherentBox

A very common pattern is to create a block of coherent memory with the
content of an already-existing slice of bytes (e.g. a loaded firmware
blob).

`CoherentBox` makes this easier, but still implies a potentially
panicking operation with `copy_from_slice` that requires a `PANIC`
comment.

Add `from_slice_with_attrs` and `from_slice` methods to both `Coherent`
and `CoherentBox` to turn this into a trivial one-step operation.

Reviewed-by: Andreas Hindborg <a.hindborg@kernel.org>
Reviewed-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Danilo Krummrich <dakr@kernel.org>
Link: https://patch.msgid.link/20260327-b4-nova-dma-removal-v2-1-616e1d0b5cb3@nvidia.com
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
master
Alexandre Courbot 2026-03-27 00:22:07 +09:00
parent 6dd782af1e
commit 816718c611
1 changed files with 107 additions and 0 deletions

View File

@ -453,6 +453,66 @@ impl<T: AsBytes + FromBytes> CoherentBox<[T]> {
Ok(())
}
/// Allocates a region of coherent memory of the same size as `data` and initializes it with a
/// copy of its contents.
///
/// This is the [`CoherentBox`] variant of [`Coherent::from_slice_with_attrs`].
///
/// # Examples
///
/// ```
/// use core::ops::Deref;
///
/// # use kernel::device::{Bound, Device};
/// use kernel::dma::{
/// attrs::*,
/// CoherentBox
/// };
///
/// # fn test(dev: &Device<Bound>) -> Result {
/// let data = [0u8, 1u8, 2u8, 3u8];
/// let c: CoherentBox<[u8]> =
/// CoherentBox::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
///
/// assert_eq!(c.deref(), &data);
/// # Ok::<(), Error>(()) }
/// ```
pub fn from_slice_with_attrs(
dev: &device::Device<Bound>,
data: &[T],
gfp_flags: kernel::alloc::Flags,
dma_attrs: Attrs,
) -> Result<Self>
where
T: Copy,
{
let mut slice = Self(Coherent::<T>::alloc_slice_with_attrs(
dev,
data.len(),
gfp_flags,
dma_attrs,
)?);
// PANIC: `slice` was created with length `data.len()`.
slice.copy_from_slice(data);
Ok(slice)
}
/// Performs the same functionality as [`CoherentBox::from_slice_with_attrs`], except the
/// `dma_attrs` is 0 by default.
#[inline]
pub fn from_slice(
dev: &device::Device<Bound>,
data: &[T],
gfp_flags: kernel::alloc::Flags,
) -> Result<Self>
where
T: Copy,
{
Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
}
}
impl<T: AsBytes + FromBytes> CoherentBox<T> {
@ -839,6 +899,53 @@ impl<T: AsBytes + FromBytes> Coherent<T> {
) -> Result<Coherent<[T]>> {
Self::zeroed_slice_with_attrs(dev, len, gfp_flags, Attrs(0))
}
/// Allocates a region of coherent memory of the same size as `data` and initializes it with a
/// copy of its contents.
///
/// # Examples
///
/// ```
/// # use kernel::device::{Bound, Device};
/// use kernel::dma::{
/// attrs::*,
/// Coherent
/// };
///
/// # fn test(dev: &Device<Bound>) -> Result {
/// let data = [0u8, 1u8, 2u8, 3u8];
/// // `c` has the same content as `data`.
/// let c: Coherent<[u8]> =
/// Coherent::from_slice_with_attrs(dev, &data, GFP_KERNEL, DMA_ATTR_NO_WARN)?;
///
/// # Ok::<(), Error>(()) }
/// ```
#[inline]
pub fn from_slice_with_attrs(
dev: &device::Device<Bound>,
data: &[T],
gfp_flags: kernel::alloc::Flags,
dma_attrs: Attrs,
) -> Result<Coherent<[T]>>
where
T: Copy,
{
CoherentBox::from_slice_with_attrs(dev, data, gfp_flags, dma_attrs).map(Into::into)
}
/// Performs the same functionality as [`Coherent::from_slice_with_attrs`], except the
/// `dma_attrs` is 0 by default.
#[inline]
pub fn from_slice(
dev: &device::Device<Bound>,
data: &[T],
gfp_flags: kernel::alloc::Flags,
) -> Result<Coherent<[T]>>
where
T: Copy,
{
Self::from_slice_with_attrs(dev, data, gfp_flags, Attrs(0))
}
}
impl<T> Coherent<[T]> {