From: Robin Murphy <robin.murphy@arm.com>
To: Abdiel Janulgue <abdiel.janulgue@gmail.com>,
acourbot@nvidia.com, dakr@kernel.org, jgg@ziepe.ca,
lyude@redhat.com
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <lossin@kernel.org>,
"Andreas Hindborg" <a.hindborg@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
"Trevor Gross" <tmgross@umich.edu>,
"Tamir Duberstein" <tamird@gmail.com>,
"FUJITA Tomonori" <fujita.tomonori@gmail.com>,
"open list" <linux-kernel@vger.kernel.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Randy Dunlap" <rdunlap@infradead.org>,
"Herbert Xu" <herbert@gondor.apana.org.au>,
"Caleb Sander Mateos" <csander@purestorage.com>,
"Petr Tesarik" <petr@tesarici.cz>,
"Sui Jingfeng" <sui.jingfeng@linux.dev>,
"Marek Szyprowski" <m.szyprowski@samsung.com>,
airlied@redhat.com,
"open list:DMA MAPPING HELPERS" <iommu@lists.linux.dev>,
rust-for-linux@vger.kernel.org
Subject: Re: [PATCH v3 1/2] rust: add initial scatterlist abstraction
Date: Fri, 1 Aug 2025 19:26:16 +0100 [thread overview]
Message-ID: <8bc8b565-6bc9-4fa5-8677-192ed969c9d0@arm.com> (raw)
In-Reply-To: <20250718103359.1026240-2-abdiel.janulgue@gmail.com>
On 2025-07-18 11:33 am, Abdiel Janulgue wrote:
[...]
> +impl<T, M> SGTable<T, M>
> +where
> + T: Borrow<bindings::sg_table>,
> + M: MappedState,
> +{
> + /// Returns an immutable iterator over the scatter-gather table.
> + pub fn iter(&self) -> SGTableIter<'_> {
> + SGTableIter {
> + // SAFETY: dereferenced pointer is valid due to the type invariants on `SGTable`.
> + pos: Some(unsafe { SGEntry::as_ref(self.table.borrow().sgl) }),
> + }
> + }
> +}
> +
> +/// Provides a list of pages that can be used to build a `SGTable`.
> +pub trait SGTablePages {
> + /// Returns an iterator to the pages providing the backing memory of `self`.
This seems a bit unclear. In the C API we have 4 distinct iterators:
for_each_sgtable_sg
for_each_sgtable_dma_sg
for_each_sgtable_page
for_each_sgtable_dma_page
The first one is for iterating the segments in CPU space, i.e. simply
each SGEntry, "orig_nents" times from the start or until sg_next() is
NULL. This is typically what you want for copying data in and out.
The second is for iterating the DMA segments once mapped, which is then
"nents" times from the start or whichever of sg_next() being NULL or
sg_dma_len() being 0 happens first (since "nents" <= "orig_nents"). This
is typically what you want for building your actual device
descriptors/commands from the (dma_address,dma_length) tuples.
The last two are for slightly more specialised users who want to walk
the whole list effectvely linearly in literal PAGE_SIZE steps, in either
CPU space or (mapped) DMA space respectively.
The comments here rather sound like they're trying to describe #3, but
(based on looking at the C calls and taking a vague guess at what all
the Rust around them means) the implementation below sure *seems* a lot
more like it's actually #1... For a useful abstraction I'd think you'd
want at least #1 and #2, however I know the main motivation here is GPU
drivers, and they are the primary users of #3 and #4, so I suspect
you'll probably want to support both per-SGEntry and per-Page iteration,
in both CPU and DMA flavours, sooner rather than later.
> + ///
> + /// Implementers should return an iterator which provides information regarding each page entry to
> + /// build the `SGTable`. The first element in the tuple is a reference to the Page, the second element
> + /// as the offset into the page, and the third as the length of data. The fields correspond to the
> + /// first three fields of the C `struct scatterlist`.
> + fn iter<'a>(&'a self) -> impl Iterator<Item = (&'a Page, usize, usize)>;
> +
> + /// Returns the number of pages in the list.
> + fn entries(&self) -> usize;
> +}
> +
> +/// An iterator through `SGTable` entries.
> +pub struct SGTableIter<'a> {
> + pos: Option<&'a SGEntry>,
> +}
> +
> +impl<'a> Iterator for SGTableIter<'a> {
> + type Item = &'a SGEntry;
> +
> + fn next(&mut self) -> Option<Self::Item> {
> + let entry = self.pos;
> + // SAFETY: `sg` is an immutable reference and is equivalent to `scatterlist` via its type
> + // invariants, so its safe to use with sg_next.
> + let next = unsafe { bindings::sg_next(self.pos?.as_raw()) };
> +
> + // SAFETY: `sg_next` returns either a valid pointer to a `scatterlist`, or null if we
> + // are at the end of the scatterlist.
> + self.pos = (!next.is_null()).then(|| unsafe { SGEntry::as_ref(next) });
> + entry
> + }
> +}
> +
> +impl<'a, T, M> IntoIterator for &'a SGTable<T, M>
> +where
> + T: Borrow<bindings::sg_table>,
> + M: MappedState,
> +{
> + type Item = &'a SGEntry;
> + type IntoIter = SGTableIter<'a>;
> +
> + fn into_iter(self) -> Self::IntoIter {
> + self.iter()
> + }
> +}
> +
> +impl<T> SGTable<T, Unmapped>
> +where
> + T: BorrowMut<bindings::sg_table>,
> +{
> + /// Map this scatter-gather table describing a buffer for DMA by the `Device`.
> + ///
> + /// To prevent the table from being mapped more than once, this call consumes `self` and transfers
> + /// ownership of resources to the new `SGTable<_, ManagedMapping>` object.
> + pub fn dma_map(
> + mut self,
> + dev: &Device<Bound>,
> + dir: DmaDataDirection,
> + ) -> Result<SGTable<T, ManagedMapping>> {
> + // SAFETY: Invariants on `Device<Bound>` and `SGTable` ensures that the pointers are valid.
> + let ret = unsafe {
> + bindings::dma_map_sgtable(
> + dev.as_raw(),
> + self.table.borrow_mut(),
> + dir as i32,
> + bindings::DMA_ATTR_NO_WARN as usize,
This should probably be up to the user rather than baked into the
abstraction. For streaming mappings (as opposed to coherent
allocations), NO_WARN only has any effect at all for PowerPC and SWIOTLB
anyway. And for the latter, the warning is commonly hit by unexpectedly
trying to bounce an inappropriately large buffer due to not setting a
DMA mask correctly, so more often than not it is helpful.
Users trying cleverer things like i915, where they anticipate failure
and can deal with it non-fatally, should of course still have the option
to request NO_WARN if they want, but I'd expect them to be in the minority.
Thanks,
Robin.
next prev parent reply other threads:[~2025-08-01 18:26 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-18 10:33 [PATCH v3 0/2] " Abdiel Janulgue
2025-07-18 10:33 ` [PATCH v3 1/2] " Abdiel Janulgue
2025-07-23 0:44 ` Daniel Almeida
2025-07-24 5:40 ` Alexandre Courbot
2025-08-04 8:56 ` Abdiel Janulgue
2025-08-05 15:42 ` Jason Gunthorpe
2025-08-05 16:12 ` Danilo Krummrich
2025-07-24 20:19 ` Lyude Paul
2025-07-26 14:10 ` Alexandre Courbot
2025-08-01 18:26 ` Robin Murphy [this message]
2025-08-04 9:04 ` Alexandre Courbot
2025-08-08 13:13 ` Andreas Hindborg
2025-08-08 20:23 ` Benno Lossin
2025-07-18 10:33 ` [PATCH v3 2/2] samples: rust: add sample code for " Abdiel Janulgue
2025-07-23 0:54 ` Daniel Almeida
2025-07-23 8:07 ` Alexandre Courbot
2025-08-08 12:18 ` Andreas Hindborg
2025-07-18 10:50 ` [PATCH v3 0/2] rust: add initial " 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=8bc8b565-6bc9-4fa5-8677-192ed969c9d0@arm.com \
--to=robin.murphy@arm.com \
--cc=a.hindborg@kernel.org \
--cc=abdiel.janulgue@gmail.com \
--cc=acourbot@nvidia.com \
--cc=airlied@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=csander@purestorage.com \
--cc=dakr@kernel.org \
--cc=fujita.tomonori@gmail.com \
--cc=gary@garyguo.net \
--cc=herbert@gondor.apana.org.au \
--cc=iommu@lists.linux.dev \
--cc=jgg@ziepe.ca \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=m.szyprowski@samsung.com \
--cc=ojeda@kernel.org \
--cc=petr@tesarici.cz \
--cc=rdunlap@infradead.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=sui.jingfeng@linux.dev \
--cc=tamird@gmail.com \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®