1 // Copyright 2019 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use crate::pci::{ 6 PciBarConfiguration, PciClassCode, PciConfiguration, PciDevice, PciDeviceError, PciHeaderType, 7 PciInterruptPin, PciProgrammingInterface, PciSerialBusSubClass, 8 }; 9 use crate::register_space::{Register, RegisterSpace}; 10 use crate::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider; 11 use crate::usb::xhci::xhci::Xhci; 12 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider; 13 use crate::usb::xhci::xhci_regs::{init_xhci_mmio_space_and_regs, XhciRegs}; 14 use crate::utils::FailHandle; 15 use resources::{Alloc, SystemAllocator}; 16 use std::mem; 17 use std::os::unix::io::RawFd; 18 use std::sync::atomic::{AtomicBool, Ordering}; 19 use std::sync::Arc; 20 use sys_util::{error, EventFd, GuestMemory}; 21 22 const XHCI_BAR0_SIZE: u64 = 0x10000; 23 24 #[derive(Clone, Copy)] 25 enum UsbControllerProgrammingInterface { 26 Usb3HostController = 0x30, 27 } 28 29 impl PciProgrammingInterface for UsbControllerProgrammingInterface { get_register_value(&self) -> u830 fn get_register_value(&self) -> u8 { 31 *self as u8 32 } 33 } 34 35 /// Use this handle to fail xhci controller. 36 pub struct XhciFailHandle { 37 usbcmd: Register<u32>, 38 usbsts: Register<u32>, 39 xhci_failed: AtomicBool, 40 } 41 42 impl XhciFailHandle { new(regs: &XhciRegs) -> XhciFailHandle43 pub fn new(regs: &XhciRegs) -> XhciFailHandle { 44 XhciFailHandle { 45 usbcmd: regs.usbcmd.clone(), 46 usbsts: regs.usbsts.clone(), 47 xhci_failed: AtomicBool::new(false), 48 } 49 } 50 } 51 52 impl FailHandle for XhciFailHandle { 53 /// Fail this controller. Will set related registers and flip failed bool. fail(&self)54 fn fail(&self) { 55 // set run/stop to stop. 56 const USBCMD_STOPPED: u32 = 0; 57 // Set host system error bit. 58 const USBSTS_HSE: u32 = 1 << 2; 59 self.usbcmd.set_value(USBCMD_STOPPED); 60 self.usbsts.set_value(USBSTS_HSE); 61 62 self.xhci_failed.store(true, Ordering::SeqCst); 63 error!("xhci controller stopped working"); 64 } 65 66 /// Returns true if xhci is already failed. failed(&self) -> bool67 fn failed(&self) -> bool { 68 self.xhci_failed.load(Ordering::SeqCst) 69 } 70 } 71 72 // Xhci controller should be created with backend device provider. Then irq should be assigned 73 // before initialized. We are not making `failed` as a state here to optimize performance. Cause we 74 // need to set failed in other threads. 75 enum XhciControllerState { 76 Unknown, 77 Created { 78 device_provider: HostBackendDeviceProvider, 79 }, 80 IrqAssigned { 81 device_provider: HostBackendDeviceProvider, 82 irq_evt: EventFd, 83 irq_resample_evt: EventFd, 84 }, 85 Initialized { 86 mmio: RegisterSpace, 87 // Xhci init could fail. 88 #[allow(dead_code)] 89 xhci: Option<Arc<Xhci>>, 90 fail_handle: Arc<dyn FailHandle>, 91 }, 92 } 93 94 /// xHCI PCI interface implementation. 95 pub struct XhciController { 96 config_regs: PciConfiguration, 97 pci_bus_dev: Option<(u8, u8)>, 98 mem: GuestMemory, 99 bar0: u64, // bar0 in config_regs will be changed by guest. Not sure why. 100 state: XhciControllerState, 101 } 102 103 impl XhciController { 104 /// Create new xhci controller. new(mem: GuestMemory, usb_provider: HostBackendDeviceProvider) -> Self105 pub fn new(mem: GuestMemory, usb_provider: HostBackendDeviceProvider) -> Self { 106 let config_regs = PciConfiguration::new( 107 0x01b73, // fresco logic, (google = 0x1ae0) 108 0x1000, // fresco logic pdk. This chip has broken msi. See kernel xhci-pci.c 109 PciClassCode::SerialBusController, 110 &PciSerialBusSubClass::USB, 111 Some(&UsbControllerProgrammingInterface::Usb3HostController), 112 PciHeaderType::Device, 113 0, 114 0, 115 ); 116 XhciController { 117 config_regs, 118 pci_bus_dev: None, 119 mem, 120 bar0: 0, 121 state: XhciControllerState::Created { 122 device_provider: usb_provider, 123 }, 124 } 125 } 126 127 /// Init xhci controller when it's forked. init_when_forked(&mut self)128 pub fn init_when_forked(&mut self) { 129 match mem::replace(&mut self.state, XhciControllerState::Unknown) { 130 XhciControllerState::IrqAssigned { 131 device_provider, 132 irq_evt, 133 irq_resample_evt, 134 } => { 135 let (mmio, regs) = init_xhci_mmio_space_and_regs(); 136 let fail_handle: Arc<dyn FailHandle> = Arc::new(XhciFailHandle::new(®s)); 137 let xhci = match Xhci::new( 138 fail_handle.clone(), 139 self.mem.clone(), 140 device_provider, 141 irq_evt, 142 irq_resample_evt, 143 regs, 144 ) { 145 Ok(xhci) => Some(xhci), 146 Err(_) => { 147 error!("fail to init xhci"); 148 fail_handle.fail(); 149 return; 150 } 151 }; 152 153 self.state = XhciControllerState::Initialized { 154 mmio, 155 xhci, 156 fail_handle, 157 } 158 } 159 _ => { 160 error!("xhci controller is in a wrong state"); 161 return; 162 } 163 } 164 } 165 } 166 167 impl PciDevice for XhciController { debug_label(&self) -> String168 fn debug_label(&self) -> String { 169 "xhci controller".to_owned() 170 } 171 assign_bus_dev(&mut self, bus: u8, device: u8)172 fn assign_bus_dev(&mut self, bus: u8, device: u8) { 173 self.pci_bus_dev = Some((bus, device)); 174 } 175 keep_fds(&self) -> Vec<RawFd>176 fn keep_fds(&self) -> Vec<RawFd> { 177 match &self.state { 178 XhciControllerState::Created { device_provider } => device_provider.keep_fds(), 179 _ => { 180 error!("xhci controller is in a wrong state"); 181 vec![] 182 } 183 } 184 } 185 assign_irq( &mut self, irq_evt: EventFd, irq_resample_evt: EventFd, irq_num: u32, irq_pin: PciInterruptPin, )186 fn assign_irq( 187 &mut self, 188 irq_evt: EventFd, 189 irq_resample_evt: EventFd, 190 irq_num: u32, 191 irq_pin: PciInterruptPin, 192 ) { 193 match mem::replace(&mut self.state, XhciControllerState::Unknown) { 194 XhciControllerState::Created { device_provider } => { 195 self.config_regs.set_irq(irq_num as u8, irq_pin); 196 self.state = XhciControllerState::IrqAssigned { 197 device_provider, 198 irq_evt, 199 irq_resample_evt, 200 } 201 } 202 _ => { 203 error!("xhci controller is in a wrong state"); 204 return; 205 } 206 } 207 } 208 allocate_io_bars( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError>209 fn allocate_io_bars( 210 &mut self, 211 resources: &mut SystemAllocator, 212 ) -> std::result::Result<Vec<(u64, u64)>, PciDeviceError> { 213 let (bus, dev) = self 214 .pci_bus_dev 215 .expect("assign_bus_dev must be called prior to allocate_io_bars"); 216 // xHCI spec 5.2.1. 217 let bar0_addr = resources 218 .mmio_allocator() 219 .allocate( 220 XHCI_BAR0_SIZE, 221 Alloc::PciBar { bus, dev, bar: 0 }, 222 "xhci_bar0".to_string(), 223 ) 224 .map_err(|e| PciDeviceError::IoAllocationFailed(XHCI_BAR0_SIZE, e))?; 225 let bar0_config = PciBarConfiguration::default() 226 .set_register_index(0) 227 .set_address(bar0_addr) 228 .set_size(XHCI_BAR0_SIZE); 229 self.config_regs 230 .add_pci_bar(&bar0_config) 231 .map_err(|e| PciDeviceError::IoRegistrationFailed(bar0_addr, e))?; 232 self.bar0 = bar0_addr; 233 Ok(vec![(bar0_addr, XHCI_BAR0_SIZE)]) 234 } 235 config_registers(&self) -> &PciConfiguration236 fn config_registers(&self) -> &PciConfiguration { 237 &self.config_regs 238 } 239 config_registers_mut(&mut self) -> &mut PciConfiguration240 fn config_registers_mut(&mut self) -> &mut PciConfiguration { 241 &mut self.config_regs 242 } 243 read_bar(&mut self, addr: u64, data: &mut [u8])244 fn read_bar(&mut self, addr: u64, data: &mut [u8]) { 245 let bar0 = self.bar0; 246 if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE { 247 return; 248 } 249 match &self.state { 250 XhciControllerState::Initialized { mmio, .. } => { 251 // Read bar would still work even if it's already failed. 252 mmio.read(addr - bar0, data); 253 } 254 _ => { 255 error!("xhci controller is in a wrong state"); 256 return; 257 } 258 } 259 } 260 write_bar(&mut self, addr: u64, data: &[u8])261 fn write_bar(&mut self, addr: u64, data: &[u8]) { 262 let bar0 = self.bar0; 263 if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE { 264 return; 265 } 266 match &self.state { 267 XhciControllerState::Initialized { 268 mmio, fail_handle, .. 269 } => { 270 if !fail_handle.failed() { 271 mmio.write(addr - bar0, data); 272 } 273 } 274 _ => { 275 error!("xhci controller is in a wrong state"); 276 return; 277 } 278 } 279 } on_device_sandboxed(&mut self)280 fn on_device_sandboxed(&mut self) { 281 self.init_when_forked(); 282 } 283 } 284