242 lines
5.9 KiB
Rust

use core::mem::{size_of, MaybeUninit};
use bytemuck::{Pod, Zeroable};
use device_api::dma::DmaAllocator;
use libk::dma::{BusAddress, DmaBuffer};
use libk_util::sync::IrqSafeSpinlock;
use ygg_driver_usb::error::UsbError;
use yggdrasil_abi::define_bitfields;
use super::{command::CommandReply, GenericRing};
pub enum Event {
PortChange(usize),
CommandCompletion {
address: BusAddress,
reply: CommandReply,
},
Transfer {
address: BusAddress,
slot_id: u8,
endpoint_id: u8,
status: u32,
},
}
#[repr(C, align(16))]
pub struct EventRingSegment {
address: BusAddress,
// Number of TRBs supported by the ring segment. Valid values are 16 to 4096
size: u16,
_0: u16,
_1: u32,
}
pub struct EventRingSegmentTable {
entries: DmaBuffer<[EventRingSegment]>,
}
struct EventRingInner {
trbs: DmaBuffer<[MaybeUninit<RawEventTrb>]>,
dequeue_index: usize,
cycle_bit: bool,
}
pub struct EventRing {
inner: IrqSafeSpinlock<EventRingInner>,
capacity: usize,
}
impl EventRingSegmentTable {
pub fn for_event_rings(dma: &dyn DmaAllocator, rings: &[&EventRing]) -> Result<Self, UsbError> {
let entries = DmaBuffer::new_slice_with(
dma,
|i| EventRingSegment {
address: rings[i].bus_base(),
size: rings[i].capacity.try_into().unwrap(),
_0: 0,
_1: 0,
},
rings.len(),
)
.map_err(UsbError::MemoryError)?;
Ok(Self { entries })
}
pub fn bus_address(&self) -> BusAddress {
self.entries.bus_address()
}
pub fn capacity(&self) -> usize {
self.entries.len()
}
}
impl GenericRing for EventRing {
fn bus_base(&self) -> BusAddress {
self.inner.lock().trbs.bus_address()
}
}
impl EventRingInner {
fn try_dequeue(&mut self) -> Option<Event> {
let trb = unsafe { self.trbs[self.dequeue_index].assume_init_ref() };
// TRB cannot be consumed -- its cycle bit not toggled
let trb_cycle = trb.cycle_bit();
if trb_cycle != self.cycle_bit {
return None;
}
self.dequeue_index += 1;
if self.dequeue_index == self.trbs.len() {
self.dequeue_index = 0;
self.cycle_bit = !self.cycle_bit;
}
trb.into_event()
}
}
impl EventRing {
pub fn new(dma: &dyn DmaAllocator, capacity: usize) -> Result<Self, UsbError> {
let trbs = DmaBuffer::new_zeroed_slice(dma, capacity).map_err(UsbError::MemoryError)?;
Ok(Self {
inner: IrqSafeSpinlock::new(EventRingInner {
trbs,
dequeue_index: 0,
cycle_bit: true,
}),
capacity,
})
}
pub fn try_dequeue(&self) -> Option<Event> {
self.inner.lock().try_dequeue()
}
pub fn dequeue_pointer(&self) -> BusAddress {
let i = self.inner.lock();
i.trbs
.bus_address()
.add(i.dequeue_index * size_of::<RawEventTrb>())
}
}
// TRB implementations
define_bitfields! {
pub TransferEventStatus : u32 {
(24..32) => completion_code,
(0..24) => sub_length
}
}
define_bitfields! {
pub TransferEventFlags : u32 {
(24..32) => slot_id,
(16..20) => endpoint_id,
}
}
define_bitfields! {
pub CommandCompletionEventStatus : u32 {
(24..32) => completion_code,
(0..24) => completion_parameter
}
}
define_bitfields! {
pub CommandCompletionEventFlags : u32 {
(24..32) => slot_id,
}
}
define_bitfields! {
pub PortStatusChangeEventAddress : u32 {
(24..32) => port_id
}
}
define_bitfields! {
pub RawEventFlags : u32 {
(10..16) => ty,
0 => cycle
}
}
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
#[repr(C, align(16))]
pub struct TransferEventTrb {
pub address: BusAddress,
pub status: TransferEventStatus,
pub flags: TransferEventFlags,
}
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
#[repr(C, align(16))]
pub struct CommandCompletionEventTrb {
pub address: BusAddress,
pub status: CommandCompletionEventStatus,
pub flags: CommandCompletionEventFlags,
}
#[derive(Clone, Copy, Debug, Pod, Zeroable)]
#[repr(C, align(16))]
pub struct PortStatusChangeEventTrb {
pub address: PortStatusChangeEventAddress,
_0: [u32; 3],
}
#[derive(Clone, Copy, Pod, Zeroable)]
#[repr(C, align(16))]
pub struct RawEventTrb {
_0: [u32; 3],
pub flags: RawEventFlags,
}
impl RawEventTrb {
pub fn into_event(self) -> Option<Event> {
match self.flags.ty() {
32 => {
let transfer: TransferEventTrb = bytemuck::cast(self);
Some(Event::Transfer {
address: transfer.address,
slot_id: transfer.flags.slot_id() as _,
endpoint_id: transfer.flags.endpoint_id() as _,
status: transfer.status.into_raw(),
})
}
33 => {
let command: CommandCompletionEventTrb = bytemuck::cast(self);
Some(Event::CommandCompletion {
address: command.address,
reply: CommandReply {
completion_code: command.status.completion_code() as _,
completion_parameter: command.status.completion_parameter(),
slot_id: command.flags.slot_id() as _,
},
})
}
34 => {
let port_status: PortStatusChangeEventTrb = bytemuck::cast(self);
Some(Event::PortChange(port_status.address.port_id() as _))
}
ty => {
log::warn!("Unhandled event TRB with type: {}", ty);
None
}
}
}
pub fn cycle_bit(&self) -> bool {
self.flags.cycle()
}
}