• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2019 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 use std::mem;
6 use std::sync::atomic::AtomicBool;
7 use std::sync::atomic::Ordering;
8 use std::sync::Arc;
9 
10 use base::error;
11 use base::AsRawDescriptor;
12 use base::RawDescriptor;
13 use resources::Alloc;
14 use resources::AllocOptions;
15 use resources::SystemAllocator;
16 use vm_memory::GuestMemory;
17 
18 use crate::pci::BarRange;
19 use crate::pci::PciAddress;
20 use crate::pci::PciBarConfiguration;
21 use crate::pci::PciBarPrefetchable;
22 use crate::pci::PciBarRegionType;
23 use crate::pci::PciClassCode;
24 use crate::pci::PciConfiguration;
25 use crate::pci::PciDevice;
26 use crate::pci::PciDeviceError;
27 use crate::pci::PciHeaderType;
28 use crate::pci::PciInterruptPin;
29 use crate::pci::PciProgrammingInterface;
30 use crate::pci::PciSerialBusSubClass;
31 use crate::register_space::Register;
32 use crate::register_space::RegisterSpace;
33 use crate::usb::host_backend::host_backend_device_provider::HostBackendDeviceProvider;
34 use crate::usb::xhci::xhci::Xhci;
35 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
36 use crate::usb::xhci::xhci_regs::init_xhci_mmio_space_and_regs;
37 use crate::usb::xhci::xhci_regs::XhciRegs;
38 use crate::utils::FailHandle;
39 use crate::IrqLevelEvent;
40 use crate::Suspendable;
41 
42 const XHCI_BAR0_SIZE: u64 = 0x10000;
43 
44 #[derive(Clone, Copy)]
45 enum UsbControllerProgrammingInterface {
46     Usb3HostController = 0x30,
47 }
48 
49 impl PciProgrammingInterface for UsbControllerProgrammingInterface {
get_register_value(&self) -> u850     fn get_register_value(&self) -> u8 {
51         *self as u8
52     }
53 }
54 
55 /// Use this handle to fail xhci controller.
56 pub struct XhciFailHandle {
57     usbcmd: Register<u32>,
58     usbsts: Register<u32>,
59     xhci_failed: AtomicBool,
60 }
61 
62 impl XhciFailHandle {
new(regs: &XhciRegs) -> XhciFailHandle63     pub fn new(regs: &XhciRegs) -> XhciFailHandle {
64         XhciFailHandle {
65             usbcmd: regs.usbcmd.clone(),
66             usbsts: regs.usbsts.clone(),
67             xhci_failed: AtomicBool::new(false),
68         }
69     }
70 }
71 
72 impl FailHandle for XhciFailHandle {
73     /// Fail this controller. Will set related registers and flip failed bool.
fail(&self)74     fn fail(&self) {
75         // set run/stop to stop.
76         const USBCMD_STOPPED: u32 = 0;
77         // Set host system error bit.
78         const USBSTS_HSE: u32 = 1 << 2;
79         self.usbcmd.set_value(USBCMD_STOPPED);
80         self.usbsts.set_value(USBSTS_HSE);
81 
82         self.xhci_failed.store(true, Ordering::SeqCst);
83         error!("xhci controller stopped working");
84     }
85 
86     /// Returns true if xhci is already failed.
failed(&self) -> bool87     fn failed(&self) -> bool {
88         self.xhci_failed.load(Ordering::SeqCst)
89     }
90 }
91 
92 // Xhci controller should be created with backend device provider. Then irq should be assigned
93 // before initialized. We are not making `failed` as a state here to optimize performance. Cause we
94 // need to set failed in other threads.
95 enum XhciControllerState {
96     Unknown,
97     Created {
98         device_provider: HostBackendDeviceProvider,
99     },
100     IrqAssigned {
101         device_provider: HostBackendDeviceProvider,
102         irq_evt: IrqLevelEvent,
103     },
104     Initialized {
105         mmio: RegisterSpace,
106         // Xhci init could fail.
107         #[allow(dead_code)]
108         xhci: Option<Arc<Xhci>>,
109         fail_handle: Arc<dyn FailHandle>,
110     },
111 }
112 
113 /// xHCI PCI interface implementation.
114 pub struct XhciController {
115     config_regs: PciConfiguration,
116     pci_address: Option<PciAddress>,
117     mem: GuestMemory,
118     state: XhciControllerState,
119 }
120 
121 impl XhciController {
122     /// Create new xhci controller.
new(mem: GuestMemory, usb_provider: HostBackendDeviceProvider) -> Self123     pub fn new(mem: GuestMemory, usb_provider: HostBackendDeviceProvider) -> Self {
124         let config_regs = PciConfiguration::new(
125             0x01b73, // fresco logic, (google = 0x1ae0)
126             0x1000,  // fresco logic pdk. This chip has broken msi. See kernel xhci-pci.c
127             PciClassCode::SerialBusController,
128             &PciSerialBusSubClass::Usb,
129             Some(&UsbControllerProgrammingInterface::Usb3HostController),
130             PciHeaderType::Device,
131             0,
132             0,
133             0,
134         );
135         XhciController {
136             config_regs,
137             pci_address: None,
138             mem,
139             state: XhciControllerState::Created {
140                 device_provider: usb_provider,
141             },
142         }
143     }
144 
145     /// Init xhci controller when it's forked.
init_when_forked(&mut self)146     pub fn init_when_forked(&mut self) {
147         match mem::replace(&mut self.state, XhciControllerState::Unknown) {
148             XhciControllerState::IrqAssigned {
149                 device_provider,
150                 irq_evt,
151             } => {
152                 let (mmio, regs) = init_xhci_mmio_space_and_regs();
153                 let fail_handle: Arc<dyn FailHandle> = Arc::new(XhciFailHandle::new(&regs));
154                 let xhci = match Xhci::new(
155                     fail_handle.clone(),
156                     self.mem.clone(),
157                     device_provider,
158                     irq_evt,
159                     regs,
160                 ) {
161                     Ok(xhci) => Some(xhci),
162                     Err(_) => {
163                         error!("fail to init xhci");
164                         fail_handle.fail();
165                         return;
166                     }
167                 };
168 
169                 self.state = XhciControllerState::Initialized {
170                     mmio,
171                     xhci,
172                     fail_handle,
173                 }
174             }
175             _ => {
176                 error!("xhci controller is in a wrong state");
177             }
178         }
179     }
180 }
181 
182 impl PciDevice for XhciController {
debug_label(&self) -> String183     fn debug_label(&self) -> String {
184         "xhci controller".to_owned()
185     }
186 
allocate_address( &mut self, resources: &mut SystemAllocator, ) -> Result<PciAddress, PciDeviceError>187     fn allocate_address(
188         &mut self,
189         resources: &mut SystemAllocator,
190     ) -> Result<PciAddress, PciDeviceError> {
191         if self.pci_address.is_none() {
192             self.pci_address = match resources.allocate_pci(0, self.debug_label()) {
193                 Some(Alloc::PciBar {
194                     bus,
195                     dev,
196                     func,
197                     bar: _,
198                 }) => Some(PciAddress { bus, dev, func }),
199                 _ => None,
200             }
201         }
202         self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
203     }
204 
keep_rds(&self) -> Vec<RawDescriptor>205     fn keep_rds(&self) -> Vec<RawDescriptor> {
206         match &self.state {
207             XhciControllerState::Created { device_provider } => device_provider.keep_rds(),
208             XhciControllerState::IrqAssigned {
209                 device_provider,
210                 irq_evt,
211             } => {
212                 let mut keep_rds = device_provider.keep_rds();
213                 keep_rds.push(irq_evt.get_trigger().as_raw_descriptor());
214                 keep_rds.push(irq_evt.get_resample().as_raw_descriptor());
215                 keep_rds
216             }
217             _ => {
218                 error!("xhci controller is in a wrong state");
219                 vec![]
220             }
221         }
222     }
223 
assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32)224     fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
225         match mem::replace(&mut self.state, XhciControllerState::Unknown) {
226             XhciControllerState::Created { device_provider } => {
227                 self.config_regs.set_irq(irq_num as u8, pin);
228                 self.state = XhciControllerState::IrqAssigned {
229                     device_provider,
230                     irq_evt,
231                 }
232             }
233             _ => {
234                 error!("xhci controller is in a wrong state");
235             }
236         }
237     }
238 
allocate_io_bars( &mut self, resources: &mut SystemAllocator, ) -> std::result::Result<Vec<BarRange>, PciDeviceError>239     fn allocate_io_bars(
240         &mut self,
241         resources: &mut SystemAllocator,
242     ) -> std::result::Result<Vec<BarRange>, PciDeviceError> {
243         let address = self
244             .pci_address
245             .expect("assign_address must be called prior to allocate_io_bars");
246         // xHCI spec 5.2.1.
247         let bar0_addr = resources
248             .allocate_mmio(
249                 XHCI_BAR0_SIZE,
250                 Alloc::PciBar {
251                     bus: address.bus,
252                     dev: address.dev,
253                     func: address.func,
254                     bar: 0,
255                 },
256                 "xhci_bar0".to_string(),
257                 AllocOptions::new()
258                     .max_address(u32::MAX.into())
259                     .align(XHCI_BAR0_SIZE),
260             )
261             .map_err(|e| PciDeviceError::IoAllocationFailed(XHCI_BAR0_SIZE, e))?;
262         let bar0_config = PciBarConfiguration::new(
263             0,
264             XHCI_BAR0_SIZE,
265             PciBarRegionType::Memory32BitRegion,
266             PciBarPrefetchable::NotPrefetchable,
267         )
268         .set_address(bar0_addr);
269         self.config_regs
270             .add_pci_bar(bar0_config)
271             .map_err(|e| PciDeviceError::IoRegistrationFailed(bar0_addr, e))?;
272         Ok(vec![BarRange {
273             addr: bar0_addr,
274             size: XHCI_BAR0_SIZE,
275             prefetchable: false,
276         }])
277     }
278 
get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration>279     fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
280         self.config_regs.get_bar_configuration(bar_num)
281     }
282 
read_config_register(&self, reg_idx: usize) -> u32283     fn read_config_register(&self, reg_idx: usize) -> u32 {
284         self.config_regs.read_reg(reg_idx)
285     }
286 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])287     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
288         self.config_regs.write_reg(reg_idx, offset, data)
289     }
290 
read_bar(&mut self, addr: u64, data: &mut [u8])291     fn read_bar(&mut self, addr: u64, data: &mut [u8]) {
292         let bar0 = self.config_regs.get_bar_addr(0);
293         if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE {
294             return;
295         }
296         match &self.state {
297             XhciControllerState::Initialized { mmio, .. } => {
298                 // Read bar would still work even if it's already failed.
299                 mmio.read(addr - bar0, data);
300             }
301             _ => {
302                 error!("xhci controller is in a wrong state");
303             }
304         }
305     }
306 
write_bar(&mut self, addr: u64, data: &[u8])307     fn write_bar(&mut self, addr: u64, data: &[u8]) {
308         let bar0 = self.config_regs.get_bar_addr(0);
309         if addr < bar0 || addr > bar0 + XHCI_BAR0_SIZE {
310             return;
311         }
312         match &self.state {
313             XhciControllerState::Initialized {
314                 mmio, fail_handle, ..
315             } => {
316                 if !fail_handle.failed() {
317                     mmio.write(addr - bar0, data);
318                 }
319             }
320             _ => {
321                 error!("xhci controller is in a wrong state");
322             }
323         }
324     }
325 
on_device_sandboxed(&mut self)326     fn on_device_sandboxed(&mut self) {
327         self.init_when_forked();
328     }
329 }
330 
331 impl Suspendable for XhciController {}
332