public inbox for pve-devel@lists.proxmox.com
 help / color / mirror / Atom feed
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 3/9] pci: legacy: generate q35 chipset devices and hostpcie root ports
Date: Thu, 29 Oct 2026 14:31:24 +0100	[thread overview]
Message-ID: <DMHCY5JNS70G.25HKWPX5XBMST@proxmox.com> (raw)
In-Reply-To: <20261015081041.743422-4-d.csapak@proxmox.com>

Comments inline.

On Thu Oct 15, 2026 at 10:10 AM CEST, Dominik Csapak wrote:
> Until now, the q35 chipset devices were added via the pve-q35-4.0.cfg
> machine config file, and the root ports for hostpcie4 and above were
> added by the caller for each configured device.
>
> The latter can leave a root port without a function 0 in its slot,
> e.g. when only hostpci5 is configured. Since guests only scan the
> other functions of a slot when function 0 exists (Linux stops in
> `pci_scan_slot()`), such a device was not visible in the guest.
>
> To fix that and to have the layout as the single source for the pci
> hierarchy, generate both in `pci_bus_devices`:
> * the chipset devices with the same ids, properties and order as in
>   the config file, which a test checks against a copy of it. Machines
>   older than 4.0 used pve-q35.cfg instead, but those are not supported
>   anymore.
> * the root ports of the configured hostpcie devices, plus the one on
>   function 0 of each used slot. Devices that were already visible keep
>   their address, and Windows 7 guests still don't get any root ports.
>
> Since the devices of running guests must not change for live
> migration, we only generate the chipset devices starting with machine
> version 11.1+pve1. For older machines, `uses_q35_config_file` tells
> the caller to keep using the config file.
>
> This replaces `print_pcie_root_port`, as we now decide here which root
> ports are needed.
>
> Signed-off-by: Dominik Csapak <d.csapak@proxmox.com>
> ---

[snip]

> diff --git a/pve-qemu-server-pci/src/lib.rs b/pve-qemu-server-pci/src/lib.rs
> index fc982ce..a5d82a4 100644
> --- a/pve-qemu-server-pci/src/lib.rs
> +++ b/pve-qemu-server-pci/src/lib.rs
> @@ -11,7 +11,7 @@
>  pub mod constants;
>  
>  mod hardware_config;
> -pub use hardware_config::HardwareConfig;
> +pub use hardware_config::{HardwareConfig, HostpcieDevice};
>  
>  mod types;
>  pub use types::*;
> diff --git a/pve-qemu-server-pci/src/types/layout.rs b/pve-qemu-server-pci/src/types/layout.rs
> index 889b961..91b1d78 100644
> --- a/pve-qemu-server-pci/src/types/layout.rs
> +++ b/pve-qemu-server-pci/src/types/layout.rs
> @@ -1,4 +1,4 @@
> -use std::collections::VecDeque;
> +use std::collections::{HashSet, VecDeque};
>  
>  use crate::constants::{FUNCTIONS_PER_DEVICE, SLOTS_PER_BUS, USABLE_SLOTS_PER_BUS};
>  use crate::{Bus, Device, LayoutError, PciAddress, PveBridge};
> @@ -48,6 +48,46 @@ pub struct Layout<'a> {
>  }
>  
>  impl Layout<'_> {
> +    /// Returns the root ports `devices` are attached to in layout order, plus
> +    /// the one on function 0 of each used slot, as guests only look for further
> +    /// functions if function 0 exists.
> +    pub fn root_ports(&self, devices: &[Device]) -> Vec<RootPort> {
> +        let attached: HashSet<PciAddress> = devices
> +            .iter()
> +            .filter_map(|device| self.find_device(device).ok())
> +            .collect();
> +        let is_used = |port: &RootPort| attached.contains(&PciAddress::new(port.id, 0, 0));
> +
> +        let ports: Vec<RootPort> = self
> +            .iter()
> +            .filter_map(|used| match used.device {
> +                #[expect(deprecated)]
> +                Device::RootPort(id @ (Bus::RootPort(index) | Bus::LegacyRootPort(index))) => {
> +                    Some(RootPort {
> +                        addr: used.addr,
> +                        id,
> +                        index,
> +                    })
> +                }
> +                _ => None,
> +            })
> +            .collect();
> +        let used_slots: HashSet<(Bus, u8)> = ports
> +            .iter()
> +            .filter(|port| is_used(port))
> +            .map(|port| (port.addr.bus, port.addr.device))
> +            .collect();
> +
> +        ports
> +            .into_iter()
> +            .filter(|port| {
> +                is_used(port)
> +                    || (port.addr.function == 0
> +                        && used_slots.contains(&(port.addr.bus, port.addr.device)))
> +            })
> +            .collect()
> +    }
> +
>      /// Looks up the address of a device in this layout.
>      ///
>      /// The first match wins, so the order of the layout is significant: a
> @@ -68,6 +108,27 @@ impl Layout<'_> {
>      }
>  }
>  
> +/// A PCIe root port of a layout.
> +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
> +pub struct RootPort {
> +    pub addr: PciAddress,
> +    /// The bus the root port forms.
> +    pub id: Bus,
> +    /// The number of the root port, also used as port and chassis number.
> +    pub index: u8,
> +}
> +
> +impl RootPort {
> +    /// Renders the QEMU `-device` argument for this root port.
> +    pub fn to_qemu_device(&self) -> String {
> +        let RootPort { addr, id, index } = self;
> +        format!(
> +            "pcie-root-port,id={id},addr={:02x}.{},x-speed=16,x-width=32,multifunction=on,bus={},port={index},chassis={index}",
> +            addr.device, addr.function, addr.bus,

nit: I understand that setting multifunction=on shouldnt cause any harm
here, but IMO it should still be encoded in RootPort. e.g.

pub struct RootPort {
    pub addr: PciAddress,
    /// The bus the root port forms.
    pub id: Bus,
    /// The number of the root port, also used as port and chassis number.
    pub index: u8,
	pub multifunction: bool,
}

> +        )
> +    }
> +}
> +

nit: I understand that setting multifunction=on shouldnt cause any harm
here, but IMO it should still be encoded in RootPort. e.g.

pub struct RootPort {
    pub addr: PciAddress,
    /// The bus the root port forms.
    pub id: Bus,
    /// The number of the root port, also used as port and chassis number.
    pub index: u8,
    pub multifunction: bool,
}

>  /// The address a layout assigns to a device.
>  #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
>  pub struct AddressAssignment {

[snip]




  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 [this message]
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
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=DMHCY5JNS70G.25HKWPX5XBMST@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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
Service provided by Proxmox Server Solutions GmbH | Privacy | Legal