1#![allow(clippy::result_large_err)]
6
7mod command_ring_controller;
8mod device_slot;
9mod event_ring;
10mod interrupter;
11mod intr_resample_handler;
12mod ring_buffer;
13mod ring_buffer_controller;
14mod ring_buffer_stop_cb;
15mod transfer_ring_controller;
16#[allow(dead_code)]
17mod xhci_abi;
18#[allow(dead_code)]
19mod xhci_regs;
20
21pub mod scatter_gather_buffer;
22pub mod usb_hub;
23pub mod xhci_backend_device;
24pub mod xhci_backend_device_provider;
25pub mod xhci_controller;
26pub mod xhci_transfer;
27
28use std::sync::Arc;
29use std::thread;
30
31use base::debug;
32use base::error;
33use remain::sorted;
34use sync::Mutex;
35use thiserror::Error;
36use vm_memory::GuestAddress;
37use vm_memory::GuestMemory;
38
39use crate::usb::backend::error::Error as BackendProviderError;
40use crate::usb::xhci::command_ring_controller::CommandRingController;
41use crate::usb::xhci::command_ring_controller::CommandRingControllerError;
42use crate::usb::xhci::device_slot::DeviceSlots;
43use crate::usb::xhci::device_slot::Error as DeviceSlotError;
44use crate::usb::xhci::interrupter::Error as InterrupterError;
45use crate::usb::xhci::interrupter::Interrupter;
46use crate::usb::xhci::intr_resample_handler::IntrResampleHandler;
47use crate::usb::xhci::ring_buffer_stop_cb::RingBufferStopCallback;
48use crate::usb::xhci::usb_hub::UsbHub;
49use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
50use crate::usb::xhci::xhci_regs::*;
51use crate::utils::Error as UtilsError;
52use crate::utils::EventLoop;
53use crate::utils::FailHandle;
54use crate::IrqLevelEvent;
55
56#[sorted]
57#[derive(Error, Debug)]
58pub enum Error {
59 #[error("failed to clone irq event: {0}")]
60 CloneIrqEvent(base::Error),
61 #[error("failed to clone resample event: {0}")]
62 CloneResampleEvent(base::Error),
63 #[error("failed to create command ring controller: {0}")]
64 CreateCommandRingController(CommandRingControllerError),
65 #[error("failed to enable interrupter: {0}")]
66 EnableInterrupter(InterrupterError),
67 #[error("failed to get device slot: {0}")]
68 GetDeviceSlot(u8),
69 #[error("failed to reset port")]
70 ResetPort,
71 #[error("failed to ring doorbell: {0}")]
72 RingDoorbell(DeviceSlotError),
73 #[error("failed to send interrupt: {0}")]
74 SendInterrupt(InterrupterError),
75 #[error("failed to set interrupter moderation: {0}")]
76 SetModeration(InterrupterError),
77 #[error("failed to setup event ring and event handler busy: {0}")]
78 SetupEventRing(InterrupterError),
79 #[error("failed to start event loop: {0}")]
80 StartEventLoop(UtilsError),
81 #[error("failed to start backend provider: {0}")]
82 StartProvider(BackendProviderError),
83 #[error("failed to start resample handler")]
84 StartResampleHandler,
85}
86
87type Result<T> = std::result::Result<T, Error>;
88
89pub struct Xhci {
91 fail_handle: Arc<dyn FailHandle>,
92 regs: XhciRegs,
93 interrupter: Arc<Mutex<Interrupter>>,
94 command_ring_controller: Arc<CommandRingController>,
95 device_slots: DeviceSlots,
96 event_loop: Arc<EventLoop>,
97 event_loop_join_handle: Option<thread::JoinHandle<()>>,
98 #[allow(dead_code)]
102 intr_resample_handler: Arc<IntrResampleHandler>,
103 #[allow(dead_code)]
104 device_provider: Box<dyn XhciBackendDeviceProvider>,
105}
106
107impl Xhci {
108 pub fn new(
110 fail_handle: Arc<dyn FailHandle>,
111 mem: GuestMemory,
112 device_provider: Box<dyn XhciBackendDeviceProvider>,
113 interrupt_evt: IrqLevelEvent,
114 regs: XhciRegs,
115 ) -> Result<Arc<Self>> {
116 let (event_loop, join_handle) =
117 EventLoop::start("xhci".to_string(), Some(fail_handle.clone()))
118 .map_err(Error::StartEventLoop)?;
119 let irq_evt = interrupt_evt
120 .get_trigger()
121 .try_clone()
122 .map_err(Error::CloneIrqEvent)?;
123 let interrupter = Arc::new(Mutex::new(Interrupter::new(mem.clone(), irq_evt, ®s)));
124 let event_loop = Arc::new(event_loop);
125 let irq_resample_evt = interrupt_evt
126 .get_resample()
127 .try_clone()
128 .map_err(Error::CloneResampleEvent)?;
129 let intr_resample_handler =
130 IntrResampleHandler::start(&event_loop, interrupter.clone(), irq_resample_evt)
131 .ok_or(Error::StartResampleHandler)?;
132 let hub = Arc::new(UsbHub::new(®s, interrupter.clone()));
133
134 let mut device_provider = device_provider;
135 device_provider
136 .start(fail_handle.clone(), event_loop.clone(), hub.clone())
137 .map_err(Error::StartProvider)?;
138
139 let device_slots = DeviceSlots::new(
140 fail_handle.clone(),
141 regs.dcbaap.clone(),
142 hub,
143 interrupter.clone(),
144 event_loop.clone(),
145 mem.clone(),
146 );
147 let command_ring_controller = CommandRingController::new(
148 mem,
149 event_loop.clone(),
150 device_slots.clone(),
151 interrupter.clone(),
152 )
153 .map_err(Error::CreateCommandRingController)?;
154 let xhci = Arc::new(Xhci {
155 fail_handle,
156 regs,
157 intr_resample_handler,
158 interrupter,
159 command_ring_controller,
160 device_slots,
161 device_provider,
162 event_loop,
163 event_loop_join_handle: Some(join_handle),
164 });
165 Self::init_reg_callbacks(&xhci);
166 Ok(xhci)
167 }
168
169 fn init_reg_callbacks(xhci: &Arc<Xhci>) {
170 let xhci_weak = Arc::downgrade(xhci);
173 xhci.regs.usbcmd.set_write_cb(move |val: u32| {
174 let xhci = xhci_weak.upgrade().unwrap();
177 let r = xhci.usbcmd_callback(val);
178 xhci.handle_register_callback_result(r, 0)
179 });
180
181 let xhci_weak = Arc::downgrade(xhci);
182 xhci.regs.crcr.set_write_cb(move |val: u64| {
183 let xhci = xhci_weak.upgrade().unwrap();
184 xhci.crcr_callback(val)
185 });
186
187 for i in 0..xhci.regs.portsc.len() {
188 let xhci_weak = Arc::downgrade(xhci);
189 xhci.regs.portsc[i].set_write_cb(move |val: u32| {
190 let xhci = xhci_weak.upgrade().unwrap();
191 let r = xhci.portsc_callback(i as u32, val);
192 xhci.handle_register_callback_result(r, 0)
193 });
194 }
195
196 for i in 0..xhci.regs.doorbells.len() {
197 let xhci_weak = Arc::downgrade(xhci);
198 xhci.regs.doorbells[i].set_write_cb(move |val: u32| {
199 let xhci = xhci_weak.upgrade().unwrap();
200 let r = xhci.doorbell_callback(i as u32, val);
201 xhci.handle_register_callback_result(r, ());
202 val
203 });
204 }
205
206 let xhci_weak = Arc::downgrade(xhci);
207 xhci.regs.iman.set_write_cb(move |val: u32| {
208 let xhci = xhci_weak.upgrade().unwrap();
209 let r = xhci.iman_callback(val);
210 xhci.handle_register_callback_result(r, ());
211 val
212 });
213
214 let xhci_weak = Arc::downgrade(xhci);
215 xhci.regs.imod.set_write_cb(move |val: u32| {
216 let xhci = xhci_weak.upgrade().unwrap();
217 let r = xhci.imod_callback(val);
218 xhci.handle_register_callback_result(r, ());
219 val
220 });
221
222 let xhci_weak = Arc::downgrade(xhci);
223 xhci.regs.erstsz.set_write_cb(move |val: u32| {
224 let xhci = xhci_weak.upgrade().unwrap();
225 let r = xhci.erstsz_callback(val);
226 xhci.handle_register_callback_result(r, ());
227 val
228 });
229
230 let xhci_weak = Arc::downgrade(xhci);
231 xhci.regs.erstba.set_write_cb(move |val: u64| {
232 let xhci = xhci_weak.upgrade().unwrap();
233 let r = xhci.erstba_callback(val);
234 xhci.handle_register_callback_result(r, ());
235 val
236 });
237
238 let xhci_weak = Arc::downgrade(xhci);
239 xhci.regs.erdp.set_write_cb(move |val: u64| {
240 let xhci = xhci_weak.upgrade().unwrap();
241 let r = xhci.erdp_callback(val);
242 xhci.handle_register_callback_result(r, ());
243 val
244 });
245 }
246
247 fn handle_register_callback_result<T>(&self, r: Result<T>, t: T) -> T {
248 match r {
249 Ok(v) => v,
250 Err(e) => {
251 error!("xhci controller failed: {}", e);
252 self.fail_handle.fail();
253 t
254 }
255 }
256 }
257
258 fn usbcmd_callback(&self, value: u32) -> Result<u32> {
260 if (value & USB_CMD_RESET) > 0 {
261 debug!("xhci_controller: reset controller");
262 self.reset();
263 return Ok(value & (!USB_CMD_RESET));
264 }
265
266 if (value & USB_CMD_RUNSTOP) > 0 {
267 debug!("xhci_controller: clear halt bits");
268 self.regs.usbsts.clear_bits(USB_STS_HALTED);
269 } else {
270 debug!("xhci_controller: halt device");
271 self.halt();
272 self.regs.crcr.clear_bits(CRCR_COMMAND_RING_RUNNING);
273 }
274
275 let enabled = (value & USB_CMD_INTERRUPTER_ENABLE) > 0
277 && (self.regs.iman.get_value() & IMAN_INTERRUPT_ENABLE) > 0;
278 debug!("xhci_controller: interrupter enable?: {}", enabled);
279 self.interrupter
280 .lock()
281 .set_enabled(enabled)
282 .map_err(Error::EnableInterrupter)?;
283 Ok(value)
284 }
285
286 fn crcr_callback(&self, value: u64) -> u64 {
288 let _trace = cros_tracing::trace_event!(USB, "crcr_callback", value);
289 if (self.regs.crcr.get_value() & CRCR_COMMAND_RING_RUNNING) == 0 {
290 self.command_ring_controller
291 .set_dequeue_pointer(GuestAddress(value & CRCR_COMMAND_RING_POINTER));
292 self.command_ring_controller
293 .set_consumer_cycle_state((value & CRCR_RING_CYCLE_STATE) > 0);
294 value
295 } else {
296 error!("Write to crcr while command ring is running");
297 self.regs.crcr.get_value()
298 }
299 }
300
301 fn portsc_callback(&self, index: u32, value: u32) -> Result<u32> {
303 let _trace = cros_tracing::trace_event!(USB, "portsc_callback", index, value);
304 let mut value = value;
305 let port_id = (index + 1) as u8;
306 if (value & PORTSC_PORT_RESET) > 0 || (value & PORTSC_WARM_PORT_RESET) > 0 {
308 self.device_slots
309 .reset_port(port_id)
310 .map_err(|_| Error::ResetPort)?;
311 value &= !PORTSC_PORT_LINK_STATE_MASK;
312 value &= !PORTSC_PORT_RESET;
313 value |= PORTSC_PORT_ENABLED;
314 value |= PORTSC_PORT_RESET_CHANGE;
315 self.interrupter
316 .lock()
317 .send_port_status_change_trb(port_id)
318 .map_err(Error::SendInterrupt)?;
319 }
320 Ok(value)
321 }
322
323 fn doorbell_callback(&self, index: u32, value: u32) -> Result<()> {
325 let _trace = cros_tracing::trace_event!(USB, "doorbell_callback", index, value);
326 let target = (value & DOORBELL_TARGET) as u8;
327 let stream_id: u16 = (value >> DOORBELL_STREAM_ID_OFFSET) as u16;
328 if (self.regs.usbcmd.get_value() & USB_CMD_RUNSTOP) > 0 {
329 if index == 0 {
331 if target != 0 || stream_id != 0 {
332 return Ok(());
333 }
334 self.regs.crcr.set_bits(CRCR_COMMAND_RING_RUNNING);
335 self.command_ring_controller.start();
336 } else {
337 self.device_slots
338 .slot(index as u8)
339 .ok_or(Error::GetDeviceSlot(index as u8))?
340 .ring_doorbell(target, stream_id)
341 .map_err(Error::RingDoorbell)?;
342 }
343 }
344 Ok(())
345 }
346
347 fn iman_callback(&self, value: u32) -> Result<()> {
349 let _trace = cros_tracing::trace_event!(USB, "iman_callback", value);
350 let enabled = ((value & IMAN_INTERRUPT_ENABLE) > 0)
351 && ((self.regs.usbcmd.get_value() & USB_CMD_INTERRUPTER_ENABLE) > 0);
352 self.interrupter
353 .lock()
354 .set_enabled(enabled)
355 .map_err(Error::EnableInterrupter)
356 }
357
358 fn imod_callback(&self, value: u32) -> Result<()> {
360 let _trace = cros_tracing::trace_event!(USB, "imod_callback", value);
361 self.interrupter
362 .lock()
363 .set_moderation(
364 (value & IMOD_INTERRUPT_MODERATION_INTERVAL) as u16,
365 (value >> IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET) as u16,
366 )
367 .map_err(Error::SetModeration)
368 }
369
370 fn erstsz_callback(&self, value: u32) -> Result<()> {
372 let _trace = cros_tracing::trace_event!(USB, "erstsz_callback", value);
373 self.interrupter
374 .lock()
375 .set_event_ring_seg_table_size((value & ERSTSZ_SEGMENT_TABLE_SIZE) as u16)
376 .map_err(Error::SetupEventRing)
377 }
378
379 fn erstba_callback(&self, value: u64) -> Result<()> {
381 let _trace = cros_tracing::trace_event!(USB, "erstba_callback", value);
382 self.interrupter
383 .lock()
384 .set_event_ring_seg_table_base_addr(GuestAddress(
385 value & ERSTBA_SEGMENT_TABLE_BASE_ADDRESS,
386 ))
387 .map_err(Error::SetupEventRing)
388 }
389
390 fn erdp_callback(&self, value: u64) -> Result<()> {
392 let _trace = cros_tracing::trace_event!(USB, "erdp_callback", value);
393 self.interrupter
394 .lock()
395 .set_event_ring_dequeue_pointer(
396 GuestAddress(value & ERDP_EVENT_RING_DEQUEUE_POINTER),
397 (value & ERDP_EVENT_HANDLER_BUSY) > 0,
398 )
399 .map_err(Error::SetupEventRing)
400 }
401
402 fn reset(&self) {
403 self.regs.usbsts.set_bits(USB_STS_CONTROLLER_NOT_READY);
404 let usbsts = self.regs.usbsts.clone();
405 self.device_slots.stop_all_and_reset(move || {
406 usbsts.clear_bits(USB_STS_CONTROLLER_NOT_READY);
407 });
408 }
409
410 fn halt(&self) {
411 let usbsts = self.regs.usbsts.clone();
412 self.device_slots
413 .stop_all(RingBufferStopCallback::new(move || {
414 usbsts.set_bits(USB_STS_HALTED);
415 }));
416 }
417}
418
419impl Drop for Xhci {
420 fn drop(&mut self) {
421 self.event_loop.stop();
422 if let Some(join_handle) = self.event_loop_join_handle.take() {
423 let _ = join_handle.join();
424 }
425 }
426}