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