public inbox for drm-ai-reviews@public-inbox.freedesktop.org
 help / color / mirror / Atom feed
* Claude review: gpu: nova-core: gsp: add command_size helper
  2026-02-19  7:30 ` [PATCH v2 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
@ 2026-02-19  8:43   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-19  8:43 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

> +fn command_size<M>(command: &M) -> usize
> +where
> +    M: CommandToGsp,
> +{
> +    size_of::<M::Command>() + command.variable_payload_len()
> +}

Simple extraction of a repeated pattern into a helper. Initially private, made `pub(crate)` in patch 8. No issues.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support
@ 2026-02-26 11:45 Eliot Courtney
  2026-02-26 11:45 ` [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically Eliot Courtney
                   ` (9 more replies)
  0 siblings, 10 replies; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

GSP commands over 16 pages need to be sent using "continuation records"
which essentially means splitting the payload over multiple commands.

This series adds a command type `ContinuationRecord` which just writes
its header and whatever payload it is given. It also adds types
`SplitState` and `SplitCommand` which support splitting a large RPC
into smaller ones while transparently letting regular sized RPCs be sent
without extra copies.

The send pathway uses `SplitState` to send all commands, but if
the command fits into 16 pages, it still writes directly into the
command queue. If it is larger than 16 pages and needs continuation
records, it writes into a staging buffer, so there is one copy.

Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
Changes in v3:
- Rebased onto drm-rust-next
- Added some doc comments
- Reworded command_size doc comment
- Link to v2: https://lore.kernel.org/r/20260219-cmdq-continuation-v2-0-2e8b7615536f@nvidia.com

Changes in v2:
- Added doccoments
- Renamed driver_bytes_available_to_write to driver_write_area_size
- allocate_command_with_timeout merged allocate_command with timeout parameter
- Replaced hardcoded GSP_PAGE_SIZE * 16 with bindings
- Changed oversized command error from EIO to EMSGSIZE
- Added EMSGSIZE to kernel/error.rs
- Split WrappingCommand functionality into SplitState + SplitCommand enum
- Made max_size a const (MAX_CMD_SIZE)
- Removed send_continuation_record + added comment for type inference
- send_single_command now consumes the command
- Extracted command_size + used in SplitState 
- Link to v1: https://lore.kernel.org/r/20260212-cmdq-continuation-v1-0-73079ded55e6@nvidia.com

---
Eliot Courtney (9):
      gpu: nova-core: gsp: sort MsgFunction variants alphabetically
      gpu: nova-core: gsp: add mechanism to wait for space on command queue
      rust: add EMSGSIZE error code
      gpu: nova-core: gsp: add checking oversized commands
      gpu: nova-core: gsp: clarify invariant on command queue
      gpu: nova-core: gsp: unconditionally call variable payload handling
      gpu: nova-core: gsp: add command_size helper
      gpu: nova-core: gsp: support large RPCs via continuation record
      gpu: nova-core: gsp: add tests for SplitState

 drivers/gpu/nova-core/gsp/cmdq.rs                 | 116 +++++++---
 drivers/gpu/nova-core/gsp/commands.rs             | 258 +++++++++++++++++++++-
 drivers/gpu/nova-core/gsp/fw.rs                   |  75 ++++---
 drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs |   1 +
 rust/kernel/error.rs                              |   1 +
 5 files changed, 393 insertions(+), 58 deletions(-)
---
base-commit: 4a49fe23e357b48845e31fe9c28a802c05458198
change-id: 20260203-cmdq-continuation-b99f3d5966c3

Best regards,
-- 
Eliot Courtney <ecourtney@nvidia.com>


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 2/9] gpu: nova-core: gsp: add mechanism to wait for space on command queue Eliot Courtney
                   ` (8 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

There is no particular order required here and keeping them alphabetical
will help preventing future mistakes.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/fw.rs | 67 +++++++++++++++++++++--------------------
 1 file changed, 35 insertions(+), 32 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index f1797e1f0d9d..4b998485360b 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -191,34 +191,34 @@ pub(crate) fn new(gsp_firmware: &GspFirmware, fb_layout: &FbLayout) -> Self {
 #[repr(u32)]
 pub(crate) enum MsgFunction {
     // Common function codes
-    Nop = bindings::NV_VGPU_MSG_FUNCTION_NOP,
-    SetGuestSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO,
-    AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT,
+    AllocChannelDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA,
+    AllocCtxDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA,
     AllocDevice = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE,
     AllocMemory = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY,
-    AllocCtxDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA,
-    AllocChannelDma = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA,
-    MapMemory = bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY,
-    BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA,
     AllocObject = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT,
+    AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT,
+    BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA,
     Free = bindings::NV_VGPU_MSG_FUNCTION_FREE,
-    Log = bindings::NV_VGPU_MSG_FUNCTION_LOG,
     GetGspStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO,
-    SetRegistry = bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY,
-    GspSetSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO,
+    GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO,
     GspInitPostObjGpu = bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU,
     GspRmControl = bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL,
-    GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO,
+    GspSetSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO,
+    Log = bindings::NV_VGPU_MSG_FUNCTION_LOG,
+    MapMemory = bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY,
+    Nop = bindings::NV_VGPU_MSG_FUNCTION_NOP,
+    SetGuestSystemInfo = bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO,
+    SetRegistry = bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY,
 
     // Event codes
     GspInitDone = bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE,
+    GspLockdownNotice = bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE,
+    GspPostNoCat = bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD,
     GspRunCpuSequencer = bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER,
-    PostEvent = bindings::NV_VGPU_MSG_EVENT_POST_EVENT,
-    RcTriggered = bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED,
     MmuFaultQueued = bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED,
     OsErrorLog = bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG,
-    GspPostNoCat = bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD,
-    GspLockdownNotice = bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE,
+    PostEvent = bindings::NV_VGPU_MSG_EVENT_POST_EVENT,
+    RcTriggered = bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED,
     UcodeLibOsPrint = bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT,
 }
 
@@ -227,38 +227,41 @@ impl TryFrom<u32> for MsgFunction {
 
     fn try_from(value: u32) -> Result<MsgFunction> {
         match value {
-            bindings::NV_VGPU_MSG_FUNCTION_NOP => Ok(MsgFunction::Nop),
-            bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO => {
-                Ok(MsgFunction::SetGuestSystemInfo)
-            }
-            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot),
+            // Common function codes
+            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA => Ok(MsgFunction::AllocChannelDma),
+            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA => Ok(MsgFunction::AllocCtxDma),
             bindings::NV_VGPU_MSG_FUNCTION_ALLOC_DEVICE => Ok(MsgFunction::AllocDevice),
             bindings::NV_VGPU_MSG_FUNCTION_ALLOC_MEMORY => Ok(MsgFunction::AllocMemory),
-            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CTX_DMA => Ok(MsgFunction::AllocCtxDma),
-            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_CHANNEL_DMA => Ok(MsgFunction::AllocChannelDma),
-            bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY => Ok(MsgFunction::MapMemory),
-            bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma),
             bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT => Ok(MsgFunction::AllocObject),
+            bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot),
+            bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma),
             bindings::NV_VGPU_MSG_FUNCTION_FREE => Ok(MsgFunction::Free),
-            bindings::NV_VGPU_MSG_FUNCTION_LOG => Ok(MsgFunction::Log),
             bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO => Ok(MsgFunction::GetGspStaticInfo),
-            bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY => Ok(MsgFunction::SetRegistry),
-            bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO => Ok(MsgFunction::GspSetSystemInfo),
+            bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo),
             bindings::NV_VGPU_MSG_FUNCTION_GSP_INIT_POST_OBJGPU => {
                 Ok(MsgFunction::GspInitPostObjGpu)
             }
             bindings::NV_VGPU_MSG_FUNCTION_GSP_RM_CONTROL => Ok(MsgFunction::GspRmControl),
-            bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo),
+            bindings::NV_VGPU_MSG_FUNCTION_GSP_SET_SYSTEM_INFO => Ok(MsgFunction::GspSetSystemInfo),
+            bindings::NV_VGPU_MSG_FUNCTION_LOG => Ok(MsgFunction::Log),
+            bindings::NV_VGPU_MSG_FUNCTION_MAP_MEMORY => Ok(MsgFunction::MapMemory),
+            bindings::NV_VGPU_MSG_FUNCTION_NOP => Ok(MsgFunction::Nop),
+            bindings::NV_VGPU_MSG_FUNCTION_SET_GUEST_SYSTEM_INFO => {
+                Ok(MsgFunction::SetGuestSystemInfo)
+            }
+            bindings::NV_VGPU_MSG_FUNCTION_SET_REGISTRY => Ok(MsgFunction::SetRegistry),
+
+            // Event codes
             bindings::NV_VGPU_MSG_EVENT_GSP_INIT_DONE => Ok(MsgFunction::GspInitDone),
+            bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE => Ok(MsgFunction::GspLockdownNotice),
+            bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD => Ok(MsgFunction::GspPostNoCat),
             bindings::NV_VGPU_MSG_EVENT_GSP_RUN_CPU_SEQUENCER => {
                 Ok(MsgFunction::GspRunCpuSequencer)
             }
-            bindings::NV_VGPU_MSG_EVENT_POST_EVENT => Ok(MsgFunction::PostEvent),
-            bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED => Ok(MsgFunction::RcTriggered),
             bindings::NV_VGPU_MSG_EVENT_MMU_FAULT_QUEUED => Ok(MsgFunction::MmuFaultQueued),
             bindings::NV_VGPU_MSG_EVENT_OS_ERROR_LOG => Ok(MsgFunction::OsErrorLog),
-            bindings::NV_VGPU_MSG_EVENT_GSP_POST_NOCAT_RECORD => Ok(MsgFunction::GspPostNoCat),
-            bindings::NV_VGPU_MSG_EVENT_GSP_LOCKDOWN_NOTICE => Ok(MsgFunction::GspLockdownNotice),
+            bindings::NV_VGPU_MSG_EVENT_POST_EVENT => Ok(MsgFunction::PostEvent),
+            bindings::NV_VGPU_MSG_EVENT_RC_TRIGGERED => Ok(MsgFunction::RcTriggered),
             bindings::NV_VGPU_MSG_EVENT_UCODE_LIBOS_PRINT => Ok(MsgFunction::UcodeLibOsPrint),
             _ => Err(EINVAL),
         }

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 2/9] gpu: nova-core: gsp: add mechanism to wait for space on command queue
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
  2026-02-26 11:45 ` [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 3/9] rust: add EMSGSIZE error code Eliot Courtney
                   ` (7 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Add a timeout to `allocate_command` which waits for space on the GSP
command queue. It uses a similar timeout to nouveau.

This lets `send_command` wait for space to free up in the command queue.
This is required to support continuation records which can fill up the
queue.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs | 39 +++++++++++++++++++++++++++------------
 1 file changed, 27 insertions(+), 12 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 87dbbd6d1be9..efbbc89f4d8a 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -250,6 +250,19 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
         }
     }
 
+    /// Returns the size of the region of the CPU message queue that the driver is currently allowed
+    /// to write to, in bytes.
+    fn driver_write_area_size(&self) -> usize {
+        let tx = self.cpu_write_ptr();
+        let rx = self.gsp_read_ptr();
+
+        // `rx` and `tx` are both in `0..MSGQ_NUM_PAGES` per the invariants of `gsp_read_ptr` and
+        // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES -
+        // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`.
+        let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
+        num::u32_as_usize(slots) * GSP_PAGE_SIZE
+    }
+
     /// Returns the region of the GSP message queue that the driver is currently allowed to read
     /// from.
     ///
@@ -281,15 +294,22 @@ fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
     }
 
     /// Allocates a region on the command queue that is large enough to send a command of `size`
-    /// bytes.
+    /// bytes, waiting for space to become available based on the provided timeout.
     ///
     /// This returns a [`GspCommand`] ready to be written to by the caller.
     ///
     /// # Errors
     ///
-    /// - `EAGAIN` if the driver area is too small to hold the requested command.
+    /// - `ETIMEDOUT` if space does not become available within the timeout.
     /// - `EIO` if the command header is not properly aligned.
-    fn allocate_command(&mut self, size: usize) -> Result<GspCommand<'_>> {
+    fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand<'_>> {
+        read_poll_timeout(
+            || Ok(self.driver_write_area_size()),
+            |available_bytes| *available_bytes >= size_of::<GspMsgElement>() + size,
+            Delta::ZERO,
+            timeout,
+        )?;
+
         // Get the current writable area as an array of bytes.
         let (slice_1, slice_2) = {
             let (slice_1, slice_2) = self.driver_write_area();
@@ -298,13 +318,6 @@ fn allocate_command(&mut self, size: usize) -> Result<GspCommand<'_>> {
             (slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
         };
 
-        // If the GSP is still processing previous messages the shared region
-        // may be full in which case we will have to retry once the GSP has
-        // processed the existing commands.
-        if size_of::<GspMsgElement>() + size > slice_1.len() + slice_2.len() {
-            return Err(EAGAIN);
-        }
-
         // Extract area for the `GspMsgElement`.
         let (header, slice_1) = GspMsgElement::from_bytes_mut_prefix(slice_1).ok_or(EIO)?;
 
@@ -497,7 +510,7 @@ fn notify_gsp(bar: &Bar0) {
     ///
     /// # Errors
     ///
-    /// - `EAGAIN` if there was not enough space in the command queue to send the command.
+    /// - `ETIMEDOUT` if space does not become available within the timeout.
     /// - `EIO` if the variable payload requested by the command has not been entirely
     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
     ///
@@ -509,7 +522,9 @@ pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
         Error: From<M::InitError>,
     {
         let command_size = size_of::<M::Command>() + command.variable_payload_len();
-        let dst = self.gsp_mem.allocate_command(command_size)?;
+        let dst = self
+            .gsp_mem
+            .allocate_command(command_size, Delta::from_secs(1))?;
 
         // Extract area for the command itself.
         let (cmd, payload_1) = M::Command::from_bytes_mut_prefix(dst.contents.0).ok_or(EIO)?;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 3/9] rust: add EMSGSIZE error code
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
  2026-02-26 11:45 ` [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically Eliot Courtney
  2026-02-26 11:45 ` [PATCH v3 2/9] gpu: nova-core: gsp: add mechanism to wait for space on command queue Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-26 14:04   ` Miguel Ojeda
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 4/9] gpu: nova-core: gsp: add checking oversized commands Eliot Courtney
                   ` (6 subsequent siblings)
  9 siblings, 2 replies; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Add the EMSGSIZE error code, which indicates that a message is too
long.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 rust/kernel/error.rs | 1 +
 1 file changed, 1 insertion(+)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 258b12afdcba..10fcf1f0404d 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -67,6 +67,7 @@ macro_rules! declare_err {
     declare_err!(EDOM, "Math argument out of domain of func.");
     declare_err!(ERANGE, "Math result not representable.");
     declare_err!(EOVERFLOW, "Value too large for defined data type.");
+    declare_err!(EMSGSIZE, "Message too long.");
     declare_err!(ETIMEDOUT, "Connection timed out.");
     declare_err!(ERESTARTSYS, "Restart the system call.");
     declare_err!(ERESTARTNOINTR, "System call was interrupted by a signal and will be restarted.");

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 4/9] gpu: nova-core: gsp: add checking oversized commands
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (2 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 3/9] rust: add EMSGSIZE error code Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 5/9] gpu: nova-core: gsp: clarify invariant on command queue Eliot Courtney
                   ` (5 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

The limit is 16 pages for a single command sent to the GSP. Return an
error if `allocate_command` is called with a too large size.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs                 | 7 ++++++-
 drivers/gpu/nova-core/gsp/fw.rs                   | 4 ++++
 drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs | 1 +
 3 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index efbbc89f4d8a..3c2652be74bf 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -32,7 +32,8 @@
             GspMsgElement,
             MsgFunction,
             MsgqRxHeader,
-            MsgqTxHeader, //
+            MsgqTxHeader,
+            GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, //
         },
         PteArray,
         GSP_PAGE_SHIFT,
@@ -300,9 +301,13 @@ fn driver_write_area_size(&self) -> usize {
     ///
     /// # Errors
     ///
+    /// - `EMSGSIZE` if the command is larger than [`GSP_MSG_QUEUE_ELEMENT_SIZE_MAX`].
     /// - `ETIMEDOUT` if space does not become available within the timeout.
     /// - `EIO` if the command header is not properly aligned.
     fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand<'_>> {
+        if size_of::<GspMsgElement>() + size > GSP_MSG_QUEUE_ELEMENT_SIZE_MAX {
+            return Err(EMSGSIZE);
+        }
         read_poll_timeout(
             || Ok(self.driver_write_area_size()),
             |available_bytes| *available_bytes >= size_of::<GspMsgElement>() + size,
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 4b998485360b..6005362450cb 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -39,6 +39,10 @@
     },
 };
 
+/// Maximum size of a single GSP message queue element in bytes.
+pub(crate) const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: usize =
+    num::u32_as_usize(bindings::GSP_MSG_QUEUE_ELEMENT_SIZE_MAX);
+
 /// Empty type to group methods related to heap parameters for running the GSP firmware.
 enum GspFwHeapParams {}
 
diff --git a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
index 6d25fe0bffa9..334e8be5fde8 100644
--- a/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
+++ b/drivers/gpu/nova-core/gsp/fw/r570_144/bindings.rs
@@ -43,6 +43,7 @@ fn fmt(&self, fmt: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
 pub const GSP_FW_WPR_META_REVISION: u32 = 1;
 pub const GSP_FW_WPR_META_MAGIC: i64 = -2577556379034558285;
 pub const REGISTRY_TABLE_ENTRY_TYPE_DWORD: u32 = 1;
+pub const GSP_MSG_QUEUE_ELEMENT_SIZE_MAX: u32 = 65536;
 pub type __u8 = ffi::c_uchar;
 pub type __u16 = ffi::c_ushort;
 pub type __u32 = ffi::c_uint;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 5/9] gpu: nova-core: gsp: clarify invariant on command queue
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (3 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 4/9] gpu: nova-core: gsp: add checking oversized commands Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 6/9] gpu: nova-core: gsp: unconditionally call variable payload handling Eliot Courtney
                   ` (4 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Clarify why using only the first returned slice from allocate_command
for the message headers is okay.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 3c2652be74bf..3653212efa7a 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -531,7 +531,9 @@ pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
             .gsp_mem
             .allocate_command(command_size, Delta::from_secs(1))?;
 
-        // Extract area for the command itself.
+        // Extract area for the command itself. The GSP message header and the command header
+        // together are guaranteed to fit entirely into a single page, so it's ok to only look
+        // at `dst.contents.0` here.
         let (cmd, payload_1) = M::Command::from_bytes_mut_prefix(dst.contents.0).ok_or(EIO)?;
 
         // Fill the header and command in-place.

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 6/9] gpu: nova-core: gsp: unconditionally call variable payload handling
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (4 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 5/9] gpu: nova-core: gsp: clarify invariant on command queue Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
                   ` (3 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Unconditionally call the variable length payload code, which is a no-op
if there is no such payload but could defensively catch some coding
errors by e.g. checking that the allocated size is completely filled.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 3653212efa7a..9f74f0898d90 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -545,16 +545,14 @@ pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
             command.init().__init(core::ptr::from_mut(cmd))?;
         }
 
-        // Fill the variable-length payload.
-        if command_size > size_of::<M::Command>() {
-            let mut sbuffer =
-                SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]);
-            command.init_variable_payload(&mut sbuffer)?;
+        // Fill the variable-length payload, which may be empty.
+        let mut sbuffer = SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]);
+        command.init_variable_payload(&mut sbuffer)?;
 
-            if !sbuffer.is_empty() {
-                return Err(EIO);
-            }
+        if !sbuffer.is_empty() {
+            return Err(EIO);
         }
+        drop(sbuffer);
 
         // Compute checksum now that the whole message is ready.
         dst.header

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 7/9] gpu: nova-core: gsp: add command_size helper
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (5 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 6/9] gpu: nova-core: gsp: unconditionally call variable payload handling Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 8/9] gpu: nova-core: gsp: support large RPCs via continuation record Eliot Courtney
                   ` (2 subsequent siblings)
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Add a helper function which computes the size of a command.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 9f74f0898d90..4a663a5b3437 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -450,6 +450,15 @@ struct GspMessage<'a> {
     contents: (&'a [u8], &'a [u8]),
 }
 
+/// Computes the total size of the command (including its variable-length payload) without the
+/// [`GspMsgElement`] header.
+fn command_size<M>(command: &M) -> usize
+where
+    M: CommandToGsp,
+{
+    size_of::<M::Command>() + command.variable_payload_len()
+}
+
 /// GSP command queue.
 ///
 /// Provides the ability to send commands and receive messages from the GSP using a shared memory
@@ -526,7 +535,7 @@ pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
         Error: From<M::InitError>,
     {
-        let command_size = size_of::<M::Command>() + command.variable_payload_len();
+        let command_size = command_size(&command);
         let dst = self
             .gsp_mem
             .allocate_command(command_size, Delta::from_secs(1))?;

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 8/9] gpu: nova-core: gsp: support large RPCs via continuation record
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (6 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  2026-02-26 11:45 ` [PATCH v3 9/9] gpu: nova-core: gsp: add tests for SplitState Eliot Courtney
  2026-02-27  2:21 ` Claude review: gpu: nova-core: gsp: add continuation record support Claude Code Review Bot
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Splits large RPCs if necessary and sends the remaining parts using
continuation records. RPCs that do not need continuation records
continue to write directly into the command buffer. Ones that do write
into a staging buffer first, so there is one copy.

Continuation record for receive is not necessary to support at the
moment because those replies do not need to be read and are currently
drained by retrying `receive_msg` on ERANGE.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/cmdq.rs     |  43 +++++++++-
 drivers/gpu/nova-core/gsp/commands.rs | 144 +++++++++++++++++++++++++++++++++-
 drivers/gpu/nova-core/gsp/fw.rs       |   4 +
 3 files changed, 187 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index 4a663a5b3437..d68b93ddf7cc 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -28,6 +28,10 @@
 use crate::{
     driver::Bar0,
     gsp::{
+        commands::{
+            ContinuationRecord,
+            SplitState, //
+        },
         fw::{
             GspMsgElement,
             MsgFunction,
@@ -452,7 +456,7 @@ struct GspMessage<'a> {
 
 /// Computes the total size of the command (including its variable-length payload) without the
 /// [`GspMsgElement`] header.
-fn command_size<M>(command: &M) -> usize
+pub(crate) fn command_size<M>(command: &M) -> usize
 where
     M: CommandToGsp,
 {
@@ -520,7 +524,7 @@ fn notify_gsp(bar: &Bar0) {
             .write(bar);
     }
 
-    /// Sends `command` to the GSP.
+    /// Sends `command` to the GSP, without splitting it.
     ///
     /// # Errors
     ///
@@ -529,7 +533,7 @@ fn notify_gsp(bar: &Bar0) {
     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
     ///
     /// Error codes returned by the command initializers are propagated as-is.
-    pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
+    fn send_single_command<M>(&mut self, bar: &Bar0, command: M) -> Result
     where
         M: CommandToGsp,
         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
@@ -588,6 +592,39 @@ pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
         Ok(())
     }
 
+    /// Sends `command` to the GSP.
+    ///
+    /// The command may be split into multiple messages if it is large.
+    ///
+    /// # Errors
+    ///
+    /// - `ETIMEDOUT` if space does not become available within the timeout.
+    /// - `EIO` if the variable payload requested by the command has not been entirely
+    ///   written to by its [`CommandToGsp::init_variable_payload`] method.
+    ///
+    /// Error codes returned by the command initializers are propagated as-is.
+    pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
+    where
+        M: CommandToGsp,
+        Error: From<M::InitError>,
+    {
+        let mut state = SplitState::new(&command)?;
+
+        self.send_single_command(bar, state.command(command))?;
+
+        while let Some(continuation) = state.next_continuation_record() {
+            dev_dbg!(
+                &self.dev,
+                "GSP RPC: send continuation: size=0x{:x}\n",
+                command_size(&continuation),
+            );
+            // Turbofish needed because the compiler cannot infer M here.
+            self.send_single_command::<ContinuationRecord<'_>>(bar, continuation)?;
+        }
+
+        Ok(())
+    }
+
     /// Wait for a message to become available on the message queue.
     ///
     /// This works purely at the transport layer and does not interpret or validate the message
diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 8f270eca33be..6ffd0b9cbf05 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -4,6 +4,7 @@
     array,
     convert::Infallible,
     ffi::FromBytesUntilNulError,
+    marker::PhantomData,
     str::Utf8Error, //
 };
 
@@ -22,13 +23,16 @@
     driver::Bar0,
     gsp::{
         cmdq::{
+            command_size,
             Cmdq,
             CommandToGsp,
             MessageFromGsp, //
         },
         fw::{
             commands::*,
-            MsgFunction, //
+            GspMsgElement,
+            MsgFunction,
+            GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, //
         },
     },
     sbuffer::SBufferIter,
@@ -242,3 +246,141 @@ pub(crate) fn get_gsp_info(cmdq: &mut Cmdq, bar: &Bar0) -> Result<GetGspStaticIn
         }
     }
 }
+
+/// The `ContinuationRecord` command.
+pub(crate) struct ContinuationRecord<'a> {
+    data: &'a [u8],
+}
+
+impl<'a> ContinuationRecord<'a> {
+    /// Creates a new `ContinuationRecord` command with the given data.
+    pub(crate) fn new(data: &'a [u8]) -> Self {
+        Self { data }
+    }
+}
+
+impl<'a> CommandToGsp for ContinuationRecord<'a> {
+    const FUNCTION: MsgFunction = MsgFunction::ContinuationRecord;
+    type Command = ();
+    type InitError = Infallible;
+
+    fn init(&self) -> impl Init<Self::Command, Self::InitError> {
+        <()>::init_zeroed()
+    }
+
+    fn variable_payload_len(&self) -> usize {
+        self.data.len()
+    }
+
+    fn init_variable_payload(
+        &self,
+        dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
+    ) -> Result {
+        dst.write_all(self.data)
+    }
+}
+
+/// Wrapper that splits a command across continuation records if needed.
+pub(crate) struct SplitState<C: CommandToGsp> {
+    state: Option<(KVVec<u8>, usize)>,
+    _phantom: PhantomData<C>,
+}
+
+impl<C: CommandToGsp> SplitState<C> {
+    /// Maximum command size that fits in a single queue element.
+    const MAX_CMD_SIZE: usize = GSP_MSG_QUEUE_ELEMENT_SIZE_MAX - size_of::<GspMsgElement>();
+
+    /// Maximum size of the variable payload that can be sent in the main command.
+    const MAX_FIRST_PAYLOAD_SIZE: usize = Self::MAX_CMD_SIZE - size_of::<C::Command>();
+
+    /// Creates a new `SplitState` for the given command.
+    ///
+    /// If the command is too large, it will be split into a main command and some number of
+    /// continuation records.
+    pub(crate) fn new(inner: &C) -> Result<Self> {
+        if command_size(inner) > Self::MAX_CMD_SIZE {
+            let mut staging =
+                KVVec::<u8>::from_elem(0u8, inner.variable_payload_len(), GFP_KERNEL)?;
+            let mut sbuffer = SBufferIter::new_writer([staging.as_mut_slice(), &mut []]);
+            inner.init_variable_payload(&mut sbuffer)?;
+            if !sbuffer.is_empty() {
+                return Err(EIO);
+            }
+            drop(sbuffer);
+
+            Ok(Self {
+                state: Some((staging, Self::MAX_FIRST_PAYLOAD_SIZE)),
+                _phantom: PhantomData,
+            })
+        } else {
+            Ok(Self {
+                state: None,
+                _phantom: PhantomData,
+            })
+        }
+    }
+
+    /// Returns the main command.
+    pub(crate) fn command(&self, inner: C) -> SplitCommand<'_, C> {
+        if let Some((staging, _)) = &self.state {
+            SplitCommand::Split(inner, staging)
+        } else {
+            SplitCommand::Single(inner)
+        }
+    }
+
+    /// Returns the next continuation record, or `None` if there are no more.
+    pub(crate) fn next_continuation_record(&mut self) -> Option<ContinuationRecord<'_>> {
+        let (staging, offset) = self.state.as_mut()?;
+
+        let remaining = staging.len() - *offset;
+        if remaining > 0 {
+            let chunk_size = remaining.min(Self::MAX_CMD_SIZE);
+            let record = ContinuationRecord::new(&staging[*offset..(*offset + chunk_size)]);
+            *offset += chunk_size;
+            Some(record)
+        } else {
+            None
+        }
+    }
+}
+
+/// Wrapper enum that represents either a single command or a split command with its staging buffer.
+pub(crate) enum SplitCommand<'a, C: CommandToGsp> {
+    /// A command that fits in a single queue element.
+    Single(C),
+    /// A command split across continuation records, with its full payload in a staging buffer.
+    Split(C, &'a [u8]),
+}
+
+impl<'a, C: CommandToGsp> CommandToGsp for SplitCommand<'a, C> {
+    const FUNCTION: MsgFunction = C::FUNCTION;
+    type Command = C::Command;
+    type InitError = C::InitError;
+
+    fn init(&self) -> impl Init<Self::Command, Self::InitError> {
+        match self {
+            SplitCommand::Single(cmd) => cmd.init(),
+            SplitCommand::Split(cmd, _) => cmd.init(),
+        }
+    }
+
+    fn variable_payload_len(&self) -> usize {
+        match self {
+            SplitCommand::Single(cmd) => cmd.variable_payload_len(),
+            SplitCommand::Split(_, _) => SplitState::<C>::MAX_FIRST_PAYLOAD_SIZE,
+        }
+    }
+
+    fn init_variable_payload(
+        &self,
+        dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
+    ) -> Result {
+        match self {
+            SplitCommand::Single(cmd) => cmd.init_variable_payload(dst),
+            SplitCommand::Split(_, staging) => {
+                dst.write_all(&staging[..self.variable_payload_len()])
+            }
+        }
+    }
+}
diff --git a/drivers/gpu/nova-core/gsp/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs
index 6005362450cb..25fca1f6db2c 100644
--- a/drivers/gpu/nova-core/gsp/fw.rs
+++ b/drivers/gpu/nova-core/gsp/fw.rs
@@ -202,6 +202,7 @@ pub(crate) enum MsgFunction {
     AllocObject = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT,
     AllocRoot = bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT,
     BindCtxDma = bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA,
+    ContinuationRecord = bindings::NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD,
     Free = bindings::NV_VGPU_MSG_FUNCTION_FREE,
     GetGspStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO,
     GetStaticInfo = bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO,
@@ -239,6 +240,9 @@ fn try_from(value: u32) -> Result<MsgFunction> {
             bindings::NV_VGPU_MSG_FUNCTION_ALLOC_OBJECT => Ok(MsgFunction::AllocObject),
             bindings::NV_VGPU_MSG_FUNCTION_ALLOC_ROOT => Ok(MsgFunction::AllocRoot),
             bindings::NV_VGPU_MSG_FUNCTION_BIND_CTX_DMA => Ok(MsgFunction::BindCtxDma),
+            bindings::NV_VGPU_MSG_FUNCTION_CONTINUATION_RECORD => {
+                Ok(MsgFunction::ContinuationRecord)
+            }
             bindings::NV_VGPU_MSG_FUNCTION_FREE => Ok(MsgFunction::Free),
             bindings::NV_VGPU_MSG_FUNCTION_GET_GSP_STATIC_INFO => Ok(MsgFunction::GetGspStaticInfo),
             bindings::NV_VGPU_MSG_FUNCTION_GET_STATIC_INFO => Ok(MsgFunction::GetStaticInfo),

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v3 9/9] gpu: nova-core: gsp: add tests for SplitState
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (7 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 8/9] gpu: nova-core: gsp: support large RPCs via continuation record Eliot Courtney
@ 2026-02-26 11:45 ` Eliot Courtney
  2026-02-27  2:22   ` Claude review: " Claude Code Review Bot
  2026-02-27  2:21 ` Claude review: gpu: nova-core: gsp: add continuation record support Claude Code Review Bot
  9 siblings, 1 reply; 23+ messages in thread
From: Eliot Courtney @ 2026-02-26 11:45 UTC (permalink / raw)
  To: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross
  Cc: nouveau, dri-devel, linux-kernel, rust-for-linux, Eliot Courtney,
	Zhi Wang

Add tests for SplitState. They cover boundary conditions at the split
points to make sure the right number of continuation records are made.
They also check that the data concatenated is correct.

Tested-by: Zhi Wang <zhiw@nvidia.com>
Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>
---
 drivers/gpu/nova-core/gsp/commands.rs | 114 ++++++++++++++++++++++++++++++++++
 1 file changed, 114 insertions(+)

diff --git a/drivers/gpu/nova-core/gsp/commands.rs b/drivers/gpu/nova-core/gsp/commands.rs
index 6ffd0b9cbf05..74f875755e53 100644
--- a/drivers/gpu/nova-core/gsp/commands.rs
+++ b/drivers/gpu/nova-core/gsp/commands.rs
@@ -384,3 +384,117 @@ fn init_variable_payload(
         }
     }
 }
+
+#[kunit_tests(nova_core_gsp_commands)]
+mod tests {
+    use super::*;
+
+    struct TestPayload {
+        data: KVVec<u8>,
+    }
+
+    impl TestPayload {
+        fn generate_pattern(len: usize) -> Result<KVVec<u8>> {
+            let mut data = KVVec::with_capacity(len, GFP_KERNEL)?;
+            for i in 0..len {
+                data.push(i as u8, GFP_KERNEL)?;
+            }
+            Ok(data)
+        }
+
+        fn new(len: usize) -> Result<Self> {
+            Ok(Self {
+                data: Self::generate_pattern(len)?,
+            })
+        }
+    }
+
+    impl CommandToGsp for TestPayload {
+        const FUNCTION: MsgFunction = MsgFunction::Nop;
+        type Command = ();
+        type InitError = Infallible;
+
+        fn init(&self) -> impl Init<Self::Command, Self::InitError> {
+            <()>::init_zeroed()
+        }
+
+        fn variable_payload_len(&self) -> usize {
+            self.data.len()
+        }
+
+        fn init_variable_payload(
+            &self,
+            dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
+        ) -> Result {
+            dst.write_all(self.data.as_slice())
+        }
+    }
+
+    const MAX_CMD_SIZE: usize = SplitState::<TestPayload>::MAX_CMD_SIZE;
+
+    fn read_payload(cmd: &impl CommandToGsp) -> Result<KVVec<u8>> {
+        let len = cmd.variable_payload_len();
+        let mut buf = KVVec::from_elem(0u8, len, GFP_KERNEL)?;
+        let mut sbuf = SBufferIter::new_writer([buf.as_mut_slice(), &mut []]);
+        cmd.init_variable_payload(&mut sbuf)?;
+        drop(sbuf);
+        Ok(buf)
+    }
+
+    struct SplitTest {
+        payload_size: usize,
+        num_continuations: usize,
+    }
+
+    fn check_split(t: SplitTest) -> Result {
+        let payload = TestPayload::new(t.payload_size)?;
+        let mut state = SplitState::new(&payload)?;
+
+        let mut buf = read_payload(&state.command(payload))?;
+        assert!(buf.len() <= MAX_CMD_SIZE);
+
+        let mut num_continuations = 0;
+        while let Some(cont) = state.next_continuation_record() {
+            let payload = read_payload(&cont)?;
+            assert!(payload.len() <= MAX_CMD_SIZE);
+            buf.extend_from_slice(&payload, GFP_KERNEL)?;
+            num_continuations += 1;
+        }
+
+        assert_eq!(num_continuations, t.num_continuations);
+        assert_eq!(
+            buf.as_slice(),
+            TestPayload::generate_pattern(t.payload_size)?.as_slice()
+        );
+        Ok(())
+    }
+
+    #[test]
+    fn split_command() -> Result {
+        check_split(SplitTest {
+            payload_size: 0,
+            num_continuations: 0,
+        })?;
+        check_split(SplitTest {
+            payload_size: MAX_CMD_SIZE,
+            num_continuations: 0,
+        })?;
+        check_split(SplitTest {
+            payload_size: MAX_CMD_SIZE + 1,
+            num_continuations: 1,
+        })?;
+        check_split(SplitTest {
+            payload_size: MAX_CMD_SIZE * 2,
+            num_continuations: 1,
+        })?;
+        check_split(SplitTest {
+            payload_size: MAX_CMD_SIZE * 2 + 1,
+            num_continuations: 2,
+        })?;
+        check_split(SplitTest {
+            payload_size: MAX_CMD_SIZE * 3 + MAX_CMD_SIZE / 2,
+            num_continuations: 3,
+        })?;
+        Ok(())
+    }
+}

-- 
2.53.0


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v3 3/9] rust: add EMSGSIZE error code
  2026-02-26 11:45 ` [PATCH v3 3/9] rust: add EMSGSIZE error code Eliot Courtney
@ 2026-02-26 14:04   ` Miguel Ojeda
  2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
  1 sibling, 0 replies; 23+ messages in thread
From: Miguel Ojeda @ 2026-02-26 14:04 UTC (permalink / raw)
  To: Eliot Courtney
  Cc: Danilo Krummrich, Alice Ryhl, Alexandre Courbot, David Airlie,
	Simona Vetter, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg,
	Trevor Gross, nouveau, dri-devel, linux-kernel, rust-for-linux,
	Zhi Wang

On Thu, Feb 26, 2026 at 12:46 PM Eliot Courtney <ecourtney@nvidia.com> wrote:
>
> Add the EMSGSIZE error code, which indicates that a message is too
> long.
>
> Tested-by: Zhi Wang <zhiw@nvidia.com>
> Signed-off-by: Eliot Courtney <ecourtney@nvidia.com>

Acked-by: Miguel Ojeda <ojeda@kernel.org>

I checked that it is placed in the right spot in the list :)

Thanks!

Cheers,
Miguel

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add continuation record support
  2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
                   ` (8 preceding siblings ...)
  2026-02-26 11:45 ` [PATCH v3 9/9] gpu: nova-core: gsp: add tests for SplitState Eliot Courtney
@ 2026-02-27  2:21 ` Claude Code Review Bot
  9 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Overall Series Review

Subject: gpu: nova-core: gsp: add continuation record support
Author: Eliot Courtney <ecourtney@nvidia.com>
Patches: 11
Reviewed: 2026-02-27T12:21:58.086630

---

This is a well-structured 9-patch series from Eliot Courtney at NVIDIA that adds continuation record support to the nova-core GSP command queue. The series enables sending RPCs larger than 16 pages (64KB) by splitting them into multiple queue elements. The patches are logically ordered with incremental preparation steps (1-7) leading to the core implementation (8) and tests (9).

The overall design is sound: a `SplitState` type determines whether splitting is needed, a `SplitCommand` enum transparently wraps the original command so that small commands still write directly to the queue (zero-copy), while large commands stage their variable payload into a `KVVec` buffer and then dispatch it in chunks. The continuation record protocol itself is simple — just a header followed by raw payload bytes.

The code quality is good, the abstractions are clean, and the tests cover the important boundary conditions. I have a few observations, mostly minor.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: sort MsgFunction variants alphabetically
  2026-02-26 11:45 ` [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Pure alphabetical re-ordering of the `MsgFunction` enum variants and the corresponding `TryFrom<u32>` match arms. Also adds section comments (`// Common function codes`, `// Event codes`) to the match block for clarity.

No issues. Straightforward cleanup that makes the enum easier to maintain.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add mechanism to wait for space on command queue
  2026-02-26 11:45 ` [PATCH v3 2/9] gpu: nova-core: gsp: add mechanism to wait for space on command queue Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Adds `driver_write_area_size()` and changes `allocate_command` from returning `EAGAIN` to polling with `read_poll_timeout`. The 1-second timeout matches nouveau's approach.

The circular buffer arithmetic in `driver_write_area_size()` looks correct:

```rust
let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
```

The `-1` reserves one slot to distinguish full from empty, which is standard for circular buffers.

**Minor observation**: The `Delta::ZERO` sleep period in `read_poll_timeout` means this is a busy-poll. For a 1-second timeout that's acceptable in this context (the GSP should drain commands quickly), but if this is ever used with longer timeouts it could waste CPU. Not a problem for the current use case.

The error code change from `EAGAIN` to `ETIMEDOUT` is appropriate since the caller no longer retries.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: rust: add EMSGSIZE error code
  2026-02-26 11:45 ` [PATCH v3 3/9] rust: add EMSGSIZE error code Eliot Courtney
  2026-02-26 14:04   ` Miguel Ojeda
@ 2026-02-27  2:21   ` Claude Code Review Bot
  1 sibling, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

One-line addition of `EMSGSIZE` to `rust/kernel/error.rs`. Trivial and correct.

**Note**: The insertion position breaks the alphabetical ordering of the existing error codes (`EOVERFLOW` is errno 75, `EMSGSIZE` is errno 90, `ETIMEDOUT` is errno 110). The actual numeric order is maintained, which is fine.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add checking oversized commands
  2026-02-26 11:45 ` [PATCH v3 4/9] gpu: nova-core: gsp: add checking oversized commands Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Adds the `GSP_MSG_QUEUE_ELEMENT_SIZE_MAX` constant (65536 = 16 pages) and an early size check in `allocate_command`:

```rust
if size_of::<GspMsgElement>() + size > GSP_MSG_QUEUE_ELEMENT_SIZE_MAX {
    return Err(EMSGSIZE);
}
```

This is placed before the `read_poll_timeout` call, which is correct — there's no point polling for space that will never be large enough. The constant is pulled from the C bindings, keeping the Rust code in sync with the hardware definition.

One small cleanup: the `//` line-break marker moves from `MsgqTxHeader` to `GSP_MSG_QUEUE_ELEMENT_SIZE_MAX` in the imports. Fine.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: clarify invariant on command queue
  2026-02-26 11:45 ` [PATCH v3 5/9] gpu: nova-core: gsp: clarify invariant on command queue Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Adds a comment explaining why only `dst.contents.0` is used for the command header extraction:

```rust
// The GSP message header and the command header
// together are guaranteed to fit entirely into a single page, so it's ok to only look
// at `dst.contents.0` here.
```

This is a useful clarification. The guarantee holds because `GspMsgElement` + any `Command` struct header is well under 4KB (one GSP page). The comment helps readers understand why the wrap-around second slice isn't needed for the header portion.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: unconditionally call variable payload handling
  2026-02-26 11:45 ` [PATCH v3 6/9] gpu: nova-core: gsp: unconditionally call variable payload handling Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Removes the `if command_size > size_of::<M::Command>()` guard around variable payload initialization and calls it unconditionally. The explicit `drop(sbuffer)` is added to release mutable borrows before the checksum computation.

This change is motivated by patch 8: the `SplitCommand` wrapper needs the `SBufferIter` to be created unconditionally. It also adds a defensive check — `sbuffer.is_empty()` will catch cases where a command claims `variable_payload_len() == 0` but the `init_variable_payload` impl disagrees.

The `drop(sbuffer)` is worth noting — it's needed because `sbuffer` holds mutable borrows on `payload_1` and `dst.contents.1`, which would otherwise prevent access to `dst.header` for checksum computation. Good practice to make this explicit.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add command_size helper
  2026-02-26 11:45 ` [PATCH v3 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Extracts the `size_of::<M::Command>() + command.variable_payload_len()` calculation into a standalone `command_size()` function. This is used in the existing `send_command` and will be reused in patch 8's `SplitState::new()`.

```rust
fn command_size<M>(command: &M) -> usize
where
    M: CommandToGsp,
{
    size_of::<M::Command>() + command.variable_payload_len()
}
```

Clean factoring. No issues.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: support large RPCs via continuation record
  2026-02-26 11:45 ` [PATCH v3 8/9] gpu: nova-core: gsp: support large RPCs via continuation record Eliot Courtney
@ 2026-02-27  2:21   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:21 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

This is the core patch. Three new types are introduced:

**`ContinuationRecord<'a>`**: A simple command that writes its payload as-is, using `type Command = ()` (zero-size header). This correctly means the entire element payload is variable data.

**`SplitState<C>`**: Determines whether splitting is needed and manages the staging buffer. Key constants:

```rust
const MAX_CMD_SIZE: usize = GSP_MSG_QUEUE_ELEMENT_SIZE_MAX - size_of::<GspMsgElement>();
const MAX_FIRST_PAYLOAD_SIZE: usize = Self::MAX_CMD_SIZE - size_of::<C::Command>();
```

The split decision in `new()` is correct — only when `command_size(inner) > MAX_CMD_SIZE` does staging occur. The staging buffer is populated eagerly by calling `inner.init_variable_payload()` once, which avoids calling the user's init function multiple times.

**`SplitCommand<'a, C>`**: An enum wrapping either the original command (`Single`) or the truncated first-chunk version (`Split`). The `CommandToGsp` impl for `Split` truncates `variable_payload_len()` to `MAX_FIRST_PAYLOAD_SIZE` and copies from the staging buffer.

The updated `send_command` flow is clean:

```rust
let mut state = SplitState::new(&command)?;
self.send_single_command(bar, state.command(command))?;
while let Some(continuation) = state.next_continuation_record() {
    self.send_single_command::<ContinuationRecord<'_>>(bar, continuation)?;
}
```

**One observation**: `command_size` is changed from `fn` to `pub(crate) fn` to allow access from `commands.rs`. This is a minor visibility escalation that's fine for a crate-internal function.

**Observation on `next_continuation_record` continuation chunk sizing**: Each continuation record gets at most `MAX_CMD_SIZE` bytes of payload. Since `ContinuationRecord` has `type Command = ()` (zero-size), the total element size is `size_of::<GspMsgElement>() + chunk_size`, which maxes out at exactly `GSP_MSG_QUEUE_ELEMENT_SIZE_MAX`. This correctly stays within the per-element limit and won't trigger the `EMSGSIZE` check added in patch 4.

**Minor style nit**: The `_phantom: PhantomData` field in `SplitState` exists because the struct needs to carry the `C` type parameter for the associated constants (`MAX_CMD_SIZE`, `MAX_FIRST_PAYLOAD_SIZE`). This is a standard Rust pattern and is fine.

**Question for the author**: The cover letter mentions "continuation record for receive is not necessary to support at the moment because those replies do not need to be read and are currently drained by retrying `receive_msg` on ERANGE." Is there a concern that GSP could *respond* with continuation records to these large RPCs? If so, silently draining them seems fragile if future RPCs need to read large responses. A `dev_warn!` or tracking note might be useful there, though this is outside the scope of this series.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add tests for SplitState
  2026-02-26 11:45 ` [PATCH v3 9/9] gpu: nova-core: gsp: add tests for SplitState Eliot Courtney
@ 2026-02-27  2:22   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-02-27  2:22 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Adds kunit tests with a `TestPayload` helper (using `Command = ()` and `MsgFunction::Nop`). The `check_split` function verifies both the number of continuation records and that concatenating all payloads reproduces the original data.

The boundary conditions tested are:

| `payload_size` | Expected continuations | Reason |
|---|---|---|
| 0 | 0 | Empty payload, no split |
| `MAX_CMD_SIZE` | 0 | Exactly fits single element |
| `MAX_CMD_SIZE + 1` | 1 | Overflows by 1 byte |
| `MAX_CMD_SIZE * 2` | 1 | Two full chunks |
| `MAX_CMD_SIZE * 2 + 1` | 2 | Two full + 1 byte overflow |
| `MAX_CMD_SIZE * 3.5` | 3 | Partial last chunk |

Good coverage of the boundary conditions. The data integrity check (`assert_eq!(buf.as_slice(), ...)`) validates both splitting and reassembly.

**Observation**: Since `TestPayload` uses `Command = ()`, `MAX_FIRST_PAYLOAD_SIZE == MAX_CMD_SIZE`. A test with a non-zero-sized `Command` type would also exercise the case where the first chunk has less variable payload space than continuation chunks. This is a minor gap — the logic is straightforward (`MAX_FIRST_PAYLOAD_SIZE = MAX_CMD_SIZE - size_of::<Command>()`), but a test would provide extra confidence.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Claude review: gpu: nova-core: gsp: add command_size helper
  2026-03-02 11:42 ` [PATCH v4 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
@ 2026-03-03  3:34   ` Claude Code Review Bot
  0 siblings, 0 replies; 23+ messages in thread
From: Claude Code Review Bot @ 2026-03-03  3:34 UTC (permalink / raw)
  To: dri-devel-reviews

Patch Review

Extracts the command size calculation into a standalone function:

```rust
pub(crate) fn command_size<M>(command: &M) -> usize
where
    M: CommandToGsp,
{
    size_of::<M::Command>() + command.variable_payload_len()
}
```

Clean extraction. Made `pub(crate)` for reuse in the continuation module.

---
Generated by Claude Code Patch Reviewer

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2026-03-03  3:34 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-02-26 11:45 [PATCH v3 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
2026-02-26 11:45 ` [PATCH v3 1/9] gpu: nova-core: gsp: sort MsgFunction variants alphabetically Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 2/9] gpu: nova-core: gsp: add mechanism to wait for space on command queue Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 3/9] rust: add EMSGSIZE error code Eliot Courtney
2026-02-26 14:04   ` Miguel Ojeda
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 4/9] gpu: nova-core: gsp: add checking oversized commands Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 5/9] gpu: nova-core: gsp: clarify invariant on command queue Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 6/9] gpu: nova-core: gsp: unconditionally call variable payload handling Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 8/9] gpu: nova-core: gsp: support large RPCs via continuation record Eliot Courtney
2026-02-27  2:21   ` Claude review: " Claude Code Review Bot
2026-02-26 11:45 ` [PATCH v3 9/9] gpu: nova-core: gsp: add tests for SplitState Eliot Courtney
2026-02-27  2:22   ` Claude review: " Claude Code Review Bot
2026-02-27  2:21 ` Claude review: gpu: nova-core: gsp: add continuation record support Claude Code Review Bot
  -- strict thread matches above, loose matches on Subject: below --
2026-03-02 11:42 [PATCH v4 0/9] " Eliot Courtney
2026-03-02 11:42 ` [PATCH v4 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
2026-03-03  3:34   ` Claude review: " Claude Code Review Bot
2026-02-19  7:30 [PATCH v2 0/9] gpu: nova-core: gsp: add continuation record support Eliot Courtney
2026-02-19  7:30 ` [PATCH v2 7/9] gpu: nova-core: gsp: add command_size helper Eliot Courtney
2026-02-19  8:43   ` Claude review: " Claude Code Review Bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox