• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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(&regs));
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