Skip to content

Commit 8050f34

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 6562df9 commit 8050f34

File tree

4 files changed

+39
-50
lines changed

4 files changed

+39
-50
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: 2 additions & 39 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

@@ -155,7 +152,6 @@ pub struct PciConfigurationState {
155152
registers: Vec<u32>,
156153
writable_bits: Vec<u32>,
157154
last_capability: Option<(usize, usize)>,
158-
msix_cap_reg_idx: Option<usize>,
159155
}
160156

161157
#[derive(Debug)]
@@ -168,8 +164,6 @@ pub struct PciConfiguration {
168164
writable_bits: [u32; NUM_CONFIGURATION_REGISTERS], // writable bits for each register.
169165
// Contains the byte offset and size of the last capability.
170166
last_capability: Option<(usize, usize)>,
171-
msix_cap_reg_idx: Option<usize>,
172-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
173167
}
174168

175169
impl PciConfiguration {
@@ -183,7 +177,6 @@ impl PciConfiguration {
183177
subclass: &dyn PciSubclass,
184178
subsystem_vendor_id: u16,
185179
subsystem_id: u16,
186-
msix_config: Option<Arc<Mutex<MsixConfig>>>,
187180
) -> Self {
188181
let mut registers = [0u32; NUM_CONFIGURATION_REGISTERS];
189182
let mut writable_bits = [0u32; NUM_CONFIGURATION_REGISTERS];
@@ -202,22 +195,15 @@ impl PciConfiguration {
202195
registers,
203196
writable_bits,
204197
last_capability: None,
205-
msix_cap_reg_idx: None,
206-
msix_config,
207198
}
208199
}
209200

210201
/// 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 {
202+
pub fn type0_from_state(state: PciConfigurationState) -> Self {
215203
PciConfiguration {
216204
registers: state.registers.try_into().unwrap(),
217205
writable_bits: state.writable_bits.try_into().unwrap(),
218206
last_capability: state.last_capability,
219-
msix_cap_reg_idx: state.msix_cap_reg_idx,
220-
msix_config,
221207
}
222208
}
223209

@@ -227,7 +213,6 @@ impl PciConfiguration {
227213
registers: self.registers.to_vec(),
228214
writable_bits: self.writable_bits.to_vec(),
229215
last_capability: self.last_capability,
230-
msix_cap_reg_idx: self.msix_cap_reg_idx,
231216
}
232217
}
233218

@@ -333,8 +318,7 @@ impl PciConfiguration {
333318
self.writable_bits[cap_offset / 4] = MSI_CAPABILITY_REGISTER_MASK;
334319
}
335320
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;
321+
self.writable_bits[cap_offset / 4] = MSIX_CAPABILITY_REGISTER_MASK;
338322
}
339323
_ => {}
340324
}
@@ -358,26 +342,6 @@ impl PciConfiguration {
358342
return;
359343
}
360344

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-
381345
match data.len() {
382346
1 => self.write_byte(reg_idx * 4 + u64_to_usize(offset), data[0]),
383347
2 => self.write_word(
@@ -592,7 +556,6 @@ mod tests {
592556
&PciMultimediaSubclass::AudioController,
593557
0xABCD,
594558
0x2468,
595-
None,
596559
)
597560
}
598561

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)