Merge branch 'xhci-csz' into 'master'

xhci: support 64-bit contexts (CSZ)

See merge request redox-os/drivers!283
This commit is contained in:
Jeremy Soller
2025-09-12 09:42:58 -06:00
9 changed files with 185 additions and 125 deletions
+20 -3
View File
@@ -22,6 +22,9 @@
//! - USB2 - [Universal Serial Bus Specification](https://www.usb.org/document-library/usb-20-specification)
//! - USB32 - [Universal Serial Bus 3.2 Specification Revision 1.1](https://usb.org/document-library/usb-32-revision-11-june-2022)
//!
#![allow(warnings)]
#![feature(generic_const_exprs)]
#[macro_use]
extern crate bitflags;
@@ -117,8 +120,11 @@ fn main() {
redox_daemon::Daemon::new(daemon).expect("xhcid: failed to daemonize");
}
fn daemon(daemon: redox_daemon::Daemon) -> ! {
let mut pcid_handle = PciFunctionHandle::connect_default();
//TODO: cleanup CSZ support
fn daemon_with_context_size<const N: usize>(
daemon: redox_daemon::Daemon,
mut pcid_handle: PciFunctionHandle,
) -> ! {
let pci_config = pcid_handle.config();
let mut name = pci_config.func.name();
@@ -147,7 +153,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
daemon.ready().expect("xhcid: failed to notify parent");
let hci = Arc::new(
Xhci::new(scheme_name, address, interrupt_method, pcid_handle)
Xhci::<N>::new(scheme_name, address, interrupt_method, pcid_handle)
.expect("xhcid: failed to allocate device"),
);
@@ -179,3 +185,14 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
}
}
}
fn daemon(daemon: redox_daemon::Daemon) -> ! {
let mut pcid_handle = PciFunctionHandle::connect_default();
let address = unsafe { pcid_handle.map_bar(0) }.ptr.as_ptr() as usize;
let cap = unsafe { &mut *(address as *mut xhci::CapabilityRegs) };
if cap.csz() {
daemon_with_context_size::<{ xhci::CONTEXT_64 }>(daemon, pcid_handle)
} else {
daemon_with_context_size::<{ xhci::CONTEXT_32 }>(daemon, pcid_handle)
}
}
+9
View File
@@ -120,6 +120,10 @@ pub struct CapabilityRegs {
pub const HCC_PARAMS1_AC64_BIT: u32 = 1 << HCC_PARAMS1_AC64_SHIFT;
/// The shift to use to get the AC64 bit from HCCParams1. See [CapabilityRegs]
pub const HCC_PARAMS1_AC64_SHIFT: u8 = 0;
/// The mask to use to get the CSZ bit from HCCPARAMS1. See [CapabilityRegs]
pub const HCC_PARAMS1_CSZ_BIT: u32 = 1 << HCC_PARAMS1_CSZ_SHIFT;
/// The shift to use to get the CSZ bit from HCCParams1. See [CapabilityRegs]
pub const HCC_PARAMS1_CSZ_SHIFT: u8 = 2;
/// The Mask to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs]
pub const HCC_PARAMS1_MAXPSASIZE_MASK: u32 = 0xF000; // 15:12
/// The shift to use to get the MAXPSASIZE value from HCCParams1. See [CapabilityRegs]
@@ -161,6 +165,11 @@ impl CapabilityRegs {
self.hcc_params1.readf(HCC_PARAMS1_AC64_BIT)
}
/// Gets the context size (CSZ) bit from HCCParams1.
pub fn csz(&self) -> bool {
self.hcc_params1.readf(HCC_PARAMS1_CSZ_BIT)
}
/// Gets the LEC bit from HCCParams2.
pub fn lec(&self) -> bool {
self.hcc_params2.readf(HCC_PARAMS2_LEC_BIT)
+49 -26
View File
@@ -10,24 +10,25 @@ use common::dma::Dma;
use super::ring::Ring;
use super::Xhci;
pub const CONTEXT_32: usize = 0;
pub const CONTEXT_64: usize = 1;
#[repr(C, packed)]
pub struct SlotContext {
struct Rsvd64<const N: usize>([[Mmio<u32>; 8]; N]);
#[repr(C, packed)]
pub struct SlotContext<const N: usize> {
pub a: Mmio<u32>,
pub b: Mmio<u32>,
pub c: Mmio<u32>,
pub d: Mmio<u32>,
_rsvd: [Mmio<u32>; 4],
_rsvd64: Rsvd64<N>,
}
pub const SLOT_CONTEXT_STATE_MASK: u32 = 0xF800_0000;
pub const SLOT_CONTEXT_STATE_SHIFT: u8 = 27;
impl SlotContext {
pub fn state(&self) -> u8 {
((self.d.read() & SLOT_CONTEXT_STATE_MASK) >> SLOT_CONTEXT_STATE_SHIFT) as u8
}
}
#[repr(u8)]
pub enum SlotState {
EnabledOrDisabled = 0,
@@ -37,32 +38,34 @@ pub enum SlotState {
}
#[repr(C, packed)]
pub struct EndpointContext {
pub struct EndpointContext<const N: usize> {
pub a: Mmio<u32>,
pub b: Mmio<u32>,
pub trl: Mmio<u32>,
pub trh: Mmio<u32>,
pub c: Mmio<u32>,
_rsvd: [Mmio<u32>; 3],
_rsvd64: Rsvd64<N>,
}
pub const ENDPOINT_CONTEXT_STATUS_MASK: u32 = 0x7;
#[repr(C, packed)]
pub struct DeviceContext {
pub slot: SlotContext,
pub endpoints: [EndpointContext; 31],
pub struct DeviceContext<const N: usize> {
pub slot: SlotContext<N>,
pub endpoints: [EndpointContext<N>; 31],
}
#[repr(C, packed)]
pub struct InputContext {
pub struct InputContext<const N: usize> {
pub drop_context: Mmio<u32>,
pub add_context: Mmio<u32>,
_rsvd: [Mmio<u32>; 5],
pub control: Mmio<u32>,
pub device: DeviceContext,
_rsvd64: Rsvd64<N>,
pub device: DeviceContext<N>,
}
impl InputContext {
impl<const N: usize> InputContext<N> {
pub fn dump_control(&self) {
debug!(
"INPUT CONTEXT: {} {} [{} {} {} {} {}] {}",
@@ -78,19 +81,19 @@ impl InputContext {
}
}
pub struct DeviceContextList {
pub struct DeviceContextList<const N: usize> {
pub dcbaa: Dma<[u64; 256]>,
pub contexts: Box<[Dma<DeviceContext>]>,
pub contexts: Box<[Dma<DeviceContext<N>>]>,
}
impl DeviceContextList {
pub fn new(ac64: bool, max_slots: u8) -> Result<DeviceContextList> {
let mut dcbaa = unsafe { Xhci::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? };
impl<const N: usize> DeviceContextList<N> {
pub fn new(ac64: bool, max_slots: u8) -> Result<Self> {
let mut dcbaa = unsafe { Xhci::<N>::alloc_dma_zeroed_raw::<[u64; 256]>(ac64)? };
let mut contexts = vec![];
// Create device context buffers for each slot
for i in 0..max_slots as usize {
let context: Dma<DeviceContext> = unsafe { Xhci::alloc_dma_zeroed_raw(ac64) }?;
let context: Dma<DeviceContext<N>> = unsafe { Xhci::<N>::alloc_dma_zeroed_raw(ac64) }?;
dcbaa[i] = context.physical() as u64;
contexts.push(context);
}
@@ -134,19 +137,24 @@ pub struct StreamContextArray {
}
impl StreamContextArray {
pub fn new(ac64: bool, count: usize) -> Result<Self> {
pub fn new<const N: usize>(ac64: bool, count: usize) -> Result<Self> {
unsafe {
Ok(Self {
contexts: Xhci::alloc_dma_zeroed_unsized_raw(ac64, count)?,
contexts: Xhci::<N>::alloc_dma_zeroed_unsized_raw(ac64, count)?,
rings: BTreeMap::new(),
})
}
}
pub fn add_ring(&mut self, ac64: bool, stream_id: u16, link: bool) -> Result<()> {
pub fn add_ring<const N: usize>(
&mut self,
ac64: bool,
stream_id: u16,
link: bool,
) -> Result<()> {
// NOTE: stream_id 0 is reserved
assert_ne!(stream_id, 0);
let ring = Ring::new(ac64, 16, link)?;
let ring = Ring::new::<N>(ac64, 16, link)?;
let pointer = ring.register();
let sct = StreamContextType::PrimaryRing;
@@ -182,8 +190,9 @@ pub struct ScratchpadBufferArray {
pub pages: Vec<Dma<[u8; PAGE_SIZE]>>,
}
impl ScratchpadBufferArray {
pub fn new(ac64: bool, entries: u16) -> Result<Self> {
let mut entries = unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? };
pub fn new<const N: usize>(ac64: bool, entries: u16) -> Result<Self> {
let mut entries =
unsafe { Xhci::<N>::alloc_dma_zeroed_unsized_raw(ac64, entries as usize)? };
let pages = entries
.iter_mut()
@@ -203,3 +212,17 @@ impl ScratchpadBufferArray {
self.entries.physical()
}
}
#[cfg(test)]
mod test {
use super::*;
use core::mem;
#[test]
fn context_size() {
assert_eq!(mem::size_of::<SlotContext<CONTEXT_32>>(), 32);
assert_eq!(mem::size_of::<SlotContext<CONTEXT_64>>(), 64);
assert_eq!(mem::size_of::<EndpointContext<CONTEXT_32>>(), 32);
assert_eq!(mem::size_of::<EndpointContext<CONTEXT_64>>(), 64);
}
}
+4 -4
View File
@@ -11,13 +11,13 @@ pub struct DeviceEnumerationRequest {
pub port_id: PortId,
}
pub struct DeviceEnumerator {
hci: Arc<Xhci>,
pub struct DeviceEnumerator<const N: usize> {
hci: Arc<Xhci<N>>,
request_queue: crossbeam_channel::Receiver<DeviceEnumerationRequest>,
}
impl DeviceEnumerator {
pub fn new(hci: Arc<Xhci>) -> Self {
impl<const N: usize> DeviceEnumerator<N> {
pub fn new(hci: Arc<Xhci<N>>) -> Self {
let request_queue = hci.device_enumerator_receiver.clone();
DeviceEnumerator { hci, request_queue }
}
+3 -3
View File
@@ -23,10 +23,10 @@ pub struct EventRing {
}
impl EventRing {
pub fn new(ac64: bool) -> Result<EventRing> {
pub fn new<const N: usize>(ac64: bool) -> Result<EventRing> {
let mut ring = EventRing {
ste: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, 1)? },
ring: Ring::new(ac64, 256, false)?,
ste: unsafe { Xhci::<N>::alloc_dma_zeroed_unsized_raw(ac64, 1)? },
ring: Ring::new::<N>(ac64, 256, false)?,
};
ring.ste[0]
+6 -6
View File
@@ -92,8 +92,8 @@ impl StateKind {
}
}
pub struct IrqReactor {
hci: Arc<Xhci>,
pub struct IrqReactor<const N: usize> {
hci: Arc<Xhci<N>>,
irq_file: Option<File>,
irq_receiver: Receiver<NewPendingTrb>,
device_enumerator_sender: Sender<DeviceEnumerationRequest>,
@@ -104,8 +104,8 @@ pub struct IrqReactor {
pub type NewPendingTrb = State;
impl IrqReactor {
pub fn new(hci: Arc<Xhci>, irq_file: Option<File>) -> Self {
impl<const N: usize> IrqReactor<N> {
pub fn new(hci: Arc<Xhci<N>>, irq_file: Option<File>) -> Self {
let device_enumerator_sender = hci.device_enumerator_sender.clone();
let irq_receiver = hci.irq_reactor_receiver.clone();
@@ -559,7 +559,7 @@ pub struct EventDoorbell {
}
impl EventDoorbell {
pub fn new(hci: &Xhci, index: usize, data: u32) -> Self {
pub fn new<const N: usize>(hci: &Xhci<N>, index: usize, data: u32) -> Self {
Self {
//TODO: simplify this logic, maybe just use a raw pointer?
dbs: hci.dbs.clone(),
@@ -625,7 +625,7 @@ impl Future for EventTrbFuture {
}
}
impl Xhci {
impl<const N: usize> Xhci<N> {
pub fn get_transfer_trb(&self, paddr: u64, id: RingId) -> Option<Trb> {
self.with_ring(id, |ring| ring.phys_addr_to_entry(self.cap.ac64(), paddr))
.flatten()
+64 -50
View File
@@ -43,8 +43,12 @@ mod runtime;
pub mod scheme;
mod trb;
use self::capability::CapabilityRegs;
use self::context::{DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray};
pub use self::capability::CapabilityRegs;
use self::context::{
DeviceContextList, InputContext, ScratchpadBufferArray, StreamContextArray,
SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT,
};
pub use self::context::{CONTEXT_32, CONTEXT_64};
use self::doorbell::Doorbell;
use self::event::EventRing;
use self::extended::{CapabilityId, ExtendedCapabilitiesIter, ProtocolSpeed, SupportedProtoCap};
@@ -73,7 +77,7 @@ pub enum InterruptMethod {
Msi,
}
impl Xhci {
impl<const N: usize> Xhci<N> {
/// Gets descriptors, before the port state is initiated.
async fn get_desc_raw<T>(
&self,
@@ -246,7 +250,7 @@ impl Xhci {
}
/// The eXtensible Host Controller Interface (XHCI) data structure
pub struct Xhci {
pub struct Xhci<const N: usize> {
// immutable
/// The Host Controller Interface Capability Registers. These read-only registers specify the
/// limits and capabilities of the host controller implementation (See XHCI section 5.3)
@@ -270,7 +274,7 @@ pub struct Xhci {
primary_event_ring: Mutex<EventRing>,
// immutable
dev_ctx: DeviceContextList,
dev_ctx: DeviceContextList<N>,
scratchpad_buf_arr: Option<ScratchpadBufferArray>,
// used for the extended capabilities, and so far none of them are mutated, and thus no lock.
@@ -278,7 +282,7 @@ pub struct Xhci {
handles: CHashMap<usize, scheme::Handle>,
next_handle: AtomicUsize,
port_states: CHashMap<PortId, PortState>,
port_states: CHashMap<PortId, PortState<N>>,
drivers: CHashMap<PortId, Vec<process::Child>>,
scheme_name: String,
@@ -297,19 +301,19 @@ pub struct Xhci {
device_enumerator_receiver: Receiver<DeviceEnumerationRequest>,
}
unsafe impl Send for Xhci {}
unsafe impl Sync for Xhci {}
unsafe impl<const N: usize> Send for Xhci<N> {}
unsafe impl<const N: usize> Sync for Xhci<N> {}
struct PortState {
struct PortState<const N: usize> {
slot: u8,
protocol_speed: &'static ProtocolSpeed,
cfg_idx: Option<u8>,
input_context: Mutex<Dma<InputContext>>,
input_context: Mutex<Dma<InputContext<N>>>,
dev_desc: Option<DevDesc>,
endpoint_states: BTreeMap<u8, EndpointState>,
}
impl PortState {
impl<const N: usize> PortState<N> {
//TODO: fetch using endpoint number instead
fn get_endp_desc(&self, endp_idx: u8) -> Option<&EndpDesc> {
let cfg_idx = self.cfg_idx?;
@@ -350,13 +354,13 @@ impl EndpointState {
}
}
impl Xhci {
impl<const N: usize> Xhci<N> {
pub fn new(
scheme_name: String,
address: usize,
interrupt_method: InterruptMethod,
pcid_handle: PciFunctionHandle,
) -> Result<Xhci> {
) -> Result<Self> {
//Locate the capability registers from the mapped PCI Bar
let cap = unsafe { &mut *(address as *mut CapabilityRegs) };
debug!("CAP REGS BASE {:X}", address);
@@ -419,7 +423,7 @@ impl Xhci {
// Create the command ring with 4096 / 16 (TRB size) entries, so that it uses all of the
// DMA allocation (which is at least a 4k page).
let entries_per_page = PAGE_SIZE / mem::size_of::<Trb>();
let cmd = Ring::new(cap.ac64(), entries_per_page, true)?;
let cmd = Ring::new::<N>(cap.ac64(), entries_per_page, true)?;
let (irq_reactor_sender, irq_reactor_receiver) = crossbeam_channel::unbounded();
@@ -439,7 +443,7 @@ impl Xhci {
scratchpad_buf_arr: None, // initialized in init()
cmd: Mutex::new(cmd),
primary_event_ring: Mutex::new(EventRing::new(cap.ac64())?),
primary_event_ring: Mutex::new(EventRing::new::<N>(cap.ac64())?),
handles: CHashMap::new(),
next_handle: AtomicUsize::new(0),
port_states: CHashMap::new(),
@@ -469,7 +473,11 @@ impl Xhci {
// Warm reset
debug!("Reset xHC");
self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_HCRST, true);
self.op
.get_mut()
.unwrap()
.usb_cmd
.writef(USB_CMD_HCRST, true);
while self.op.get_mut().unwrap().usb_cmd.readf(USB_CMD_HCRST) {
thread::yield_now();
}
@@ -531,7 +539,11 @@ impl Xhci {
debug!("Enabling Primary Interrupter.");
int.iman.writef(1 << 1 | 1, true);
}
self.op.get_mut().unwrap().usb_cmd.writef(USB_CMD_INTE, true);
self.op
.get_mut()
.unwrap()
.usb_cmd
.writef(USB_CMD_INTE, true);
// Setup the scratchpad buffers that are required for the xHC to function.
self.setup_scratchpads()?;
@@ -674,7 +686,7 @@ impl Xhci {
if buf_count == 0 {
return Ok(());
}
let scratchpad_buf_arr = ScratchpadBufferArray::new(self.cap.ac64(), buf_count)?;
let scratchpad_buf_arr = ScratchpadBufferArray::new::<N>(self.cap.ac64(), buf_count)?;
self.dev_ctx.dcbaa[0] = scratchpad_buf_arr.register() as u64;
debug!(
"Setting up {} scratchpads, at {:#0x}",
@@ -733,7 +745,8 @@ impl Xhci {
}
pub fn slot_state(&self, slot: usize) -> u8 {
self.dev_ctx.contexts[slot].slot.state()
((self.dev_ctx.contexts[slot].slot.d.read() & SLOT_CONTEXT_STATE_MASK)
>> SLOT_CONTEXT_STATE_SHIFT) as u8
}
pub unsafe fn alloc_dma_zeroed_raw<T>(_ac64: bool) -> Result<Dma<T>> {
// TODO: ac64
@@ -792,7 +805,7 @@ impl Xhci {
.lookup_psiv(port_id, speed)
.expect("Failed to retrieve speed ID");
let mut input = unsafe { self.alloc_dma_zeroed::<InputContext>()? };
let mut input = unsafe { self.alloc_dma_zeroed::<InputContext<N>>()? };
info!("Attempting to address the device");
let mut ring = match self
@@ -940,7 +953,7 @@ impl Xhci {
pub async fn update_max_packet_size(
&self,
input_context: &mut Dma<InputContext>,
input_context: &mut Dma<InputContext<N>>,
slot_id: u8,
dev_desc: usb::DeviceDescriptor8Byte,
) -> Result<()> {
@@ -951,11 +964,10 @@ impl Xhci {
// For later USB versions, packet_size is the shift
1u32 << dev_desc.packet_size
};
let endp_ctx = &mut input_context.device.endpoints[0];
let mut b = endp_ctx.b.read();
let mut b = input_context.device.endpoints[0].b.read();
b &= 0x0000_FFFF;
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
input_context.device.endpoints[0].b.write(b);
let (event_trb, command_trb) = self
.execute_command(|trb, cycle| {
@@ -971,7 +983,7 @@ impl Xhci {
pub async fn update_default_control_pipe(
&self,
input_context: &mut Dma<InputContext>,
input_context: &mut Dma<InputContext<N>>,
slot_id: u8,
dev_desc: &DevDesc,
) -> Result<()> {
@@ -986,11 +998,10 @@ impl Xhci {
// For later USB versions, packet_size is the shift
1u32 << dev_desc.packet_size
};
let endp_ctx = &mut input_context.device.endpoints[0];
let mut b = endp_ctx.b.read();
let mut b = input_context.device.endpoints[0].b.read();
b &= 0x0000_FFFF;
b |= (new_max_packet_size) << 16;
endp_ctx.b.write(b);
input_context.device.endpoints[0].b.write(b);
let (event_trb, command_trb) = self
.execute_command(|trb, cycle| {
@@ -1007,7 +1018,7 @@ impl Xhci {
pub async fn address_device(
&self,
input_context: &mut Dma<InputContext>,
input_context: &mut Dma<InputContext<N>>,
port: PortId,
slot_ty: u8,
slot: u8,
@@ -1044,19 +1055,17 @@ impl Xhci {
}
}
let mut ring = Ring::new(self.cap.ac64(), 16, true)?;
let mut ring = Ring::new::<N>(self.cap.ac64(), 16, true)?;
{
input_context.add_context.write(1 << 1 | 1); // Enable the slot (zeroth bit) and the control endpoint (first bit).
let slot_ctx = &mut input_context.device.slot;
let route_string = port.route_string;
let context_entries = 1u8;
let hub = false;
assert_eq!(route_string & 0x000F_FFFF, route_string);
slot_ctx.a.write(
input_context.device.slot.a.write(
route_string
| (u32::from(speed) << 20)
| (u32::from(mtt) << 25)
@@ -1067,7 +1076,7 @@ impl Xhci {
let max_exit_latency = 0u16;
let root_hub_port_num = port.root_hub_port_num;
let number_of_ports = 0u8;
slot_ctx.b.write(
input_context.device.slot.b.write(
u32::from(max_exit_latency)
| (u32::from(root_hub_port_num) << 16)
| (u32::from(number_of_ports) << 24),
@@ -1078,29 +1087,28 @@ impl Xhci {
let interrupter = 0u8;
assert_eq!(ttt & 0b11, ttt);
slot_ctx.c.write(
input_context.device.slot.c.write(
u32::from(parent_hub_slot_id)
| (u32::from(parent_port_num) << 8)
| (u32::from(ttt) << 16)
| (u32::from(interrupter) << 22),
);
let endp_ctx = &mut input_context.device.endpoints[0];
let max_error_count = 3u8; // recommended value according to the XHCI spec
let ep_ty = 4u8; // control endpoint, bidirectional
let max_packet_size: u32 = if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() {
8
} else if protocol_speed.is_highspeed() {
64
} else {
512
};
let max_packet_size: u32 =
if protocol_speed.is_lowspeed() || protocol_speed.is_fullspeed() {
8
} else if protocol_speed.is_highspeed() {
64
} else {
512
};
let host_initiate_disable = false; // only applies to streams
let max_burst_size = 0u8; // TODO
assert_eq!(max_error_count & 0b11, max_error_count);
endp_ctx.b.write(
input_context.device.endpoints[0].b.write(
(u32::from(max_error_count) << 1)
| (u32::from(ep_ty) << 3)
| (u32::from(host_initiate_disable) << 7)
@@ -1110,12 +1118,18 @@ impl Xhci {
let dequeue_cycle_state = true;
let tr = ring.register();
endp_ctx.trh.write((tr >> 32) as u32);
endp_ctx.trl.write((tr as u32) | u32::from(dequeue_cycle_state));
input_context.device.endpoints[0]
.trh
.write((tr >> 32) as u32);
input_context.device.endpoints[0]
.trl
.write((tr as u32) | u32::from(dequeue_cycle_state));
// The default control pipe can always use 8 bytes
let avg_trb_len = 8u8;
endp_ctx.c.write(u32::from(avg_trb_len));
input_context.device.endpoints[0]
.c
.write(u32::from(avg_trb_len));
}
let input_context_physical = input_context.physical();
@@ -1394,7 +1408,7 @@ impl Xhci {
.find(|speed| speed.psiv() == psiv)
}
}
pub fn start_irq_reactor(hci: &Arc<Xhci>, irq_file: Option<File>) {
pub fn start_irq_reactor<const N: usize>(hci: &Arc<Xhci<N>>, irq_file: Option<File>) {
let hci_clone = Arc::clone(&hci);
debug!("About to start IRQ reactor");
@@ -1405,7 +1419,7 @@ pub fn start_irq_reactor(hci: &Arc<Xhci>, irq_file: Option<File>) {
}));
}
pub fn start_device_enumerator(hci: &Arc<Xhci>) {
pub fn start_device_enumerator<const N: usize>(hci: &Arc<Xhci<N>>) {
let hci_clone = Arc::clone(&hci);
debug!("About to start Device Enumerator");
+2 -2
View File
@@ -15,10 +15,10 @@ pub struct Ring {
}
impl Ring {
pub fn new(ac64: bool, length: usize, link: bool) -> Result<Ring> {
pub fn new<const N: usize>(ac64: bool, length: usize, link: bool) -> Result<Ring> {
Ok(Ring {
link,
trbs: unsafe { Xhci::alloc_dma_zeroed_unsized_raw(ac64, length)? },
trbs: unsafe { Xhci::<N>::alloc_dma_zeroed_unsized_raw(ac64, length)? },
i: 0,
cycle: link,
})
+28 -31
View File
@@ -40,7 +40,10 @@ use syscall::{
use super::{port, usb};
use super::{EndpointState, PortId, Xhci};
use super::context::{SlotState, StreamContextArray, StreamContextType};
use super::context::{
SlotState, StreamContextArray, StreamContextType, CONTEXT_32, CONTEXT_64,
SLOT_CONTEXT_STATE_MASK, SLOT_CONTEXT_STATE_SHIFT,
};
use super::extended::ProtocolSpeed;
use super::irq_reactor::{EventDoorbell, RingId};
use super::ring::Ring;
@@ -543,7 +546,7 @@ impl AnyDescriptor {
}
}
impl Xhci {
impl<const N: usize> Xhci<N> {
async fn new_if_desc(
&self,
port_id: PortId,
@@ -927,13 +930,13 @@ impl Xhci {
fn port_state(
&self,
port: PortId,
) -> Result<chashmap::ReadGuard<'_, PortId, super::PortState>> {
) -> Result<chashmap::ReadGuard<'_, PortId, super::PortState<N>>> {
self.port_states.get(&port).ok_or(Error::new(EBADF))
}
fn port_state_mut(
&self,
port: PortId,
) -> Result<chashmap::WriteGuard<'_, PortId, super::PortState>> {
) -> Result<chashmap::WriteGuard<'_, PortId, super::PortState<N>>> {
self.port_states.get_mut(&port).ok_or(Error::new(EBADF))
}
@@ -1103,10 +1106,10 @@ impl Xhci {
let ring_ptr = if usb_log_max_streams.is_some() {
let mut array =
StreamContextArray::new(self.cap.ac64(), 1 << (primary_streams + 1))?;
StreamContextArray::new::<N>(self.cap.ac64(), 1 << (primary_streams + 1))?;
// TODO: Use as many stream rings as needed.
array.add_ring(self.cap.ac64(), 1, true)?;
array.add_ring::<N>(self.cap.ac64(), 1, true)?;
let array_ptr = array.register();
assert_eq!(
@@ -1124,7 +1127,7 @@ impl Xhci {
array_ptr
} else {
let ring = Ring::new(self.cap.ac64(), 16, true)?;
let ring = Ring::new::<N>(self.cap.ac64(), 16, true)?;
let ring_ptr = ring.register();
assert_eq!(
@@ -1146,23 +1149,15 @@ impl Xhci {
let mut input_context = port_state.input_context.lock().unwrap();
input_context.add_context.writef(1 << endp_num_xhc, true);
let endp_ctx = input_context
.device
.endpoints
.get_mut(endp_num_xhc as usize - 1)
.ok_or_else(|| {
warn!("failed to find endpoint {}", endp_num_xhc - 1);
Error::new(EIO)
})?;
endp_ctx.a.write(
let endp_i = endp_num_xhc as usize - 1;
input_context.device.endpoints[endp_i].a.write(
u32::from(mult) << 8
| u32::from(primary_streams) << 10
| u32::from(linear_stream_array) << 15
| u32::from(interval) << 16
| u32::from(max_esit_payload_hi) << 24,
);
endp_ctx.b.write(
input_context.device.endpoints[endp_i].b.write(
max_error_count << 1
| u32::from(ep_ty) << 3
| u32::from(host_initiate_disable) << 7
@@ -1170,10 +1165,14 @@ impl Xhci {
| u32::from(max_packet_size) << 16,
);
endp_ctx.trl.write(ring_ptr as u32);
endp_ctx.trh.write((ring_ptr >> 32) as u32);
input_context.device.endpoints[endp_i]
.trl
.write(ring_ptr as u32);
input_context.device.endpoints[endp_i]
.trh
.write((ring_ptr >> 32) as u32);
endp_ctx
input_context.device.endpoints[endp_i]
.c
.write(u32::from(avg_trb_len) | (u32::from(max_esit_payload_lo) << 16));
@@ -2099,7 +2098,7 @@ impl Xhci {
}
}
impl SchemeSync for &Xhci {
impl<const N: usize> SchemeSync for &Xhci<N> {
fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
if ctx.uid != 0 {
return Err(Error::new(EACCES));
@@ -2237,13 +2236,13 @@ impl SchemeSync for &Xhci {
},
&mut Handle::PortState(port_num) => {
let ps = self.port_states.get(&port_num).ok_or(Error::new(EBADF))?;
let state = self
let ctx = self
.dev_ctx
.contexts
.get(ps.slot as usize)
.ok_or(Error::new(EBADF))?
.slot
.state();
.ok_or(Error::new(EBADF))?;
let state = ((ctx.slot.d.read() & SLOT_CONTEXT_STATE_MASK)
>> SLOT_CONTEXT_STATE_SHIFT) as u8;
let string = match state {
0 => Some(PortState::EnabledOrDisabled),
@@ -2257,7 +2256,7 @@ impl SchemeSync for &Xhci {
.unwrap_or("unknown")
.as_bytes();
Ok(Xhci::write_dyn_string(string, buf, offset))
Ok(Xhci::<N>::write_dyn_string(string, buf, offset))
}
&mut Handle::PortReq(port_num, ref mut st) => {
let state = std::mem::replace(st, PortReqState::Tmp);
@@ -2316,7 +2315,7 @@ impl SchemeSync for &Xhci {
}
}
}
impl Xhci {
impl<const N: usize> Xhci<N> {
pub fn on_close(&self, fd: usize) {
self.handles.remove(&fd);
}
@@ -2351,9 +2350,7 @@ impl Xhci {
.contexts
.get(slot as usize)
.ok_or(Error::new(EBADFD))?
.endpoints
.get(endp_num_xhc as usize - 1)
.ok_or(Error::new(EBADFD))?
.endpoints[endp_num_xhc as usize - 1]
.a
.read()
& super::context::ENDPOINT_CONTEXT_STATUS_MASK;