slot.rs 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. use core::cell::UnsafeCell;
  2. use core::ptr::NonNull;
  3. use core::task::{Poll, Waker};
  4. use eonix_mm::address::{Addr as _, PAddr};
  5. use eonix_mm::paging::Folio as _;
  6. use eonix_sync::{Spin, SpinIrq as _};
  7. use super::command_table::CommandTable;
  8. use super::CommandHeader;
  9. use crate::kernel::constants::EIO;
  10. use crate::kernel::mem::FolioOwned;
  11. use crate::KResult;
  12. pub struct CommandList {
  13. base: NonNull<u8>,
  14. _page: FolioOwned,
  15. }
  16. unsafe impl Send for CommandList {}
  17. unsafe impl Sync for CommandList {}
  18. pub struct CommandSlot<'a> {
  19. cmdheader: &'a UnsafeCell<CommandHeader>,
  20. /// [`Self::control`] might be used in irq handlers.
  21. control: &'a Spin<SlotControl>,
  22. }
  23. unsafe impl Send for CommandSlot<'_> {}
  24. unsafe impl Sync for CommandSlot<'_> {}
  25. struct SlotControl {
  26. state: SlotState,
  27. waker: Option<Waker>,
  28. }
  29. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  30. enum SlotState {
  31. Idle,
  32. Working,
  33. Finished,
  34. Error,
  35. }
  36. impl CommandList {
  37. fn cmdheaders(&self) -> &[UnsafeCell<CommandHeader>; 32] {
  38. unsafe { self.base.cast().as_ref() }
  39. }
  40. fn controls_ptr(base: NonNull<u8>) -> NonNull<Spin<SlotControl>> {
  41. // 24 bytes for SlotControl and extra 8 bytes for Spin.
  42. const_assert_eq!(size_of::<Spin<SlotControl>>(), 32);
  43. unsafe { base.add(size_of::<UnsafeCell<CommandHeader>>() * 32).cast() }
  44. }
  45. fn controls(&self) -> &[Spin<SlotControl>; 32] {
  46. unsafe { Self::controls_ptr(self.base).cast().as_ref() }
  47. }
  48. pub fn cmdlist_base(&self) -> PAddr {
  49. self._page.start()
  50. }
  51. pub fn recv_fis_base(&self) -> PAddr {
  52. self._page.start()
  53. + (size_of::<UnsafeCell<CommandHeader>>() + size_of::<Spin<SlotControl>>()) * 32
  54. }
  55. pub fn get(&self, index: usize) -> CommandSlot {
  56. CommandSlot {
  57. cmdheader: &self.cmdheaders()[index],
  58. control: &self.controls()[index],
  59. }
  60. }
  61. pub fn new() -> Self {
  62. let mut page = FolioOwned::alloc();
  63. page.as_bytes_mut().fill(0);
  64. let base = page.get_ptr();
  65. let controls_ptr = Self::controls_ptr(base);
  66. for i in 0..32 {
  67. unsafe {
  68. controls_ptr.add(i).write(Spin::new(SlotControl {
  69. state: SlotState::Idle,
  70. waker: None,
  71. }));
  72. }
  73. }
  74. Self {
  75. base: page.get_ptr(),
  76. _page: page,
  77. }
  78. }
  79. }
  80. impl Drop for CommandList {
  81. fn drop(&mut self) {
  82. let controls_ptr = Self::controls_ptr(self.base);
  83. for i in 0..32 {
  84. unsafe {
  85. controls_ptr.add(i).drop_in_place();
  86. }
  87. }
  88. }
  89. }
  90. impl CommandSlot<'_> {
  91. pub fn handle_irq(&self) {
  92. // We are already in the IRQ handler.
  93. let mut control = self.control.lock();
  94. assert_eq!(control.state, SlotState::Working);
  95. let cmdheader = unsafe {
  96. // SAFETY: The IRQ handler is only called after the command
  97. // is finished.
  98. &mut *self.cmdheader.get()
  99. };
  100. // TODO: Check errors.
  101. cmdheader.bytes_transferred = 0;
  102. cmdheader.prdt_length = 0;
  103. control.state = SlotState::Finished;
  104. if let Some(waker) = control.waker.take() {
  105. waker.wake();
  106. }
  107. }
  108. pub fn prepare_command(&self, cmdtable: &CommandTable, write: bool) {
  109. let mut control = self.control.lock_irq();
  110. assert_eq!(control.state, SlotState::Idle);
  111. let cmdheader = unsafe {
  112. // SAFETY: We are in the idle state.
  113. &mut *self.cmdheader.get()
  114. };
  115. cmdheader.first = 0x05; // FIS type
  116. if write {
  117. cmdheader.first |= 0x40;
  118. }
  119. cmdheader.second = 0x00;
  120. cmdheader.prdt_length = cmdtable.prdt_len() as u16;
  121. cmdheader.bytes_transferred = 0;
  122. cmdheader.command_table_base = cmdtable.base().addr() as u64;
  123. cmdheader._reserved = [0; 4];
  124. control.state = SlotState::Working;
  125. }
  126. pub async fn wait_finish(&self) -> KResult<()> {
  127. core::future::poll_fn(|ctx| {
  128. let mut control = self.control.lock_irq();
  129. match control.state {
  130. SlotState::Idle => unreachable!("Poll called in idle state"),
  131. SlotState::Working => {
  132. control.waker = Some(ctx.waker().clone());
  133. Poll::Pending
  134. }
  135. SlotState::Finished => {
  136. control.state = SlotState::Idle;
  137. Poll::Ready(Ok(()))
  138. }
  139. SlotState::Error => {
  140. control.state = SlotState::Idle;
  141. // TODO: Report errors.
  142. Poll::Ready(Err(EIO))
  143. }
  144. }
  145. })
  146. .await
  147. }
  148. }