xref: /aosp_15_r20/external/crosvm/devices/src/usb/xhci/interrupter.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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