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