Re: [PATCH 14/27] gpu: nova-core: add GMC API message types
Zhi Wang <[email protected]>
| Newsgroups | dev.linux.lists.nova-gpu,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <20260820135352.6e387428@inno-dell> |
On Tue, 18 Aug 2026 20:52:07 -0700 John Hubbard <[email protected]> wrote: snip > +/// GMC API message header. > +/// > +/// Matches the `GMCAPI_HEADER` struct from Open RM. The `command` > field carries +/// flags in the high byte and a 24-bit command ID in > the low bits. `size` is the +/// payload size for both requests and > responses, while the union at offset 16 +/// carries the maximum > response size for requests and the status for responses. +#[repr(C)] > +#[derive(Zeroable)] > +pub(crate) struct GmcApiHeader { > + /// GMC command identifier with flags in the high byte. > + pub(crate) command: u32, > + /// Payload size in bytes. > + pub(crate) size: u32, > + /// Sequence number for matching requests to responses. > + pub(crate) sequence: u64, > + /// Request: maximum response size. Response: `NV_STATUS` code. > + pub(crate) max_resp_or_status: u32, > + reserved: [u32; 5], > +} > + > +static_assert!(size_of::<GmcApiHeader>() == 40); > + Should we use the GMCAPI_HEADER in the r000 bindings? Z. > +// SAFETY: All fields are integer types with no uninitialized > padding bytes. +unsafe impl AsBytes for GmcApiHeader {} > + > +// SAFETY: All fields are integer types for which all bit patterns > are valid. +unsafe impl FromBytes for GmcApiHeader {} > + > +/// Header for an unencrypted GMC API message in the GSP command > queue. +/// > +/// The fields before `gmc` match `GSP_MSG_QUEUE_ELEMENT` through its > +/// `noEncryption` union member. `gmc` occupies the start of that > member's +/// flexible payload array, and the GMC command payload > follows this structure. +#[repr(C)] > +pub(crate) struct GspGmcMsgElement { > + mctp_magic: u32, > + mctp_payload_size: u32, > + mctp_header: MctpHeader, > + nvdm_header: NvdmHeader, > + nvdm_payload_size: u32, > + reserved: u32, > + pub(crate) gmc: GmcApiHeader, > +} > + > +static_assert!( > + core::mem::offset_of!(GspGmcMsgElement, mctp_magic) > + == core::mem::offset_of!(r000_00::GSP_MSG_QUEUE_ELEMENT, > mctpMagic) +); > +static_assert!( > + core::mem::offset_of!(GspGmcMsgElement, mctp_payload_size) > + == core::mem::offset_of!(r000_00::GSP_MSG_QUEUE_ELEMENT, > mctpPayloadSize) +); > +static_assert!( > + core::mem::offset_of!(GspGmcMsgElement, mctp_header) > + == core::mem::offset_of!(r000_00::GSP_MSG_QUEUE_ELEMENT, > mctpHeader) +); > +static_assert!( > + core::mem::offset_of!(GspGmcMsgElement, nvdm_header) > + == core::mem::offset_of!(r000_00::GSP_MSG_QUEUE_ELEMENT, > nvdmHeader) +); > + > +#[expect(dead_code)] > +impl GspGmcMsgElement { > + /// Creates a new GMC message element. > + /// > + /// `payload_size` is the size of the command payload following > this header. > + /// `command_id` is the GMC command identifier. > + /// `sequence` is the sequence number for request/response > matching. > + /// `max_response_size` is the maximum expected response payload > size. > + pub(crate) fn init( > + command_id: u32, > + sequence: u64, > + payload_size: usize, > + max_response_size: u32, > + ) -> impl Init<Self, Error> { > + try_init!(GspGmcMsgElement { > + mctp_magic: MCTP_MAGIC, > + // Despite the name, this counts the element header as > well as the payload. > + mctp_payload_size: size_of::<Self>() > + .checked_add(payload_size) > + .ok_or(EOVERFLOW)? > + .try_into() > + .map_err(|_| EOVERFLOW)?, > + mctp_header: MctpHeader::single_packet(), > + nvdm_header: NvdmHeader::new(NvdmType::GmcApi), > + nvdm_payload_size: size_of::<GmcApiHeader>() > + .checked_add(payload_size) > + .ok_or(EOVERFLOW)? > + .try_into() > + .map_err(|_| EOVERFLOW)?, > + reserved: 0u32, > + gmc: GmcApiHeader { > + command: command_id, > + size: payload_size.try_into().map_err(|_| > EOVERFLOW)?, > + sequence, > + max_resp_or_status: max_response_size, > + reserved: [0; 5], > + }, > + }) > + } > + > + /// Returns the total length of the message, transport and GMC > headers included. > + pub(crate) fn length(&self) -> usize { > + num::u32_as_usize(self.mctp_payload_size) > + } > + > + /// Returns the number of elements (i.e. memory pages) used by > this message. > + pub(crate) fn element_count(&self) -> u32 { > + self.mctp_payload_size > + .div_ceil(num::usize_into_u32::<GSP_PAGE_SIZE>()) > + } > +} > + > +// SAFETY: All fields are integer types with no uninitialized > padding bytes. +unsafe impl AsBytes for GspGmcMsgElement {} > + > +// SAFETY: All fields are integer types for which all bit patterns > are valid. +unsafe impl FromBytes for GspGmcMsgElement {} > + > /// Arguments for GSP startup. > #[repr(transparent)] > #[derive(Zeroable)] > diff --git a/drivers/gpu/nova-core/mctp.rs > b/drivers/gpu/nova-core/mctp.rs index 03546213da28..0ae88bef2a05 > 100644 --- a/drivers/gpu/nova-core/mctp.rs > +++ b/drivers/gpu/nova-core/mctp.rs > @@ -28,6 +28,8 @@ pub(crate) enum NvdmType with TryFrom<Bounded<u32, > 8>> { Cot = 0x14, > /// FSP command response. > FspResponse = 0x15, > + /// GMC API message (GSP command queue). > + GmcApi = 0x26, > } > } >