[Denali] Reset HBA and iterate over ports.
This commit is contained in:
parent
7d4c882f2b
commit
df79233bbb
|
@ -13,6 +13,10 @@ impl PortServer {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn from_cap(port_cap: Capability) -> Self {
|
||||||
|
Self { port_cap }
|
||||||
|
}
|
||||||
|
|
||||||
pub fn create_client_cap(&self) -> Result<z_cap_t, ZError> {
|
pub fn create_client_cap(&self) -> Result<z_cap_t, ZError> {
|
||||||
self.port_cap
|
self.port_cap
|
||||||
.duplicate(!kZionPerm_Read)
|
.duplicate(!kZionPerm_Read)
|
||||||
|
|
|
@ -295,6 +295,18 @@ pub fn port_poll(
|
||||||
Ok((num_bytes, num_caps))
|
Ok((num_bytes, num_caps))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn register_irq(irq_num: u64) -> Result<Capability, ZError> {
|
||||||
|
let mut port_cap: z_cap_t = 0;
|
||||||
|
syscall(
|
||||||
|
zion::kZionIrqRegister,
|
||||||
|
&zion::ZIrqRegisterReq {
|
||||||
|
irq_num,
|
||||||
|
port_cap: &mut port_cap,
|
||||||
|
},
|
||||||
|
)?;
|
||||||
|
Ok(Capability::take(port_cap))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn endpoint_create() -> Result<Capability, ZError> {
|
pub fn endpoint_create() -> Result<Capability, ZError> {
|
||||||
let mut endpoint_cap: z_cap_t = 0;
|
let mut endpoint_cap: z_cap_t = 0;
|
||||||
syscall(
|
syscall(
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
use mammoth::mem::MemoryRegion;
|
use alloc::boxed::Box;
|
||||||
|
use core::{ffi::c_void, mem::MaybeUninit};
|
||||||
|
|
||||||
use bitfield_struct::bitfield;
|
use mammoth::{mem::MemoryRegion, thread::Thread, zion::ZError};
|
||||||
|
|
||||||
|
use super::{hba::AhciHba, port::AhciPortHba};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
pub struct PciDeviceHeader {
|
pub struct PciDeviceHeader {
|
||||||
pub vendor_id: u16,
|
pub vendor_id: u16,
|
||||||
|
@ -20,7 +24,7 @@ pub struct PciDeviceHeader {
|
||||||
pub abar: u32,
|
pub abar: u32,
|
||||||
__: u32,
|
__: u32,
|
||||||
pub subsystem_id: u32,
|
pub subsystem_id: u32,
|
||||||
pub expansion_rom: u16,
|
pub expansion_rom: u32,
|
||||||
pub cap_ptr: u8,
|
pub cap_ptr: u8,
|
||||||
___: [u8; 7],
|
___: [u8; 7],
|
||||||
pub interrupt_line: u8,
|
pub interrupt_line: u8,
|
||||||
|
@ -29,166 +33,12 @@ pub struct PciDeviceHeader {
|
||||||
pub max_latency: u8,
|
pub max_latency: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
const fn increment(val: u8) -> u8 {
|
|
||||||
val + 1
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
|
||||||
#[repr(u8)]
|
|
||||||
enum InterfaceSpeedSupport {
|
|
||||||
Reserved = 0b0000,
|
|
||||||
// 1.5 Gbps
|
|
||||||
Gen1 = 0b0001,
|
|
||||||
// 3 Gbps
|
|
||||||
Gen2 = 0b0010,
|
|
||||||
// 6 Gbps
|
|
||||||
Gen3 = 0b0011,
|
|
||||||
Unknown = 0b1111,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InterfaceSpeedSupport {
|
|
||||||
const fn from_bits(value: u8) -> Self {
|
|
||||||
match value {
|
|
||||||
0b0000 => Self::Reserved,
|
|
||||||
0b0001 => Self::Gen1,
|
|
||||||
0b0010 => Self::Gen2,
|
|
||||||
0b0011 => Self::Gen3,
|
|
||||||
_ => Self::Unknown,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bitfield(u32)]
|
|
||||||
pub struct AhciCapabilities {
|
|
||||||
#[bits(5, access = RO, from = increment)]
|
|
||||||
num_ports: u8,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_external_sata: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
enclosure_management_supported: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
command_completed_coalescing_supported: bool,
|
|
||||||
|
|
||||||
#[bits(5, access = RO, from = increment)]
|
|
||||||
num_commands: u8,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
partial_state_capable: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
slumber_state_capable: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
pio_multiple_drq_block: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
fis_based_switching_supported: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_port_multiplier: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_ahci_mode_only: bool,
|
|
||||||
|
|
||||||
__: bool,
|
|
||||||
|
|
||||||
#[bits(4, access = RO)]
|
|
||||||
interface_speed_support: InterfaceSpeedSupport,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_command_list_override: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_activity_led: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_aggressive_link_power_management: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_staggered_spin_up: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_mechanical_presence_switch: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_snotification_register: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_native_command_queueing: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_64_bit_addressing: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bitfield(u32)]
|
|
||||||
pub struct AhciGlobalControl {
|
|
||||||
hba_reset: bool,
|
|
||||||
interrupt_enable: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
msi_revert_to_single_message: bool,
|
|
||||||
|
|
||||||
#[bits(28)]
|
|
||||||
__: u32,
|
|
||||||
|
|
||||||
ahci_enable: bool,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bitfield(u32)]
|
|
||||||
pub struct AhciCapabilitiesExtended {
|
|
||||||
#[bits(access = RO)]
|
|
||||||
bios_os_handoff: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
nvmhci_present: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
automatic_partial_to_slumber_transitions: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_device_sleep: bool,
|
|
||||||
|
|
||||||
#[bits(access = RO)]
|
|
||||||
supports_aggressive_device_sleep_management: bool,
|
|
||||||
|
|
||||||
#[bits(27)]
|
|
||||||
__: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[bitfield(u32)]
|
|
||||||
pub struct AhciBiosHandoffControl {
|
|
||||||
bios_owned_semaphore: bool,
|
|
||||||
os_owned_semaphore: bool,
|
|
||||||
smi_on_os_ownership_change_enable: bool,
|
|
||||||
os_ownership_change: bool,
|
|
||||||
bios_busy: bool,
|
|
||||||
|
|
||||||
#[bits(27)]
|
|
||||||
__: u32,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
#[repr(C, packed)]
|
|
||||||
pub struct AhciHba {
|
|
||||||
pub capabilities: AhciCapabilities,
|
|
||||||
global_host_control: AhciGlobalControl,
|
|
||||||
interrupt_status: u32,
|
|
||||||
port_implemented: u32,
|
|
||||||
version: u32,
|
|
||||||
ccc_ctl: u32, // 0x14, Command completion coalescing control
|
|
||||||
ccc_pts: u32, // 0x18, Command completion coalescing ports
|
|
||||||
em_loc: u32, // 0x1C, Enclosure management location
|
|
||||||
em_ctl: u32, // 0x20, Enclosure management control
|
|
||||||
capabilities_ext: AhciCapabilitiesExtended,
|
|
||||||
bohc: AhciBiosHandoffControl,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct AhciController {
|
pub struct AhciController {
|
||||||
pci_memory: MemoryRegion,
|
pci_memory: MemoryRegion,
|
||||||
hba_memory: MemoryRegion,
|
hba_memory: MemoryRegion,
|
||||||
|
irq_port: Option<mammoth::port::PortServer>,
|
||||||
|
irq_thread: Option<Box<Thread>>,
|
||||||
|
ports: [Option<PortController<'static>>; 32],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AhciController {
|
impl AhciController {
|
||||||
|
@ -203,9 +53,97 @@ impl AhciController {
|
||||||
};
|
};
|
||||||
let hba_memory =
|
let hba_memory =
|
||||||
MemoryRegion::direct_physical(pci_device_header.abar as u64, 0x1100).unwrap();
|
MemoryRegion::direct_physical(pci_device_header.abar as u64, 0x1100).unwrap();
|
||||||
Self {
|
let mut controller = Self {
|
||||||
pci_memory,
|
pci_memory,
|
||||||
hba_memory,
|
hba_memory,
|
||||||
|
irq_port: None,
|
||||||
|
irq_thread: None,
|
||||||
|
ports: [const { None }; 32],
|
||||||
|
};
|
||||||
|
mammoth::debug!("{:?}", controller.pci_header());
|
||||||
|
controller.init();
|
||||||
|
controller
|
||||||
|
}
|
||||||
|
|
||||||
|
fn init(&mut self) {
|
||||||
|
self.ahci_hba().global_host_control.with_hba_reset(true);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
if !self.ahci_hba().global_host_control.hba_reset() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.ahci_hba().global_host_control.with_ahci_enable(true);
|
||||||
|
|
||||||
|
mammoth::syscall::thread_sleep(50).unwrap();
|
||||||
|
|
||||||
|
self.register_irq();
|
||||||
|
|
||||||
|
self.init_ports();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_server(&self) -> Result<Box<Thread>, ZError> {
|
||||||
|
let thread_entry = |server_ptr: *const c_void| {
|
||||||
|
let server = unsafe {
|
||||||
|
(server_ptr as *mut Self)
|
||||||
|
.as_mut()
|
||||||
|
.expect("Failed to convert to server")
|
||||||
|
};
|
||||||
|
server.irq_loop();
|
||||||
|
};
|
||||||
|
Thread::spawn(
|
||||||
|
thread_entry,
|
||||||
|
self as *const Self as *const core::ffi::c_void,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn register_irq(&mut self) {
|
||||||
|
let irq_num = match self.pci_header().interrupt_pin {
|
||||||
|
1 => mammoth::zion::kZIrqPci1,
|
||||||
|
2 => mammoth::zion::kZIrqPci2,
|
||||||
|
3 => mammoth::zion::kZIrqPci3,
|
||||||
|
4 => mammoth::zion::kZIrqPci4,
|
||||||
|
_ => panic!(
|
||||||
|
"Unrecognized pci interrupt pin {}",
|
||||||
|
self.pci_header().interrupt_pin
|
||||||
|
),
|
||||||
|
};
|
||||||
|
self.irq_port = Some(mammoth::port::PortServer::from_cap(
|
||||||
|
mammoth::syscall::register_irq(irq_num).unwrap(),
|
||||||
|
));
|
||||||
|
|
||||||
|
self.irq_thread = Some(self.run_server().unwrap());
|
||||||
|
|
||||||
|
self.ahci_hba()
|
||||||
|
.global_host_control
|
||||||
|
.with_interrupt_enable(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn irq_loop(&self) {}
|
||||||
|
|
||||||
|
fn init_ports(&mut self) {
|
||||||
|
for i in 0..(self.ahci_hba().capabilities.num_ports() as usize) {
|
||||||
|
let port_index = 1 << i;
|
||||||
|
if (self.ahci_hba().port_implemented & port_index) != port_index {
|
||||||
|
mammoth::debug!("Skipping port {}, not implemented", i);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let port_offset: usize = 0x100 + (0x80 * i);
|
||||||
|
let port_size = size_of::<AhciPortHba>();
|
||||||
|
let port_limit = port_offset + port_size;
|
||||||
|
let port = unsafe {
|
||||||
|
self.hba_memory.mut_slice::<u8>()[port_offset..port_limit]
|
||||||
|
.as_mut_ptr()
|
||||||
|
.cast::<AhciPortHba>()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.ports[i] = Some(PortController::new(port));
|
||||||
|
self.ports[i].as_ref().unwrap().identify();
|
||||||
|
mammoth::debug!("Identifying port {}", i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,3 +169,15 @@ impl AhciController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct PortController<'a> {
|
||||||
|
ahci_port_hba: &'a AhciPortHba,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> PortController<'a> {
|
||||||
|
fn new(ahci_port_hba: &'a AhciPortHba) -> Self {
|
||||||
|
Self { ahci_port_hba }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn identify(&self) {}
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
use bitfield_struct::bitfield;
|
||||||
|
|
||||||
|
const fn increment(val: u8) -> u8 {
|
||||||
|
val + 1
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[repr(u8)]
|
||||||
|
enum InterfaceSpeedSupport {
|
||||||
|
Reserved = 0b0000,
|
||||||
|
// 1.5 Gbps
|
||||||
|
Gen1 = 0b0001,
|
||||||
|
// 3 Gbps
|
||||||
|
Gen2 = 0b0010,
|
||||||
|
// 6 Gbps
|
||||||
|
Gen3 = 0b0011,
|
||||||
|
Unknown = 0b1111,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InterfaceSpeedSupport {
|
||||||
|
const fn from_bits(value: u8) -> Self {
|
||||||
|
match value {
|
||||||
|
0b0000 => Self::Reserved,
|
||||||
|
0b0001 => Self::Gen1,
|
||||||
|
0b0010 => Self::Gen2,
|
||||||
|
0b0011 => Self::Gen3,
|
||||||
|
_ => Self::Unknown,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u32)]
|
||||||
|
pub struct AhciCapabilities {
|
||||||
|
#[bits(5, access = RO, from = increment)]
|
||||||
|
pub num_ports: u8,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_external_sata: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
enclosure_management_supported: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
command_completed_coalescing_supported: bool,
|
||||||
|
|
||||||
|
#[bits(5, access = RO, from = increment)]
|
||||||
|
num_commands: u8,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
partial_state_capable: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
slumber_state_capable: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
pio_multiple_drq_block: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
fis_based_switching_supported: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_port_multiplier: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_ahci_mode_only: bool,
|
||||||
|
|
||||||
|
__: bool,
|
||||||
|
|
||||||
|
#[bits(4, access = RO)]
|
||||||
|
interface_speed_support: InterfaceSpeedSupport,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_command_list_override: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_activity_led: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_aggressive_link_power_management: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_staggered_spin_up: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_mechanical_presence_switch: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_snotification_register: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_native_command_queueing: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_64_bit_addressing: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u32)]
|
||||||
|
pub struct AhciGlobalControl {
|
||||||
|
pub hba_reset: bool,
|
||||||
|
pub interrupt_enable: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
pub msi_revert_to_single_message: bool,
|
||||||
|
|
||||||
|
#[bits(28)]
|
||||||
|
__: u32,
|
||||||
|
|
||||||
|
pub ahci_enable: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u32)]
|
||||||
|
pub struct AhciCapabilitiesExtended {
|
||||||
|
#[bits(access = RO)]
|
||||||
|
bios_os_handoff: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
nvmhci_present: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
automatic_partial_to_slumber_transitions: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_device_sleep: bool,
|
||||||
|
|
||||||
|
#[bits(access = RO)]
|
||||||
|
supports_aggressive_device_sleep_management: bool,
|
||||||
|
|
||||||
|
#[bits(27)]
|
||||||
|
__: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[bitfield(u32)]
|
||||||
|
pub struct AhciBiosHandoffControl {
|
||||||
|
bios_owned_semaphore: bool,
|
||||||
|
os_owned_semaphore: bool,
|
||||||
|
smi_on_os_ownership_change_enable: bool,
|
||||||
|
os_ownership_change: bool,
|
||||||
|
bios_busy: bool,
|
||||||
|
|
||||||
|
#[bits(27)]
|
||||||
|
__: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AhciHba {
|
||||||
|
pub capabilities: AhciCapabilities,
|
||||||
|
pub global_host_control: AhciGlobalControl,
|
||||||
|
pub interrupt_status: u32,
|
||||||
|
pub port_implemented: u32,
|
||||||
|
pub version: u32,
|
||||||
|
pub ccc_ctl: u32, // 0x14, Command completion coalescing control
|
||||||
|
pub ccc_pts: u32, // 0x18, Command completion coalescing ports
|
||||||
|
pub em_loc: u32, // 0x1C, Enclosure management location
|
||||||
|
pub em_ctl: u32, // 0x20, Enclosure management control
|
||||||
|
pub capabilities_ext: AhciCapabilitiesExtended,
|
||||||
|
pub bohc: AhciBiosHandoffControl,
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
mod controller;
|
mod controller;
|
||||||
|
mod hba;
|
||||||
mod port;
|
mod port;
|
||||||
|
|
||||||
pub use controller::AhciController;
|
pub use controller::AhciController;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use bitfield_struct::bitfield;
|
||||||
|
|
||||||
#[bitfield(u32)]
|
#[bitfield(u32)]
|
||||||
struct AhciPortInterruptStatus {
|
struct AhciPortInterruptStatus {
|
||||||
device_to_host_register_fis_interrupt: bool,
|
device_to_host_register_fis_interrupt: bool,
|
||||||
|
@ -377,7 +379,7 @@ struct AhciDeviceSleep {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C, packed)]
|
#[repr(C, packed)]
|
||||||
struct AhciPortHba {
|
pub struct AhciPortHba {
|
||||||
command_list_base: u64,
|
command_list_base: u64,
|
||||||
fis_base: u64,
|
fis_base: u64,
|
||||||
interrupt_status: AhciPortInterruptStatus,
|
interrupt_status: AhciPortInterruptStatus,
|
||||||
|
|
Loading…
Reference in New Issue