block/ahci: proper AHCI port init

This commit is contained in:
Mark Poliakov 2024-02-04 13:15:18 +02:00
parent f03b390933
commit 7d7bba78b7
4 changed files with 44 additions and 9 deletions

View File

@ -24,6 +24,8 @@ ygg_driver_block = { path = "driver/block/core" }
ygg_driver_net_core = { path = "driver/net/core" } ygg_driver_net_core = { path = "driver/net/core" }
ygg_driver_net_loopback = { path = "driver/net/loopback" } ygg_driver_net_loopback = { path = "driver/net/loopback" }
ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] } ygg_driver_virtio_net = { path = "driver/virtio/net", features = ["pci"] }
ygg_driver_ahci = { path = "driver/block/ahci" }
kernel-fs = { path = "driver/fs/kernel-fs" } kernel-fs = { path = "driver/fs/kernel-fs" }
memfs = { path = "driver/fs/memfs" } memfs = { path = "driver/fs/memfs" }
@ -58,7 +60,6 @@ acpi-system = { git = "https://github.com/alnyan/acpi-system.git" }
# TODO currently only supported here # TODO currently only supported here
xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" } xhci_lib = { git = "https://github.com/rust-osdev/xhci.git", package = "xhci" }
ygg_driver_nvme = { path = "driver/block/nvme" } ygg_driver_nvme = { path = "driver/block/nvme" }
ygg_driver_ahci = { path = "driver/block/ahci" }
[features] [features]
default = ["fb_console"] default = ["fb_console"]

View File

@ -5,13 +5,20 @@
extern crate alloc; extern crate alloc;
use alloc::{boxed::Box, format, vec, vec::Vec}; use alloc::{boxed::Box, format, vec, vec::Vec};
use bytemuck::Zeroable;
use data::ReceivedFis;
use device_api::{ use device_api::{
interrupt::{InterruptAffinity, InterruptHandler}, interrupt::{InterruptAffinity, InterruptHandler},
Device, Device,
}; };
use error::AhciError; use error::AhciError;
use kernel_fs::devfs; 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 port::AhciPort;
use regs::{PortRegs, Regs}; use regs::{PortRegs, Regs};
use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable};
@ -38,6 +45,7 @@ const MAX_DRIVES: usize = (b'z' - b'a') as usize;
pub struct AhciController { pub struct AhciController {
regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>, regs: IrqSafeSpinlock<DeviceMemoryIo<'static, Regs>>,
ports: OneTimeInit<Vec<&'static AhciPort>>, ports: OneTimeInit<Vec<&'static AhciPort>>,
received_fis_buffers: OneTimeInit<[Option<PageBox<ReceivedFis>>; 16]>,
version: Version, version: Version,
max_port_count: usize, max_port_count: usize,
@ -67,6 +75,23 @@ impl AhciController {
drop(regs); 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 = &regs.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 { for i in 0..self.max_port_count {
if pi & (1 << i) == 0 { if pi & (1 << i) == 0 {
continue; 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 = info.config_space.bar(5).ok_or(Error::InvalidOperation)?;
let bar5 = bar5.as_memory().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)?; info.init_interrupts(PreferredInterruptMode::Msi)?;
// // TODO support regular PCI interrupts (ACPI dependency) // // TODO support regular PCI interrupts (ACPI dependency)
@ -202,21 +232,18 @@ pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> {
// Map the registers // Map the registers
let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?; let regs = unsafe { DeviceMemoryIo::<Regs>::map(bar5, Default::default()) }?;
let version = Version::try_from(regs.VS.get())?; let version = Version::try_from(regs.VS.get())?;
let ahci_only = regs.CAP.matches_all(CAP::SAM::SET); let ahci_only = regs.CAP.matches_all(CAP::SAM::SET);
let max_port_count = regs.CAP.read(CAP::NP) as usize; let max_port_count = regs.CAP.read(CAP::NP) as usize;
let has_64_bit = regs.CAP.matches_all(CAP::S64A::SET); 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 // TODO extract Number of Command Slots
let ahci = Box::leak(Box::new(AhciController { let ahci = Box::leak(Box::new(AhciController {
regs: IrqSafeSpinlock::new(regs), regs: IrqSafeSpinlock::new(regs),
ports: OneTimeInit::new(), ports: OneTimeInit::new(),
received_fis_buffers: OneTimeInit::new(),
version, version,
max_port_count, max_port_count,
ahci_only, ahci_only,

View File

@ -75,6 +75,8 @@ impl PortInner {
)?; )?;
// Sync before send // Sync before send
// XXX do this properly
#[cfg(target_arch = "x86_64")]
unsafe { unsafe {
core::arch::asm!("wbinvd"); core::arch::asm!("wbinvd");
} }

View File

@ -358,6 +358,13 @@ impl AArch64 {
0x1000, 0x1000,
ygg_driver_virtio_net::probe, 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(); let dt = self.dt.get();
@ -389,8 +396,6 @@ impl AArch64 {
); );
infoln!("Initializing aarch64 platform"); infoln!("Initializing aarch64 platform");
dt.dump(crate::debug::LogLevel::Debug);
let nodes = dt.root().children(); let nodes = dt.root().children();
if let Err(error) = if let Err(error) =
devtree::enumerate_dt(address_cells, size_cells, nodes, |_, probe| { devtree::enumerate_dt(address_cells, size_cells, nodes, |_, probe| {