Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/pci/msi.rs
5394 views
1
// Copyright 2022 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
#![cfg_attr(windows, allow(dead_code))]
6
7
use base::error;
8
use base::AsRawDescriptor;
9
use base::Event;
10
use base::RawDescriptor;
11
use base::Tube;
12
use bit_field::*;
13
use vm_control::PciId;
14
use vm_control::VmIrqRequest;
15
use vm_control::VmIrqResponse;
16
use zerocopy::FromBytes;
17
use zerocopy::Immutable;
18
use zerocopy::IntoBytes;
19
use zerocopy::KnownLayout;
20
21
use crate::pci::pci_configuration::PciCapConfig;
22
use crate::pci::pci_configuration::PciCapConfigWriteResult;
23
use crate::pci::PciCapability;
24
use crate::pci::PciCapabilityID;
25
26
// MSI registers
27
pub const PCI_MSI_NEXT_POINTER: u32 = 0x1; // Next cap pointer
28
pub const PCI_MSI_FLAGS: u32 = 0x2; // Message Control
29
const PCI_MSI_FLAGS_ENABLE: u16 = 0x0001; // MSI feature enabled
30
pub const PCI_MSI_FLAGS_64BIT: u16 = 0x0080; // 64-bit addresses allowed
31
pub const PCI_MSI_FLAGS_MASKBIT: u16 = 0x0100; // Per-vector masking capable
32
const PCI_MSI_ADDRESS_LO: u32 = 0x4; // MSI address lower 32 bits
33
const PCI_MSI_ADDRESS_HI: u32 = 0x8; // MSI address upper 32 bits (if 64 bit allowed)
34
const PCI_MSI_DATA_32: u32 = 0x8; // 16 bits of data for 32-bit message address
35
const PCI_MSI_DATA_64: u32 = 0xC; // 16 bits of date for 64-bit message address
36
37
// MSI length
38
const MSI_LENGTH_32BIT_WITHOUT_MASK: u32 = 0xA;
39
const MSI_LENGTH_32BIT_WITH_MASK: u32 = 0x14;
40
const MSI_LENGTH_64BIT_WITHOUT_MASK: u32 = 0xE;
41
const MSI_LENGTH_64BIT_WITH_MASK: u32 = 0x18;
42
43
pub enum MsiStatus {
44
Enabled,
45
Disabled,
46
NothingToDo,
47
}
48
49
/// Wrapper over MSI Capability Structure
50
pub struct MsiConfig {
51
is_64bit: bool,
52
mask_cap: bool,
53
ctrl: u16,
54
address: u64,
55
data: u16,
56
vm_socket_irq: Tube,
57
irqfd: Option<Event>,
58
gsi: Option<u32>,
59
device_id: u32,
60
device_name: String,
61
pci_address: Option<resources::PciAddress>,
62
}
63
64
impl MsiConfig {
65
pub fn new(
66
is_64bit: bool,
67
mask_cap: bool,
68
vm_socket_irq: Tube,
69
device_id: u32,
70
device_name: String,
71
) -> Self {
72
let mut ctrl: u16 = 0;
73
if is_64bit {
74
ctrl |= PCI_MSI_FLAGS_64BIT;
75
}
76
if mask_cap {
77
ctrl |= PCI_MSI_FLAGS_MASKBIT;
78
}
79
MsiConfig {
80
is_64bit,
81
mask_cap,
82
ctrl,
83
address: 0,
84
data: 0,
85
vm_socket_irq,
86
irqfd: None,
87
gsi: None,
88
device_id,
89
device_name,
90
pci_address: None,
91
}
92
}
93
94
/// PCI address of the associated device.
95
pub fn set_pci_address(&mut self, pci_address: resources::PciAddress) {
96
self.pci_address = Some(pci_address);
97
}
98
99
fn len(&self) -> u32 {
100
match (self.is_64bit, self.mask_cap) {
101
(true, true) => MSI_LENGTH_64BIT_WITH_MASK,
102
(true, false) => MSI_LENGTH_64BIT_WITHOUT_MASK,
103
(false, true) => MSI_LENGTH_32BIT_WITH_MASK,
104
(false, false) => MSI_LENGTH_32BIT_WITHOUT_MASK,
105
}
106
}
107
108
pub fn is_msi_reg(&self, offset: u32, index: u64, len: usize) -> bool {
109
let msi_len = self.len();
110
index >= offset as u64
111
&& index + len as u64 <= (offset + msi_len) as u64
112
&& len as u32 <= msi_len
113
}
114
115
pub fn read_msi_capability(&self, offset: u32, data: u32) -> u32 {
116
if offset == 0 {
117
(self.ctrl as u32) << 16 | (data & u16::MAX as u32)
118
} else {
119
data
120
}
121
}
122
123
pub fn write_msi_capability(&mut self, offset: u32, data: &[u8]) -> MsiStatus {
124
let len = data.len();
125
let mut ret = MsiStatus::NothingToDo;
126
let old_address = self.address;
127
let old_data = self.data;
128
129
// write msi ctl
130
if len == 2 && offset == PCI_MSI_FLAGS {
131
let was_enabled = self.is_msi_enabled();
132
let value: [u8; 2] = [data[0], data[1]];
133
self.ctrl = u16::from_le_bytes(value);
134
let is_enabled = self.is_msi_enabled();
135
if !was_enabled && is_enabled {
136
self.enable();
137
ret = MsiStatus::Enabled;
138
} else if was_enabled && !is_enabled {
139
ret = MsiStatus::Disabled;
140
}
141
} else if len == 4 && offset == PCI_MSI_ADDRESS_LO && !self.is_64bit {
142
//write 32 bit message address
143
let value: [u8; 8] = [data[0], data[1], data[2], data[3], 0, 0, 0, 0];
144
self.address = u64::from_le_bytes(value);
145
} else if len == 4 && offset == PCI_MSI_ADDRESS_LO && self.is_64bit {
146
// write 64 bit message address low part
147
let value: [u8; 8] = [data[0], data[1], data[2], data[3], 0, 0, 0, 0];
148
self.address &= !0xffffffff;
149
self.address |= u64::from_le_bytes(value);
150
} else if len == 4 && offset == PCI_MSI_ADDRESS_HI && self.is_64bit {
151
//write 64 bit message address high part
152
let value: [u8; 8] = [0, 0, 0, 0, data[0], data[1], data[2], data[3]];
153
self.address &= 0xffffffff;
154
self.address |= u64::from_le_bytes(value);
155
} else if len == 8 && offset == PCI_MSI_ADDRESS_LO && self.is_64bit {
156
// write 64 bit message address
157
let value: [u8; 8] = [
158
data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
159
];
160
self.address = u64::from_le_bytes(value);
161
} else if len == 2
162
&& ((offset == PCI_MSI_DATA_32 && !self.is_64bit)
163
|| (offset == PCI_MSI_DATA_64 && self.is_64bit))
164
{
165
// write message data
166
let value: [u8; 2] = [data[0], data[1]];
167
self.data = u16::from_le_bytes(value);
168
}
169
170
if self.is_msi_enabled() && (old_address != self.address || old_data != self.data) {
171
self.add_msi_route();
172
}
173
174
ret
175
}
176
177
pub fn is_msi_enabled(&self) -> bool {
178
self.ctrl & PCI_MSI_FLAGS_ENABLE == PCI_MSI_FLAGS_ENABLE
179
}
180
181
fn add_msi_route(&self) {
182
let gsi = match self.gsi {
183
Some(g) => g,
184
None => {
185
error!("Add msi route but gsi is none");
186
return;
187
}
188
};
189
// Only used on aarch64, but make sure it is initialized correctly on all archs for better
190
// test coverage.
191
#[allow(unused_variables)]
192
let pci_address = self
193
.pci_address
194
.expect("MsixConfig: must call set_pci_address before config writes");
195
if let Err(e) = self.vm_socket_irq.send(&VmIrqRequest::AddMsiRoute {
196
gsi,
197
msi_address: self.address,
198
msi_data: self.data.into(),
199
#[cfg(target_arch = "aarch64")]
200
pci_address,
201
}) {
202
error!("failed to send AddMsiRoute request at {:?}", e);
203
return;
204
}
205
match self.vm_socket_irq.recv() {
206
Ok(VmIrqResponse::Err(e)) => error!("failed to call AddMsiRoute request {:?}", e),
207
Ok(_) => {}
208
Err(e) => error!("failed to receive AddMsiRoute response {:?}", e),
209
}
210
}
211
212
fn allocate_one_msi(&mut self) {
213
let irqfd = match self.irqfd.take() {
214
Some(e) => e,
215
None => match Event::new() {
216
Ok(e) => e,
217
Err(e) => {
218
error!("failed to create event: {:?}", e);
219
return;
220
}
221
},
222
};
223
224
let request = VmIrqRequest::AllocateOneMsi {
225
irqfd,
226
device_id: PciId::from(self.device_id).into(),
227
queue_id: 0,
228
device_name: self.device_name.clone(),
229
};
230
let request_result = self.vm_socket_irq.send(&request);
231
232
// Stash the irqfd in self immediately because we used take above.
233
self.irqfd = match request {
234
VmIrqRequest::AllocateOneMsi { irqfd, .. } => Some(irqfd),
235
_ => unreachable!(),
236
};
237
238
if let Err(e) = request_result {
239
error!("failed to send AllocateOneMsi request: {:?}", e);
240
return;
241
}
242
243
match self.vm_socket_irq.recv() {
244
Ok(VmIrqResponse::AllocateOneMsi { gsi }) => self.gsi = Some(gsi),
245
_ => error!("failed to receive AllocateOneMsi Response"),
246
}
247
}
248
249
fn enable(&mut self) {
250
if self.gsi.is_none() || self.irqfd.is_none() {
251
self.allocate_one_msi();
252
}
253
254
self.add_msi_route();
255
}
256
257
pub fn get_irqfd(&self) -> Option<&Event> {
258
self.irqfd.as_ref()
259
}
260
261
pub fn destroy(&mut self) {
262
if let Some(gsi) = self.gsi {
263
if let Some(irqfd) = self.irqfd.take() {
264
let request = VmIrqRequest::ReleaseOneIrq { gsi, irqfd };
265
if self.vm_socket_irq.send(&request).is_ok() {
266
let _ = self.vm_socket_irq.recv::<VmIrqResponse>();
267
}
268
}
269
}
270
}
271
272
/// Return the raw descriptor of the MSI device socket
273
pub fn get_msi_socket(&self) -> RawDescriptor {
274
self.vm_socket_irq.as_raw_descriptor()
275
}
276
277
pub fn trigger(&self) {
278
if let Some(irqfd) = self.irqfd.as_ref() {
279
irqfd.signal().unwrap();
280
}
281
}
282
}
283
284
#[bitfield]
285
#[derive(Copy, Clone, FromBytes, Immutable, IntoBytes, KnownLayout)]
286
pub struct MsiCtrl {
287
enable: B1,
288
multi_msg_capable: B3,
289
multi_msg_enable: B3,
290
is_64bit: B1,
291
per_vector_masking: B1,
292
extended_msg_data_capable: B1,
293
extended_msg_data_enable: B1,
294
reserved: B5,
295
}
296
297
#[allow(dead_code)]
298
#[repr(C)]
299
#[derive(Clone, Copy, FromBytes, Immutable, IntoBytes, KnownLayout)]
300
/// MSI Capability Structure
301
pub struct MsiCap {
302
// To make add_capability() happy
303
_cap_vndr: u8,
304
_cap_next: u8,
305
// Message Control Register
306
msg_ctl: MsiCtrl,
307
// Message Address
308
msg_addr: u32,
309
// Msi Vary structure
310
msi_vary: [u8; 16],
311
}
312
313
impl PciCapability for MsiCap {
314
fn bytes(&self) -> &[u8] {
315
self.as_bytes()
316
}
317
318
fn id(&self) -> PciCapabilityID {
319
PciCapabilityID::MessageSignalledInterrupts
320
}
321
322
fn writable_bits(&self) -> Vec<u32> {
323
// Check spec for detail
324
match (
325
self.msg_ctl.get_is_64bit(),
326
self.msg_ctl.get_per_vector_masking(),
327
) {
328
(0, 0) => vec![0x0471_0000, 0xffff_fffc, 0xffff_ffff],
329
(0, 1) => vec![0x0471_0000, 0xffff_fffc, 0xffff_ffff, 0xffff_ffff],
330
(1, 0) => vec![
331
0x0471_0000,
332
0xffff_fffc,
333
0xffff_ffff,
334
0xffff_ffff,
335
0x0000_0000,
336
],
337
(1, 1) => vec![
338
0x0471_0000,
339
0xffff_fffc,
340
0xffff_ffff,
341
0xffff_ffff,
342
0xffff_ffff,
343
0x0000_0000,
344
],
345
(_, _) => Vec::new(),
346
}
347
}
348
}
349
350
impl MsiCap {
351
pub fn new(is_64bit: bool, mask_cap: bool) -> Self {
352
let mut msg_ctl = MsiCtrl::new();
353
if is_64bit {
354
msg_ctl.set_is_64bit(1);
355
}
356
if mask_cap {
357
msg_ctl.set_per_vector_masking(1);
358
}
359
MsiCap {
360
_cap_vndr: 0,
361
_cap_next: 0,
362
msg_ctl,
363
msg_addr: 0,
364
msi_vary: [0; 16],
365
}
366
}
367
}
368
369
const MSI_CONFIG_READ_MASK: [u32; MSI_LENGTH_64BIT_WITH_MASK as usize / 4] =
370
[0xffff_0000, 0, 0, 0, 0, 0];
371
372
impl PciCapConfig for MsiConfig {
373
fn read_mask(&self) -> &'static [u32] {
374
let num_regs = self.len().div_ceil(4);
375
&MSI_CONFIG_READ_MASK[0..(num_regs as usize)]
376
}
377
378
fn read_reg(&self, reg_idx: usize) -> u32 {
379
self.read_msi_capability(reg_idx as u32 * 4, 0)
380
}
381
382
fn write_reg(
383
&mut self,
384
reg_idx: usize,
385
offset: u64,
386
data: &[u8],
387
) -> Option<Box<dyn PciCapConfigWriteResult>> {
388
let offset = reg_idx as u32 * 4 + offset as u32;
389
self.write_msi_capability(offset, data);
390
None
391
}
392
}
393
394