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