slot.rs 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. use super::{command_table::CommandTable, CommandHeader};
  2. use crate::KResult;
  3. use core::pin::pin;
  4. use eonix_mm::address::Addr as _;
  5. use eonix_sync::{Spin, SpinIrq as _, WaitList};
  6. pub struct CommandSlot<'a> {
  7. /// # Usage
  8. /// `inner.cmdheader` might be used in irq handler. So in order to wait for
  9. /// commands to finish, we should use `lock_irq` on `inner`
  10. inner: Spin<CommandSlotInner<'a>>,
  11. wait_list: WaitList,
  12. }
  13. struct CommandSlotInner<'a> {
  14. state: SlotState,
  15. cmdheader: &'a mut CommandHeader,
  16. }
  17. #[derive(Debug, PartialEq, Eq, Clone, Copy)]
  18. enum SlotState {
  19. Idle,
  20. Working,
  21. Finished,
  22. Error,
  23. }
  24. impl<'a> CommandSlot<'a> {
  25. pub fn new(cmdheader: &'a mut CommandHeader) -> Self {
  26. Self {
  27. inner: Spin::new(CommandSlotInner {
  28. state: SlotState::Idle,
  29. cmdheader,
  30. }),
  31. wait_list: WaitList::new(),
  32. }
  33. }
  34. pub fn handle_irq(&self) {
  35. let mut inner = self.inner.lock();
  36. debug_assert_eq!(inner.state, SlotState::Working);
  37. // TODO: Check errors.
  38. inner.state = SlotState::Finished;
  39. inner.cmdheader.bytes_transferred = 0;
  40. inner.cmdheader.prdt_length = 0;
  41. self.wait_list.notify_all();
  42. }
  43. pub fn prepare_command(&self, cmdtable: &CommandTable, write: bool) {
  44. let mut inner = self.inner.lock_irq();
  45. let cmdheader = &mut inner.cmdheader;
  46. cmdheader.first = 0x05; // FIS type
  47. if write {
  48. cmdheader.first |= 0x40;
  49. }
  50. cmdheader.second = 0x00;
  51. cmdheader.prdt_length = cmdtable.prdt_len();
  52. cmdheader.bytes_transferred = 0;
  53. cmdheader.command_table_base = cmdtable.base().addr() as u64;
  54. cmdheader._reserved = [0; 4];
  55. inner.state = SlotState::Working;
  56. }
  57. pub async fn wait_finish(&self) -> KResult<()> {
  58. let mut inner = loop {
  59. let inner = self.inner.lock_irq();
  60. if inner.state != SlotState::Working {
  61. break inner;
  62. }
  63. let mut wait = pin!(self.wait_list.prepare_to_wait());
  64. wait.as_mut().add_to_wait_list();
  65. if inner.state != SlotState::Working {
  66. break inner;
  67. }
  68. drop(inner);
  69. wait.await;
  70. };
  71. inner.state = SlotState::Idle;
  72. Ok(())
  73. }
  74. }