From 5b223c06d0bcd4c936bad3ad6ec8324fd0ba16a6 Mon Sep 17 00:00:00 2001 From: Jeremy Soller Date: Mon, 13 Feb 2017 22:15:19 -0700 Subject: [PATCH] Improve XHCI driver --- pcid/src/main.rs | 2 +- xhcid/src/main.rs | 67 +++----------- xhcid/src/xhci.rs | 220 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 232 insertions(+), 57 deletions(-) create mode 100644 xhcid/src/xhci.rs diff --git a/pcid/src/main.rs b/pcid/src/main.rs index 935a8f1c02..0ef7c58666 100644 --- a/pcid/src/main.rs +++ b/pcid/src/main.rs @@ -142,7 +142,7 @@ fn main() { command.arg(&arg); } - println!("PCID SPAWN {:?}", command); + //println!("PCID SPAWN {:?}", command); match command.spawn() { Ok(mut child) => match child.wait() { diff --git a/xhcid/src/main.rs b/xhcid/src/main.rs index fb94771704..fe4a064962 100644 --- a/xhcid/src/main.rs +++ b/xhcid/src/main.rs @@ -1,59 +1,12 @@ +#[macro_use] +extern crate bitflags; extern crate syscall; -use std::{env, slice}; -use syscall::io::{Mmio, Io}; +use std::env; -#[repr(packed)] -pub struct XhciCap { - len: Mmio, - _rsvd: Mmio, - hci_ver: Mmio, - hcs_params1: Mmio, - hcs_params2: Mmio, - hcs_params3: Mmio, - hcc_params1: Mmio, - db_offset: Mmio, - rts_offset: Mmio, - hcc_params2: Mmio -} +use xhci::Xhci; -#[repr(packed)] -pub struct XhciOp { - usb_cmd: Mmio, - usb_std: Mmio, - page_size: Mmio, - _rsvd: [Mmio; 2], - dn_ctrl: Mmio, - crcr: [Mmio; 2], - _rsvd2: [Mmio; 4], - dcbaap: [Mmio; 2], - config: Mmio, -} - -pub struct Xhci { - cap: &'static mut XhciCap, - op: &'static mut XhciOp, - ports: &'static mut [Mmio] -} - -impl Xhci { - pub fn new(address: usize) -> Xhci { - let cap = unsafe { &mut *(address as *mut XhciCap) }; - - let op_base = address + cap.len.read() as usize; - let op = unsafe { &mut *(op_base as *mut XhciOp) }; - - let port_base = op_base + 0x400; - let port_len = ((cap.hcs_params1.read() & 0xFF000000) >> 24) as usize; - let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut Mmio, port_len) }; - - Xhci { - cap: cap, - op: op, - ports: ports - } - } -} +mod xhci; fn main() { let mut args = env::args().skip(1); @@ -69,10 +22,12 @@ fn main() { // Daemonize if unsafe { syscall::clone(0).unwrap() } == 0 { let address = unsafe { syscall::physmap(bar, 4096, syscall::MAP_WRITE).expect("xhcid: failed to map address") }; - { - let mut xhci = Xhci::new(address); - for (i, port) in xhci.ports.iter().enumerate() { - println!("XHCI Port {}: {:X}", i, port.read()); + match Xhci::new(address) { + Ok(mut xhci) => { + xhci.init(); + }, + Err(err) => { + println!("xhcid: error: {}", err); } } unsafe { let _ = syscall::physunmap(address); } diff --git a/xhcid/src/xhci.rs b/xhcid/src/xhci.rs new file mode 100644 index 0000000000..afd78e5eaf --- /dev/null +++ b/xhcid/src/xhci.rs @@ -0,0 +1,220 @@ +use std::slice; +use syscall::error::Result; +use syscall::io::{Dma, Mmio, Io}; + +#[repr(packed)] +struct Trb { + pub data: u64, + pub status: u32, + pub control: u32, +} + +impl Trb { + pub fn from_type(trb_type: u32) -> Self { + Trb { + data: 0, + status: 0, + control: (trb_type & 0x3F) << 10, + } + } +} + +#[repr(packed)] +pub struct XhciCap { + len: Mmio, + _rsvd: Mmio, + hci_ver: Mmio, + hcs_params1: Mmio, + hcs_params2: Mmio, + hcs_params3: Mmio, + hcc_params1: Mmio, + db_offset: Mmio, + rts_offset: Mmio, + hcc_params2: Mmio +} + +#[repr(packed)] +pub struct XhciOp { + usb_cmd: Mmio, + usb_sts: Mmio, + page_size: Mmio, + _rsvd: [Mmio; 2], + dn_ctrl: Mmio, + crcr: Mmio, + _rsvd2: [Mmio; 4], + dcbaap: Mmio, + config: Mmio, +} + +bitflags! { + flags XhciPortFlags: u32 { + const PORT_CCS = 1 << 0, + const PORT_PED = 1 << 1, + const PORT_OCA = 1 << 3, + const PORT_PR = 1 << 4, + const PORT_PP = 1 << 9, + const PORT_PIC_AMB = 1 << 14, + const PORT_PIC_GRN = 1 << 15, + const PORT_LWS = 1 << 16, + const PORT_CSC = 1 << 17, + const PORT_PEC = 1 << 18, + const PORT_WRC = 1 << 19, + const PORT_OCC = 1 << 20, + const PORT_PRC = 1 << 21, + const PORT_PLC = 1 << 22, + const PORT_CEC = 1 << 23, + const PORT_CAS = 1 << 24, + const PORT_WCE = 1 << 25, + const PORT_WDE = 1 << 26, + const PORT_WOE = 1 << 27, + const PORT_DR = 1 << 30, + const PORT_WPR = 1 << 31, + } +} + +pub struct XhciPort(Mmio); + +impl XhciPort { + fn read(&self) -> u32 { + self.0.read() + } + + fn state(&self) -> u32 { + (self.read() & (0b111 << 5)) >> 5 + } + + fn speed(&self) -> u32 { + (self.read() & (0b1111 << 10)) >> 10 + } + + fn flags(&self) -> XhciPortFlags { + XhciPortFlags::from_bits_truncate(self.read()) + } +} + +pub struct XhciDoorbell(Mmio); + +impl XhciDoorbell { + fn read(&self) -> u32 { + self.0.read() + } + + fn write(&mut self, data: u32) { + self.0.write(data); + } +} + +#[repr(packed)] +pub struct XhciSlotContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct XhciEndpointContext { + inner: [u8; 32] +} + +#[repr(packed)] +pub struct XhciDeviceContext { + slot: XhciSlotContext, + endpoints: [XhciEndpointContext; 15] +} + +pub struct Xhci { + cap: &'static mut XhciCap, + op: &'static mut XhciOp, + ports: &'static mut [XhciPort], + dbs: &'static mut [XhciDoorbell], + dev_baa: Dma<[u64; 256]>, + dev_ctxs: Vec>, + cmds: Dma<[Trb; 256]>, +} + +impl Xhci { + pub fn new(address: usize) -> Result { + let cap = unsafe { &mut *(address as *mut XhciCap) }; + + let op_base = address + cap.len.read() as usize; + let op = unsafe { &mut *(op_base as *mut XhciOp) }; + + let max_slots; + let max_ports; + + { + // Wait until controller is ready + while op.usb_sts.readf(1 << 11) { + println!(" - Waiting for XHCI ready"); + } + + // Set run/stop to 0 + op.usb_cmd.writef(1, false); + + // Wait until controller not running + while ! op.usb_sts.readf(1) { + println!(" - Waiting for XHCI stopped"); + } + + // Read maximum slots and ports + let hcs_params1 = cap.hcs_params1.read(); + max_slots = hcs_params1 & 0xFF; + max_ports = (hcs_params1 & 0xFF000000) >> 24; + + println!(" - Max Slots: {}, Max Ports {}", max_slots, max_ports); + + // Set enabled slots + op.config.write(max_slots); + println!(" - Enabled Slots: {}", op.config.read() & 0xFF); + } + + let port_base = op_base + 0x400; + let ports = unsafe { slice::from_raw_parts_mut(port_base as *mut XhciPort, max_ports as usize) }; + + let db_base = op_base + cap.db_offset.read() as usize; + let dbs = unsafe { slice::from_raw_parts_mut(db_base as *mut XhciDoorbell, 256) }; + + let mut xhci = Xhci { + cap: cap, + op: op, + ports: ports, + dbs: dbs, + dev_baa: Dma::zeroed()?, + dev_ctxs: Vec::new(), + cmds: Dma::zeroed()?, + }; + + { + // Create device context buffers for each slot + for i in 0..max_slots as usize { + let dev_ctx: Dma = Dma::zeroed()?; + xhci.dev_baa[i] = dev_ctx.physical() as u64; + xhci.dev_ctxs.push(dev_ctx); + } + + // Set device context address array pointer + xhci.op.dcbaap.write(xhci.dev_baa.physical() as u64); + + // Set command ring control register + xhci.op.crcr.write(xhci.cmds.physical() as u64); + + // Set run/stop to 1 + xhci.op.usb_cmd.writef(1, true); + + // Wait until controller is running + while xhci.op.usb_sts.readf(1) { + println!(" - Waiting for XHCI running"); + } + } + + Ok(xhci) + } + + pub fn init(&mut self) { + for (i, port) in self.ports.iter().enumerate() { + let data = port.read(); + let state = port.state(); + let speed = port.speed(); + let flags = port.flags(); + println!(" + XHCI Port {}: {:X}, State {}, Speed {}, Flags {:?}", i, data, state, speed, flags); + } + } +}