devices/usb/xhci/
interrupter.rs

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
5use std::time::Duration;
6use std::time::Instant;
7
8use base::Clock;
9use base::Error as SysError;
10use base::Event;
11use remain::sorted;
12use thiserror::Error;
13use vm_memory::GuestAddress;
14use vm_memory::GuestMemory;
15
16use super::event_ring::Error as EventRingError;
17use super::event_ring::EventRing;
18use super::xhci_abi::CommandCompletionEventTrb;
19use super::xhci_abi::Error as TrbError;
20use super::xhci_abi::PortStatusChangeEventTrb;
21use super::xhci_abi::TransferEventTrb;
22use super::xhci_abi::Trb;
23use super::xhci_abi::TrbCast;
24use super::xhci_abi::TrbCompletionCode;
25use super::xhci_abi::TrbType;
26use super::xhci_regs::XhciRegs;
27use super::xhci_regs::ERDP_EVENT_HANDLER_BUSY;
28use super::xhci_regs::IMAN_INTERRUPT_PENDING;
29use super::xhci_regs::USB_STS_EVENT_INTERRUPT;
30use crate::register_space::Register;
31
32#[sorted]
33#[derive(Error, Debug)]
34pub 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
47type 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.
51pub 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
65impl Interrupter {
66    /// Create a new interrupter.
67    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.
85    pub fn event_ring_is_empty(&self) -> bool {
86        self.event_ring.is_empty()
87    }
88
89    /// Add event to event ring.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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
203    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
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}