xref: /linux/drivers/gpu/nova-core/gsp/cmdq.rs (revision 4da879a0d3fd170a70994b73baa554c6913918b5)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 use core::{
4     cmp,
5     mem,
6     sync::atomic::{
7         fence,
8         Ordering, //
9     }, //
10 };
11 
12 use kernel::{
13     device,
14     dma::{
15         CoherentAllocation,
16         DmaAddress, //
17     },
18     dma_write,
19     io::poll::read_poll_timeout,
20     prelude::*,
21     sync::aref::ARef,
22     time::Delta,
23     transmute::{
24         AsBytes,
25         FromBytes, //
26     },
27 };
28 
29 use crate::{
30     driver::Bar0,
31     gsp::{
32         fw::{
33             GspMsgElement,
34             MsgFunction,
35             MsgqRxHeader,
36             MsgqTxHeader, //
37         },
38         PteArray,
39         GSP_PAGE_SHIFT,
40         GSP_PAGE_SIZE, //
41     },
42     num,
43     regs,
44     sbuffer::SBufferIter, //
45 };
46 
47 /// Trait implemented by types representing a command to send to the GSP.
48 ///
49 /// The main purpose of this trait is to provide [`Cmdq::send_command`] with the information it
50 /// needs to send a given command.
51 ///
52 /// [`CommandToGsp::init`] in particular is responsible for initializing the command directly
53 /// into the space reserved for it in the command queue buffer.
54 ///
55 /// Some commands may be followed by a variable-length payload. For these, the
56 /// [`CommandToGsp::variable_payload_len`] and [`CommandToGsp::init_variable_payload`] need to be
57 /// defined as well.
58 pub(crate) trait CommandToGsp {
59     /// Function identifying this command to the GSP.
60     const FUNCTION: MsgFunction;
61 
62     /// Type generated by [`CommandToGsp::init`], to be written into the command queue buffer.
63     type Command: FromBytes + AsBytes;
64 
65     /// Error type returned by [`CommandToGsp::init`].
66     type InitError;
67 
68     /// In-place command initializer responsible for filling the command in the command queue
69     /// buffer.
70     fn init(&self) -> impl Init<Self::Command, Self::InitError>;
71 
72     /// Size of the variable-length payload following the command structure generated by
73     /// [`CommandToGsp::init`].
74     ///
75     /// Most commands don't have a variable-length payload, so this is zero by default.
76     fn variable_payload_len(&self) -> usize {
77         0
78     }
79 
80     /// Method initializing the variable-length payload.
81     ///
82     /// The command buffer is circular, which means that we may need to jump back to its beginning
83     /// while in the middle of a command. For this reason, the variable-length payload is
84     /// initialized using a [`SBufferIter`].
85     ///
86     /// This method will receive a buffer of the length returned by
87     /// [`CommandToGsp::variable_payload_len`], and must write every single byte of it. Leaving
88     /// unwritten space will lead to an error.
89     ///
90     /// Most commands don't have a variable-length payload, so this does nothing by default.
91     fn init_variable_payload(
92         &self,
93         _dst: &mut SBufferIter<core::array::IntoIter<&mut [u8], 2>>,
94     ) -> Result {
95         Ok(())
96     }
97 }
98 
99 /// Trait representing messages received from the GSP.
100 ///
101 /// This trait tells [`Cmdq::receive_msg`] how it can receive a given type of message.
102 pub(crate) trait MessageFromGsp: Sized {
103     /// Function identifying this message from the GSP.
104     const FUNCTION: MsgFunction;
105 
106     /// Error type returned by [`MessageFromGsp::read`].
107     type InitError;
108 
109     /// Type containing the raw message to be read from the message queue.
110     type Message: FromBytes;
111 
112     /// Method reading the message from the message queue and returning it.
113     ///
114     /// From a `Self::Message` and a [`SBufferIter`], constructs an instance of `Self` and returns
115     /// it.
116     fn read(
117         msg: &Self::Message,
118         sbuffer: &mut SBufferIter<core::array::IntoIter<&[u8], 2>>,
119     ) -> Result<Self, Self::InitError>;
120 }
121 
122 /// Number of GSP pages making the [`Msgq`].
123 pub(crate) const MSGQ_NUM_PAGES: u32 = 0x3f;
124 
125 /// Circular buffer of a [`Msgq`].
126 ///
127 /// This area of memory is to be shared between the driver and the GSP to exchange commands or
128 /// messages.
129 #[repr(C, align(0x1000))]
130 #[derive(Debug)]
131 struct MsgqData {
132     data: [[u8; GSP_PAGE_SIZE]; num::u32_as_usize(MSGQ_NUM_PAGES)],
133 }
134 
135 // Annoyingly we are forced to use a literal to specify the alignment of
136 // `MsgqData`, so check that it corresponds to the actual GSP page size here.
137 static_assert!(align_of::<MsgqData>() == GSP_PAGE_SIZE);
138 
139 /// Unidirectional message queue.
140 ///
141 /// Contains the data for a message queue, that either the driver or GSP writes to.
142 ///
143 /// Note that while the write pointer of `tx` corresponds to the `msgq` of the same instance, the
144 /// read pointer of `rx` actually refers to the `Msgq` owned by the other side.
145 /// This design ensures that only the driver or GSP ever writes to a given instance of this struct.
146 #[repr(C)]
147 // There is no struct defined for this in the open-gpu-kernel-source headers.
148 // Instead it is defined by code in `GspMsgQueuesInit()`.
149 struct Msgq {
150     /// Header for sending messages, including the write pointer.
151     tx: MsgqTxHeader,
152     /// Header for receiving messages, including the read pointer.
153     rx: MsgqRxHeader,
154     /// The message queue proper.
155     msgq: MsgqData,
156 }
157 
158 /// Structure shared between the driver and the GSP and containing the command and message queues.
159 #[repr(C)]
160 struct GspMem {
161     /// Self-mapping page table entries.
162     ptes: PteArray<{ GSP_PAGE_SIZE / size_of::<u64>() }>,
163     /// CPU queue: the driver writes commands here, and the GSP reads them. It also contains the
164     /// write and read pointers that the CPU updates.
165     ///
166     /// This member is read-only for the GSP.
167     cpuq: Msgq,
168     /// GSP queue: the GSP writes messages here, and the driver reads them. It also contains the
169     /// write and read pointers that the GSP updates.
170     ///
171     /// This member is read-only for the driver.
172     gspq: Msgq,
173 }
174 
175 // SAFETY: These structs don't meet the no-padding requirements of AsBytes but
176 // that is not a problem because they are not used outside the kernel.
177 unsafe impl AsBytes for GspMem {}
178 
179 // SAFETY: These structs don't meet the no-padding requirements of FromBytes but
180 // that is not a problem because they are not used outside the kernel.
181 unsafe impl FromBytes for GspMem {}
182 
183 /// Wrapper around [`GspMem`] to share it with the GPU using a [`CoherentAllocation`].
184 ///
185 /// This provides the low-level functionality to communicate with the GSP, including allocation of
186 /// queue space to write messages to and management of read/write pointers.
187 ///
188 /// This is shared with the GSP, with clear ownership rules regarding the command queues:
189 ///
190 /// * The driver owns (i.e. can write to) the part of the CPU message queue between the CPU write
191 ///   pointer and the GSP read pointer. This region is returned by [`Self::driver_write_area`].
192 /// * The driver owns (i.e. can read from) the part of the GSP message queue between the CPU read
193 ///   pointer and the GSP write pointer. This region is returned by [`Self::driver_read_area`].
194 struct DmaGspMem(CoherentAllocation<GspMem>);
195 
196 impl DmaGspMem {
197     /// Allocate a new instance and map it for `dev`.
198     fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
199         const MSGQ_SIZE: u32 = num::usize_into_u32::<{ size_of::<Msgq>() }>();
200         const RX_HDR_OFF: u32 = num::usize_into_u32::<{ mem::offset_of!(Msgq, rx) }>();
201 
202         let gsp_mem =
203             CoherentAllocation::<GspMem>::alloc_coherent(dev, 1, GFP_KERNEL | __GFP_ZERO)?;
204         dma_write!(gsp_mem, [0]?.ptes, PteArray::new(gsp_mem.dma_handle())?);
205         dma_write!(
206             gsp_mem,
207             [0]?.cpuq.tx,
208             MsgqTxHeader::new(MSGQ_SIZE, RX_HDR_OFF, MSGQ_NUM_PAGES)
209         );
210         dma_write!(gsp_mem, [0]?.cpuq.rx, MsgqRxHeader::new());
211 
212         Ok(Self(gsp_mem))
213     }
214 
215     /// Returns the region of the CPU message queue that the driver is currently allowed to write
216     /// to.
217     ///
218     /// As the message queue is a circular buffer, the region may be discontiguous in memory. In
219     /// that case the second slice will have a non-zero length.
220     fn driver_write_area(&mut self) -> (&mut [[u8; GSP_PAGE_SIZE]], &mut [[u8; GSP_PAGE_SIZE]]) {
221         let tx = self.cpu_write_ptr() as usize;
222         let rx = self.gsp_read_ptr() as usize;
223 
224         // SAFETY:
225         // - The `CoherentAllocation` contains exactly one object.
226         // - We will only access the driver-owned part of the shared memory.
227         // - Per the safety statement of the function, no concurrent access will be performed.
228         let gsp_mem = &mut unsafe { self.0.as_slice_mut(0, 1) }.unwrap()[0];
229         // PANIC: per the invariant of `cpu_write_ptr`, `tx` is `<= MSGQ_NUM_PAGES`.
230         let (before_tx, after_tx) = gsp_mem.cpuq.msgq.data.split_at_mut(tx);
231 
232         if rx <= tx {
233             // The area from `tx` up to the end of the ring, and from the beginning of the ring up
234             // to `rx`, minus one unit, belongs to the driver.
235             if rx == 0 {
236                 let last = after_tx.len() - 1;
237                 (&mut after_tx[..last], &mut before_tx[0..0])
238             } else {
239                 (after_tx, &mut before_tx[..rx])
240             }
241         } else {
242             // The area from `tx` to `rx`, minus one unit, belongs to the driver.
243             //
244             // PANIC: per the invariants of `cpu_write_ptr` and `gsp_read_ptr`, `rx` and `tx` are
245             // `<= MSGQ_NUM_PAGES`, and the test above ensured that `rx > tx`.
246             (after_tx.split_at_mut(rx - tx).0, &mut before_tx[0..0])
247         }
248     }
249 
250     /// Returns the region of the GSP message queue that the driver is currently allowed to read
251     /// from.
252     ///
253     /// As the message queue is a circular buffer, the region may be discontiguous in memory. In
254     /// that case the second slice will have a non-zero length.
255     fn driver_read_area(&self) -> (&[[u8; GSP_PAGE_SIZE]], &[[u8; GSP_PAGE_SIZE]]) {
256         let tx = self.gsp_write_ptr() as usize;
257         let rx = self.cpu_read_ptr() as usize;
258 
259         // SAFETY:
260         // - The `CoherentAllocation` contains exactly one object.
261         // - We will only access the driver-owned part of the shared memory.
262         // - Per the safety statement of the function, no concurrent access will be performed.
263         let gsp_mem = &unsafe { self.0.as_slice(0, 1) }.unwrap()[0];
264         // PANIC: per the invariant of `cpu_read_ptr`, `xx` is `<= MSGQ_NUM_PAGES`.
265         let (before_rx, after_rx) = gsp_mem.gspq.msgq.data.split_at(rx);
266 
267         match tx.cmp(&rx) {
268             cmp::Ordering::Equal => (&after_rx[0..0], &after_rx[0..0]),
269             cmp::Ordering::Greater => (&after_rx[..tx], &before_rx[0..0]),
270             cmp::Ordering::Less => (after_rx, &before_rx[..tx]),
271         }
272     }
273 
274     /// Allocates a region on the command queue that is large enough to send a command of `size`
275     /// bytes.
276     ///
277     /// This returns a [`GspCommand`] ready to be written to by the caller.
278     ///
279     /// # Errors
280     ///
281     /// - `EAGAIN` if the driver area is too small to hold the requested command.
282     /// - `EIO` if the command header is not properly aligned.
283     fn allocate_command(&mut self, size: usize) -> Result<GspCommand<'_>> {
284         // Get the current writable area as an array of bytes.
285         let (slice_1, slice_2) = {
286             let (slice_1, slice_2) = self.driver_write_area();
287 
288             #[allow(clippy::incompatible_msrv)]
289             (slice_1.as_flattened_mut(), slice_2.as_flattened_mut())
290         };
291 
292         // If the GSP is still processing previous messages the shared region
293         // may be full in which case we will have to retry once the GSP has
294         // processed the existing commands.
295         if size_of::<GspMsgElement>() + size > slice_1.len() + slice_2.len() {
296             return Err(EAGAIN);
297         }
298 
299         // Extract area for the `GspMsgElement`.
300         let (header, slice_1) = GspMsgElement::from_bytes_mut_prefix(slice_1).ok_or(EIO)?;
301 
302         // Create the contents area.
303         let (slice_1, slice_2) = if slice_1.len() > size {
304             // Contents fits entirely in `slice_1`.
305             (&mut slice_1[..size], &mut slice_2[0..0])
306         } else {
307             // Need all of `slice_1` and some of `slice_2`.
308             let slice_2_len = size - slice_1.len();
309             (slice_1, &mut slice_2[..slice_2_len])
310         };
311 
312         Ok(GspCommand {
313             header,
314             contents: (slice_1, slice_2),
315         })
316     }
317 
318     // Returns the index of the memory page the GSP will write the next message to.
319     //
320     // # Invariants
321     //
322     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
323     fn gsp_write_ptr(&self) -> u32 {
324         let gsp_mem = self.0.start_ptr();
325 
326         // SAFETY:
327         //  - The 'CoherentAllocation' contains at least one object.
328         //  - By the invariants of `CoherentAllocation` the pointer is valid.
329         (unsafe { (*gsp_mem).gspq.tx.write_ptr() } % MSGQ_NUM_PAGES)
330     }
331 
332     // Returns the index of the memory page the GSP will read the next command from.
333     //
334     // # Invariants
335     //
336     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
337     fn gsp_read_ptr(&self) -> u32 {
338         let gsp_mem = self.0.start_ptr();
339 
340         // SAFETY:
341         //  - The 'CoherentAllocation' contains at least one object.
342         //  - By the invariants of `CoherentAllocation` the pointer is valid.
343         (unsafe { (*gsp_mem).gspq.rx.read_ptr() } % MSGQ_NUM_PAGES)
344     }
345 
346     // Returns the index of the memory page the CPU can read the next message from.
347     //
348     // # Invariants
349     //
350     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
351     fn cpu_read_ptr(&self) -> u32 {
352         let gsp_mem = self.0.start_ptr();
353 
354         // SAFETY:
355         //  - The ['CoherentAllocation'] contains at least one object.
356         //  - By the invariants of CoherentAllocation the pointer is valid.
357         (unsafe { (*gsp_mem).cpuq.rx.read_ptr() } % MSGQ_NUM_PAGES)
358     }
359 
360     // Informs the GSP that it can send `elem_count` new pages into the message queue.
361     fn advance_cpu_read_ptr(&mut self, elem_count: u32) {
362         let rptr = self.cpu_read_ptr().wrapping_add(elem_count) % MSGQ_NUM_PAGES;
363 
364         // Ensure read pointer is properly ordered.
365         fence(Ordering::SeqCst);
366 
367         let gsp_mem = self.0.start_ptr_mut();
368 
369         // SAFETY:
370         //  - The 'CoherentAllocation' contains at least one object.
371         //  - By the invariants of `CoherentAllocation` the pointer is valid.
372         unsafe { (*gsp_mem).cpuq.rx.set_read_ptr(rptr) };
373     }
374 
375     // Returns the index of the memory page the CPU can write the next command to.
376     //
377     // # Invariants
378     //
379     // - The returned value is between `0` and `MSGQ_NUM_PAGES`.
380     fn cpu_write_ptr(&self) -> u32 {
381         let gsp_mem = self.0.start_ptr();
382 
383         // SAFETY:
384         //  - The 'CoherentAllocation' contains at least one object.
385         //  - By the invariants of `CoherentAllocation` the pointer is valid.
386         (unsafe { (*gsp_mem).cpuq.tx.write_ptr() } % MSGQ_NUM_PAGES)
387     }
388 
389     // Informs the GSP that it can process `elem_count` new pages from the command queue.
390     fn advance_cpu_write_ptr(&mut self, elem_count: u32) {
391         let wptr = self.cpu_write_ptr().wrapping_add(elem_count) & MSGQ_NUM_PAGES;
392         let gsp_mem = self.0.start_ptr_mut();
393 
394         // SAFETY:
395         //  - The 'CoherentAllocation' contains at least one object.
396         //  - By the invariants of `CoherentAllocation` the pointer is valid.
397         unsafe { (*gsp_mem).cpuq.tx.set_write_ptr(wptr) };
398 
399         // Ensure all command data is visible before triggering the GSP read.
400         fence(Ordering::SeqCst);
401     }
402 }
403 
404 /// A command ready to be sent on the command queue.
405 ///
406 /// This is the type returned by [`DmaGspMem::allocate_command`].
407 struct GspCommand<'a> {
408     // Writable reference to the header of the command.
409     header: &'a mut GspMsgElement,
410     // Writable slices to the contents of the command. The second slice is zero unless the command
411     // loops over the command queue.
412     contents: (&'a mut [u8], &'a mut [u8]),
413 }
414 
415 /// A message ready to be processed from the message queue.
416 ///
417 /// This is the type returned by [`Cmdq::wait_for_msg`].
418 struct GspMessage<'a> {
419     // Reference to the header of the message.
420     header: &'a GspMsgElement,
421     // Slices to the contents of the message. The second slice is zero unless the message loops
422     // over the message queue.
423     contents: (&'a [u8], &'a [u8]),
424 }
425 
426 /// GSP command queue.
427 ///
428 /// Provides the ability to send commands and receive messages from the GSP using a shared memory
429 /// area.
430 pub(crate) struct Cmdq {
431     /// Device this command queue belongs to.
432     dev: ARef<device::Device>,
433     /// Current command sequence number.
434     seq: u32,
435     /// Memory area shared with the GSP for communicating commands and messages.
436     gsp_mem: DmaGspMem,
437 }
438 
439 impl Cmdq {
440     /// Offset of the data after the PTEs.
441     const POST_PTE_OFFSET: usize = core::mem::offset_of!(GspMem, cpuq);
442 
443     /// Offset of command queue ring buffer.
444     pub(crate) const CMDQ_OFFSET: usize = core::mem::offset_of!(GspMem, cpuq)
445         + core::mem::offset_of!(Msgq, msgq)
446         - Self::POST_PTE_OFFSET;
447 
448     /// Offset of message queue ring buffer.
449     pub(crate) const STATQ_OFFSET: usize = core::mem::offset_of!(GspMem, gspq)
450         + core::mem::offset_of!(Msgq, msgq)
451         - Self::POST_PTE_OFFSET;
452 
453     /// Number of page table entries for the GSP shared region.
454     pub(crate) const NUM_PTES: usize = size_of::<GspMem>() >> GSP_PAGE_SHIFT;
455 
456     /// Creates a new command queue for `dev`.
457     pub(crate) fn new(dev: &device::Device<device::Bound>) -> Result<Cmdq> {
458         let gsp_mem = DmaGspMem::new(dev)?;
459 
460         Ok(Cmdq {
461             dev: dev.into(),
462             seq: 0,
463             gsp_mem,
464         })
465     }
466 
467     /// Computes the checksum for the message pointed to by `it`.
468     ///
469     /// A message is made of several parts, so `it` is an iterator over byte slices representing
470     /// these parts.
471     fn calculate_checksum<T: Iterator<Item = u8>>(it: T) -> u32 {
472         let sum64 = it
473             .enumerate()
474             .map(|(idx, byte)| (((idx % 8) * 8) as u32, byte))
475             .fold(0, |acc, (rol, byte)| acc ^ u64::from(byte).rotate_left(rol));
476 
477         ((sum64 >> 32) as u32) ^ (sum64 as u32)
478     }
479 
480     /// Notifies the GSP that we have updated the command queue pointers.
481     fn notify_gsp(bar: &Bar0) {
482         regs::NV_PGSP_QUEUE_HEAD::default()
483             .set_address(0)
484             .write(bar);
485     }
486 
487     /// Sends `command` to the GSP.
488     ///
489     /// # Errors
490     ///
491     /// - `EAGAIN` if there was not enough space in the command queue to send the command.
492     /// - `EIO` if the variable payload requested by the command has not been entirely
493     ///   written to by its [`CommandToGsp::init_variable_payload`] method.
494     ///
495     /// Error codes returned by the command initializers are propagated as-is.
496     pub(crate) fn send_command<M>(&mut self, bar: &Bar0, command: M) -> Result
497     where
498         M: CommandToGsp,
499         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
500         Error: From<M::InitError>,
501     {
502         let command_size = size_of::<M::Command>() + command.variable_payload_len();
503         let dst = self.gsp_mem.allocate_command(command_size)?;
504 
505         // Extract area for the command itself.
506         let (cmd, payload_1) = M::Command::from_bytes_mut_prefix(dst.contents.0).ok_or(EIO)?;
507 
508         // Fill the header and command in-place.
509         let msg_element = GspMsgElement::init(self.seq, command_size, M::FUNCTION);
510         // SAFETY: `msg_header` and `cmd` are valid references, and not touched if the initializer
511         // fails.
512         unsafe {
513             msg_element.__init(core::ptr::from_mut(dst.header))?;
514             command.init().__init(core::ptr::from_mut(cmd))?;
515         }
516 
517         // Fill the variable-length payload.
518         if command_size > size_of::<M::Command>() {
519             let mut sbuffer =
520                 SBufferIter::new_writer([&mut payload_1[..], &mut dst.contents.1[..]]);
521             command.init_variable_payload(&mut sbuffer)?;
522 
523             if !sbuffer.is_empty() {
524                 return Err(EIO);
525             }
526         }
527 
528         // Compute checksum now that the whole message is ready.
529         dst.header
530             .set_checksum(Cmdq::calculate_checksum(SBufferIter::new_reader([
531                 dst.header.as_bytes(),
532                 dst.contents.0,
533                 dst.contents.1,
534             ])));
535 
536         dev_dbg!(
537             &self.dev,
538             "GSP RPC: send: seq# {}, function={}, length=0x{:x}\n",
539             self.seq,
540             M::FUNCTION,
541             dst.header.length(),
542         );
543 
544         // All set - update the write pointer and inform the GSP of the new command.
545         let elem_count = dst.header.element_count();
546         self.seq += 1;
547         self.gsp_mem.advance_cpu_write_ptr(elem_count);
548         Cmdq::notify_gsp(bar);
549 
550         Ok(())
551     }
552 
553     /// Wait for a message to become available on the message queue.
554     ///
555     /// This works purely at the transport layer and does not interpret or validate the message
556     /// beyond the advertised length in its [`GspMsgElement`].
557     ///
558     /// This method returns:
559     ///
560     /// - A reference to the [`GspMsgElement`] of the message,
561     /// - Two byte slices with the contents of the message. The second slice is empty unless the
562     ///   message loops across the message queue.
563     ///
564     /// # Errors
565     ///
566     /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
567     /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
568     ///   message queue.
569     ///
570     /// Error codes returned by the message constructor are propagated as-is.
571     fn wait_for_msg(&self, timeout: Delta) -> Result<GspMessage<'_>> {
572         // Wait for a message to arrive from the GSP.
573         let (slice_1, slice_2) = read_poll_timeout(
574             || Ok(self.gsp_mem.driver_read_area()),
575             |driver_area| !driver_area.0.is_empty(),
576             Delta::from_millis(1),
577             timeout,
578         )
579         .map(|(slice_1, slice_2)| {
580             #[allow(clippy::incompatible_msrv)]
581             (slice_1.as_flattened(), slice_2.as_flattened())
582         })?;
583 
584         // Extract the `GspMsgElement`.
585         let (header, slice_1) = GspMsgElement::from_bytes_prefix(slice_1).ok_or(EIO)?;
586 
587         dev_dbg!(
588             self.dev,
589             "GSP RPC: receive: seq# {}, function={:?}, length=0x{:x}\n",
590             header.sequence(),
591             header.function(),
592             header.length(),
593         );
594 
595         let payload_length = header.payload_length();
596 
597         // Check that the driver read area is large enough for the message.
598         if slice_1.len() + slice_2.len() < payload_length {
599             return Err(EIO);
600         }
601 
602         // Cut the message slices down to the actual length of the message.
603         let (slice_1, slice_2) = if slice_1.len() > payload_length {
604             // PANIC: we checked above that `slice_1` is at least as long as `payload_length`.
605             (slice_1.split_at(payload_length).0, &slice_2[0..0])
606         } else {
607             (
608                 slice_1,
609                 // PANIC: we checked above that `slice_1.len() + slice_2.len()` is at least as
610                 // large as `payload_length`.
611                 slice_2.split_at(payload_length - slice_1.len()).0,
612             )
613         };
614 
615         // Validate checksum.
616         if Cmdq::calculate_checksum(SBufferIter::new_reader([
617             header.as_bytes(),
618             slice_1,
619             slice_2,
620         ])) != 0
621         {
622             dev_err!(
623                 self.dev,
624                 "GSP RPC: receive: Call {} - bad checksum\n",
625                 header.sequence()
626             );
627             return Err(EIO);
628         }
629 
630         Ok(GspMessage {
631             header,
632             contents: (slice_1, slice_2),
633         })
634     }
635 
636     /// Receive a message from the GSP.
637     ///
638     /// `init` is a closure tasked with processing the message. It receives a reference to the
639     /// message in the message queue, and a [`SBufferIter`] pointing to its variable-length
640     /// payload, if any.
641     ///
642     /// The expected message is specified using the `M` generic parameter. If the pending message
643     /// is different, `EAGAIN` is returned and the unexpected message is dropped.
644     ///
645     /// This design is by no means final, but it is simple and will let us go through GSP
646     /// initialization.
647     ///
648     /// # Errors
649     ///
650     /// - `ETIMEDOUT` if `timeout` has elapsed before any message becomes available.
651     /// - `EIO` if there was some inconsistency (e.g. message shorter than advertised) on the
652     ///   message queue.
653     /// - `EINVAL` if the function of the message was unrecognized.
654     pub(crate) fn receive_msg<M: MessageFromGsp>(&mut self, timeout: Delta) -> Result<M>
655     where
656         // This allows all error types, including `Infallible`, to be used for `M::InitError`.
657         Error: From<M::InitError>,
658     {
659         let message = self.wait_for_msg(timeout)?;
660         let function = message.header.function().map_err(|_| EINVAL)?;
661 
662         // Extract the message. Store the result as we want to advance the read pointer even in
663         // case of failure.
664         let result = if function == M::FUNCTION {
665             let (cmd, contents_1) = M::Message::from_bytes_prefix(message.contents.0).ok_or(EIO)?;
666             let mut sbuffer = SBufferIter::new_reader([contents_1, message.contents.1]);
667 
668             M::read(cmd, &mut sbuffer).map_err(|e| e.into())
669         } else {
670             Err(ERANGE)
671         };
672 
673         // Advance the read pointer past this message.
674         self.gsp_mem.advance_cpu_read_ptr(u32::try_from(
675             message.header.length().div_ceil(GSP_PAGE_SIZE),
676         )?);
677 
678         result
679     }
680 
681     /// Returns the DMA handle of the command queue's shared memory region.
682     pub(crate) fn dma_handle(&self) -> DmaAddress {
683         self.gsp_mem.0.dma_handle()
684     }
685 }
686