port.rs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. use super::command::{Command, IdentifyCommand, ReadLBACommand};
  2. use super::slot::CommandSlot;
  3. use super::stats::AdapterPortStats;
  4. use super::{
  5. CommandHeader, Register, PORT_CMD_CR, PORT_CMD_FR, PORT_CMD_FRE, PORT_CMD_ST, PORT_IE_DEFAULT,
  6. };
  7. use crate::driver::ahci::command_table::CommandTable;
  8. use crate::kernel::block::{BlockDeviceRequest, BlockRequestQueue};
  9. use crate::kernel::mem::paging::Page;
  10. use crate::kernel::mem::AsMemoryBlock as _;
  11. use crate::prelude::*;
  12. use alloc::collections::vec_deque::VecDeque;
  13. use bindings::{EINVAL, EIO};
  14. use core::pin::pin;
  15. use eonix_mm::address::{Addr as _, PAddr};
  16. use eonix_runtime::task::Task;
  17. use eonix_sync::WaitList;
  18. /// An `AdapterPort` is an HBA device in AHCI mode.
  19. ///
  20. /// # Access
  21. ///
  22. /// All reads and writes to this struct is volatile
  23. ///
  24. #[allow(dead_code)]
  25. #[repr(C)]
  26. pub struct AdapterPortData {
  27. pub command_list_base: u64,
  28. pub fis_base: u64,
  29. pub interrupt_status: u32,
  30. pub interrupt_enable: u32,
  31. pub command_status: u32,
  32. _reserved2: u32,
  33. pub task_file_data: u32,
  34. pub signature: u32,
  35. pub sata_status: u32,
  36. pub sata_control: u32,
  37. pub sata_error: u32,
  38. pub sata_active: u32,
  39. pub command_issue: u32,
  40. pub sata_notification: u32,
  41. pub fis_based_switch_control: u32,
  42. _reserved1: [u32; 11],
  43. vendor: [u32; 4],
  44. }
  45. struct FreeList {
  46. free: VecDeque<u32>,
  47. working: VecDeque<u32>,
  48. }
  49. impl FreeList {
  50. fn new() -> Self {
  51. Self {
  52. free: (0..32).collect(),
  53. working: VecDeque::new(),
  54. }
  55. }
  56. }
  57. pub struct AdapterPort<'a> {
  58. pub nport: u32,
  59. regs_base: PAddr,
  60. slots: [CommandSlot<'a>; 32],
  61. free_list: Spin<FreeList>,
  62. free_list_wait: WaitList,
  63. /// Holds the command list.
  64. /// **DO NOT USE IT DIRECTLY**
  65. _page: Page,
  66. cmdlist_base: PAddr,
  67. fis_base: PAddr,
  68. stats: AdapterPortStats,
  69. }
  70. impl<'a> AdapterPort<'a> {
  71. pub fn new(base: PAddr, nport: u32) -> Self {
  72. let page = Page::alloc();
  73. let cmdlist_base = page.start();
  74. let cmdlist_size = 32 * size_of::<CommandHeader>();
  75. let fis_base = cmdlist_base + cmdlist_size;
  76. let (mut cmdheaders, _) = page.as_memblk().split_at(cmdlist_size);
  77. let slots = core::array::from_fn(move |_| {
  78. let (cmdheader, next) = cmdheaders.split_at(size_of::<CommandHeader>());
  79. cmdheaders = next;
  80. CommandSlot::new(unsafe { cmdheader.as_ptr().as_mut() })
  81. });
  82. Self {
  83. nport,
  84. regs_base: base + 0x100 + 0x80 * nport as usize,
  85. slots,
  86. free_list: Spin::new(FreeList::new()),
  87. free_list_wait: WaitList::new(),
  88. _page: page,
  89. stats: AdapterPortStats::new(),
  90. cmdlist_base,
  91. fis_base,
  92. }
  93. }
  94. }
  95. impl AdapterPort<'_> {
  96. fn command_list_base(&self) -> Register<u64> {
  97. Register::new(self.regs_base + 0x00)
  98. }
  99. fn fis_base(&self) -> Register<u64> {
  100. Register::new(self.regs_base + 0x08)
  101. }
  102. fn sata_status(&self) -> Register<u32> {
  103. Register::new(self.regs_base + 0x28)
  104. }
  105. fn command_status(&self) -> Register<u32> {
  106. Register::new(self.regs_base + 0x18)
  107. }
  108. fn command_issue(&self) -> Register<u32> {
  109. Register::new(self.regs_base + 0x38)
  110. }
  111. pub fn interrupt_status(&self) -> Register<u32> {
  112. Register::new(self.regs_base + 0x10)
  113. }
  114. fn interrupt_enable(&self) -> Register<u32> {
  115. Register::new(self.regs_base + 0x14)
  116. }
  117. pub fn status_ok(&self) -> bool {
  118. self.sata_status().read_once() & 0xf == 0x3
  119. }
  120. fn get_free_slot(&self) -> u32 {
  121. loop {
  122. let mut free_list = self.free_list.lock_irq();
  123. let free_slot = free_list.free.pop_front();
  124. if let Some(slot) = free_slot {
  125. return slot;
  126. }
  127. let mut wait = pin!(self.free_list_wait.prepare_to_wait());
  128. wait.as_mut().add_to_wait_list();
  129. drop(free_list);
  130. Task::block_on(wait);
  131. }
  132. }
  133. fn save_working(&self, slot: u32) {
  134. self.free_list.lock_irq().working.push_back(slot);
  135. }
  136. fn release_free_slot(&self, slot: u32) {
  137. self.free_list.lock_irq().free.push_back(slot);
  138. self.free_list_wait.notify_one();
  139. }
  140. pub fn handle_interrupt(&self) {
  141. let ci = self.command_issue().read_once();
  142. // no need to use `lock_irq()` inside interrupt handler
  143. let mut free_list = self.free_list.lock();
  144. free_list.working.retain(|&n| {
  145. if ci & (1 << n) != 0 {
  146. return true;
  147. }
  148. self.slots[n as usize].handle_irq();
  149. self.stats.inc_int_fired();
  150. false
  151. });
  152. }
  153. fn stop_command(&self) -> KResult<()> {
  154. let status_reg = self.command_status();
  155. let status = status_reg.read();
  156. status_reg.write_once(status & !(PORT_CMD_ST | PORT_CMD_FRE));
  157. status_reg.spinwait_clear(PORT_CMD_CR | PORT_CMD_FR)
  158. }
  159. fn start_command(&self) -> KResult<()> {
  160. let status_reg = self.command_status();
  161. status_reg.spinwait_clear(PORT_CMD_CR)?;
  162. let status = status_reg.read();
  163. status_reg.write_once(status | PORT_CMD_ST | PORT_CMD_FRE);
  164. Ok(())
  165. }
  166. fn send_command(&self, cmd: &impl Command) -> KResult<()> {
  167. let mut cmdtable = CommandTable::new();
  168. cmdtable.setup(cmd);
  169. let slot_index = self.get_free_slot();
  170. let slot = &self.slots[slot_index as usize];
  171. slot.prepare_command(&cmdtable, cmd.write());
  172. self.save_working(slot_index);
  173. let cmdissue_reg = self.command_issue();
  174. // should we clear received fis here?
  175. debug_assert!(cmdissue_reg.read_once() & (1 << slot_index) == 0);
  176. cmdissue_reg.write_once(1 << slot_index);
  177. self.stats.inc_cmd_sent();
  178. if let Err(_) = Task::block_on(slot.wait_finish()) {
  179. self.stats.inc_cmd_error();
  180. return Err(EIO);
  181. };
  182. self.release_free_slot(slot_index);
  183. Ok(())
  184. }
  185. fn identify(&self) -> KResult<()> {
  186. let cmd = IdentifyCommand::new();
  187. // TODO: check returned data
  188. self.send_command(&cmd)?;
  189. Ok(())
  190. }
  191. pub fn init(&self) -> KResult<()> {
  192. self.stop_command()?;
  193. self.command_list_base()
  194. .write(self.cmdlist_base.addr() as u64);
  195. self.fis_base().write(self.fis_base.addr() as u64);
  196. self.interrupt_enable().write_once(PORT_IE_DEFAULT);
  197. self.start_command()?;
  198. match self.identify() {
  199. Err(err) => {
  200. self.stop_command()?;
  201. Err(err)
  202. }
  203. Ok(_) => Ok(()),
  204. }
  205. }
  206. pub fn print_stats(&self, writer: &mut impl Write) -> KResult<()> {
  207. writeln!(writer, "cmd_sent: {}", self.stats.get_cmd_sent()).map_err(|_| EIO)?;
  208. writeln!(writer, "cmd_error: {}", self.stats.get_cmd_error()).map_err(|_| EIO)?;
  209. writeln!(writer, "int_fired: {}", self.stats.get_int_fired()).map_err(|_| EIO)?;
  210. Ok(())
  211. }
  212. }
  213. impl BlockRequestQueue for AdapterPort<'_> {
  214. fn max_request_pages(&self) -> u64 {
  215. 1024
  216. }
  217. fn submit(&self, req: BlockDeviceRequest) -> KResult<()> {
  218. // TODO: check disk size limit using newtype
  219. if req.count > 65535 {
  220. return Err(EINVAL);
  221. }
  222. let command = ReadLBACommand::new(req.buffer, req.sector, req.count as u16)?;
  223. self.send_command(&command)
  224. }
  225. }