Skip to content

Commit 07cd55a

Browse files
committed
pci: virtio: refactor: move MsixConfig interaction to VirtioPciDevice
Following previous commits notion, move MsixConfig handling out of PciConfiguration into VirtioPciDevice. Signed-off-by: Egor Lazarchuk <yegorlz@amazon.co.uk>
1 parent 52e119c commit 07cd55a

File tree

4 files changed

+40
-58
lines changed

4 files changed

+40
-58
lines changed

src/vmm/src/devices/virtio/transport/pci/device.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ pub struct VirtioPciDeviceState {
246246
pub pci_dev_state: VirtioPciCommonConfigState,
247247
pub msix_state: MsixConfigState,
248248
pub bars: Bars,
249+
pub msix_config_offset: u16,
249250
}
250251

251252
#[derive(Debug, thiserror::Error, displaydoc::Display)]
@@ -291,6 +292,8 @@ pub struct VirtioPciDevice {
291292

292293
// BARs region for the device
293294
pub bars: Bars,
295+
pub msix_config_offset: u16,
296+
pub msix_config: Arc<Mutex<MsixConfig>>,
294297
}
295298

296299
impl Debug for VirtioPciDevice {
@@ -330,7 +333,6 @@ impl VirtioPciDevice {
330333
subclass,
331334
VIRTIO_PCI_VENDOR_ID,
332335
pci_device_id,
333-
Some(msix_config.clone()),
334336
)
335337
}
336338

@@ -410,6 +412,8 @@ impl VirtioPciDevice {
410412
memory,
411413
cap_pci_cfg_info: VirtioPciCfgCapInfo::default(),
412414
bars: Bars::default(),
415+
msix_config,
416+
msix_config_offset: 0,
413417
};
414418

415419
Ok(virtio_pci_device)
@@ -426,10 +430,7 @@ impl VirtioPciDevice {
426430
let vectors = msix_config.vectors.clone();
427431
let msix_config = Arc::new(Mutex::new(msix_config));
428432

429-
let pci_config = PciConfiguration::type0_from_state(
430-
state.pci_configuration_state,
431-
Some(msix_config.clone()),
432-
);
433+
let pci_config = PciConfiguration::type0_from_state(state.pci_configuration_state);
433434
let virtio_common_config = VirtioPciCommonConfig::new(state.pci_dev_state);
434435
let cap_pci_cfg_info = VirtioPciCfgCapInfo {
435436
offset: state.cap_pci_cfg_offset,
@@ -455,6 +456,8 @@ impl VirtioPciDevice {
455456
memory: vm.guest_memory().clone(),
456457
cap_pci_cfg_info,
457458
bars: state.bars,
459+
msix_config,
460+
msix_config_offset: state.msix_config_offset,
458461
};
459462

460463
if state.device_activated {
@@ -537,7 +540,10 @@ impl VirtioPciDevice {
537540
VIRTIO_BAR_INDEX,
538541
MSIX_PBA_BAR_OFFSET.try_into().unwrap(),
539542
);
540-
self.configuration.add_capability(&msix_cap);
543+
// The whole Configuration region is 4K, so u16 can address it all
544+
#[allow(clippy::cast_possible_truncation)]
545+
let offset = self.configuration.add_capability(&msix_cap) as u16;
546+
self.msix_config_offset = offset;
541547
}
542548
}
543549

@@ -640,6 +646,7 @@ impl VirtioPciDevice {
640646
.expect("Poisoned lock")
641647
.state(),
642648
bars: self.bars,
649+
msix_config_offset: self.msix_config_offset,
643650
}
644651
}
645652
}
@@ -753,10 +760,18 @@ impl PciDevice for VirtioPciDevice {
753760
self.bars.write(bar_idx, offset, data);
754761
None
755762
} else {
756-
// Handle the special case where the capability VIRTIO_PCI_CAP_PCI_CFG
757-
// is accessed. This capability has a special meaning as it allows the
758-
// guest to access other capabilities without mapping the PCI BAR.
763+
// Handle access to the header of the MsixCapability. The rest of the
764+
// capability is handled by the PciConfiguration.
759765
let base = reg_idx * 4;
766+
if base == self.msix_config_offset as usize {
767+
// offset is within a 4-byte PCI config register (0..3).
768+
#[allow(clippy::cast_possible_truncation)]
769+
let offset = offset as u8;
770+
self.msix_config
771+
.lock()
772+
.unwrap()
773+
.write_msg_ctl_register(offset, data);
774+
}
760775
if base + u64_to_usize(offset) >= self.cap_pci_cfg_info.offset
761776
&& base + u64_to_usize(offset) + data.len()
762777
<= self.cap_pci_cfg_info.offset + self.cap_pci_cfg_info.cap.bytes().len()

src/vmm/src/pci/bus.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ impl PciRoot {
5252
&PciBridgeSubclass::HostBridge,
5353
0,
5454
0,
55-
None,
5655
),
5756
}
5857
}
@@ -492,7 +491,6 @@ mod tests {
492491
&PciMassStorageSubclass::SerialScsiController,
493492
0x13,
494493
0x12,
495-
None,
496494
);
497495
PciDevMock(config)
498496
}

src/vmm/src/pci/configuration.rs

Lines changed: 3 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,11 @@
55
//
66
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
77

8-
use std::sync::{Arc, Mutex};
9-
108
use byteorder::{ByteOrder, LittleEndian};
119
use pci::{PciCapabilityId, PciClassCode, PciSubclass};
1210
use serde::{Deserialize, Serialize};
1311
use zerocopy::{FromBytes, IntoBytes};
1412

15-
use super::msix::MsixConfig;
1613
use crate::logger::warn;
1714
use crate::utils::u64_to_usize;
1815

@@ -24,7 +21,6 @@ const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
2421
const ROM_BAR_REG: usize = 12;
2522
const ROM_BAR_ADDR_MASK: u32 = 0xffff_f800;
2623
const MSI_CAPABILITY_REGISTER_MASK: u32 = 0x0071_0000;
27-
const MSIX_CAPABILITY_REGISTER_MASK: u32 = 0xc000_0000;
2824
const CAPABILITY_LIST_HEAD_OFFSET: usize = 0x34;
2925
const FIRST_CAPABILITY_OFFSET: usize = 0x40;
3026
const CAPABILITY_MAX_OFFSET: usize = 192;
@@ -155,7 +151,6 @@ pub struct PciConfigurationState {
155151
registers: Vec<u32>,
156152
writable_bits: Vec<u32>,
157153
last_capability: Option<(usize, usize)>,
158-
msix_cap_reg_idx: Option<usize>,
159154
}
160155

161156
#[derive(Debug)]
@@ -168,8 +163,6 @@ pub struct PciConfiguration {
168163
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
169164
// Contains the byte offset and size of the last capability.
170165
last_capability: Option<(usize, usize)>,
171-
msix_cap_reg_idx: Option<usize>,
172-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
173166
}
174167

175168
impl PciConfiguration {
@@ -183,7 +176,6 @@ impl PciConfiguration {
183176
subclass: &dyn PciSubclass,
184177
subsystem_vendor_id: u16,
185178
subsystem_id: u16,
186-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
187179
) -> Self {
188180
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
189181
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
@@ -202,22 +194,15 @@ impl PciConfiguration {
202194
registers,
203195
writable_bits,
204196
last_capability: None,
205-
msix_cap_reg_idx: None,
206-
msix_config,
207197
}
208198
}
209199

210200
/// Create a type 0 PCI configuration from snapshot state
211-
pub fn type0_from_state(
212-
state: PciConfigurationState,
213-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
214-
) -> Self {
201+
pub fn type0_from_state(state: PciConfigurationState) -> Self {
215202
PciConfiguration {
216203
registers: state.registers.try_into().unwrap(),
217204
writable_bits: state.writable_bits.try_into().unwrap(),
218205
last_capability: state.last_capability,
219-
msix_cap_reg_idx: state.msix_cap_reg_idx,
220-
msix_config,
221206
}
222207
}
223208

@@ -227,7 +212,6 @@ impl PciConfiguration {
227212
registers: self.registers.to_vec(),
228213
writable_bits: self.writable_bits.to_vec(),
229214
last_capability: self.last_capability,
230-
msix_cap_reg_idx: self.msix_cap_reg_idx,
231215
}
232216
}
233217

@@ -328,15 +312,8 @@ impl PciConfiguration {
328312
}
329313
self.last_capability = Some((cap_offset, total_len));
330314

331-
match cap_data.id() {
332-
PciCapabilityId::MessageSignalledInterrupts => {
333-
self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
334-
}
335-
PciCapabilityId::MsiX => {
336-
self.msix_cap_reg_idx = Some(cap_offset / 4);
337-
self.writable_bits[self.msix_cap_reg_idx.unwrap()] = MSIX_CAPABILITY_REGISTER_MASK;
338-
}
339-
_ => {}
315+
if cap_data.id() == PciCapabilityId::MessageSignalledInterrupts {
316+
self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
340317
}
341318

342319
cap_offset
@@ -358,26 +335,6 @@ impl PciConfiguration {
358335
return;
359336
}
360337

361-
// Handle potential write to MSI-X message control register
362-
if let Some(msix_cap_reg_idx) = self.msix_cap_reg_idx
363-
&& let Some(msix_config) = &self.msix_config
364-
{
365-
if msix_cap_reg_idx == reg_idx && offset == 2 && data.len() == 2 {
366-
// 2-bytes write in the Message Control field
367-
msix_config
368-
.lock()
369-
.unwrap()
370-
.set_msg_ctl(LittleEndian::read_u16(data));
371-
} else if msix_cap_reg_idx == reg_idx && offset == 0 && data.len() == 4 {
372-
// 4 bytes write at the beginning. Ignore the first 2 bytes which are the
373-
// capability id and next capability pointer
374-
msix_config
375-
.lock()
376-
.unwrap()
377-
.set_msg_ctl((LittleEndian::read_u32(data) >> 16) as u16);
378-
}
379-
}
380-
381338
match data.len() {
382339
1 => self.write_byte(reg_idx * 4 + u64_to_usize(offset), data[0]),
383340
2 => self.write_word(
@@ -592,7 +549,6 @@ mod tests {
592549
&PciMultimediaSubclass::AudioController,
593550
0xABCD,
594551
0x2468,
595-
None,
596552
)
597553
}
598554

src/vmm/src/pci/msix.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use byteorder::{ByteOrder, LittleEndian};
1010
use pci::PciCapabilityId;
1111
use serde::{Deserialize, Serialize};
1212
use vm_memory::ByteValued;
13+
use zerocopy::FromBytes;
1314

1415
use crate::Vm;
1516
use crate::logger::{debug, error, warn};
@@ -205,6 +206,18 @@ impl MsixConfig {
205206
}
206207
}
207208

209+
/// Write to the Message Control register
210+
pub fn write_msg_ctl_register(&mut self, offset: u8, data: &[u8]) {
211+
if offset == 2 && data.len() == 2 {
212+
// 2-bytes write in the Message Control field
213+
self.set_msg_ctl(u16::read_from_bytes(data).unwrap());
214+
} else if offset == 0 && data.len() == 4 {
215+
// 4 bytes write at the beginning. Ignore the first 2 bytes which are the
216+
// capability id and next capability pointer
217+
self.set_msg_ctl((u32::read_from_bytes(data).unwrap() >> 16) as u16);
218+
}
219+
}
220+
208221
/// Read an MSI-X table entry
209222
pub fn read_table(&self, offset: u64, data: &mut [u8]) {
210223
assert!(data.len() <= 8);

0 commit comments

Comments
 (0)