From: "Elias Huhsovitz" <e.huhsovitz@proxmox.com>
To: "Dominik Csapak" <d.csapak@proxmox.com>, <pve-devel@lists.proxmox.com>
Subject: Re: [PATCH pve-qemu-server-rs v2 4/9] pci: layout: add grouped PCI and PCIe layouts
Date: Thu, 29 Oct 2026 14:31:39 +0100 [thread overview]
Message-ID: <DMHCYCC2OX41.2KW2QLY0DG8H@proxmox.com> (raw)
In-Reply-To: <20261015081041.743422-5-d.csapak@proxmox.com>
Comments inline.
On Thu Oct 15, 2026 at 10:10 AM CEST, Dominik Csapak wrote:
> The legacy layout grew over many releases and it shows: devices of one
> kind are spread over several buses, the bus a device lands on depends on
> how many devices of other kinds exist, and the remaining free slots are
> scattered. That makes it hard to raise any of the per-kind limits
> without further scattering the types over the available addresses.
>
> Add a second set of layouts that gives every device kind its own set of
> bridges instead. A device's address then only depends on its own index,
> so raising a limit adds bridges at the end rather than shifting anything
> that exists, and the built-in devices move to a bridge of their own to
> keep the root bus free.
>
> The new `layout` field of `HardwareConfig` selects which set is used,
> so `pci_bridge_for_device` now takes the config too. Since the layout
> is part of the guest ABI, the grouped one is only intended for new
> guests.
>
> `pci_bus_devices` returns its bridges and the hostpcie root ports,
> with the same function 0 handling as for the legacy layout.
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---
[snip]
> +
> +fn layout(pcie: bool) -> &'static Layout<'static> {
> + if pcie { &PCIE_LAYOUT } else { &PCI_LAYOUT }
> +}
> +
> +pub(crate) fn address(hw: &HardwareConfig, id: &str) -> Result<PciAddress, LayoutError> {
> + let layout = layout(hw.has_pcie());
> + layout.find_device(&id.parse()?)
> +}
> +
> +pub(crate) fn pci_bridge_for_device(hw: &HardwareConfig, id: &str) -> Option<Bus> {
> + let addr = address(hw, id).ok()?;
> + Some(addr.bus)
> +}
> +
> +pub(crate) fn pci_bus_devices(hw: &HardwareConfig) -> Result<Vec<String>, LayoutError> {
> + let mut bridges = Vec::new();
> + let layout = layout(hw.has_pcie());
> + let mut chassis_nr = 1;
> + for bridge in layout
> + .iter()
> + .filter(|d| matches!(d.device, Device::Bridge(_)))
> + {
> + let addr = bridge.addr;
> + let (model, id) = match bridge.device {
> + Device::Bridge(bus) => (bus.bridge_model(addr.bus), bus),
> + _ => continue,
> + };
> + let Some(model) = model else {
> + continue;
> + };
> + let mf = if addr.function == 0 {
> + ",multifunction=on"
Isn't the addr.function == 0 already encoded in AddressAssignment?
So we can just check for:
let mf = bridge.multifunction {
",multifunction=on"
> + } else {
> + ""
> + };
> +
> + let chassis = if model == "pci-bridge" {
> + let text = format!(",chassis_nr={chassis_nr}");
> + chassis_nr += 1;
We could consider deriving chassis_nr from something instead letting the
layout iteration assign a sequential ordering.
Similarly to how the legacy layout does it.
> + text
> + } else {
> + String::new()
> + };
> + bridges.push("-device".to_string());
> + bridges.push(format!(
> + "{model},id={id}{chassis}{}{mf}",
> + addr.to_qemu_addr()
> + ));
> + }
> +
> + for port in layout.root_ports(&hw.hostpcie()) {
> + bridges.push("-device".to_string());
> + bridges.push(port.to_qemu_device());
> + }
> +
> + Ok(bridges)
> +}
> +
[snip]
> diff --git a/pve-qemu-server-pci/src/layout/mod.rs b/pve-qemu-server-pci/src/layout/mod.rs
> index 5439c17..9a637ea 100644
> --- a/pve-qemu-server-pci/src/layout/mod.rs
> +++ b/pve-qemu-server-pci/src/layout/mod.rs
> @@ -13,6 +13,8 @@ macro_rules! single_device {
>
> pub(crate) mod legacy;
>
> +pub mod grouped;
> +
> /// Constructs a correctly sized list of bridge slots, starting at address 0x01
> /// because 0x00 is always taken by the bridge itself.
> ///
> diff --git a/pve-qemu-server-pci/src/lib.rs b/pve-qemu-server-pci/src/lib.rs
> index a5d82a4..5417fa5 100644
> --- a/pve-qemu-server-pci/src/lib.rs
> +++ b/pve-qemu-server-pci/src/lib.rs
> @@ -21,10 +21,45 @@ pub use error::LayoutError;
>
> pub mod layout;
>
> +/// The set of layouts a guest's addresses are taken from.
> +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq)]
> +pub enum PciLayout {
> + /// The layouts reproducing the addresses of the Perl implementation.
> + #[default]
> + Legacy,
> + /// The layouts giving every device kind its own set of bridges, see
> + /// [`layout::grouped`].
> + Grouped,
> +}
> +
IMHO the code for PciLayout enum should live inside layout module.
e.g. in layout/mod.rs
> +impl std::str::FromStr for PciLayout {
> + type Err = LayoutError;
> +
> + fn from_str(s: &str) -> Result<Self, Self::Err> {
> + match s {
> + "legacy" => Ok(Self::Legacy),
> + "grouped" => Ok(Self::Grouped),
> + _ => Err(LayoutError::InvalidLayout),
> + }
> + }
> +}
> +
> +impl std::fmt::Display for PciLayout {
> + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
> + f.write_str(match self {
> + PciLayout::Legacy => "legacy",
> + PciLayout::Grouped => "grouped",
> + })
> + }
> +}
> +
> /// Returns the number of the PCI bridge `id` sits on, or `None` if it is on
> /// the root bus or not a known device.
> -pub fn pci_bridge_for_device(id: &str) -> Option<Bus> {
> - layout::legacy::pci_bridge_for_device(id)
> +pub fn pci_bridge_for_device(hw: &HardwareConfig, id: &str) -> Option<Bus> {
> + match hw.layout {
> + PciLayout::Legacy => layout::legacy::pci_bridge_for_device(id),
> + PciLayout::Grouped => layout::grouped::pci_bridge_for_device(hw, id),
> + }
> }
nit naming: The function is called pci_bridge_for_device() but returns a Bus.
IMO the semantics here are a bit ambiguous.
What about renaming it to something like:
bridge_bus_for_device()
IMO we can also omit the "pci" prefix, since we are in the PCI crate.
>
> /// Returns the QEMU arguments for all devices that form the buses `hw`
> @@ -33,10 +68,16 @@ pub fn pci_bridge_for_device(id: &str) -> Option<Bus> {
> /// They are ordered so that every bus is created before the devices on it,
> /// and have to be passed before any other device that sits on these buses.
> pub fn pci_bus_devices(hw: &HardwareConfig) -> Result<Vec<String>, LayoutError> {
nit naming: we could also consider dropping the pci prefix of the
function name to "bus_devices".
> - layout::legacy::pci_bus_devices(hw)
> + match hw.layout {
> + PciLayout::Legacy => layout::legacy::pci_bus_devices(hw),
> + PciLayout::Grouped => layout::grouped::pci_bus_devices(hw),
> + }
> }
>
> /// Returns the address of the device with the configuration id `id`.
> pub fn address(hw: &HardwareConfig, id: &str) -> Result<PciAddress, LayoutError> {
> - layout::legacy::address(hw, id)
> + match hw.layout {
> + PciLayout::Legacy => layout::legacy::address(hw, id),
> + PciLayout::Grouped => layout::grouped::address(hw, id),
> + }
> }
> diff --git a/pve-qemu-server-pci/src/types/mod.rs b/pve-qemu-server-pci/src/types/mod.rs
> index 1605066..43b08c0 100644
> --- a/pve-qemu-server-pci/src/types/mod.rs
> +++ b/pve-qemu-server-pci/src/types/mod.rs
> @@ -3,6 +3,9 @@ pub use bus::{Bus, PveBridge};
>
> mod device;
> pub use device::Device;
> +// only needed to enumerate all device kinds in tests
> +#[cfg(test)]
> +pub(crate) use device::DeviceDiscriminants;
>
> mod pci_address;
> pub use pci_address::PciAddress;
next prev parent reply other threads:[~2026-10-29 13:38 UTC|newest]
Thread overview: 18+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-15 8:10 [RFC proxmox-perl-rs/qemu-server/qemu-server-rs v2 0/9] pci-handling rewrite (part 1/2/3) Dominik Csapak
2026-10-15 8:10 ` [PATCH pve-qemu-server-rs v2 1/9] add pve-qemu-server-pci crate for guest PCI address generation Dominik Csapak
2026-10-15 12:16 ` Wolfgang Bumiller
2026-10-29 13:31 ` Elias Huhsovitz
2026-10-15 8:10 ` [PATCH pve-qemu-server-rs v2 2/9] pci: legacy: generate pci bridges Dominik Csapak
2026-10-15 8:10 ` [PATCH pve-qemu-server-rs v2 3/9] pci: legacy: generate q35 chipset devices and hostpcie root ports Dominik Csapak
2026-10-29 13:31 ` Elias Huhsovitz
2026-10-15 8:10 ` [PATCH pve-qemu-server-rs v2 4/9] pci: layout: add grouped PCI and PCIe layouts Dominik Csapak
2026-10-29 13:31 ` Elias Huhsovitz [this message]
2026-10-15 8:10 ` [PATCH proxmox-perl-rs v2 5/9] pve: add bindings for `pve-qemu-server-pci` crate Dominik Csapak
2026-10-15 11:47 ` Wolfgang Bumiller
2026-10-15 8:10 ` [PATCH qemu-server v2 6/9] pci: use PVE::RS::PCI bindings for addresses and bus devices Dominik Csapak
2026-10-29 13:32 ` Elias Huhsovitz
2026-10-15 8:10 ` [PATCH qemu-server v2 7/9] tree-wide: use HardwareConfig for the machine version checks Dominik Csapak
2026-10-15 8:10 ` [PATCH qemu-server v2 8/9] cfg2cmd: q35: generate chipset devices with machine version 11.1+pve1 Dominik Csapak
2026-10-15 8:10 ` [PATCH qemu-server v2 9/9] machine: add 'pci-layout' option Dominik Csapak
2026-10-29 15:36 ` [RFC proxmox-perl-rs/qemu-server/qemu-server-rs v2 0/9] pci-handling rewrite (part 1/2/3) Fiona Ebner
2026-10-30 14:13 ` Dominik Csapak
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DMHCYCC2OX41.2KW2QLY0DG8H@proxmox.com \
--to=e.huhsovitz@proxmox.com \
--cc=d.csapak@proxmox.com \
--cc=pve-devel@lists.proxmox.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.