[PATCH v4 09/17] gpu: nova-core: log GSP events instead of discarding them

From: John Hubbard

Date: Sat Sep 12 2026 - 00:47:02 EST


The GSP posts unsolicited messages on the same queue that carries
command replies: log records, OS error and robust-channel records, and
lifecycle notices.

nova-core discarded every message that was not the reply a caller was
waiting for, and an unrecognized function code aborted the in-flight
command. The GSP's error reports never reached the kernel log.

Log every non-reply message according to its function code, on the
receive path that already reads it, and leave the in-flight command
waiting for its reply. Event payloads, such as XID numbers and log
contents, are not decoded.

Assisted-by: LLM
Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 52 ++++++++++++++++++++++++-------
1 file changed, 41 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 9f99e6bbb4fa..340760e384d0 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -557,8 +557,7 @@ fn notify_gsp(bar: Bar0<'_>) {

/// Sends `command` to the GSP and waits for the reply.
///
- /// Messages with non-matching function codes are silently consumed until the expected reply
- /// arrives.
+ /// Events that arrive before the reply are logged and consumed.
///
/// The queue is locked for the entire send+receive cycle to ensure that no other command can
/// be interleaved.
@@ -815,8 +814,8 @@ fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {

/// 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.
+ /// A message whose function code is `M::FUNCTION` is decoded and returned. Any other message
+ /// is logged as an event.
///
/// The read pointer is always advanced past the message, regardless of whether it matched.
///
@@ -825,8 +824,7 @@ fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
/// - `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.
+ /// - `ERANGE` if the message was not the awaited reply.
///
/// Error codes returned by [`MessageFromGsp::read`] are propagated as-is.
fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
@@ -835,11 +833,11 @@ fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
Error: From<M::InitError>,
{
let message = self.wait_for_msg(timeout)?;
- let function = message.header.function().map_err(|_| EINVAL)?;
+ let function = message.header.function();
+ let seq = message.header.sequence();

- // Extract the message. Store the result as we want to advance the read pointer even in
- // case of failure.
- let result = if function == M::FUNCTION {
+ // An early return here would leave the read pointer on this message.
+ let result = if matches!(function, Ok(f) if f == M::FUNCTION) {
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]);

@@ -850,11 +848,13 @@ fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
dev_warn!(
&self.dev,
"GSP message {:?} has unprocessed data\n",
- function
+ M::FUNCTION
);
}
})
} else {
+ self.log_event(function, seq);
+
Err(ERANGE)
};

@@ -865,4 +865,34 @@ fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>

result
}
+
+ /// Logs an event, meaning a message that no caller was waiting for.
+ ///
+ /// An OS error or robust-channel record is logged at error level and an unknown function code
+ /// at warning level. Every other event is recorded only by the receive trace in
+ /// [`Self::wait_for_msg`].
+ fn log_event(&self, function: Result<MsgFunction, u32>, seq: u32) {
+ match function {
+ Ok(MsgFunction::OsErrorLog) => {
+ dev_err!(&self.dev, "GSP reported an OS error (seq {})\n", seq);
+ }
+ Ok(MsgFunction::RcTriggered) => {
+ dev_err!(
+ &self.dev,
+ "GSP triggered robust-channel recovery (seq {})\n",
+ seq
+ );
+ }
+ // Nothing to do for the remaining known function codes.
+ Ok(_) => {}
+ Err(raw) => {
+ dev_warn!(
+ &self.dev,
+ "unknown GSP message function {:#x} (seq {})\n",
+ raw,
+ seq
+ );
+ }
+ }
+ }
}
--
2.55.0