xref: /aosp_15_r20/external/crosvm/devices/src/usb/xhci/xhci_controller.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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 base::SharedMemory;
14 use resources::Alloc;
15 use resources::AllocOptions;
16 use resources::SystemAllocator;
17 use vm_memory::GuestMemory;
18 
19 use crate::pci::BarRange;
20 use crate::pci::PciAddress;
21 use crate::pci::PciBarConfiguration;
22 use crate::pci::PciBarPrefetchable;
23 use crate::pci::PciBarRegionType;
24 use crate::pci::PciClassCode;
25 use crate::pci::PciConfiguration;
26 use crate::pci::PciDevice;
27 use crate::pci::PciDeviceError;
28 use crate::pci::PciHeaderType;
29 use crate::pci::PciInterruptPin;
30 use crate::pci::PciProgrammingInterface;
31 use crate::pci::PciSerialBusSubClass;
32 use crate::register_space::Register;
33 use crate::register_space::RegisterSpace;
34 use crate::usb::xhci::xhci_backend_device_provider::XhciBackendDeviceProvider;
35 use crate::usb::xhci::xhci_regs::init_xhci_mmio_space_and_regs;
36 use crate::usb::xhci::xhci_regs::XhciRegs;
37 use crate::usb::xhci::Xhci;
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: 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.
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: Box<dyn XhciBackendDeviceProvider>) -> Self123     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.
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 
setup_pci_config_mapping( &mut self, shmem: &SharedMemory, base: usize, len: usize, ) -> Result<bool, PciDeviceError>291     fn setup_pci_config_mapping(
292         &mut self,
293         shmem: &SharedMemory,
294         base: usize,
295         len: usize,
296     ) -> Result<bool, PciDeviceError> {
297         self.config_regs
298             .setup_mapping(shmem, base, len)
299             .map(|_| true)
300             .map_err(PciDeviceError::MmioSetup)
301     }
302 
read_bar(&mut self, bar_index: usize, offset: u64, data: &mut [u8])303     fn read_bar(&mut self, bar_index: usize, offset: u64, data: &mut [u8]) {
304         if bar_index != 0 {
305             return;
306         }
307 
308         match &self.state {
309             XhciControllerState::Initialized { mmio, .. } => {
310                 // Read bar would still work even if it's already failed.
311                 mmio.read(offset, data);
312             }
313             _ => {
314                 error!("xhci controller is in a wrong state");
315             }
316         }
317     }
318 
write_bar(&mut self, bar_index: usize, offset: u64, data: &[u8])319     fn write_bar(&mut self, bar_index: usize, offset: u64, data: &[u8]) {
320         if bar_index != 0 {
321             return;
322         }
323 
324         match &self.state {
325             XhciControllerState::Initialized {
326                 mmio, fail_handle, ..
327             } => {
328                 if !fail_handle.failed() {
329                     mmio.write(offset, data);
330                 }
331             }
332             _ => {
333                 error!("xhci controller is in a wrong state");
334             }
335         }
336     }
337 
on_device_sandboxed(&mut self)338     fn on_device_sandboxed(&mut self) {
339         self.init_when_forked();
340     }
341 }
342 
343 impl Suspendable for XhciController {}
344