• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 base::Error as SysError;
6 use base::Event;
7 use remain::sorted;
8 use thiserror::Error;
9 use vm_memory::GuestAddress;
10 use vm_memory::GuestMemory;
11 
12 use super::event_ring::Error as EventRingError;
13 use super::event_ring::EventRing;
14 use super::xhci_abi::CommandCompletionEventTrb;
15 use super::xhci_abi::Error as TrbError;
16 use super::xhci_abi::PortStatusChangeEventTrb;
17 use super::xhci_abi::TransferEventTrb;
18 use super::xhci_abi::Trb;
19 use super::xhci_abi::TrbCast;
20 use super::xhci_abi::TrbCompletionCode;
21 use super::xhci_abi::TrbType;
22 use super::xhci_regs::*;
23 use crate::register_space::Register;
24 
25 #[sorted]
26 #[derive(Error, Debug)]
27 pub enum Error {
28     #[error("cannot add event: {0}")]
29     AddEvent(EventRingError),
30     #[error("cannot cast trb: {0}")]
31     CastTrb(TrbError),
32     #[error("cannot send interrupt: {0}")]
33     SendInterrupt(SysError),
34     #[error("cannot set seg table base addr: {0}")]
35     SetSegTableBaseAddr(EventRingError),
36     #[error("cannot set seg table size: {0}")]
37     SetSegTableSize(EventRingError),
38 }
39 
40 type Result<T> = std::result::Result<T, Error>;
41 
42 /// See spec 4.17 for interrupters. Controller can send an event back to guest kernel driver
43 /// through interrupter.
44 pub struct Interrupter {
45     interrupt_evt: Event,
46     usbsts: Register<u32>,
47     iman: Register<u32>,
48     erdp: Register<u64>,
49     event_handler_busy: bool,
50     enabled: bool,
51     moderation_interval: u16,
52     moderation_counter: u16,
53     event_ring: EventRing,
54 }
55 
56 impl Interrupter {
57     /// Create a new interrupter.
new(mem: GuestMemory, irq_evt: Event, regs: &XhciRegs) -> Self58     pub fn new(mem: GuestMemory, irq_evt: Event, regs: &XhciRegs) -> Self {
59         Interrupter {
60             interrupt_evt: irq_evt,
61             usbsts: regs.usbsts.clone(),
62             iman: regs.iman.clone(),
63             erdp: regs.erdp.clone(),
64             event_handler_busy: false,
65             enabled: false,
66             moderation_interval: 0,
67             moderation_counter: 0,
68             event_ring: EventRing::new(mem),
69         }
70     }
71 
72     /// Returns true if event ring is empty.
event_ring_is_empty(&self) -> bool73     pub fn event_ring_is_empty(&self) -> bool {
74         self.event_ring.is_empty()
75     }
76 
77     /// Add event to event ring.
add_event(&mut self, trb: Trb) -> Result<()>78     fn add_event(&mut self, trb: Trb) -> Result<()> {
79         self.event_ring.add_event(trb).map_err(Error::AddEvent)?;
80         self.interrupt_if_needed()
81     }
82 
83     /// Send port status change trb for port.
send_port_status_change_trb(&mut self, port_id: u8) -> Result<()>84     pub fn send_port_status_change_trb(&mut self, port_id: u8) -> Result<()> {
85         let mut trb = Trb::new();
86         let psctrb = trb
87             .cast_mut::<PortStatusChangeEventTrb>()
88             .map_err(Error::CastTrb)?;
89         psctrb.set_port_id(port_id);
90         psctrb.set_completion_code(TrbCompletionCode::Success);
91         psctrb.set_trb_type(TrbType::PortStatusChangeEvent);
92         self.add_event(trb)
93     }
94 
95     /// Send command completion trb.
send_command_completion_trb( &mut self, completion_code: TrbCompletionCode, slot_id: u8, trb_addr: GuestAddress, ) -> Result<()>96     pub fn send_command_completion_trb(
97         &mut self,
98         completion_code: TrbCompletionCode,
99         slot_id: u8,
100         trb_addr: GuestAddress,
101     ) -> Result<()> {
102         let mut trb = Trb::new();
103         let ctrb = trb
104             .cast_mut::<CommandCompletionEventTrb>()
105             .map_err(Error::CastTrb)?;
106         ctrb.set_trb_pointer(trb_addr.0);
107         ctrb.set_command_completion_parameter(0);
108         ctrb.set_completion_code(completion_code);
109         ctrb.set_trb_type(TrbType::CommandCompletionEvent);
110         ctrb.set_vf_id(0);
111         ctrb.set_slot_id(slot_id);
112         self.add_event(trb)
113     }
114 
115     /// 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<()>116     pub fn send_transfer_event_trb(
117         &mut self,
118         completion_code: TrbCompletionCode,
119         trb_pointer: u64,
120         transfer_length: u32,
121         event_data: bool,
122         slot_id: u8,
123         endpoint_id: u8,
124     ) -> Result<()> {
125         let mut trb = Trb::new();
126         let event_trb = trb.cast_mut::<TransferEventTrb>().map_err(Error::CastTrb)?;
127         event_trb.set_trb_pointer(trb_pointer);
128         event_trb.set_trb_transfer_length(transfer_length);
129         event_trb.set_completion_code(completion_code);
130         event_trb.set_event_data(event_data.into());
131         event_trb.set_trb_type(TrbType::TransferEvent);
132         event_trb.set_endpoint_id(endpoint_id);
133         event_trb.set_slot_id(slot_id);
134         self.add_event(trb)
135     }
136 
137     /// Enable/Disable this interrupter.
set_enabled(&mut self, enabled: bool) -> Result<()>138     pub fn set_enabled(&mut self, enabled: bool) -> Result<()> {
139         usb_debug!("interrupter set enabled {}", enabled);
140         self.enabled = enabled;
141         self.interrupt_if_needed()
142     }
143 
144     /// Set interrupt moderation.
set_moderation(&mut self, interval: u16, counter: u16) -> Result<()>145     pub fn set_moderation(&mut self, interval: u16, counter: u16) -> Result<()> {
146         // TODO(jkwang) Moderation is not implemented yet.
147         self.moderation_interval = interval;
148         self.moderation_counter = counter;
149         self.interrupt_if_needed()
150     }
151 
152     /// Set event ring seg table size.
set_event_ring_seg_table_size(&mut self, size: u16) -> Result<()>153     pub fn set_event_ring_seg_table_size(&mut self, size: u16) -> Result<()> {
154         usb_debug!("interrupter set seg table size {}", size);
155         self.event_ring
156             .set_seg_table_size(size)
157             .map_err(Error::SetSegTableSize)
158     }
159 
160     /// Set event ring segment table base address.
set_event_ring_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()>161     pub fn set_event_ring_seg_table_base_addr(&mut self, addr: GuestAddress) -> Result<()> {
162         usb_debug!("interrupter set table base addr {:#x}", addr.0);
163         self.event_ring
164             .set_seg_table_base_addr(addr)
165             .map_err(Error::SetSegTableBaseAddr)
166     }
167 
168     /// Set event ring dequeue pointer.
set_event_ring_dequeue_pointer(&mut self, addr: GuestAddress) -> Result<()>169     pub fn set_event_ring_dequeue_pointer(&mut self, addr: GuestAddress) -> Result<()> {
170         usb_debug!("interrupter set dequeue ptr addr {:#x}", addr.0);
171         self.event_ring.set_dequeue_pointer(addr);
172         self.interrupt_if_needed()
173     }
174 
175     /// Set event hander busy.
set_event_handler_busy(&mut self, busy: bool) -> Result<()>176     pub fn set_event_handler_busy(&mut self, busy: bool) -> Result<()> {
177         usb_debug!("set event handler busy {}", busy);
178         self.event_handler_busy = busy;
179         self.interrupt_if_needed()
180     }
181 
182     /// Send and interrupt.
interrupt(&mut self) -> Result<()>183     pub fn interrupt(&mut self) -> Result<()> {
184         usb_debug!("sending interrupt");
185         self.event_handler_busy = true;
186         self.usbsts.set_bits(USB_STS_EVENT_INTERRUPT);
187         self.iman.set_bits(IMAN_INTERRUPT_PENDING);
188         self.erdp.set_bits(ERDP_EVENT_HANDLER_BUSY);
189         self.interrupt_evt.signal().map_err(Error::SendInterrupt)
190     }
191 
interrupt_if_needed(&mut self) -> Result<()>192     fn interrupt_if_needed(&mut self) -> Result<()> {
193         // TODO(dverkamp): re-add !self.event_handler_busy after solving https://crbug.com/1082930
194         if self.enabled && !self.event_ring.is_empty() {
195             self.interrupt()?;
196         }
197         Ok(())
198     }
199 }
200