[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <87senajxlv.fsf@kernel.org>
Date: Tue, 18 Mar 2025 14:07:40 +0100
From: Andreas Hindborg <a.hindborg@...nel.org>
To: "Abdiel Janulgue" <abdiel.janulgue@...il.com>
Cc: <rust-for-linux@...r.kernel.org>, <daniel.almeida@...labora.com>,
<dakr@...nel.org>, <robin.murphy@....com>, <aliceryhl@...gle.com>,
"Miguel Ojeda" <ojeda@...nel.org>, "Alex Gaynor"
<alex.gaynor@...il.com>, "Boqun Feng" <boqun.feng@...il.com>, "Gary Guo"
<gary@...yguo.net>, Björn Roy Baron
<bjorn3_gh@...tonmail.com>, "Benno
Lossin" <benno.lossin@...ton.me>, "Trevor Gross" <tmgross@...ch.edu>,
"Valentin Obst" <kernel@...entinobst.de>,
<linux-kernel@...r.kernel.org>, "Christoph Hellwig" <hch@....de>,
"Marek Szyprowski" <m.szyprowski@...sung.com>, <airlied@...hat.com>,
<iommu@...ts.linux.dev>
Subject: Re: [PATCH v15 02/11] rust: add dma coherent allocator abstraction.
"Abdiel Janulgue" <abdiel.janulgue@...il.com> writes:
[...]
> +/// Possible attributes associated with a DMA mapping.
> +///
> +/// They can be combined with the operators `|`, `&`, and `!`.
> +///
> +/// Values can be used from the [`attrs`] module.
> +///
> +/// # Examples
> +///
> +/// ```
> +/// use kernel::device::Device;
> +/// use kernel::dma::{attrs::*, CoherentAllocation};
> +///
> +/// # fn test(dev: &Device) -> Result {
> +/// let attribs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_WARN;
> +/// let c: CoherentAllocation<u64> =
> +/// CoherentAllocation::alloc_attrs(dev, 4, GFP_KERNEL, attribs)?;
> +/// # Ok::<(), Error>(()) }
> +/// ```
> +#[derive(Clone, Copy, PartialEq)]
> +#[repr(transparent)]
> +pub struct Attrs(u32);
> +
> +impl Attrs {
> + /// Get the raw representation of this attribute.
> + pub(crate) fn as_raw(self) -> crate::ffi::c_ulong {
> + self.0 as _
> + }
OT: I wonder why we do not have `usize: From<u32>`? It seems like this
should be fine, even on 32 bit systems?
> +
> + /// Check whether `flags` is contained in `self`.
> + pub fn contains(self, flags: Attrs) -> bool {
> + (self & flags) == flags
> + }
> +}
> +
> +impl core::ops::BitOr for Attrs {
> + type Output = Self;
> + fn bitor(self, rhs: Self) -> Self::Output {
> + Self(self.0 | rhs.0)
> + }
> +}
> +
> +impl core::ops::BitAnd for Attrs {
> + type Output = Self;
> + fn bitand(self, rhs: Self) -> Self::Output {
> + Self(self.0 & rhs.0)
> + }
> +}
> +
> +impl core::ops::Not for Attrs {
> + type Output = Self;
> + fn not(self) -> Self::Output {
> + Self(!self.0)
> + }
> +}
> +
> +/// DMA mapping attributes.
> +pub mod attrs {
> + use super::Attrs;
> +
> + /// Specifies that reads and writes to the mapping may be weakly ordered, that is that reads
> + /// and writes may pass each other.
> + pub const DMA_ATTR_WEAK_ORDERING: Attrs = Attrs(bindings::DMA_ATTR_WEAK_ORDERING);
> +
> + /// Specifies that writes to the mapping may be buffered to improve performance.
> + pub const DMA_ATTR_WRITE_COMBINE: Attrs = Attrs(bindings::DMA_ATTR_WRITE_COMBINE);
> +
> + /// Lets the platform to avoid creating a kernel virtual mapping for the allocated buffer.
> + pub const DMA_ATTR_NO_KERNEL_MAPPING: Attrs = Attrs(bindings::DMA_ATTR_NO_KERNEL_MAPPING);
> +
> + /// Allows platform code to skip synchronization of the CPU cache for the given buffer assuming
> + /// that it has been already transferred to 'device' domain.
> + pub const DMA_ATTR_SKIP_CPU_SYNC: Attrs = Attrs(bindings::DMA_ATTR_SKIP_CPU_SYNC);
> +
> + /// Forces contiguous allocation of the buffer in physical memory.
> + pub const DMA_ATTR_FORCE_CONTIGUOUS: Attrs = Attrs(bindings::DMA_ATTR_FORCE_CONTIGUOUS);
> +
> + /// This is a hint to the DMA-mapping subsystem that it's probably not worth the time to try
> + /// to allocate memory to in a way that gives better TLB efficiency.
The wording of in the other doc comments is different than this one and
the two next ones. Consider aligning them:
Hints the DMA-mapping subsystem that ...
> + pub const DMA_ATTR_ALLOC_SINGLE_PAGES: Attrs = Attrs(bindings::DMA_ATTR_ALLOC_SINGLE_PAGES);
> +
> + /// This tells the DMA-mapping subsystem to suppress allocation failure reports (similarly to
> + /// __GFP_NOWARN).
Tells the DMA-mapping subsystem ...
> + pub const DMA_ATTR_NO_WARN: Attrs = Attrs(bindings::DMA_ATTR_NO_WARN);
> +
> + /// Used to indicate that the buffer is fully accessible at an elevated privilege level (and
> + /// ideally inaccessible or at least read-only at lesser-privileged levels).
Indicates that the buffer ...
> + pub const DMA_ATTR_PRIVILEGED: Attrs = Attrs(bindings::DMA_ATTR_PRIVILEGED);
> +}
> +
> +/// 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
> +/// large consistent DMA regions.
I think it would be nice to have a description of what a coherent DMA
region is here. From Documentation/core-api/dma-api.rst:
Consistent memory is memory for which a write by either the device or
the processor can immediately be read by the processor or device
without having to worry about caching effects. (You may however need
to make sure to flush the processor's write buffers before telling
devices to read that memory.)
I think consistent and coherent are used interchangeably in the kernel.
If so, can we settle on just one of the terms in the rust code?
> +///
> +/// A [`CoherentAllocation`] instance contains a pointer to the allocated region (in the
> +/// processor's virtual address space) and the device address which can be given to the device
> +/// as the DMA address base of the region. The region is released once [`CoherentAllocation`]
> +/// is dropped.
> +///
> +/// # Invariants
> +///
> +/// For the lifetime of an instance of [`CoherentAllocation`], the `cpu_addr` is a valid pointer
> +/// to an allocated region of consistent memory and `dma_handle` is the DMA address base of
> +/// the region.
> +// TODO
> +//
> +// DMA allocations potentially carry device resources (e.g.IOMMU mappings), hence for soundness
> +// reasons DMA allocation would need to be embedded in a `Devres` container, in order to ensure
> +// that device resources can never survive device unbind.
> +//
> +// However, it is neither desirable nor necessary to protect the allocated memory of the DMA
> +// allocation from surviving device unbind; it would require RCU read side critical sections to
> +// access the memory, which may require subsequent unnecessary copies.
> +//
> +// Hence, find a way to revoke the device resources of a `CoherentAllocation`, but not the
> +// entire `CoherentAllocation` including the allocated memory itself.
Looking forward to seeing this solution.
Best regards,
Andreas Hindborg
Powered by blists - more mailing lists