From: Alexandre Courbot <acourbot@nvidia.com>
To: John Hubbard <jhubbard@nvidia.com>,
Danilo Krummrich <dakr@kernel.org>,
Alice Ryhl <aliceryhl@google.com>,
David Airlie <airlied@gmail.com>,
Simona Vetter <simona@ffwll.ch>,
Benno Lossin <lossin@kernel.org>, Gary Guo <gary@garyguo.net>
Cc: Alistair Popple <apopple@nvidia.com>,
Timur Tabi <ttabi@nvidia.com>,
Eliot Courtney <ecourtney@nvidia.com>,
Zhi Wang <zhiw@nvidia.com>,
nova-gpu@lists.linux.dev, dri-devel@lists.freedesktop.org,
linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org,
Alexandre Courbot <acourbot@nvidia.com>
Subject: [PATCH v2 7/9] gpu: nova-core: gsp: cmdq: move the RPC receive code into a sub-module
Date: Sun, 27 Sep 2026 22:46:24 +0900 [thread overview]
Message-ID: <20260927-cmdq-rpc-v2-7-c3f66ae73be4@nvidia.com> (raw)
In-Reply-To: <20260927-cmdq-rpc-v2-0-c3f66ae73be4@nvidia.com>
Move the types and code related to receiving a RPC message into the
`rpc` sub-module. The methods are still declared as members of
`CmdqInner` and `Cmdq`; only they are now in their own sub-module.
This is a pure move commit, with no functional change intended.
Signed-off-by: Alexandre Courbot <acourbot@nvidia.com>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 129 --------------------------------
drivers/gpu/nova-core/gsp/cmdq/rpc.rs | 132 ++++++++++++++++++++++++++++++++-
drivers/gpu/nova-core/gsp/commands.rs | 6 +-
drivers/gpu/nova-core/gsp/sequencer.rs | 4 +-
4 files changed, 137 insertions(+), 134 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 169ef0865339..16e40a52fa57 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -43,7 +43,6 @@
gsp::{
fw::{
GspMsgElement,
- MsgFunction,
MsgqRxHeader,
MsgqTxHeader,
GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, //
@@ -62,29 +61,6 @@
/// reply type are sent using [`Cmdq::send_command_no_wait`].
pub(crate) struct NoReply;
-/// Trait representing messages received from the GSP.
-///
-/// This trait tells [`Cmdq::receive_msg`] how it can receive a given type of message.
-pub(crate) trait MessageFromGsp: Sized {
- /// Function identifying this message from the GSP.
- const FUNCTION: MsgFunction;
-
- /// Error type returned by [`MessageFromGsp::read`].
- type InitError;
-
- /// Type containing the raw message to be read from the message queue.
- type Message: FromBytes;
-
- /// Method reading the message from the message queue and returning it.
- ///
- /// From a `Self::Message` and a [`SBufferIter`], constructs an instance of `Self` and returns
- /// it.
- fn read(
- msg: &Self::Message,
- sbuffer: &mut SBufferIter<core::array::IntoIter<&[u8], 2>>,
- ) -> Result<Self, Self::InitError>;
-}
-
/// Number of GSP pages making the [`Msgq`].
pub(crate) const MSGQ_NUM_PAGES: u32 = 0x3f;
@@ -490,17 +466,6 @@ fn calculate_checksum<T: Iterator<Item = u8>>(it: T) -> u32 {
fn notify_gsp(bar: Bar0<'_>) {
bar.write_reg(regs::NV_PGSP_QUEUE_HEAD::zeroed().with_address(0u32));
}
-
- /// Receive a message from the GSP.
- ///
- /// See [`CmdqInner::receive_msg`] for details.
- pub(crate) fn receive_msg<M: MessageFromGsp>(&self, timeout: Delta) -> Result<M>
- where
- // This allows all error types, including `Infallible`, to be used for `M::InitError`.
- Error: From<M::InitError>,
- {
- self.inner.lock().receive_msg(timeout)
- }
}
/// Inner mutex protected state of [`Cmdq`].
@@ -638,98 +603,4 @@ fn consume_element<R>(
result
}
-
- /// Validate the RPC layer of `element` and trim its contents down to the RPC payload.
- ///
- /// # Errors
- ///
- /// - `EIO` if the element is shorter than the payload length advertised by the RPC header.
- fn parse_rpc_message<'a>(
- dev: &device::Device,
- element: GspMessage<'a>,
- ) -> Result<GspMessage<'a>> {
- let GspMessage {
- header,
- contents: (slice_1, slice_2),
- } = element;
-
- let rpc_header = header.rpc_header();
- let payload_length = rpc_header.length();
-
- dev_dbg!(
- dev,
- "GSP RPC: receive: seq# {}, function={:?}, length=0x{:x}\n",
- rpc_header.sequence(),
- rpc_header.function(),
- payload_length,
- );
-
- // Check that the element is large enough for the message.
- if slice_1.len() + slice_2.len() < payload_length {
- return Err(EIO);
- }
-
- // Cut the message slices down to the actual length of the message.
- let (slice_1, slice_2) = if slice_1.len() > payload_length {
- // PANIC: we checked above that `slice_1` is at least as long as `payload_length`.
- (slice_1.split_at(payload_length).0, &slice_2[0..0])
- } else {
- (
- slice_1,
- // PANIC: we checked above that `slice_1.len() + slice_2.len()` is at least as
- // large as `payload_length`.
- slice_2.split_at(payload_length - slice_1.len()).0,
- )
- };
-
- Ok(GspMessage {
- header,
- contents: (slice_1, slice_2),
- })
- }
-
- /// Receive a message from the GSP.
- ///
- /// The expected message type is specified using the `M` generic parameter. If the pending
- /// message has a different function code, `ERANGE` is returned and the message is consumed.
- ///
- /// The read pointer is always advanced past the message, regardless of whether it matched or
- /// could be parsed.
- ///
- /// # Errors
- ///
- /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
- /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
- /// message queue.
- /// - `EINVAL` if the function code of the message was not recognized.
- /// - `ERANGE` if the message had a recognized but non-matching function code.
- ///
- /// Error codes returned by [`MessageFromGsp::read`] are propagated as-is.
- fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
- where
- // This allows all error types, including `Infallible`, to be used for `M::InitError`.
- Error: From<M::InitError>,
- {
- let dev = self.dev;
-
- self.consume_element(timeout, |element| {
- let message = Self::parse_rpc_message(dev, element)?;
- let function = message.header.rpc_header().function().map_err(|_| EINVAL)?;
-
- if function != M::FUNCTION {
- return Err(ERANGE);
- }
-
- let (cmd, contents_1) = M::Message::from_bytes_prefix(message.contents.0).ok_or(EIO)?;
- let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]);
-
- M::read(cmd, &mut sbuffer)
- .map_err(|e| e.into())
- .inspect(|_| {
- if !sbuffer.is_empty() {
- dev_warn!(dev, "GSP message {:?} has unprocessed data\n", function);
- }
- })
- })
- }
}
diff --git a/drivers/gpu/nova-core/gsp/cmdq/rpc.rs b/drivers/gpu/nova-core/gsp/cmdq/rpc.rs
index 3bafe456efd6..a0e1e7e20ac3 100644
--- a/drivers/gpu/nova-core/gsp/cmdq/rpc.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq/rpc.rs
@@ -6,7 +6,9 @@
mod continuation;
use kernel::{
+ device,
prelude::*,
+ time::Delta,
transmute::{
AsBytes,
FromBytes, //
@@ -35,7 +37,7 @@
use super::{
Cmdq,
CmdqInner,
- MessageFromGsp, //
+ GspMessage, //
};
/// Trait implemented by types representing a command to send to the GSP.
@@ -100,6 +102,29 @@ fn size(&self) -> usize {
}
}
+/// Trait representing messages received from the GSP.
+///
+/// This trait tells [`Cmdq::receive_msg`] how it can receive a given type of message.
+pub(crate) trait MessageFromGsp: Sized {
+ /// Function identifying this message from the GSP.
+ const FUNCTION: MsgFunction;
+
+ /// Error type returned by [`MessageFromGsp::read`].
+ type InitError;
+
+ /// Type containing the raw message to be read from the message queue.
+ type Message: FromBytes;
+
+ /// Method reading the message from the message queue and returning it.
+ ///
+ /// From a `Self::Message` and a [`SBufferIter`], constructs an instance of `Self` and returns
+ /// it.
+ fn read(
+ msg: &Self::Message,
+ sbuffer: &mut SBufferIter<core::array::IntoIter<&[u8], 2>>,
+ ) -> Result<Self, Self::InitError>;
+}
+
impl CmdqInner<'_> {
/// Sends `command` to the GSP, without splitting it.
///
@@ -191,6 +216,100 @@ fn send_command<M>(&mut self, command: M) -> Result
}
}
}
+
+ /// Validate the RPC layer of `element` and trim its contents down to the RPC payload.
+ ///
+ /// # Errors
+ ///
+ /// - `EIO` if the element is shorter than the payload length advertised by the RPC header.
+ fn parse_rpc_message<'a>(
+ dev: &device::Device,
+ element: GspMessage<'a>,
+ ) -> Result<GspMessage<'a>> {
+ let GspMessage {
+ header,
+ contents: (slice_1, slice_2),
+ } = element;
+
+ let rpc_header = header.rpc_header();
+ let payload_length = rpc_header.length();
+
+ dev_dbg!(
+ dev,
+ "GSP RPC: receive: seq# {}, function={:?}, length=0x{:x}\n",
+ rpc_header.sequence(),
+ rpc_header.function(),
+ payload_length,
+ );
+
+ // Check that the element is large enough for the message.
+ if slice_1.len() + slice_2.len() < payload_length {
+ return Err(EIO);
+ }
+
+ // Cut the message slices down to the actual length of the message.
+ let (slice_1, slice_2) = if slice_1.len() > payload_length {
+ // PANIC: we checked above that `slice_1` is at least as long as `payload_length`.
+ (slice_1.split_at(payload_length).0, &slice_2[0..0])
+ } else {
+ (
+ slice_1,
+ // PANIC: we checked above that `slice_1.len() + slice_2.len()` is at least as
+ // large as `payload_length`.
+ slice_2.split_at(payload_length - slice_1.len()).0,
+ )
+ };
+
+ Ok(GspMessage {
+ header,
+ contents: (slice_1, slice_2),
+ })
+ }
+
+ /// Receive a message from the GSP.
+ ///
+ /// The expected message type is specified using the `M` generic parameter. If the pending
+ /// message has a different function code, `ERANGE` is returned and the message is consumed.
+ ///
+ /// The read pointer is always advanced past the message, regardless of whether it matched or
+ /// could be parsed.
+ ///
+ /// # Errors
+ ///
+ /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
+ /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
+ /// message queue.
+ /// - `EINVAL` if the function code of the message was not recognized.
+ /// - `ERANGE` if the message had a recognized but non-matching function code.
+ ///
+ /// Error codes returned by [`MessageFromGsp::read`] are propagated as-is.
+ fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
+ where
+ // This allows all error types, including `Infallible`, to be used for `M::InitError`.
+ Error: From<M::InitError>,
+ {
+ let dev = self.dev;
+
+ self.consume_element(timeout, |element| {
+ let message = Self::parse_rpc_message(dev, element)?;
+ let function = message.header.rpc_header().function().map_err(|_| EINVAL)?;
+
+ if function != M::FUNCTION {
+ return Err(ERANGE);
+ }
+
+ let (cmd, contents_1) = M::Message::from_bytes_prefix(message.contents.0).ok_or(EIO)?;
+ let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]);
+
+ M::read(cmd, &mut sbuffer)
+ .map_err(|e| e.into())
+ .inspect(|_| {
+ if !sbuffer.is_empty() {
+ dev_warn!(dev, "GSP message {:?} has unprocessed data\n", function);
+ }
+ })
+ })
+ }
}
impl Cmdq<'_> {
@@ -245,4 +364,15 @@ pub(crate) fn send_command_no_wait<M>(&self, command: M) -> Result
{
self.inner.lock().send_command(command)
}
+
+ /// Receive a message from the GSP.
+ ///
+ /// See [`CmdqInner::receive_msg`] for details.
+ pub(crate) fn receive_msg<M: MessageFromGsp>(&self, timeout: Delta) -> Result<M>
+ where
+ // This allows all error types, including `Infallible`, to be used for `M::InitError`.
+ Error: From<M::InitError>,
+ {
+ self.inner.lock().receive_msg(timeout)
+ }
}
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 03bd0d881934..25a5a8d33d64 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -23,9 +23,11 @@
gpu::Chipset,
gsp::{
cmdq::{
- rpc::CommandToGsp,
+ rpc::{
+ CommandToGsp,
+ MessageFromGsp, //
+ },
Cmdq,
- MessageFromGsp,
NoReply, //
},
fw::{
diff --git a/drivers/gpu/nova-core/gsp/sequencer.rs b/drivers/gpu/nova-core/gsp/sequencer.rs
index dae34c11eb05..ebf13867746f 100644
--- a/drivers/gpu/nova-core/gsp/sequencer.rs
+++ b/drivers/gpu/nova-core/gsp/sequencer.rs
@@ -28,8 +28,8 @@
},
gsp::{
cmdq::{
- Cmdq,
- MessageFromGsp, //
+ rpc::MessageFromGsp,
+ Cmdq, //
},
fw,
GspBootContext,
--
2.55.0
next prev parent reply other threads:[~2026-09-27 13:46 UTC|newest]
Thread overview: 25+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-27 13:46 [PATCH v2 0/9] gpu: nova-core: gsp: prepare the command queue for r000 dual-message types Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 1/9] gpu: nova-core: gsp: cmdq: validate checksum earlier on receive Alexandre Courbot
2026-09-28 4:25 ` Eliot Courtney
2026-09-28 6:24 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 2/9] gpu: nova-core: gsp: introduce and use proper RpcMessageHeader type Alexandre Courbot
2026-09-28 4:43 ` Eliot Courtney
2026-09-28 6:22 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 3/9] gpu: nova-core: gsp: cmdq: group the RPC-specific part of send_single_command Alexandre Courbot
2026-09-28 4:52 ` Eliot Courtney
2026-09-27 13:46 ` [PATCH v2 4/9] gpu: nova-core: gsp: cmdq: split the transport part of the send path Alexandre Courbot
2026-09-28 5:16 ` Eliot Courtney
2026-09-28 6:19 ` Alexandre Courbot
2026-09-28 6:40 ` Eliot Courtney
2026-09-28 11:35 ` Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 5/9] gpu: nova-core: gsp: cmdq: move the RPC send code into a sub-module Alexandre Courbot
2026-09-27 13:46 ` [PATCH v2 6/9] gpu: nova-core: gsp: cmdq: split the transport part of the receive path Alexandre Courbot
2026-09-28 3:19 ` Alexandre Courbot
2026-09-27 13:46 ` Alexandre Courbot [this message]
2026-09-27 13:46 ` [PATCH v2 8/9] gpu: nova-core: gsp: move the RPC commands into a sub-module Alexandre Courbot
2026-09-28 5:25 ` Eliot Courtney
2026-09-28 9:20 ` Zhi Wang
2026-09-28 11:40 ` Alexandre Courbot
2026-09-28 15:11 ` Zhi Wang
2026-09-27 13:46 ` [PATCH v2 9/9] gpu: nova-core: gsp: add `rpc` to RPC message send/receive methods Alexandre Courbot
2026-09-28 5:32 ` Eliot Courtney
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=20260927-cmdq-rpc-v2-7-c3f66ae73be4@nvidia.com \
--to=acourbot@nvidia.com \
--cc=airlied@gmail.com \
--cc=aliceryhl@google.com \
--cc=apopple@nvidia.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=ecourtney@nvidia.com \
--cc=gary@garyguo.net \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=lossin@kernel.org \
--cc=nova-gpu@lists.linux.dev \
--cc=rust-for-linux@vger.kernel.org \
--cc=simona@ffwll.ch \
--cc=ttabi@nvidia.com \
--cc=zhiw@nvidia.com \
/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®