devices/usb/xhci/
mod.rs

1// Copyright 2018 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#![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
89/// xHCI controller implementation.
90pub 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    // resample handler and device provider only lives on EventLoop to handle corresponding events.
99    // By design, event loop only hold weak reference. We need to keep a strong reference here to
100    // keep it alive.
101    #[allow(dead_code)]
102    intr_resample_handler: Arc<IntrResampleHandler>,
103    #[allow(dead_code)]
104    device_provider: Box<dyn XhciBackendDeviceProvider>,
105    /// USB device files to attach once the guest XHCI driver is ready (writes USBCMD Run bit).
106    pending_usb_devices: Mutex<Vec<std::fs::File>>,
107}
108
109impl Xhci {
110    /// Create a new xHCI controller.
111    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    /// Create a new xHCI controller with USB devices to attach at startup.
129    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, &regs)));
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(&regs, 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        // All the callbacks will hold a weak reference to avoid memory leak. Thos weak upgrade
192        // should never fail.
193        let xhci_weak = Arc::downgrade(xhci);
194        xhci.regs.usbcmd.set_write_cb(move |val: u32| {
195            // All the weak reference upgrade should never fail. xhci hold reference to the
196            // registers, callback won't be invoked if xhci is gone.
197            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    // Callback for usbcmd register write.
280    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        // Enable interrupter if needed.
297        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        // Attach any pending USB devices now that the guest XHCI driver is running.
306        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    // Callback for crcr register write.
320    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    // Callback for portsc register write.
335    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        // xHCI spec 4.19.5. Note: we might want to change this logic if we support USB 3.0.
340        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    // Callback for doorbell register write.
357    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            // First doorbell is for command ring.
363            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    // Callback for iman register write.
381    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    // Callback for imod register write.
392    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    // Callback for erstsz register write.
404    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    // Callback for erstba register write.
413    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    // Callback for erdp register write.
424    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}