Skip to content
Draft
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10546,6 +10546,7 @@ dependencies = [
"get_resources",
"guid",
"hyperv_ic_resources",
"initrd_cpio",
"inspect",
"jiff",
"kmsg",
Expand Down
60 changes: 42 additions & 18 deletions openvmm/openvmm_entry/src/ttrpc/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ use openvmm_defs::config::NumaDistance;
use openvmm_defs::config::NumaNode;
use openvmm_defs::config::NumaTopology;
use openvmm_defs::config::PcieDeviceConfig;
use openvmm_defs::config::PcieGenericInitiatorConfig;
use openvmm_defs::config::PcieMmioRangeConfig;
use openvmm_defs::config::PciePortConfig;
use openvmm_defs::config::PcieRootComplexConfig;
Expand Down Expand Up @@ -785,22 +786,21 @@ impl VmService {

// Build the PCIe topology (root complexes, switches, and the devices
// attached behind their ports).
let (pcie_root_complexes, pcie_switches, pcie_devices) =
if let Some(pcie) = req_config.pcie.take() {
build_pcie_topology(pcie, &registry).await?
} else {
(Vec::new(), Vec::new(), Vec::new())
};
let pcie = if let Some(pcie) = req_config.pcie.take() {
build_pcie_topology(pcie, &registry).await?
} else {
BuiltPcieTopology::default()
};

let mut config = Config {
// TODO: devices, other stuff
load_mode,
ide_disks: vec![],
floppy_disks: vec![],
pcie_root_complexes,
pcie_devices,
pcie_switches,
pcie_generic_initiators: vec![],
pcie_root_complexes: pcie.root_complexes,
pcie_devices: pcie.devices,
pcie_switches: pcie.switches,
pcie_generic_initiators: pcie.generic_initiators,
vpci_devices: vec![],
numa,
chipset: chipset.chipset,
Expand Down Expand Up @@ -1484,16 +1484,21 @@ fn pcie_mmio_range_config(size: u64, base: Option<u64>) -> anyhow::Result<PcieMm
/// a list of root complexes (each carrying its root ports), a list of switches
/// (each referencing its parent port), and a list of devices (each referencing
/// the port it sits behind).
#[derive(Default)]
struct BuiltPcieTopology {
root_complexes: Vec<PcieRootComplexConfig>,
switches: Vec<PcieSwitchConfig>,
devices: Vec<PcieDeviceConfig>,
generic_initiators: Vec<PcieGenericInitiatorConfig>,
}

async fn build_pcie_topology(
topology: vmservice::PcieTopologyConfig,
registry: &FdRegistry,
) -> anyhow::Result<(
Vec<PcieRootComplexConfig>,
Vec<PcieSwitchConfig>,
Vec<PcieDeviceConfig>,
)> {
) -> anyhow::Result<BuiltPcieTopology> {
let vmservice::PcieTopologyConfig {
root_complexes: proto_root_complexes,
generic_initiators,
} = topology;
let mut root_complexes = Vec::new();
let mut switches = Vec::new();
Expand Down Expand Up @@ -1522,14 +1527,17 @@ async fn build_pcie_topology(
hotplug,
attached,
devfn,
acs_capabilities_supported,
} = root_port;
ports.push(PciePortConfig {
name: port_name.clone(),
devfn: devfn
.map(|d| d.try_into().context("devfn out of range"))
.transpose()?,
hotplug,
acs_capabilities_supported: None,
acs_capabilities_supported: acs_capabilities_supported
.map(|acs| acs.try_into().context("ACS capability mask out of range"))
.transpose()?,
cxl: false,
});
if let Some(attached) = attached {
Expand Down Expand Up @@ -1562,7 +1570,20 @@ async fn build_pcie_topology(
});
}

Ok((root_complexes, switches, devices))
let generic_initiators = generic_initiators
.into_iter()
.map(|initiator| PcieGenericInitiatorConfig {
port_name: initiator.port_name,
node: initiator.node,
})
.collect();

Ok(BuiltPcieTopology {
root_complexes,
switches,
devices,
generic_initiators,
})
}

/// Walks a single proto `PcieAttachment` (the thing behind one port): either an
Expand Down Expand Up @@ -1591,14 +1612,17 @@ fn walk_pcie_attachment(
hotplug,
attached,
devfn,
acs_capabilities_supported,
} = downstream;
ports.push(PciePortConfig {
name: downstream_name.clone(),
devfn: devfn
.map(|d| d.try_into().context("devfn out of range"))
.transpose()?,
hotplug,
acs_capabilities_supported: None,
acs_capabilities_supported: acs_capabilities_supported
.map(|acs| acs.try_into().context("ACS capability mask out of range"))
.transpose()?,
cxl: false,
});
if let Some(attached) = attached {
Expand Down
12 changes: 12 additions & 0 deletions openvmm/openvmm_ttrpc_vmservice/src/vmservice.proto
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,16 @@ message NumaDistance {
message PcieTopologyConfig {
// The PCIe root complexes in the VM.
repeated PcieRootComplex root_complexes = 1;
// Devices that act as initiators for device-only NUMA nodes.
repeated PcieGenericInitiator generic_initiators = 2;
}

// Associates the device behind a PCIe port with a NUMA proximity domain.
message PcieGenericInitiator {
// Port directly upstream of the initiator device.
string port_name = 1;
// NUMA node for which the device is an initiator.
uint32 node = 2;
}

// A PCIe root complex.
Expand Down Expand Up @@ -411,6 +421,8 @@ message PciePort {
// Device/function (`device << 3 | function`) to place this port at on its
// bus. Absent => lowest available devfn.
optional uint32 devfn = 4;
// ACS capability bits exposed by this port. Absent => default capabilities.
optional uint32 acs_capabilities_supported = 5;
}

// A PCIe switch: a set of downstream ports, each of which may have its own
Expand Down
1 change: 1 addition & 0 deletions vmm_tests/vmm_tests/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ tmk_tests.workspace = true
petri_artifacts_common.workspace = true
petri.workspace = true
inspect.workspace = true
initrd_cpio.workspace = true

get_resources.workspace = true
openvmm_defs.workspace = true
Expand Down
Loading
Loading