1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2019 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Duration; 6*bb4ee6a4SAndroid Build Coastguard Worker use std::time::Instant; 7*bb4ee6a4SAndroid Build Coastguard Worker 8*bb4ee6a4SAndroid Build Coastguard Worker use base::Clock; 9*bb4ee6a4SAndroid Build Coastguard Worker use base::Error as SysError; 10*bb4ee6a4SAndroid Build Coastguard Worker use base::Event; 11*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted; 12*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error; 13*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestAddress; 14*bb4ee6a4SAndroid Build Coastguard Worker use vm_memory::GuestMemory; 15*bb4ee6a4SAndroid Build Coastguard Worker 16*bb4ee6a4SAndroid Build Coastguard Worker use super::event_ring::Error as EventRingError; 17*bb4ee6a4SAndroid Build Coastguard Worker use super::event_ring::EventRing; 18*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::CommandCompletionEventTrb; 19*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::Error as TrbError; 20*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::PortStatusChangeEventTrb; 21*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::TransferEventTrb; 22*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::Trb; 23*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::TrbCast; 24*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::TrbCompletionCode; 25*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_abi::TrbType; 26*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_regs::XhciRegs; 27*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_regs::ERDP_EVENT_HANDLER_BUSY; 28*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_regs::IMAN_INTERRUPT_PENDING; 29*bb4ee6a4SAndroid Build Coastguard Worker use super::xhci_regs::USB_STS_EVENT_INTERRUPT; 30*bb4ee6a4SAndroid Build Coastguard Worker use crate::register_space::Register; 31*bb4ee6a4SAndroid Build Coastguard Worker 32*bb4ee6a4SAndroid Build Coastguard Worker #[sorted] 33*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)] 34*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error { 35*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot add event: {0}")] 36*bb4ee6a4SAndroid Build Coastguard Worker AddEvent(EventRingError), 37*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot cast trb: {0}")] 38*bb4ee6a4SAndroid Build Coastguard Worker CastTrb(TrbError), 39*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot send interrupt: {0}")] 40*bb4ee6a4SAndroid Build Coastguard Worker SendInterrupt(SysError), 41*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot set seg table base addr: {0}")] 42*bb4ee6a4SAndroid Build Coastguard Worker SetSegTableBaseAddr(EventRingError), 43*bb4ee6a4SAndroid Build Coastguard Worker #[error("cannot set seg table size: {0}")] 44*bb4ee6a4SAndroid Build Coastguard Worker SetSegTableSize(EventRingError), 45*bb4ee6a4SAndroid Build Coastguard Worker } 46*bb4ee6a4SAndroid Build Coastguard Worker 47*bb4ee6a4SAndroid Build Coastguard Worker type Result<T> = std::result::Result<T, Error>; 48*bb4ee6a4SAndroid Build Coastguard Worker 49*bb4ee6a4SAndroid Build Coastguard Worker /// See spec 4.17 for interrupters. Controller can send an event back to guest kernel driver 50*bb4ee6a4SAndroid Build Coastguard Worker /// through interrupter. 51*bb4ee6a4SAndroid Build Coastguard Worker pub struct Interrupter { 52*bb4ee6a4SAndroid Build Coastguard Worker interrupt_evt: Event, 53*bb4ee6a4SAndroid Build Coastguard Worker usbsts: Register<u32>, 54*bb4ee6a4SAndroid Build Coastguard Worker iman: Register<u32>, 55*bb4ee6a4SAndroid Build Coastguard Worker erdp: Register<u64>, 56*bb4ee6a4SAndroid Build Coastguard Worker event_handler_busy: bool, 57*bb4ee6a4SAndroid Build Coastguard Worker enabled: bool, 58*bb4ee6a4SAndroid Build Coastguard Worker moderation_interval: u16, 59*bb4ee6a4SAndroid Build Coastguard Worker moderation_counter: u16, 60*bb4ee6a4SAndroid Build Coastguard Worker event_ring: EventRing, 61*bb4ee6a4SAndroid Build Coastguard Worker last_interrupt_time: Instant, 62*bb4ee6a4SAndroid Build Coastguard Worker clock: Clock, 63*bb4ee6a4SAndroid Build Coastguard Worker } 64*bb4ee6a4SAndroid Build Coastguard Worker 65*bb4ee6a4SAndroid Build Coastguard Worker impl Interrupter { 66*bb4ee6a4SAndroid Build Coastguard Worker /// Create a new interrupter. new(mem: GuestMemory, irq_evt: Event, regs: &XhciRegs) -> Self67*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(mem: GuestMemory, irq_evt: Event, regs: &XhciRegs) -> Self { 68*bb4ee6a4SAndroid Build Coastguard Worker let clock = Clock::new(); 69*bb4ee6a4SAndroid Build Coastguard Worker Interrupter { 70*bb4ee6a4SAndroid Build Coastguard Worker interrupt_evt: irq_evt, 71*bb4ee6a4SAndroid Build Coastguard Worker usbsts: regs.usbsts.clone(), 72*bb4ee6a4SAndroid Build Coastguard Worker iman: regs.iman.clone(), 73*bb4ee6a4SAndroid Build Coastguard Worker erdp: regs.erdp.clone(), 74*bb4ee6a4SAndroid Build Coastguard Worker event_handler_busy: false, 75*bb4ee6a4SAndroid Build Coastguard Worker enabled: false, 76*bb4ee6a4SAndroid Build Coastguard Worker moderation_interval: 4000, // default to 1ms as per xhci 5.5.2.2 77*bb4ee6a4SAndroid Build Coastguard Worker moderation_counter: 0, // xhci specs leave this as undefined 78*bb4ee6a4SAndroid Build Coastguard Worker event_ring: EventRing::new(mem), 79*bb4ee6a4SAndroid Build Coastguard Worker last_interrupt_time: clock.now(), 80*bb4ee6a4SAndroid Build Coastguard Worker clock, 81*bb4ee6a4SAndroid Build Coastguard Worker } 82*bb4ee6a4SAndroid Build Coastguard Worker } 83*bb4ee6a4SAndroid Build Coastguard Worker 84*bb4ee6a4SAndroid Build Coastguard Worker /// Returns true if event ring is empty. event_ring_is_empty(&self) -> bool85*bb4ee6a4SAndroid Build Coastguard Worker pub fn event_ring_is_empty(&self) -> bool { 86*bb4ee6a4SAndroid Build Coastguard Worker self.event_ring.is_empty() 87*bb4ee6a4SAndroid Build Coastguard Worker } 88*bb4ee6a4SAndroid Build Coastguard Worker 89*bb4ee6a4SAndroid Build Coastguard Worker /// Add event to event ring. add_event(&mut self, trb: Trb) -> Result<()>90*bb4ee6a4SAndroid Build Coastguard Worker fn add_event(&mut self, trb: Trb) -> Result<()> { 91*bb4ee6a4SAndroid Build Coastguard Worker self.event_ring.add_event(trb).map_err(Error::AddEvent)?; 92*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_if_needed() 93*bb4ee6a4SAndroid Build Coastguard Worker } 94*bb4ee6a4SAndroid Build Coastguard Worker 95*bb4ee6a4SAndroid Build Coastguard Worker /// Send port status change trb for port. send_port_status_change_trb(&mut self, port_id: u8) -> Result<()>96*bb4ee6a4SAndroid Build Coastguard Worker pub fn send_port_status_change_trb(&mut self, port_id: u8) -> Result<()> { 97*bb4ee6a4SAndroid Build Coastguard Worker let mut trb = Trb::new(); 98*bb4ee6a4SAndroid Build Coastguard Worker let psctrb = trb 99*bb4ee6a4SAndroid Build Coastguard Worker .cast_mut::<PortStatusChangeEventTrb>() 100*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::CastTrb)?; 101*bb4ee6a4SAndroid Build Coastguard Worker psctrb.set_port_id(port_id); 102*bb4ee6a4SAndroid Build Coastguard Worker psctrb.set_completion_code(TrbCompletionCode::Success); 103*bb4ee6a4SAndroid Build Coastguard Worker psctrb.set_trb_type(TrbType::PortStatusChangeEvent); 104*bb4ee6a4SAndroid Build Coastguard Worker self.add_event(trb) 105*bb4ee6a4SAndroid Build Coastguard Worker } 106*bb4ee6a4SAndroid Build Coastguard Worker 107*bb4ee6a4SAndroid Build Coastguard Worker /// Send command completion trb. send_command_completion_trb( &mut self, completion_code: TrbCompletionCode, slot_id: u8, trb_addr: GuestAddress, ) -> Result<()>108*bb4ee6a4SAndroid Build Coastguard Worker pub fn send_command_completion_trb( 109*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 110*bb4ee6a4SAndroid Build Coastguard Worker completion_code: TrbCompletionCode, 111*bb4ee6a4SAndroid Build Coastguard Worker slot_id: u8, 112*bb4ee6a4SAndroid Build Coastguard Worker trb_addr: GuestAddress, 113*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 114*bb4ee6a4SAndroid Build Coastguard Worker let mut trb = Trb::new(); 115*bb4ee6a4SAndroid Build Coastguard Worker let ctrb = trb 116*bb4ee6a4SAndroid Build Coastguard Worker .cast_mut::<CommandCompletionEventTrb>() 117*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::CastTrb)?; 118*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_trb_pointer(trb_addr.0); 119*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_command_completion_parameter(0); 120*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_completion_code(completion_code); 121*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_trb_type(TrbType::CommandCompletionEvent); 122*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_vf_id(0); 123*bb4ee6a4SAndroid Build Coastguard Worker ctrb.set_slot_id(slot_id); 124*bb4ee6a4SAndroid Build Coastguard Worker self.add_event(trb) 125*bb4ee6a4SAndroid Build Coastguard Worker } 126*bb4ee6a4SAndroid Build Coastguard Worker 127*bb4ee6a4SAndroid Build Coastguard Worker /// Send transfer event trb. send_transfer_event_trb( &mut self, completion_code: TrbCompletionCode, trb_pointer: u64, transfer_length: u32, event_data: bool, slot_id: u8, endpoint_id: u8, ) -> Result<()>128*bb4ee6a4SAndroid Build Coastguard Worker pub fn send_transfer_event_trb( 129*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 130*bb4ee6a4SAndroid Build Coastguard Worker completion_code: TrbCompletionCode, 131*bb4ee6a4SAndroid Build Coastguard Worker trb_pointer: u64, 132*bb4ee6a4SAndroid Build Coastguard Worker transfer_length: u32, 133*bb4ee6a4SAndroid Build Coastguard Worker event_data: bool, 134*bb4ee6a4SAndroid Build Coastguard Worker slot_id: u8, 135*bb4ee6a4SAndroid Build Coastguard Worker endpoint_id: u8, 136*bb4ee6a4SAndroid Build Coastguard Worker ) -> Result<()> { 137*bb4ee6a4SAndroid Build Coastguard Worker let mut trb = Trb::new(); 138*bb4ee6a4SAndroid Build Coastguard Worker let event_trb = trb.cast_mut::<TransferEventTrb>().map_err(Error::CastTrb)?; 139*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_trb_pointer(trb_pointer); 140*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_trb_transfer_length(transfer_length); 141*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_completion_code(completion_code); 142*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_event_data(event_data.into()); 143*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_trb_type(TrbType::TransferEvent); 144*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_endpoint_id(endpoint_id); 145*bb4ee6a4SAndroid Build Coastguard Worker event_trb.set_slot_id(slot_id); 146*bb4ee6a4SAndroid Build Coastguard Worker self.add_event(trb) 147*bb4ee6a4SAndroid Build Coastguard Worker } 148*bb4ee6a4SAndroid Build Coastguard Worker 149*bb4ee6a4SAndroid Build Coastguard Worker /// Enable/Disable this interrupter. set_enabled(&mut self, enabled: bool) -> Result<()>150*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_enabled(&mut self, enabled: bool) -> Result<()> { 151*bb4ee6a4SAndroid Build Coastguard Worker xhci_trace!("interrupter set_enabled({})", enabled); 152*bb4ee6a4SAndroid Build Coastguard Worker self.enabled = enabled; 153*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_if_needed() 154*bb4ee6a4SAndroid Build Coastguard Worker } 155*bb4ee6a4SAndroid Build Coastguard Worker 156*bb4ee6a4SAndroid Build Coastguard Worker /// Set interrupt moderation. set_moderation(&mut self, interval: u16, counter: u16) -> Result<()>157*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_moderation(&mut self, interval: u16, counter: u16) -> Result<()> { 158*bb4ee6a4SAndroid Build Coastguard Worker xhci_trace!("interrupter set_moderation({}, {})", interval, counter); 159*bb4ee6a4SAndroid Build Coastguard Worker self.moderation_interval = interval; 160*bb4ee6a4SAndroid Build Coastguard Worker self.moderation_counter = counter; 161*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_if_needed() 162*bb4ee6a4SAndroid Build Coastguard Worker } 163*bb4ee6a4SAndroid Build Coastguard Worker 164*bb4ee6a4SAndroid Build Coastguard Worker /// Set event ring seg table size. set_event_ring_seg_table_size(&mut self, size: u16) -> Result<()>165*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_event_ring_seg_table_size(&mut self, size: u16) -> Result<()> { 166*bb4ee6a4SAndroid Build Coastguard Worker xhci_trace!("interrupter set_event_ring_seg_table_size({})", size); 167*bb4ee6a4SAndroid Build Coastguard Worker self.event_ring 168*bb4ee6a4SAndroid Build Coastguard Worker .set_seg_table_size(size) 169*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::SetSegTableSize) 170*bb4ee6a4SAndroid Build Coastguard Worker } 171*bb4ee6a4SAndroid Build Coastguard Worker 172*bb4ee6a4SAndroid Build Coastguard Worker /// Set event ring segment table base address. set_event_ring_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()>173*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_event_ring_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()> { 174*bb4ee6a4SAndroid Build Coastguard Worker xhci_trace!("interrupter set_table_base_addr({:#x})", addr.0); 175*bb4ee6a4SAndroid Build Coastguard Worker self.event_ring 176*bb4ee6a4SAndroid Build Coastguard Worker .set_seg_table_base_addr(addr) 177*bb4ee6a4SAndroid Build Coastguard Worker .map_err(Error::SetSegTableBaseAddr) 178*bb4ee6a4SAndroid Build Coastguard Worker } 179*bb4ee6a4SAndroid Build Coastguard Worker 180*bb4ee6a4SAndroid Build Coastguard Worker /// Set event ring dequeue pointer. set_event_ring_dequeue_pointer(&mut self, addr: GuestAddress, busy: bool) -> Result<()>181*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_event_ring_dequeue_pointer(&mut self, addr: GuestAddress, busy: bool) -> Result<()> { 182*bb4ee6a4SAndroid Build Coastguard Worker xhci_trace!( 183*bb4ee6a4SAndroid Build Coastguard Worker "interrupter set_dequeue_pointer(addr = {:#x}, busy = {})", 184*bb4ee6a4SAndroid Build Coastguard Worker addr.0, 185*bb4ee6a4SAndroid Build Coastguard Worker busy 186*bb4ee6a4SAndroid Build Coastguard Worker ); 187*bb4ee6a4SAndroid Build Coastguard Worker self.event_ring.set_dequeue_pointer(addr); 188*bb4ee6a4SAndroid Build Coastguard Worker self.event_handler_busy = busy; 189*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_if_needed() 190*bb4ee6a4SAndroid Build Coastguard Worker } 191*bb4ee6a4SAndroid Build Coastguard Worker 192*bb4ee6a4SAndroid Build Coastguard Worker /// Send and interrupt. interrupt(&mut self) -> Result<()>193*bb4ee6a4SAndroid Build Coastguard Worker pub fn interrupt(&mut self) -> Result<()> { 194*bb4ee6a4SAndroid Build Coastguard Worker self.event_handler_busy = true; 195*bb4ee6a4SAndroid Build Coastguard Worker self.usbsts.set_bits(USB_STS_EVENT_INTERRUPT); 196*bb4ee6a4SAndroid Build Coastguard Worker self.iman.set_bits(IMAN_INTERRUPT_PENDING); 197*bb4ee6a4SAndroid Build Coastguard Worker self.erdp.set_bits(ERDP_EVENT_HANDLER_BUSY); 198*bb4ee6a4SAndroid Build Coastguard Worker self.moderation_counter = self.moderation_interval; 199*bb4ee6a4SAndroid Build Coastguard Worker self.last_interrupt_time = self.clock.now(); 200*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt_evt.signal().map_err(Error::SendInterrupt) 201*bb4ee6a4SAndroid Build Coastguard Worker } 202*bb4ee6a4SAndroid Build Coastguard Worker interrupt_interval(&self) -> Duration203*bb4ee6a4SAndroid Build Coastguard Worker fn interrupt_interval(&self) -> Duration { 204*bb4ee6a4SAndroid Build Coastguard Worker // Formula from xhci spec 4.17.2 in nanoseconds, but we use the imodc value instead of the 205*bb4ee6a4SAndroid Build Coastguard Worker // imodi value because our implementation automatically adjusts the range of the duration 206*bb4ee6a4SAndroid Build Coastguard Worker // based on the remaining time left in the moderation counter, which may be software 207*bb4ee6a4SAndroid Build Coastguard Worker // defined. 208*bb4ee6a4SAndroid Build Coastguard Worker Duration::new(0, 250 * u32::from(self.moderation_counter)) 209*bb4ee6a4SAndroid Build Coastguard Worker } 210*bb4ee6a4SAndroid Build Coastguard Worker interrupt_if_needed(&mut self) -> Result<()>211*bb4ee6a4SAndroid Build Coastguard Worker fn interrupt_if_needed(&mut self) -> Result<()> { 212*bb4ee6a4SAndroid Build Coastguard Worker let can_interrupt = self.last_interrupt_time.elapsed() >= self.interrupt_interval(); 213*bb4ee6a4SAndroid Build Coastguard Worker if self.enabled && can_interrupt && !self.event_ring.is_empty() && !self.event_handler_busy 214*bb4ee6a4SAndroid Build Coastguard Worker { 215*bb4ee6a4SAndroid Build Coastguard Worker self.interrupt()?; 216*bb4ee6a4SAndroid Build Coastguard Worker } 217*bb4ee6a4SAndroid Build Coastguard Worker Ok(()) 218*bb4ee6a4SAndroid Build Coastguard Worker } 219*bb4ee6a4SAndroid Build Coastguard Worker } 220