[PATCH v2 16/31] gpu: nova-core: add GMC send path
John Hubbard <[email protected]>
| Newsgroups | dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
The r000 GSP-RM boot protocol requires the driver to send GSP_INIT as a GMC command. GMC and RPC commands share the command queue and sequence counter. GMC queue elements carry a GMC API header and no checksum. Add the GMC send path needed for GSP_INIT. Assisted-by: Cursor:claude-opus-5 Reviewed-by: Timur Tabi <[email protected]> Reviewed-by: Zhi Wang <[email protected]> Signed-off-by: John Hubbard <[email protected]> --- drivers/gpu/nova-core/gsp/cmdq.rs | 59 +++++++++++++++++++++++++++++++ drivers/gpu/nova-core/gsp/fw.rs | 1 - 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/nova-core/gsp/cmdq.rs b/drivers/gpu/nova-core/gsp/cmdq.rs index babec37716b5..6470b1b673b6 100644 --- a/drivers/gpu/nova-core/gsp/cmdq.rs +++ b/drivers/gpu/nova-core/gsp/cmdq.rs @@ -52,6 +52,7 @@ driver::Bar0, gsp::{ fw::{ + GspGmcMsgElement, GspMsgElement, MsgFunction, MsgqRxHeader, @@ -963,6 +964,64 @@ fn send_command<M>(&mut self, bar: Bar0<'_>, command: M) -> Result<u32> Ok(rpc_seq) } + /// Sends a GMC API command to the GSP. + /// + /// `command_id` is the GMC command identifier (from `GMCAPI_COMMANDS`). + /// `payload` is the command-specific data following the [`super::fw::GmcApiHeader`]. + /// `max_response_size` is the maximum expected response payload size. + /// + /// The command carries the next RPC sequence number, which the GSP echoes in its response. + /// The number is consumed whether or not the send succeeds. + /// + /// # Errors + /// + /// - `EMSGSIZE` if the command exceeds the maximum queue element size. + /// - `ETIMEDOUT` if space does not become available within the timeout. + /// - `EIO` if the command header is not properly aligned. + #[expect(dead_code)] + fn send_gmc( + &mut self, + bar: Bar0<'_>, + command_id: u32, + payload: &[u8], + max_response_size: u32, + ) -> Result { + let rpc_seq = self.rpc_seq; + self.rpc_seq = self.rpc_seq.wrapping_add(1); + + let dst = self + .gsp_mem + .allocate_command::<GspGmcMsgElement>(payload.len(), Self::ALLOCATE_TIMEOUT)?; + + let msg_element = GspGmcMsgElement::init( + command_id, + u64::from(rpc_seq), + payload.len(), + max_response_size, + ); + // SAFETY: `dst.header` points to a valid, writable `GspGmcMsgElement` region. + unsafe { + msg_element.__init(core::ptr::from_mut(dst.header))?; + } + + SBufferIter::new_writer([&mut dst.contents.0[..], &mut dst.contents.1[..]]) + .write_all(payload)?; + + dev_dbg!( + &self.dev, + "GSP GMC: send: seq# {}, command_id=0x{:x}, length=0x{:x}\n", + rpc_seq, + command_id, + dst.header.length(), + ); + + let elem_count = dst.header.element_count(); + self.gsp_mem.advance_cpu_write_ptr(elem_count); + Cmdq::notify_gsp(bar); + + 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/fw.rs b/drivers/gpu/nova-core/gsp/fw.rs index 2b938802495c..2d7ea46332e6 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs +++ b/drivers/gpu/nova-core/gsp/fw.rs @@ -1036,7 +1036,6 @@ pub(crate) struct GspGmcMsgElement { == core::mem::offset_of!(r000_00::GSP_MSG_QUEUE_ELEMENT, nvdmHeader) ); -#[expect(dead_code)] impl GspGmcMsgElement { /// Creates a new GMC message element. /// -- 2.55.0