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, ®s))); 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(®s, 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