cmdq.rs 24 KB

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