From 7d7bba78b7de6d7feffa7f3febd7a8d7fd8bee62 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Sun, 4 Feb 2024 13:15:18 +0200 Subject: [PATCH] block/ahci: proper AHCI port init --- Cargo.toml | 3 ++- driver/block/ahci/src/lib.rs | 39 +++++++++++++++++++++++++++++------ driver/block/ahci/src/port.rs | 2 ++ src/arch/aarch64/mod.rs | 9 ++++++-- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5433a7a9..ee0702c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ ygg_driver_block = { path = "driver/block/core" } ygg_driver_net_core = { path = "driver/net/core" } ygg_driver_net_loopback = { path = "driver/net/loopback" } ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] } +ygg_driver_ahci = { path = "driver/block/ahci" } + kernel-fs = { path = "driver/fs/kernel-fs" } memfs = { path = "driver/fs/memfs" } @@ -58,7 +60,6 @@ acpi-system = { git = "https://github.com/alnyan/acpi-system.git" } # TODO currently only supported here xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } ygg_driver_nvme = { path = "driver/block/nvme" } -ygg_driver_ahci = { path = "driver/block/ahci" } [features] default = ["fb_console"] diff --git a/driver/block/ahci/src/lib.rs b/driver/block/ahci/src/lib.rs index 53e9cc2a..795aa636 100644 --- a/driver/block/ahci/src/lib.rs +++ b/driver/block/ahci/src/lib.rs @@ -5,13 +5,20 @@ extern crate alloc; use alloc::{boxed::Box, format, vec, vec::Vec}; +use bytemuck::Zeroable; +use data::ReceivedFis; use device_api::{ interrupt::{InterruptAffinity, InterruptHandler}, Device, }; use error::AhciError; use kernel_fs::devfs; -use kernel_util::{mem::device::DeviceMemoryIo, runtime, sync::IrqSafeSpinlock, util::OneTimeInit}; +use kernel_util::{ + mem::{address::AsPhysicalAddress, device::DeviceMemoryIo, PageBox}, + runtime, + sync::IrqSafeSpinlock, + util::OneTimeInit, +}; use port::AhciPort; use regs::{PortRegs, Regs}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; @@ -38,6 +45,7 @@ const MAX_DRIVES: usize = (b'z' - b'a') as usize; pub struct AhciController { regs: IrqSafeSpinlock>, ports: OneTimeInit>, + received_fis_buffers: OneTimeInit<[Option>; 16]>, version: Version, max_port_count: usize, @@ -67,6 +75,23 @@ impl AhciController { drop(regs); + let mut fis_buffers = [const { None }; 16]; + // Allocate FIS receive buffers for the ports + for i in 0..self.max_port_count { + if pi & (1 << i) == 0 { + continue; + } + + let regs = self.regs.lock(); + let port = ®s.PORTS[i]; + + let buffer = PageBox::new(ReceivedFis::zeroed()).map_err(AhciError::MemoryError)?; + port.set_received_fis_address_64(unsafe { buffer.as_physical_address() }); + fis_buffers[i] = Some(buffer); + } + + self.received_fis_buffers.init(fis_buffers); + for i in 0..self.max_port_count { if pi & (1 << i) == 0 { continue; @@ -192,6 +217,11 @@ pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> { let bar5 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?; let bar5 = bar5.as_memory().ok_or(Error::InvalidOperation)?; + let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); + cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); + cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; + info.config_space.set_command(cmd.bits()); + info.init_interrupts(PreferredInterruptMode::Msi)?; // // TODO support regular PCI interrupts (ACPI dependency) @@ -202,21 +232,18 @@ pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> { // Map the registers let regs = unsafe { DeviceMemoryIo::::map(bar5, Default::default()) }?; + let version = Version::try_from(regs.VS.get())?; let ahci_only = regs.CAP.matches_all(CAP::SAM::SET); let max_port_count = regs.CAP.read(CAP::NP) as usize; let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET); - let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command()); - cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO); - cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER; - info.config_space.set_command(cmd.bits()); - // TODO extract Number of Command Slots let ahci = Box::leak(Box::new(AhciController { regs: IrqSafeSpinlock::new(regs), ports: OneTimeInit::new(), + received_fis_buffers: OneTimeInit::new(), version, max_port_count, ahci_only, diff --git a/driver/block/ahci/src/port.rs b/driver/block/ahci/src/port.rs index 8b1da03c..0333faa7 100644 --- a/driver/block/ahci/src/port.rs +++ b/driver/block/ahci/src/port.rs @@ -75,6 +75,8 @@ impl PortInner { )?; // Sync before send + // XXX do this properly + #[cfg(target_arch = "x86_64")] unsafe { core::arch::asm!("wbinvd"); } diff --git a/src/arch/aarch64/mod.rs b/src/arch/aarch64/mod.rs index 4df427c6..59ba329a 100644 --- a/src/arch/aarch64/mod.rs +++ b/src/arch/aarch64/mod.rs @@ -358,6 +358,13 @@ impl AArch64 { 0x1000, ygg_driver_virtio_net::probe, ); + ygg_driver_pci::register_class_driver( + "AHCI SATA Controller", + 0x01, + Some(0x06), + Some(0x01), + ygg_driver_ahci::probe, + ); let dt = self.dt.get(); @@ -389,8 +396,6 @@ impl AArch64 { ); infoln!("Initializing aarch64 platform"); - dt.dump(crate::debug::LogLevel::Debug); - let nodes = dt.root().children(); if let Err(error) = devtree::enumerate_dt(address_cells, size_cells, nodes, |_, probe| {