block/ahci: proper AHCI port init
This commit is contained in:
parent
f03b390933
commit
7d7bba78b7
@ -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"]
|
||||
|
@ -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<DeviceMemoryIo<'static, Regs>>,
|
||||
ports: OneTimeInit<Vec<&'static AhciPort>>,
|
||||
received_fis_buffers: OneTimeInit<[Option<PageBox<ReceivedFis>>; 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::<Regs>::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,
|
||||
|
@ -75,6 +75,8 @@ impl PortInner {
|
||||
)?;
|
||||
|
||||
// Sync before send
|
||||
// XXX do this properly
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
unsafe {
|
||||
core::arch::asm!("wbinvd");
|
||||
}
|
||||
|
@ -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| {
|
||||
|
Loading…
x
Reference in New Issue
Block a user