Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/usb/xhci/xhci_controller.rs
5394 views
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 {
50
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 {
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
72
impl 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.
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.
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
182
impl 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
335
impl Suspendable for XhciController {}
336
337