[PATCH v2 14/31] gpu: nova-core: generalize allocate_command() for variable headers
From: John Hubbard
Date: Fri Aug 21 2026 - 21:57:17 EST
The GMC command path uses a different message element header from the
VGPU-style RPC path, but the two share the queue, the space accounting,
and the wrapping rules. Make allocate_command() and GspCommand generic
over the header type, defaulting to GspMsgElement so the existing RPC
callers are unchanged.
No functional changes.
Assisted-by: Cursor:claude-opus-5
Reviewed-by: Timur Tabi <ttabi@xxxxxxxxxx>
Reviewed-by: Zhi Wang <zhiw@xxxxxxxxxx>
Signed-off-by: John Hubbard <jhubbard@xxxxxxxxxx>
---
drivers/gpu/nova-core/gsp/cmdq.rs | 22 +++++++++++++++-------
1 file changed, 15 insertions(+), 7 deletions(-)
diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs
index a46d8927da1b..babec37716b5 100644
--- a/drivers/gpu/nova-core/gsp/cmdq.rs
+++ b/drivers/gpu/nova-core/gsp/cmdq.rs
@@ -365,6 +365,8 @@ fn driver_write_area_size(&self) -> usize {
/// Allocates a region on the command queue that is large enough to send a command of `size`
/// bytes, waiting for space to become available based on the provided timeout.
///
+ /// The type parameter `H` selects the message element header, [`GspMsgElement`] for RM RPC.
+ ///
/// This returns a [`GspCommand`] ready to be written to by the caller.
///
/// # Errors
@@ -372,13 +374,17 @@ fn driver_write_area_size(&self) -> usize {
/// - `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 {
+ fn allocate_command<H: FromBytes + AsBytes>(
+ &mut self,
+ size: usize,
+ timeout: Delta,
+ ) -> Result<GspCommand<'_, H>> {
+ if size_of::<H>() + 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,
+ |available_bytes| *available_bytes >= size_of::<H>() + size,
Delta::from_micros(1),
timeout,
)?;
@@ -390,8 +396,8 @@ fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand
(slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
};
- // Extract area for the `GspMsgElement`.
- let (header, slice_1) = GspMsgElement::from_bytes_mut_prefix(slice_1).ok_or(EIO)?;
+ // Extract area for the message element header.
+ let (header, slice_1) = H::from_bytes_mut_prefix(slice_1).ok_or(EIO)?;
// Create the contents area.
let (slice_1, slice_2) = if slice_1.len() > size {
@@ -609,10 +615,12 @@ fn driver_read_area_v2(
/// A command ready to be sent on the command queue.
///
+/// The type parameter `H` is the message element header type, [`GspMsgElement`] for RM RPC.
+///
/// This is the type returned by [`DmaGspMem::allocate_command`].
-struct GspCommand<'a> {
+struct GspCommand<'a, H = GspMsgElement> {
// Writable reference to the header of the command.
- header: &'a mut GspMsgElement,
+ header: &'a mut H,
// Writable slices to the contents of the command. The second slice is zero unless the command
// loops over the command queue.
contents: (&'a mut [u8], &'a mut [u8]),
--
2.55.0