[PATCH v3 31/33] gpu: nova-core: gsp: split the reply match out of the RPC receive path
From: John Hubbard
Date: Thu Sep 17 2026 - 21:13:30 EST
GSP-RM posts RPC and GMC messages on one queue, so a receive path has
to decode each element by its kind before it can match an RPC reply.
The RPC receive path matched the reply inline, in the function that
also waited for the element and advanced the read pointer past it. A
dispatch on the element kind in that function would have nested the
whole match one level deeper.
Move the match into a helper of its own, which decodes the awaited
reply or logs the message. The receive path keeps the wait and the
read pointer advance.
The following patch adds the dispatch.
No functional changes.
Assisted-by: LLM
Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 58 ++++++++++++++++++++++---------
1 file changed, 41 insertions(+), 17 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index fc26c7d8aac0..2258c4f2cfd1 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -915,12 +915,8 @@ fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
/// Receives a message from the GSP.
///
- /// A message whose function code is `M::FUNCTION` is decoded and returned. Any other message
- /// is logged as an event.
- ///
- /// With `expected_seq` set, the message must carry that RPC sequence number too. A message
- /// with the expected function code and a different sequence is a stale reply to a command
- /// that already timed out, so it is logged and dropped rather than classified as an event.
+ /// [`Self::match_rpc_reply`] decodes the message as the awaited reply of type `M`, or logs it.
+ /// `expected_seq` narrows the match.
///
/// The read pointer advances past the message in every case, including a decode failure.
///
@@ -942,13 +938,48 @@ fn receive_msg<M: MessageFromGsp>(
Error: From<M::InitError>,
{
let message = self.wait_for_msg(timeout)?;
+
+ // An early return here would leave the read pointer on this message.
+ let result = self.match_rpc_reply::<M>(&message, expected_seq);
+
+ // Advance the read pointer past this message.
+ self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
+ message.header.length().div_ceil(GSP_PAGE_SIZE),
+ )?);
+
+ result
+ }
+
+ /// Decodes `message` as the awaited reply of type `M`, or logs it.
+ ///
+ /// A message whose function code is `M::FUNCTION` is decoded and returned. Any other message
+ /// is logged as an event.
+ ///
+ /// With `expected_seq` set, the message must carry that RPC sequence number too. A message
+ /// with the expected function code and a different sequence is a stale reply to a command
+ /// that already timed out, so it is logged as stale rather than as an event.
+ ///
+ /// # Errors
+ ///
+ /// - `EIO` if the matched message is too short for `M::Message`.
+ /// - `ENOMSG` if the message is not the awaited reply.
+ ///
+ /// Error codes returned by [`MessageFromGsp::read`] are propagated as-is.
+ fn match_rpc_reply<M: MessageFromGsp>(
+ &self,
+ message: &GspMessage<'_>,
+ expected_seq: Option<u32>,
+ ) -> Result<M>
+ where
+ // This allows all error types, including `Infallible`, to be used for `M::InitError`.
+ Error: From<M::InitError>,
+ {
let function = message.header.function();
let seq = message.header.sequence();
let func_matches = matches!(function, Ok(f) if f == M::FUNCTION);
let matched = func_matches && expected_seq.is_none_or(|expected| seq == expected);
- // An early return here would leave the read pointer on this message.
- let result = if matched {
+ if matched {
match M::Message::from_bytes_prefix(message.contents.0) {
Some((cmd, contents_1)) => {
let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]);
@@ -984,20 +1015,13 @@ fn receive_msg<M: MessageFromGsp>(
}
Err(ENOMSG)
- };
-
- // Advance the read pointer past this message.
- self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
- message.header.length().div_ceil(GSP_PAGE_SIZE),
- )?);
-
- result
+ }
}
/// Receives a message of type `M`, waiting up to [`Cmdq::RECEIVE_TIMEOUT`] from the call.
///
/// Any other message that arrives first is logged as an event and does not extend the
- /// deadline. `expected_seq` narrows the match as [`Self::receive_msg`] describes.
+ /// deadline. `expected_seq` narrows the match as [`Self::match_rpc_reply`] describes.
///
/// # Errors
///
--
2.55.0