Re: [PATCH 17/27] gpu: nova-core: gsp: add GMC dispatch on receive
Zhi Wang <[email protected]>
| Newsgroups | dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260820153006.5ae7e7e4@inno-dell> |
On Tue, 18 Aug 2026 20:52:10 -0700 John Hubbard <[email protected]> wrote: > The r000 boot path delivers the load-and-execute steps as GMC events > keyed by command id, where the RPC path keys on a function code, so > the boot loop needs its own dispatch. snip > + fn receive_gmc_and_dispatch<R>( > + &mut self, > + timeout: Delta, > + handler: impl FnOnce(u32, &[u8], &[u8]) -> Option<R>, > + ) -> Result<Option<R>> { > + let message = self.wait_for_gmc_msg(timeout)?; > + let header = message.header; > + let length = header.length(); > + > + // The RPC and GMC elements share every field through > `nvdm_header`, so `gmc` holds an > + // RPC header rather than a GMC one unless the NVDM type > says otherwise. > + let result = if header.is_gmc_api() { > + let command_id = header.gmc.command_id(); > + IMO, should we check header.gmc.size == payload_length()? as now we know it is a GMC message now. Not sure if gmc.size < payload_length() is a valid use case. > + dev_dbg!( > + &self.dev, > + "GSP GMC: event: seq# {}, command_id=0x{:x}, > length=0x{:x}\n", > + header.gmc.sequence, > + command_id, > + length, > + ); > + > + handler(command_id, message.contents.0, > message.contents.1) > + } else { > + dev_warn!(&self.dev, "GSP GMC: dropping non-GMC queue > element\n"); > + None > + }; > + > + self.gsp_mem > + > .advance_cpu_read_ptr(u32::try_from(length.div_ceil(GSP_PAGE_SIZE))?); > + > + Ok(result) > + } > } > diff --git a/drivers/gpu/nova-core/gsp/fw.rs > b/drivers/gpu/nova-core/gsp/fw.rs index 9e6b5ec6aadb..83f7d2042aa1 > 100644 --- a/drivers/gpu/nova-core/gsp/fw.rs > +++ b/drivers/gpu/nova-core/gsp/fw.rs > @@ -975,8 +975,19 @@ pub(crate) struct GmcApiHeader { > reserved: [u32; 5], > } > > +/// Command identifier bits of [`GmcApiHeader::command`], matching > Open RM's +/// `GMCAPI_HEADER_COMMAND_ID_MASK`. The remaining byte > carries flags. +const GMCAPI_COMMAND_ID_MASK: u32 = 0x00ff_ffff; > + > static_assert!(size_of::<GmcApiHeader>() == 40); > > +impl GmcApiHeader { > + /// Returns the command identifier, without the flag byte. > + pub(crate) fn command_id(&self) -> u32 { > + self.command & GMCAPI_COMMAND_ID_MASK > + } > +} > + > // SAFETY: All fields are integer types with no uninitialized > padding bytes. unsafe impl AsBytes for GmcApiHeader {} > > @@ -1070,6 +1081,15 @@ pub(crate) fn has_valid_magic(&self) -> bool { > self.mctp_magic == MCTP_MAGIC > } > > + /// Returns `true` if the NVDM header routes this element to the > GSP's GMC dispatch. > + /// > + /// A [`GspMsgElement`] and a [`GspGmcMsgElement`] share every > field through `nvdm_header`, > + /// so the NVDM type is what distinguishes the two on the queue, > and `gmc` holds an RPC > + /// header rather than a GMC one when this returns `false`. > + pub(crate) fn is_gmc_api(&self) -> bool { > + self.nvdm_header.validate(NvdmType::GmcApi) > + } > + > /// Returns the number of elements (i.e. memory pages) used by > this message. pub(crate) fn element_count(&self) -> u32 { > self.mctp_payload_size