From: "Danilo Krummrich" <dakr@kernel.org>
To: "Alistair Popple" <apopple@nvidia.com>
Cc: rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org,
acourbot@nvidia.com, "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>,
"David Airlie" <airlied@gmail.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Maarten Lankhorst" <maarten.lankhorst@linux.intel.com>,
"Maxime Ripard" <mripard@kernel.org>,
"Thomas Zimmermann" <tzimmermann@suse.de>,
"John Hubbard" <jhubbard@nvidia.com>,
"Joel Fernandes" <joelagnelf@nvidia.com>,
"Timur Tabi" <ttabi@nvidia.com>,
linux-kernel@vger.kernel.org, nouveau@lists.freedesktop.org,
"Lyude Paul" <lyude@redhat.com>
Subject: Re: [PATCH v4 04/13] gpu: nova-core: Add a slice-buffer (sbuffer) datastructure
Date: Wed, 08 Oct 2025 18:41:40 +0200 [thread overview]
Message-ID: <DDD39JHAI4ED.2BGLWYNIRA987@kernel.org> (raw)
In-Reply-To: <20251008001253.437911-5-apopple@nvidia.com>
On Wed Oct 8, 2025 at 2:12 AM CEST, Alistair Popple wrote:
> diff --git a/drivers/gpu/nova-core/sbuffer.rs b/drivers/gpu/nova-core/sbuffer.rs
> new file mode 100644
> index 000000000000..e82f9d97ad21
> --- /dev/null
> +++ b/drivers/gpu/nova-core/sbuffer.rs
> @@ -0,0 +1,191 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use core::ops::Deref;
> +
> +use kernel::alloc::KVec;
> +use kernel::error::code::*;
> +use kernel::prelude::*;
> +
> +/// A buffer abstraction for discontiguous byte slices.
> +///
> +/// This allows you to treat multiple non-contiguous `&mut [u8]` slices
> +/// as a single stream-like read/write buffer.
> +///
> +/// Example:
> +///
> +/// let mut buf1 = [0u8; 3];
> +/// let mut buf2 = [0u8; 5];
> +/// let mut sbuffer = SWriteBuffer::new([&buf1, &buf2]);
> +///
> +/// let data = b"hellowo";
Not that it matters, but "hellowo"? :)
> +/// let result = sbuffer.write_all(0, data);
> +///
> +/// A sliding window of slices to proceed.
> +///
> +/// Both read and write buffers are implemented in terms of operating on slices of a requested
> +/// size. This base class implements logic that can be shared between the two to support that.
> +///
> +/// `S` is a slice type, `I` is an iterator yielding `S`.
> +pub(crate) struct SBuffer<I: Iterator> {
> + /// `Some` if we are not at the end of the data yet.
> + cur_slice: Option<I::Item>,
> + /// All the slices remaining after `cur_slice`.
> + slices: I,
> +}
Does it make sense to split SBuffer into itself and a separate SBufferIter that
keeps a reference to the SBuffer? If not, I'd rename it to SBufferIter to make
it obvious to the user that it is an iterator type.
> +impl<'a, I> SBuffer<I>
> +where
> + I: Iterator,
> +{
> + #[expect(unused)]
> + pub(crate) fn new_reader(slices: impl IntoIterator<IntoIter = I>) -> Self
> + where
> + I: Iterator<Item = &'a [u8]>,
> + {
> + Self::new(slices)
> + }
> +
> + #[expect(unused)]
> + pub(crate) fn new_writer(slices: impl IntoIterator<IntoIter = I>) -> Self
> + where
> + I: Iterator<Item = &'a mut [u8]>,
> + {
> + Self::new(slices)
> + }
Please add some documentation for the constructors.
> + fn new(slices: impl IntoIterator<IntoIter = I>) -> Self
> + where
> + I::Item: Deref<Target = [u8]>,
> + {
> + let mut slices = slices.into_iter();
> +
> + Self {
> + // Skip empty slices to avoid trouble down the road.
> + cur_slice: slices.find(|s| !s.deref().is_empty()),
> + slices,
> + }
> + }
> +
> + fn get_slice_internal(
> + &mut self,
> + len: usize,
> + mut f: impl FnMut(I::Item, usize) -> (I::Item, I::Item),
> + ) -> Option<I::Item>
> + where
> + I::Item: Deref<Target = [u8]>,
> + {
> + match self.cur_slice.take() {
> + None => None,
> + Some(cur_slice) => {
> + if len >= cur_slice.len() {
> + // Caller requested more data than is in the current slice, return it entirely
> + // and prepare the following slice for being used. Skip empty slices to avoid
> + // trouble.
> + self.cur_slice = self.slices.find(|s| !s.is_empty());
> +
> + Some(cur_slice)
> + } else {
> + // The current slice can satisfy the request, split it and return a slice of
> + // the requested size.
> + let (ret, next) = f(cur_slice, len);
> + self.cur_slice = Some(next);
> +
> + Some(ret)
> + }
> + }
> + }
> + }
> +}
> +
> +/// Provides a way to get non-mutable slices of data to read from.
> +impl<'a, I> SBuffer<I>
> +where
> + I: Iterator<Item = &'a [u8]>,
> +{
> + /// Returns a slice of at most `len` bytes, or `None` if we are at the end of the data.
> + ///
> + /// If a slice shorter than `len` bytes has been returned, the caller can call this method
> + /// again until it returns `None` to try and obtain the remainder of the data.
> + fn get_slice(&mut self, len: usize) -> Option<&'a [u8]> {
> + self.get_slice_internal(len, |s, pos| s.split_at(pos))
> + }
> +
> + /// Ideally we would implement `Read`, but it is not available in `core`.
> + /// So mimic `std::io::Read::read_exact`.
> + #[expect(unused)]
> + pub(crate) fn read_exact(&mut self, mut dst: &mut [u8]) -> Result {
> + while !dst.is_empty() {
> + match self.get_slice(dst.len()) {
> + None => return Err(ETOOSMALL),
ETOOSMALL is an NFS error code (it should also never be exposed to userspace). I
suggest to implement a custom error type instead and make it resolve to ENOSPC
or probably just EINVAL instead.
> + Some(src) => {
> + let dst_slice;
> + (dst_slice, dst) = dst.split_at_mut(src.len());
> + dst_slice.copy_from_slice(src);
> + }
> + }
> + }
> +
> + Ok(())
> + }
> +
> + /// Read all the remaining data into a `KVec`.
> + ///
> + /// `self` will be empty after this operation.
> + #[expect(unused)]
> + pub(crate) fn read_into_kvec(&mut self, flags: kernel::alloc::Flags) -> Result<KVec<u8>> {
> + let mut buf = KVec::<u8>::new();
> +
> + if let Some(slice) = core::mem::take(&mut self.cur_slice) {
> + buf.extend_from_slice(slice, flags)?;
> + }
> + for slice in &mut self.slices {
> + buf.extend_from_slice(slice, flags)?;
> + }
> +
> + Ok(buf)
> + }
> +}
> +
> +/// Provides a way to get mutable slices of data to write into.
> +impl<'a, I> SBuffer<I>
> +where
> + I: Iterator<Item = &'a mut [u8]>,
> +{
> + /// Returns a mutable slice of at most `len` bytes, or `None` if we are at the end of the data.
> + ///
> + /// If a slice shorter than `len` bytes has been returned, the caller can call this method
> + /// again until it returns `None` to try and obtain the remainder of the data.
> + fn get_slice_mut(&mut self, len: usize) -> Option<&'a mut [u8]> {
> + self.get_slice_internal(len, |s, pos| s.split_at_mut(pos))
> + }
> +
> + /// Ideally we would implement `Write`, but it is not available in `core`.
> + /// So mimic `std::io::Write::write_all`.
> + #[expect(unused)]
> + pub(crate) fn write_all(&mut self, mut src: &[u8]) -> Result {
> + while !src.is_empty() {
> + match self.get_slice_mut(src.len()) {
> + None => return Err(ETOOSMALL),
> + Some(dst) => {
> + let src_slice;
> + (src_slice, src) = src.split_at(dst.len());
> + dst.copy_from_slice(src_slice);
> + }
> + }
> + }
> +
> + Ok(())
> + }
> +}
> +
> +impl<'a, I> Iterator for SBuffer<I>
> +where
> + I: Iterator<Item = &'a [u8]>,
> +{
> + type Item = u8;
> +
> + fn next(&mut self) -> Option<Self::Item> {
> + // Returned slices are guaranteed to not be empty so we can safely index the first entry.
> + self.get_slice(1).map(|s| s[0])
> + }
> +}
> --
> 2.50.1
next prev parent reply other threads:[~2025-10-08 16:41 UTC|newest]
Thread overview: 29+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-10-08 0:12 [PATCH v4 00/13] gpu: nova-core: Boot GSP to RISC-V active Alistair Popple
2025-10-08 0:12 ` [PATCH v4 01/13] gpu: nova-core: Set correct DMA mask Alistair Popple
2025-10-08 10:30 ` Danilo Krummrich
2025-10-08 22:34 ` Alistair Popple
2025-10-08 0:12 ` [PATCH v4 02/13] gpu: nova-core: Create initial Gsp Alistair Popple
2025-10-08 16:01 ` Danilo Krummrich
2025-10-09 1:14 ` Alistair Popple
2025-10-08 0:12 ` [PATCH v4 03/13] gpu: nova-core: gsp: Create wpr metadata Alistair Popple
2025-10-08 16:11 ` Danilo Krummrich
2025-10-08 0:12 ` [PATCH v4 04/13] gpu: nova-core: Add a slice-buffer (sbuffer) datastructure Alistair Popple
2025-10-08 16:41 ` Danilo Krummrich [this message]
2025-10-09 1:29 ` Alistair Popple
2025-10-08 16:56 ` Miguel Ojeda
2025-10-09 21:41 ` Joel Fernandes
2025-10-08 0:12 ` [PATCH v4 05/13] gpu: nova-core: Add GSP command queue bindings Alistair Popple
2025-10-08 0:12 ` [PATCH v4 06/13] gpu: nova-core: gsp: Add GSP command queue handling Alistair Popple
2025-10-08 0:12 ` [PATCH v4 07/13] gpu: nova-core: gsp: Create rmargs Alistair Popple
2025-10-08 0:12 ` [PATCH v4 08/13] gpu: nova-core: Add bindings and accessors for GspSystemInfo Alistair Popple
2025-10-08 0:12 ` [PATCH v4 09/13] gpu: nova-core: Add bindings for the GSP RM registry tables Alistair Popple
2025-10-08 0:12 ` [PATCH v4 10/13] gpu: nova-core: gsp: Create RM registry and sysinfo commands Alistair Popple
2025-10-08 0:12 ` [PATCH v4 11/13] nova-core: falcon: Add support to check if RISC-V is active Alistair Popple
2025-10-08 0:12 ` [PATCH v4 12/13] nova-core: falcon: Add support to write firmware version Alistair Popple
2025-10-08 3:21 ` Timur Tabi
2025-10-08 4:56 ` Joel Fernandes
2025-10-08 5:16 ` Alistair Popple
2025-10-08 0:12 ` [PATCH v4 13/13] nova-core: gsp: Boot GSP Alistair Popple
2025-10-08 10:38 ` [PATCH v4 00/13] gpu: nova-core: Boot GSP to RISC-V active Danilo Krummrich
2025-10-08 10:41 ` Danilo Krummrich
2025-10-08 22:21 ` Alistair Popple
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=DDD39JHAI4ED.2BGLWYNIRA987@kernel.org \
--to=dakr@kernel.org \
--cc=a.hindborg@kernel.org \
--cc=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=dri-devel@lists.freedesktop.org \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=joelagnelf@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=lyude@redhat.com \
--cc=maarten.lankhorst@linux.intel.com \
--cc=mripard@kernel.org \
--cc=nouveau@lists.freedesktop.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=tmgross@umich.edu \
--cc=ttabi@nvidia.com \
--cc=tzimmermann@suse.de \
/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.