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 pending_usb_devices: Mutex<Vec<std::fs::File>>,
107}
108
109impl Xhci {
110 pub fn new(
112 fail_handle: Arc<dyn FailHandle>,
113 mem: GuestMemory,
114 device_provider: Box<dyn XhciBackendDeviceProvider>,
115 interrupt_evt: IrqLevelEvent,
116 regs: XhciRegs,
117 ) -> Result<Arc<Self>> {
118 Self::new_with_devices(
119 fail_handle,
120 mem,
121 device_provider,
122 interrupt_evt,
123 regs,
124 Vec::new(),
125 )
126 }
127
128 pub fn new_with_devices(
130 fail_handle: Arc<dyn FailHandle>,
131 mem: GuestMemory,
132 mut device_provider: Box<dyn XhciBackendDeviceProvider>,
133 interrupt_evt: IrqLevelEvent,
134 regs: XhciRegs,
135 initial_usb_devices: Vec<std::fs::File>,
136 ) -> Result<Arc<Self>> {
137 let (event_loop, join_handle) =
138 EventLoop::start("xhci".to_string(), Some(fail_handle.clone()))
139 .map_err(Error::StartEventLoop)?;
140 let irq_evt = interrupt_evt
141 .get_trigger()
142 .try_clone()
143 .map_err(Error::CloneIrqEvent)?;
144 let interrupter = Arc::new(Mutex::new(Interrupter::new(mem.clone(), irq_evt, ®s)));
145 let event_loop = Arc::new(event_loop);
146 let irq_resample_evt = interrupt_evt
147 .get_resample()
148 .try_clone()
149 .map_err(Error::CloneResampleEvent)?;
150 let intr_resample_handler =
151 IntrResampleHandler::start(&event_loop, interrupter.clone(), irq_resample_evt)
152 .ok_or(Error::StartResampleHandler)?;
153 let hub = Arc::new(UsbHub::new(®s, interrupter.clone()));
154
155 device_provider
156 .start(fail_handle.clone(), event_loop.clone(), hub.clone())
157 .map_err(Error::StartProvider)?;
158
159 let device_slots = DeviceSlots::new(
160 fail_handle.clone(),
161 regs.dcbaap.clone(),
162 hub,
163 interrupter.clone(),
164 event_loop.clone(),
165 mem.clone(),
166 );
167 let command_ring_controller = CommandRingController::new(
168 mem,
169 event_loop.clone(),
170 device_slots.clone(),
171 interrupter.clone(),
172 )
173 .map_err(Error::CreateCommandRingController)?;
174 let xhci = Arc::new(Xhci {
175 fail_handle,
176 regs,
177 intr_resample_handler,
178 interrupter,
179 command_ring_controller,
180 device_slots,
181 device_provider,
182 event_loop,
183 event_loop_join_handle: Some(join_handle),
184 pending_usb_devices: Mutex::new(initial_usb_devices),
185 });
186 Self::init_reg_callbacks(&xhci);
187 Ok(xhci)
188 }
189
190 fn init_reg_callbacks(xhci: &Arc<Xhci>) {
191 let xhci_weak = Arc::downgrade(xhci);
194 xhci.regs.usbcmd.set_write_cb(move |val: u32| {
195 let xhci = xhci_weak.upgrade().unwrap();
198 let r = xhci.usbcmd_callback(val);
199 xhci.handle_register_callback_result(r, 0)
200 });
201
202 let xhci_weak = Arc::downgrade(xhci);
203 xhci.regs.crcr.set_write_cb(move |val: u64| {
204 let xhci = xhci_weak.upgrade().unwrap();
205 xhci.crcr_callback(val)
206 });
207
208 for i in 0..xhci.regs.portsc.len() {
209 let xhci_weak = Arc::downgrade(xhci);
210 xhci.regs.portsc[i].set_write_cb(move |val: u32| {
211 let xhci = xhci_weak.upgrade().unwrap();
212 let r = xhci.portsc_callback(i as u32, val);
213 xhci.handle_register_callback_result(r, 0)
214 });
215 }
216
217 for i in 0..xhci.regs.doorbells.len() {
218 let xhci_weak = Arc::downgrade(xhci);
219 xhci.regs.doorbells[i].set_write_cb(move |val: u32| {
220 let xhci = xhci_weak.upgrade().unwrap();
221 let r = xhci.doorbell_callback(i as u32, val);
222 xhci.handle_register_callback_result(r, ());
223 val
224 });
225 }
226
227 let xhci_weak = Arc::downgrade(xhci);
228 xhci.regs.iman.set_write_cb(move |val: u32| {
229 let xhci = xhci_weak.upgrade().unwrap();
230 let r = xhci.iman_callback(val);
231 xhci.handle_register_callback_result(r, ());
232 val
233 });
234
235 let xhci_weak = Arc::downgrade(xhci);
236 xhci.regs.imod.set_write_cb(move |val: u32| {
237 let xhci = xhci_weak.upgrade().unwrap();
238 let r = xhci.imod_callback(val);
239 xhci.handle_register_callback_result(r, ());
240 val
241 });
242
243 let xhci_weak = Arc::downgrade(xhci);
244 xhci.regs.erstsz.set_write_cb(move |val: u32| {
245 let xhci = xhci_weak.upgrade().unwrap();
246 let r = xhci.erstsz_callback(val);
247 xhci.handle_register_callback_result(r, ());
248 val
249 });
250
251 let xhci_weak = Arc::downgrade(xhci);
252 xhci.regs.erstba.set_write_cb(move |val: u64| {
253 let xhci = xhci_weak.upgrade().unwrap();
254 let r = xhci.erstba_callback(val);
255 xhci.handle_register_callback_result(r, ());
256 val
257 });
258
259 let xhci_weak = Arc::downgrade(xhci);
260 xhci.regs.erdp.set_write_cb(move |val: u64| {
261 let xhci = xhci_weak.upgrade().unwrap();
262 let r = xhci.erdp_callback(val);
263 xhci.handle_register_callback_result(r, ());
264 val
265 });
266 }
267
268 fn handle_register_callback_result<T>(&self, r: Result<T>, t: T) -> T {
269 match r {
270 Ok(v) => v,
271 Err(e) => {
272 error!("xhci controller failed: {}", e);
273 self.fail_handle.fail();
274 t
275 }
276 }
277 }
278
279 fn usbcmd_callback(&self, value: u32) -> Result<u32> {
281 if (value & USB_CMD_RESET) > 0 {
282 debug!("xhci_controller: reset controller");
283 self.reset();
284 return Ok(value & (!USB_CMD_RESET));
285 }
286
287 if (value & USB_CMD_RUNSTOP) > 0 {
288 debug!("xhci_controller: clear halt bits");
289 self.regs.usbsts.clear_bits(USB_STS_HALTED);
290 } else {
291 debug!("xhci_controller: halt device");
292 self.halt();
293 self.regs.crcr.clear_bits(CRCR_COMMAND_RING_RUNNING);
294 }
295
296 let enabled = (value & USB_CMD_INTERRUPTER_ENABLE) > 0
298 && (self.regs.iman.get_value() & IMAN_INTERRUPT_ENABLE) > 0;
299 debug!("xhci_controller: interrupter enable?: {}", enabled);
300 self.interrupter
301 .lock()
302 .set_enabled(enabled)
303 .map_err(Error::EnableInterrupter)?;
304
305 if (value & USB_CMD_RUNSTOP) > 0 {
307 let mut pending = self.pending_usb_devices.lock();
308 if !pending.is_empty() {
309 let files: Vec<std::fs::File> = pending.drain(..).collect();
310 drop(pending);
311 for file in files {
312 self.device_provider.attach_device(file);
313 }
314 }
315 }
316 Ok(value)
317 }
318
319 fn crcr_callback(&self, value: u64) -> u64 {
321 let _trace = cros_tracing::trace_event!(USB, "crcr_callback", value);
322 if (self.regs.crcr.get_value() & CRCR_COMMAND_RING_RUNNING) == 0 {
323 self.command_ring_controller
324 .set_dequeue_pointer(GuestAddress(value & CRCR_COMMAND_RING_POINTER));
325 self.command_ring_controller
326 .set_consumer_cycle_state((value & CRCR_RING_CYCLE_STATE) > 0);
327 value
328 } else {
329 error!("Write to crcr while command ring is running");
330 self.regs.crcr.get_value()
331 }
332 }
333
334 fn portsc_callback(&self, index: u32, value: u32) -> Result<u32> {
336 let _trace = cros_tracing::trace_event!(USB, "portsc_callback", index, value);
337 let mut value = value;
338 let port_id = (index + 1) as u8;
339 if (value & PORTSC_PORT_RESET) > 0 || (value & PORTSC_WARM_PORT_RESET) > 0 {
341 self.device_slots
342 .reset_port(port_id)
343 .map_err(|_| Error::ResetPort)?;
344 value &= !PORTSC_PORT_LINK_STATE_MASK;
345 value &= !PORTSC_PORT_RESET;
346 value |= PORTSC_PORT_ENABLED;
347 value |= PORTSC_PORT_RESET_CHANGE;
348 self.interrupter
349 .lock()
350 .send_port_status_change_trb(port_id)
351 .map_err(Error::SendInterrupt)?;
352 }
353 Ok(value)
354 }
355
356 fn doorbell_callback(&self, index: u32, value: u32) -> Result<()> {
358 let _trace = cros_tracing::trace_event!(USB, "doorbell_callback", index, value);
359 let target = (value & DOORBELL_TARGET) as u8;
360 let stream_id: u16 = (value >> DOORBELL_STREAM_ID_OFFSET) as u16;
361 if (self.regs.usbcmd.get_value() & USB_CMD_RUNSTOP) > 0 {
362 if index == 0 {
364 if target != 0 || stream_id != 0 {
365 return Ok(());
366 }
367 self.regs.crcr.set_bits(CRCR_COMMAND_RING_RUNNING);
368 self.command_ring_controller.start();
369 } else {
370 self.device_slots
371 .slot(index as u8)
372 .ok_or(Error::GetDeviceSlot(index as u8))?
373 .ring_doorbell(target, stream_id)
374 .map_err(Error::RingDoorbell)?;
375 }
376 }
377 Ok(())
378 }
379
380 fn iman_callback(&self, value: u32) -> Result<()> {
382 let _trace = cros_tracing::trace_event!(USB, "iman_callback", value);
383 let enabled = ((value & IMAN_INTERRUPT_ENABLE) > 0)
384 && ((self.regs.usbcmd.get_value() & USB_CMD_INTERRUPTER_ENABLE) > 0);
385 self.interrupter
386 .lock()
387 .set_enabled(enabled)
388 .map_err(Error::EnableInterrupter)
389 }
390
391 fn imod_callback(&self, value: u32) -> Result<()> {
393 let _trace = cros_tracing::trace_event!(USB, "imod_callback", value);
394 self.interrupter
395 .lock()
396 .set_moderation(
397 (value & IMOD_INTERRUPT_MODERATION_INTERVAL) as u16,
398 (value >> IMOD_INTERRUPT_MODERATION_COUNTER_OFFSET) as u16,
399 )
400 .map_err(Error::SetModeration)
401 }
402
403 fn erstsz_callback(&self, value: u32) -> Result<()> {
405 let _trace = cros_tracing::trace_event!(USB, "erstsz_callback", value);
406 self.interrupter
407 .lock()
408 .set_event_ring_seg_table_size((value & ERSTSZ_SEGMENT_TABLE_SIZE) as u16)
409 .map_err(Error::SetupEventRing)
410 }
411
412 fn erstba_callback(&self, value: u64) -> Result<()> {
414 let _trace = cros_tracing::trace_event!(USB, "erstba_callback", value);
415 self.interrupter
416 .lock()
417 .set_event_ring_seg_table_base_addr(GuestAddress(
418 value & ERSTBA_SEGMENT_TABLE_BASE_ADDRESS,
419 ))
420 .map_err(Error::SetupEventRing)
421 }
422
423 fn erdp_callback(&self, value: u64) -> Result<()> {
425 let _trace = cros_tracing::trace_event!(USB, "erdp_callback", value);
426 self.interrupter
427 .lock()
428 .set_event_ring_dequeue_pointer(
429 GuestAddress(value & ERDP_EVENT_RING_DEQUEUE_POINTER),
430 (value & ERDP_EVENT_HANDLER_BUSY) > 0,
431 )
432 .map_err(Error::SetupEventRing)
433 }
434
435 fn reset(&self) {
436 self.regs.usbsts.set_bits(USB_STS_CONTROLLER_NOT_READY);
437 let usbsts = self.regs.usbsts.clone();
438 self.device_slots.stop_all_and_reset(move || {
439 usbsts.clear_bits(USB_STS_CONTROLLER_NOT_READY);
440 });
441 }
442
443 fn halt(&self) {
444 let usbsts = self.regs.usbsts.clone();
445 self.device_slots
446 .stop_all(RingBufferStopCallback::new(move || {
447 usbsts.set_bits(USB_STS_HALTED);
448 }));
449 }
450}
451
452impl Drop for Xhci {
453 fn drop(&mut self) {
454 self.event_loop.stop();
455 if let Some(join_handle) = self.event_loop_join_handle.take() {
456 let _ = join_handle.join();
457 }
458 }
459}