devices/usb/xhci/
xhci_controller.rs

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
5use std::mem;
6use std::sync::atomic::AtomicBool;
7use std::sync::atomic::Ordering;
8use std::sync::Arc;
9
10use base::error;
11use base::AsRawDescriptor;
12use base::RawDescriptor;
13use base::SharedMemory;
14use resources::Alloc;
15use resources::AllocOptions;
16use resources::SystemAllocator;
17use vm_memory::GuestMemory;
18
19use crate::pci::BarRange;
20use crate::pci::PciAddress;
21use crate::pci::PciBarConfiguration;
22use crate::pci::PciBarPrefetchable;
23use crate::pci::PciBarRegionType;
24use crate::pci::PciClassCode;
25use crate::pci::PciConfiguration;
26use crate::pci::PciDevice;
27use crate::pci::PciDeviceError;
28use crate::pci::PciHeaderType;
29use crate::pci::PciInterruptPin;
30use crate::pci::PciProgrammingInterface;
31use crate::pci::PciSerialBusSubClass;
32use crate::register_space::Register;
33use crate::register_space::RegisterSpace;
34use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
35use crate::usb::xhci::xhci_regs::init_xhci_mmio_space_and_regs;
36use crate::usb::xhci::xhci_regs::XhciRegs;
37use crate::usb::xhci::Xhci;
38use crate::utils::FailHandle;
39use crate::IrqLevelEvent;
40use crate::Suspendable;
41
42const XHCI_BAR0_SIZE: u64 = 0x10000;
43
44#[derive(Clone, Copy)]
45enum UsbControllerProgrammingInterface {
46    Usb3HostController = 0x30,
47}
48
49impl PciProgrammingInterface for UsbControllerProgrammingInterface {
50    fn get_register_value(&self) -> u8 {
51        *self as u8
52    }
53}
54
55/// Use this handle to fail xhci controller.
56pub struct XhciFailHandle {
57    usbcmd: Register<u32>,
58    usbsts: Register<u32>,
59    xhci_failed: AtomicBool,
60}
61
62impl XhciFailHandle {
63    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
72impl FailHandle for XhciFailHandle {
73    /// Fail this controller. Will set related registers and flip failed bool.
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.
87    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.
95enum XhciControllerState {
96    Unknown,
97    Created {
98        device_provider: Box<dyn XhciBackendDeviceProvider>,
99    },
100    IrqAssigned {
101        device_provider: Box<dyn XhciBackendDeviceProvider>,
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.
114pub struct XhciController {
115    config_regs: PciConfiguration,
116    pci_address: Option<PciAddress>,
117    mem: GuestMemory,
118    state: XhciControllerState,
119}
120
121impl XhciController {
122    /// Create new xhci controller.
123    pub fn new(mem: GuestMemory, usb_provider: Box<dyn XhciBackendDeviceProvider>) -> Self {
124        let config_regs = PciConfiguration::new(
125            0x01b73, // fresco logic, (google = 0x1ae0)
126            0x1400,  // fresco logic fl1400. 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.
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
182impl PciDevice for XhciController {
183    fn debug_label(&self) -> String {
184        "xhci controller".to_owned()
185    }
186
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 = resources.allocate_pci(0, self.debug_label());
193        }
194        self.pci_address.ok_or(PciDeviceError::PciAllocationFailed)
195    }
196
197    fn keep_rds(&self) -> Vec<RawDescriptor> {
198        match &self.state {
199            XhciControllerState::Created { device_provider } => device_provider.keep_rds(),
200            XhciControllerState::IrqAssigned {
201                device_provider,
202                irq_evt,
203            } => {
204                let mut keep_rds = device_provider.keep_rds();
205                keep_rds.push(irq_evt.get_trigger().as_raw_descriptor());
206                keep_rds.push(irq_evt.get_resample().as_raw_descriptor());
207                keep_rds
208            }
209            _ => {
210                error!("xhci controller is in a wrong state");
211                vec![]
212            }
213        }
214    }
215
216    fn assign_irq(&mut self, irq_evt: IrqLevelEvent, pin: PciInterruptPin, irq_num: u32) {
217        match mem::replace(&mut self.state, XhciControllerState::Unknown) {
218            XhciControllerState::Created { device_provider } => {
219                self.config_regs.set_irq(irq_num as u8, pin);
220                self.state = XhciControllerState::IrqAssigned {
221                    device_provider,
222                    irq_evt,
223                }
224            }
225            _ => {
226                error!("xhci controller is in a wrong state");
227            }
228        }
229    }
230
231    fn allocate_io_bars(
232        &mut self,
233        resources: &mut SystemAllocator,
234    ) -> std::result::Result<Vec<BarRange>, PciDeviceError> {
235        let address = self
236            .pci_address
237            .expect("assign_address must be called prior to allocate_io_bars");
238        // xHCI spec 5.2.1.
239        let bar0_addr = resources
240            .allocate_mmio(
241                XHCI_BAR0_SIZE,
242                Alloc::PciBar {
243                    bus: address.bus,
244                    dev: address.dev,
245                    func: address.func,
246                    bar: 0,
247                },
248                "xhci_bar0".to_string(),
249                AllocOptions::new()
250                    .max_address(u32::MAX.into())
251                    .align(XHCI_BAR0_SIZE),
252            )
253            .map_err(|e| PciDeviceError::IoAllocationFailed(XHCI_BAR0_SIZE, e))?;
254        let bar0_config = PciBarConfiguration::new(
255            0,
256            XHCI_BAR0_SIZE,
257            PciBarRegionType::Memory32BitRegion,
258            PciBarPrefetchable::NotPrefetchable,
259        )
260        .set_address(bar0_addr);
261        self.config_regs
262            .add_pci_bar(bar0_config)
263            .map_err(|e| PciDeviceError::IoRegistrationFailed(bar0_addr, e))?;
264        Ok(vec![BarRange {
265            addr: bar0_addr,
266            size: XHCI_BAR0_SIZE,
267            prefetchable: false,
268        }])
269    }
270
271    fn get_bar_configuration(&self, bar_num: usize) -> Option<PciBarConfiguration> {
272        self.config_regs.get_bar_configuration(bar_num)
273    }
274
275    fn read_config_register(&self, reg_idx: usize) -> u32 {
276        self.config_regs.read_reg(reg_idx)
277    }
278
279    fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
280        self.config_regs.write_reg(reg_idx, offset, data);
281    }
282
283    fn setup_pci_config_mapping(
284        &mut self,
285        shmem: &SharedMemory,
286        base: usize,
287        len: usize,
288    ) -> Result<bool, PciDeviceError> {
289        self.config_regs
290            .setup_mapping(shmem, base, len)
291            .map(|_| true)
292            .map_err(PciDeviceError::MmioSetup)
293    }
294
295    fn read_bar(&mut self, bar_index: usize, offset: u64, data: &mut [u8]) {
296        if bar_index != 0 {
297            return;
298        }
299
300        match &self.state {
301            XhciControllerState::Initialized { mmio, .. } => {
302                // Read bar would still work even if it's already failed.
303                mmio.read(offset, data);
304            }
305            _ => {
306                error!("xhci controller is in a wrong state");
307            }
308        }
309    }
310
311    fn write_bar(&mut self, bar_index: usize, offset: u64, data: &[u8]) {
312        if bar_index != 0 {
313            return;
314        }
315
316        match &self.state {
317            XhciControllerState::Initialized {
318                mmio, fail_handle, ..
319            } => {
320                if !fail_handle.failed() {
321                    mmio.write(offset, data);
322                }
323            }
324            _ => {
325                error!("xhci controller is in a wrong state");
326            }
327        }
328    }
329
330    fn on_device_sandboxed(&mut self) {
331        self.init_when_forked();
332    }
333}
334
335impl Suspendable for XhciController {}