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