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_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"]
|
||||||
|
@ -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 = ®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 {
|
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,
|
||||||
|
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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| {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user