xref: /linux/drivers/gpu/nova-core/gsp/cmdq.rs (revision 23d66dbab84e8518943563df2ced14aaab28b77a)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 mod continuation;
4 
5 use core::mem;
6 
7 use kernel::{
8     device,
9     dma::{
10         Coherent,
11         DmaAddress, //
12     },
13     dma_write,
14     io::{
15         poll::read_poll_timeout,
16         Io, //
17     },
18     new_mutex,
19     prelude::*,
20     ptr,
21     sync::{
22         aref::ARef,
23         Mutex, //
24     },
25     time::Delta,
26     transmute::{
27         AsBytes,
28         FromBytes, //
29     },
30 };
31 
32 use continuation::{
33     ContinuationRecord,
34     SplitState, //
35 };
36 
37 use pin_init::pin_init_scope;
38 
39 use crate::{
40     driver::Bar0,
41     gsp::{
42         fw::{
43             GspMsgElement,
44             MsgFunction,
45             MsgqRxHeader,
46             MsgqTxHeader,
47             GSP_MSG_QUEUE_ELEMENT_SIZE_MAX, //
48         },
49         PteArray,
50         GSP_PAGE_SHIFT,
51         GSP_PAGE_SIZE, //
52     },
53     num,
54     sbuffer::SBufferIter, //
55 };
56 
57 use super::regs;
58 
59 /// Marker type representing the absence of a reply for a command. Commands using this as their
60 /// reply type are sent using [`Cmdq::send_command_no_wait`].
61 pub(crate) struct NoReply;
62 
63 /// Trait implemented by types representing a command to send to the GSP.
64 ///
65 /// The main purpose of this trait is to provide [`Cmdq`] with the information it needs to send
66 /// a given command.
67 ///
68 /// [`CommandToGsp::init`] in particular is responsible for initializing the command directly
69 /// into the space reserved for it in the command queue buffer.
70 ///
71 /// Some commands may be followed by a variable-length payload. For these, the
72 /// [`CommandToGsp::variable_payload_len`] and [`CommandToGsp::init_variable_payload`] need to be
73 /// defined as well.
74 pub(crate) trait CommandToGsp {
75     /// Function identifying this command to the GSP.
76     const FUNCTION: MsgFunction;
77 
78     /// Type generated by [`CommandToGsp::init`], to be written into the command queue buffer.
79     type Command: FromBytes + AsBytes;
80 
81     /// Type of the reply expected from the GSP, or [`NoReply`] for commands that don't
82     /// have a reply.
83     type Reply;
84 
85     /// Error type returned by [`CommandToGsp::init`].
86     type InitError;
87 
88     /// In-place command initializer responsible for filling the command in the command queue
89     /// buffer.
90     fn init(&self) -> impl Init<Self::Command, Self::InitError>;
91 
92     /// Size of the variable-length payload following the command structure generated by
93     /// [`CommandToGsp::init`].
94     ///
95     /// Most commands don't have a variable-length payload, so this is zero by default.
96     fn variable_payload_len(&self) -> usize {
97         0
98     }
99 
100     /// Method initializing the variable-length payload.
101     ///
102     /// The command buffer is circular, which means that we may need to jump back to its beginning
103     /// while in the middle of a command. For this reason, the variable-length payload is
104     /// initialized using a [`SBufferIter`].
105     ///
106     /// This method will receive a buffer of the length returned by
107     /// [`CommandToGsp::variable_payload_len`], and must write every single byte of it. Leaving
108     /// unwritten space will lead to an error.
109     ///
110     /// Most commands don't have a variable-length payload, so this does nothing by default.
111     fn init_variable_payload(
112         &self,
113         _dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
114     ) -> Result {
115         Ok(())
116     }
117 
118     /// Total size of the command (including its variable-length payload) without the
119     /// [`GspMsgElement`] header.
120     fn size(&self) -> usize {
121         size_of::<Self::Command>() + self.variable_payload_len()
122     }
123 }
124 
125 /// Trait representing messages received from the GSP.
126 ///
127 /// This trait tells [`Cmdq::receive_msg`] how it can receive a given type of message.
128 pub(crate) trait MessageFromGsp: Sized {
129     /// Function identifying this message from the GSP.
130     const FUNCTION: MsgFunction;
131 
132     /// Error type returned by [`MessageFromGsp::read`].
133     type InitError;
134 
135     /// Type containing the raw message to be read from the message queue.
136     type Message: FromBytes;
137 
138     /// Method reading the message from the message queue and returning it.
139     ///
140     /// From a `Self::Message` and a [`SBufferIter`], constructs an instance of `Self` and returns
141     /// it.
142     fn read(
143         msg: &Self::Message,
144         sbuffer: &mut SBufferIter<core::array::IntoIter<&[u8], 2>>,
145     ) -> Result<Self, Self::InitError>;
146 }
147 
148 /// Number of GSP pages making the [`Msgq`].
149 pub(crate) const MSGQ_NUM_PAGES: u32 = 0x3f;
150 
151 /// Circular buffer of a [`Msgq`].
152 ///
153 /// This area of memory is to be shared between the driver and the GSP to exchange commands or
154 /// messages.
155 #[repr(C, align(0x1000))]
156 #[derive(Debug)]
157 struct MsgqData {
158     data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
159 }
160 
161 // Annoyingly we are forced to use a literal to specify the alignment of
162 // `MsgqData`, so check that it corresponds to the actual GSP page size here.
163 static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE);
164 
165 /// Unidirectional message queue.
166 ///
167 /// Contains the data for a message queue, that either the driver or GSP writes to.
168 ///
169 /// Note that while the write pointer of `tx` corresponds to the `msgq` of the same instance, the
170 /// read pointer of `rx` actually refers to the `Msgq` owned by the other side.
171 /// This design ensures that only the driver or GSP ever writes to a given instance of this struct.
172 #[repr(C)]
173 // There is no struct defined for this in the open-gpu-kernel-source headers.
174 // Instead it is defined by code in `GspMsgQueuesInit()`.
175 // TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
176 pub(super) struct Msgq {
177     /// Header for sending messages, including the write pointer.
178     pub(super) tx: MsgqTxHeader,
179     /// Header for receiving messages, including the read pointer.
180     pub(super) rx: MsgqRxHeader,
181     /// The message queue proper.
182     msgq: MsgqData,
183 }
184 
185 /// Structure shared between the driver and the GSP and containing the command and message queues.
186 #[repr(C)]
187 // TODO: Revert to private once `IoView` projections replace the `gsp_mem` module.
188 pub(super) struct GspMem {
189     /// Self-mapping page table entries.
190     ptes: PteArray<{ Self::PTE_ARRAY_SIZE }>,
191     /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the
192     /// write and read pointers that the CPU updates. This means that the read pointer here is an
193     /// index into the GSP queue.
194     ///
195     /// This member is read-only for the GSP.
196     pub(super) cpuq: Msgq,
197     /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the
198     /// write and read pointers that the GSP updates. This means that the read pointer here is an
199     /// index into the CPU queue.
200     ///
201     /// This member is read-only for the driver.
202     pub(super) gspq: Msgq,
203 }
204 
205 impl GspMem {
206     const PTE_ARRAY_SIZE: usize = GSP_PAGE_SIZE / size_of::<u64>();
207 }
208 
209 // SAFETY: These structs don't meet the no-padding requirements of AsBytes but
210 // that is not a problem because they are not used outside the kernel.
211 unsafe impl AsBytes for GspMem {}
212 
213 // SAFETY: These structs don't meet the no-padding requirements of FromBytes but
214 // that is not a problem because they are not used outside the kernel.
215 unsafe impl FromBytes for GspMem {}
216 
217 /// Wrapper around [`GspMem`] to share it with the GPU using a [`Coherent`].
218 ///
219 /// This provides the low-level functionality to communicate with the GSP, including allocation of
220 /// queue space to write messages to and management of read/write pointers.
221 ///
222 /// This is shared with the GSP, with clear ownership rules regarding the command queues:
223 ///
224 /// * The driver owns (i.e. can write to) the part of the CPU message queue between the CPU write
225 ///   pointer and the GSP read pointer. This region is returned by [`Self::driver_write_area`].
226 /// * The driver owns (i.e. can read from) the part of the GSP message queue between the CPU read
227 ///   pointer and the GSP write pointer. This region is returned by [`Self::driver_read_area`].
228 struct DmaGspMem(Coherent<GspMem>);
229 
230 impl DmaGspMem {
231     /// Allocate a new instance and map it for `dev`.
232     fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
233         const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>();
234         const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>();
235 
236         let gsp_mem = Coherent::<GspMem>::zeroed(dev, GFP_KERNEL)?;
237 
238         let start = gsp_mem.dma_handle();
239         // Write values one by one to avoid an on-stack instance of `PteArray`.
240         for i in 0..GspMem::PTE_ARRAY_SIZE {
241             dma_write!(gsp_mem, .ptes.0[build: i], PteArray::<0>::entry(start, i)?);
242         }
243 
244         dma_write!(
245             gsp_mem,
246             .cpuq.tx,
247             MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES)
248         );
249         dma_write!(gsp_mem, .cpuq.rx, MsgqRxHeader::new());
250 
251         Ok(Self(gsp_mem))
252     }
253 
254     /// Returns the region of the CPU message queue that the driver is currently allowed to write
255     /// to.
256     ///
257     /// As the message queue is a circular buffer, the region may be discontiguous in memory. In
258     /// that case the second slice will have a non-zero length.
259     fn driver_write_area(&mut self) -> (&mut [[u8; GSP_PAGE_SIZE]], &mut [[u8; GSP_PAGE_SIZE]]) {
260         let tx = self.cpu_write_ptr();
261         let rx = self.gsp_read_ptr();
262 
263         // Pointer to the first entry of the CPU message queue.
264         let data = ptr::project!(mut self.0.as_mut_ptr(), .cpuq.msgq.data[build: 0]);
265 
266         let (tail_end, wrap_end) = if rx == 0 {
267             // The write area is non-wrapping, and stops at the second-to-last entry of the command
268             // queue (to leave the last one empty).
269             (MSGQ_NUM_PAGES - 1, 0)
270         } else if rx <= tx {
271             // The write area wraps and continues until `rx - 1`.
272             (MSGQ_NUM_PAGES, rx - 1)
273         } else {
274             // The write area doesn't wrap and stops at `rx - 1`.
275             (rx - 1, 0)
276         };
277 
278         // SAFETY:
279         // - `data` was created from a valid pointer, and `rx` and `tx` are in the
280         //   `0..MSGQ_NUM_PAGES` range per the invariants of `cpu_write_ptr` and `gsp_read_ptr`,
281         //   thus the created slices are valid.
282         // - The area starting at `tx` and ending at `rx - 2` modulo `MSGQ_NUM_PAGES`,
283         //   inclusive, belongs to the driver for writing and is not accessed concurrently by
284         //   the GSP.
285         // - The caller holds a reference to `self` for as long as the returned slices are live,
286         //   meaning the CPU write pointer cannot be advanced and thus that the returned area
287         //   remains exclusive to the CPU for the duration of the slices.
288         // - The created slices point to non-overlapping sub-ranges of `data` in all
289         //   branches (in the `rx <= tx` case, the second slice ends at `rx - 1` which is strictly
290         //   less than `tx` where the first slice starts; in the other cases the second slice is
291         //   empty), so creating two `&mut` references from them does not violate aliasing rules.
292         unsafe {
293             (
294                 core::slice::from_raw_parts_mut(
295                     data.add(num::u32_as_usize(tx)),
296                     num::u32_as_usize(tail_end - tx),
297                 ),
298                 core::slice::from_raw_parts_mut(data, num::u32_as_usize(wrap_end)),
299             )
300         }
301     }
302 
303     /// Returns the size of the region of the CPU message queue that the driver is currently allowed
304     /// to write to, in bytes.
305     fn driver_write_area_size(&self) -> usize {
306         let tx = self.cpu_write_ptr();
307         let rx = self.gsp_read_ptr();
308 
309         // `rx` and `tx` are both in `0..MSGQ_NUM_PAGES` per the invariants of `gsp_read_ptr` and
310         // `cpu_write_ptr`. The minimum value case is where `rx == 0` and `tx == MSGQ_NUM_PAGES -
311         // 1`, which gives `0 + MSGQ_NUM_PAGES - (MSGQ_NUM_PAGES - 1) - 1 == 0`.
312         let slots = (rx + MSGQ_NUM_PAGES - tx - 1) % MSGQ_NUM_PAGES;
313         num::u32_as_usize(slots) * GSP_PAGE_SIZE
314     }
315 
316     /// Returns the region of the GSP message queue that the driver is currently allowed to read
317     /// from.
318     ///
319     /// As the message queue is a circular buffer, the region may be discontiguous in memory. In
320     /// that case the second slice will have a non-zero length.
321     fn driver_read_area(&self) -> (&[[u8; GSP_PAGE_SIZE]], &[[u8; GSP_PAGE_SIZE]]) {
322         let tx = self.gsp_write_ptr();
323         let rx = self.cpu_read_ptr();
324 
325         // Pointer to the first entry of the GSP message queue.
326         let data = ptr::project!(self.0.as_ptr(), .gspq.msgq.data[build: 0]);
327 
328         let (tail_end, wrap_end) = if rx <= tx {
329             // Read area is non-wrapping and stops right before `tx`.
330             (tx, 0)
331         } else {
332             // Read area is wrapping and stops right before `tx`.
333             (MSGQ_NUM_PAGES, tx)
334         };
335 
336         // SAFETY:
337         // - `data` was created from a valid pointer, and `rx` and `tx` are in the
338         //   `0..MSGQ_NUM_PAGES` range per the invariants of `gsp_write_ptr` and `cpu_read_ptr`,
339         //   thus the created slices are valid.
340         // - The area starting at `rx` and ending at `tx - 1` modulo `MSGQ_NUM_PAGES`,
341         //   inclusive, belongs to the driver for reading and is not accessed concurrently by
342         //   the GSP.
343         // - The caller holds a reference to `self` for as long as the returned slices are live,
344         //   meaning the CPU read pointer cannot be advanced and thus that the returned area
345         //   remains exclusive to the CPU for the duration of the slices.
346         unsafe {
347             (
348                 core::slice::from_raw_parts(
349                     data.add(num::u32_as_usize(rx)),
350                     num::u32_as_usize(tail_end - rx),
351                 ),
352                 core::slice::from_raw_parts(data, num::u32_as_usize(wrap_end)),
353             )
354         }
355     }
356 
357     /// Allocates a region on the command queue that is large enough to send a command of `size`
358     /// bytes, waiting for space to become available based on the provided timeout.
359     ///
360     /// This returns a [`GspCommand`] ready to be written to by the caller.
361     ///
362     /// # Errors
363     ///
364     /// - `EMSGSIZE` if the command is larger than [`GSP_MSG_QUEUE_ELEMENT_SIZE_MAX`].
365     /// - `ETIMEDOUT` if space does not become available within the timeout.
366     /// - `EIO` if the command header is not properly aligned.
367     fn allocate_command(&mut self, size: usize, timeout: Delta) -> Result<GspCommand<'_>> {
368         if size_of::<GspMsgElement>() + size > GSP_MSG_QUEUE_ELEMENT_SIZE_MAX {
369             return Err(EMSGSIZE);
370         }
371         read_poll_timeout(
372             || Ok(self.driver_write_area_size()),
373             |available_bytes| *available_bytes >= size_of::<GspMsgElement>() + size,
374             Delta::from_micros(1),
375             timeout,
376         )?;
377 
378         // Get the current writable area as an array of bytes.
379         let (slice_1, slice_2) = {
380             let (slice_1, slice_2) = self.driver_write_area();
381 
382             (slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
383         };
384 
385         // Extract area for the `GspMsgElement`.
386         let (header, slice_1) = GspMsgElement::from_bytes_mut_prefix(slice_1).ok_or(EIO)?;
387 
388         // Create the contents area.
389         let (slice_1, slice_2) = if slice_1.len() > size {
390             // Contents fits entirely in `slice_1`.
391             (&mut slice_1[..size], &mut slice_2[0..0])
392         } else {
393             // Need all of `slice_1` and some of `slice_2`.
394             let slice_2_len = size - slice_1.len();
395             (slice_1, &mut slice_2[..slice_2_len])
396         };
397 
398         Ok(GspCommand {
399             header,
400             contents: (slice_1, slice_2),
401         })
402     }
403 
404     // Returns the index of the memory page the GSP will write the next message to.
405     //
406     // # Invariants
407     //
408     // - The returned value is within `0..MSGQ_NUM_PAGES`.
409     fn gsp_write_ptr(&self) -> u32 {
410         super::fw::gsp_mem::gsp_write_ptr(&self.0)
411     }
412 
413     // Returns the index of the memory page the GSP will read the next command from.
414     //
415     // # Invariants
416     //
417     // - The returned value is within `0..MSGQ_NUM_PAGES`.
418     fn gsp_read_ptr(&self) -> u32 {
419         super::fw::gsp_mem::gsp_read_ptr(&self.0)
420     }
421 
422     // Returns the index of the memory page the CPU can read the next message from.
423     //
424     // # Invariants
425     //
426     // - The returned value is within `0..MSGQ_NUM_PAGES`.
427     fn cpu_read_ptr(&self) -> u32 {
428         super::fw::gsp_mem::cpu_read_ptr(&self.0)
429     }
430 
431     // Informs the GSP that it can send `elem_count` new pages into the message queue.
432     fn advance_cpu_read_ptr(&mut self, elem_count: u32) {
433         super::fw::gsp_mem::advance_cpu_read_ptr(&self.0, elem_count)
434     }
435 
436     // Returns the index of the memory page the CPU can write the next command to.
437     //
438     // # Invariants
439     //
440     // - The returned value is within `0..MSGQ_NUM_PAGES`.
441     fn cpu_write_ptr(&self) -> u32 {
442         super::fw::gsp_mem::cpu_write_ptr(&self.0)
443     }
444 
445     // Informs the GSP that it can process `elem_count` new pages from the command queue.
446     fn advance_cpu_write_ptr(&mut self, elem_count: u32) {
447         super::fw::gsp_mem::advance_cpu_write_ptr(&self.0, elem_count)
448     }
449 }
450 
451 /// A command ready to be sent on the command queue.
452 ///
453 /// This is the type returned by [`DmaGspMem::allocate_command`].
454 struct GspCommand<'a> {
455     // Writable reference to the header of the command.
456     header: &'a mut GspMsgElement,
457     // Writable slices to the contents of the command. The second slice is zero unless the command
458     // loops over the command queue.
459     contents: (&'a mut [u8], &'a mut [u8]),
460 }
461 
462 /// A message ready to be processed from the message queue.
463 ///
464 /// This is the type returned by [`Cmdq::wait_for_msg`].
465 struct GspMessage<'a> {
466     // Reference to the header of the message.
467     header: &'a GspMsgElement,
468     // Slices to the contents of the message. The second slice is zero unless the message loops
469     // over the message queue.
470     contents: (&'a [u8], &'a [u8]),
471 }
472 
473 /// GSP command queue.
474 ///
475 /// Provides the ability to send commands and receive messages from the GSP using a shared memory
476 /// area.
477 #[pin_data]
478 pub(crate) struct Cmdq {
479     /// Inner mutex-protected state.
480     #[pin]
481     inner: Mutex<CmdqInner>,
482     /// DMA handle of the command queue's shared memory region.
483     pub(super) dma_handle: DmaAddress,
484 }
485 
486 impl Cmdq {
487     /// Offset of the data after the PTEs.
488     const POST_PTE_OFFSET: usize = core::mem::offset_of!(GspMem, cpuq);
489 
490     /// Offset of command queue ring buffer.
491     pub(crate) const CMDQ_OFFSET: usize = core::mem::offset_of!(GspMem, cpuq)
492         + core::mem::offset_of!(Msgq, msgq)
493         - Self::POST_PTE_OFFSET;
494 
495     /// Offset of message queue ring buffer.
496     pub(crate) const STATQ_OFFSET: usize = core::mem::offset_of!(GspMem, gspq)
497         + core::mem::offset_of!(Msgq, msgq)
498         - Self::POST_PTE_OFFSET;
499 
500     /// Number of page table entries for the GSP shared region.
501     pub(crate) const NUM_PTES: usize = size_of::<GspMem>() >> GSP_PAGE_SHIFT;
502 
503     /// Default timeout for receiving a message from the GSP.
504     pub(super) const RECEIVE_TIMEOUT: Delta = Delta::from_secs(5);
505 
506     /// Creates a new command queue for `dev`.
507     pub(crate) fn new(dev: &device::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ {
508         pin_init_scope(move || {
509             let gsp_mem = DmaGspMem::new(dev)?;
510 
511             Ok(try_pin_init!(Self {
512                 dma_handle: gsp_mem.0.dma_handle(),
513                 inner <- new_mutex!(CmdqInner {
514                     dev: dev.into(),
515                     gsp_mem,
516                     seq: 0,
517                 }),
518             }))
519         })
520     }
521 
522     /// Computes the checksum for the message pointed to by `it`.
523     ///
524     /// A message is made of several parts, so `it` is an iterator over byte slices representing
525     /// these parts.
526     fn calculate_checksum<T: Iterator<Item = u8>>(it: T) -> u32 {
527         let sum64 = it
528             .enumerate()
529             .map(|(idx, byte)| (((idx % 8) * 8) as u32, byte))
530             .fold(0, |acc, (rol, byte)| acc ^ u64::from(byte).rotate_left(rol));
531 
532         ((sum64 >> 32) as u32) ^ (sum64 as u32)
533     }
534 
535     /// Notifies the GSP that we have updated the command queue pointers.
536     fn notify_gsp(bar: Bar0<'_>) {
537         bar.write_reg(regs::NV_PGSP_QUEUE_HEAD::zeroed().with_address(0u32));
538     }
539 
540     /// Sends `command` to the GSP and waits for the reply.
541     ///
542     /// Messages with non-matching function codes are silently consumed until the expected reply
543     /// arrives.
544     ///
545     /// The queue is locked for the entire send+receive cycle to ensure that no other command can
546     /// be interleaved.
547     ///
548     /// # Errors
549     ///
550     /// - `ETIMEDOUT` if space does not become available to send the command, or if the reply is
551     ///   not received within the timeout.
552     /// - `EIO` if the variable payload requested by the command has not been entirely
553     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
554     ///
555     /// Error codes returned by the command and reply initializers are propagated as-is.
556     pub(crate) fn send_command<M>(&self, bar: Bar0<'_>, command: M) -> Result<M::Reply>
557     where
558         M: CommandToGsp,
559         M::Reply: MessageFromGsp,
560         Error: From<M::InitError>,
561         Error: From<<M::Reply as MessageFromGsp>::InitError>,
562     {
563         let mut inner = self.inner.lock();
564         inner.send_command(bar, command)?;
565 
566         loop {
567             match inner.receive_msg::<M::Reply>(Self::RECEIVE_TIMEOUT) {
568                 Ok(reply) => break Ok(reply),
569                 Err(ERANGE) => continue,
570                 Err(e) => break Err(e),
571             }
572         }
573     }
574 
575     /// Sends `command` to the GSP without waiting for a reply.
576     ///
577     /// # Errors
578     ///
579     /// - `ETIMEDOUT` if space does not become available within the timeout.
580     /// - `EIO` if the variable payload requested by the command has not been entirely
581     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
582     ///
583     /// Error codes returned by the command initializers are propagated as-is.
584     pub(crate) fn send_command_no_wait<M>(&self, bar: Bar0<'_>, command: M) -> Result
585     where
586         M: CommandToGsp<Reply = NoReply>,
587         Error: From<M::InitError>,
588     {
589         self.inner.lock().send_command(bar, command)
590     }
591 
592     /// Receive a message from the GSP.
593     ///
594     /// See [`CmdqInner::receive_msg`] for details.
595     pub(crate) fn receive_msg<M: MessageFromGsp>(&self, timeout: Delta) -> Result<M>
596     where
597         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
598         Error: From<M::InitError>,
599     {
600         self.inner.lock().receive_msg(timeout)
601     }
602 }
603 
604 /// Inner mutex protected state of [`Cmdq`].
605 struct CmdqInner {
606     /// Device this command queue belongs to.
607     dev: ARef<device::Device>,
608     /// Current command sequence number.
609     seq: u32,
610     /// Memory area shared with the GSP for communicating commands and messages.
611     gsp_mem: DmaGspMem,
612 }
613 
614 impl CmdqInner {
615     /// Timeout for waiting for space on the command queue.
616     const ALLOCATE_TIMEOUT: Delta = Delta::from_secs(1);
617 
618     /// Sends `command` to the GSP, without splitting it.
619     ///
620     /// # Errors
621     ///
622     /// - `EMSGSIZE` if the command exceeds the maximum queue element size.
623     /// - `ETIMEDOUT` if space does not become available within the timeout.
624     /// - `EIO` if the variable payload requested by the command has not been entirely
625     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
626     ///
627     /// Error codes returned by the command initializers are propagated as-is.
628     fn send_single_command<M>(&mut self, bar: Bar0<'_>, command: M) -> Result
629     where
630         M: CommandToGsp,
631         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
632         Error: From<M::InitError>,
633     {
634         let size_in_bytes = command.size();
635         let dst = self
636             .gsp_mem
637             .allocate_command(size_in_bytes, Self::ALLOCATE_TIMEOUT)?;
638 
639         // Extract area for the command itself. The GSP message header and the command header
640         // together are guaranteed to fit entirely into a single page, so it's ok to only look
641         // at `dst.contents.0` here.
642         let (cmd, payload_1) = M::Command::from_bytes_mut_prefix(dst.contents.0).ok_or(EIO)?;
643 
644         // Fill the header and command in-place.
645         let msg_element = GspMsgElement::init(self.seq, size_in_bytes, M::FUNCTION);
646         // SAFETY: `msg_header` and `cmd` are valid references, and not touched if the initializer
647         // fails.
648         unsafe {
649             msg_element.__init(core::ptr::from_mut(dst.header))?;
650             command.init().__init(core::ptr::from_mut(cmd))?;
651         }
652 
653         // Fill the variable-length payload, which may be empty.
654         let mut sbuffer = SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]);
655         command.init_variable_payload(&mut sbuffer)?;
656 
657         if !sbuffer.is_empty() {
658             return Err(EIO);
659         }
660         drop(sbuffer);
661 
662         // Compute checksum now that the whole message is ready.
663         dst.header
664             .set_checksum(Cmdq::calculate_checksum(SBufferIter::new_reader([
665                 dst.header.as_bytes(),
666                 dst.contents.0,
667                 dst.contents.1,
668             ])));
669 
670         dev_dbg!(
671             &self.dev,
672             "GSP RPC: send: seq# {}, function={:?}, length=0x{:x}\n",
673             self.seq,
674             M::FUNCTION,
675             dst.header.length(),
676         );
677 
678         // All set - update the write pointer and inform the GSP of the new command.
679         let elem_count = dst.header.element_count();
680         self.seq += 1;
681         self.gsp_mem.advance_cpu_write_ptr(elem_count);
682         Cmdq::notify_gsp(bar);
683 
684         Ok(())
685     }
686 
687     /// Sends `command` to the GSP.
688     ///
689     /// The command may be split into multiple messages if it is large.
690     ///
691     /// # Errors
692     ///
693     /// - `ETIMEDOUT` if space does not become available within the timeout.
694     /// - `EIO` if the variable payload requested by the command has not been entirely
695     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
696     ///
697     /// Error codes returned by the command initializers are propagated as-is.
698     fn send_command<M>(&mut self, bar: Bar0<'_>, command: M) -> Result
699     where
700         M: CommandToGsp,
701         Error: From<M::InitError>,
702     {
703         match SplitState::new(command)? {
704             SplitState::Single(command) => self.send_single_command(bar, command),
705             SplitState::Split(command, mut continuations) => {
706                 self.send_single_command(bar, command)?;
707 
708                 while let Some(continuation) = continuations.next() {
709                     // Turbofish needed because the compiler cannot infer M here.
710                     self.send_single_command::<ContinuationRecord<'_>>(bar, continuation)?;
711                 }
712 
713                 Ok(())
714             }
715         }
716     }
717 
718     /// Wait for a message to become available on the message queue.
719     ///
720     /// This works purely at the transport layer and does not interpret or validate the message
721     /// beyond the advertised length in its [`GspMsgElement`].
722     ///
723     /// This method returns:
724     ///
725     /// - A reference to the [`GspMsgElement`] of the message,
726     /// - Two byte slices with the contents of the message. The second slice is empty unless the
727     ///   message loops across the message queue.
728     ///
729     /// # Errors
730     ///
731     /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
732     /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
733     ///   message queue.
734     ///
735     /// Error codes returned by the message constructor are propagated as-is.
736     fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
737         // Wait for a message to arrive from the GSP.
738         let (slice_1, slice_2) = read_poll_timeout(
739             || Ok(self.gsp_mem.driver_read_area()),
740             |driver_area| !driver_area.0.is_empty(),
741             Delta::from_millis(1),
742             timeout,
743         )
744         .map(|(slice_1, slice_2)| (slice_1.as_flattened(), slice_2.as_flattened()))?;
745 
746         // Extract the `GspMsgElement`.
747         let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
748 
749         dev_dbg!(
750             &self.dev,
751             "GSP RPC: receive: seq# {}, function={:?}, length=0x{:x}\n",
752             header.sequence(),
753             header.function(),
754             header.length(),
755         );
756 
757         let payload_length = header.payload_length();
758 
759         // Check that the driver read area is large enough for the message.
760         if slice_1.len() + slice_2.len() < payload_length {
761             return Err(EIO);
762         }
763 
764         // Cut the message slices down to the actual length of the message.
765         let (slice_1, slice_2) = if slice_1.len() > payload_length {
766             // PANIC: we checked above that `slice_1` is at least as long as `payload_length`.
767             (slice_1.split_at(payload_length).0, &slice_2[0..0])
768         } else {
769             (
770                 slice_1,
771                 // PANIC: we checked above that `slice_1.len() + slice_2.len()` is at least as
772                 // large as `payload_length`.
773                 slice_2.split_at(payload_length - slice_1.len()).0,
774             )
775         };
776 
777         // Validate checksum.
778         if Cmdq::calculate_checksum(SBufferIter::new_reader([
779             header.as_bytes(),
780             slice_1,
781             slice_2,
782         ])) != 0
783         {
784             dev_err!(
785                 &self.dev,
786                 "GSP RPC: receive: Call {} - bad checksum\n",
787                 header.sequence()
788             );
789             return Err(EIO);
790         }
791 
792         Ok(GspMessage {
793             header,
794             contents: (slice_1, slice_2),
795         })
796     }
797 
798     /// Receive a message from the GSP.
799     ///
800     /// The expected message type is specified using the `M` generic parameter. If the pending
801     /// message has a different function code, `ERANGE` is returned and the message is consumed.
802     ///
803     /// The read pointer is always advanced past the message, regardless of whether it matched.
804     ///
805     /// # Errors
806     ///
807     /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
808     /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
809     ///   message queue.
810     /// - `EINVAL` if the function code of the message was not recognized.
811     /// - `ERANGE` if the message had a recognized but non-matching function code.
812     ///
813     /// Error codes returned by [`MessageFromGsp::read`] are propagated as-is.
814     fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
815     where
816         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
817         Error: From<M::InitError>,
818     {
819         let message = self.wait_for_msg(timeout)?;
820         let function = message.header.function().map_err(|_| EINVAL)?;
821 
822         // Extract the message. Store the result as we want to advance the read pointer even in
823         // case of failure.
824         let result = if function == M::FUNCTION {
825             let (cmd, contents_1) = M::Message::from_bytes_prefix(message.contents.0).ok_or(EIO)?;
826             let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]);
827 
828             M::read(cmd, &mut sbuffer)
829                 .map_err(|e| e.into())
830                 .inspect(|_| {
831                     if !sbuffer.is_empty() {
832                         dev_warn!(
833                             &self.dev,
834                             "GSP message {:?} has unprocessed data\n",
835                             function
836                         );
837                     }
838                 })
839         } else {
840             Err(ERANGE)
841         };
842 
843         // Advance the read pointer past this message.
844         self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
845             message.header.length().div_ceil(GSP_PAGE_SIZE),
846         )?);
847 
848         result
849     }
850 }
851