With this, we can now tell qemu-server to choose the first avaiable
devices, which makes using vGPUs and SR-IOV capable devices much easier
to use, since the user does not have to hardcode the device, but can
give a list of identical ones, and qemu-server chooses dynamically.

note that we require the devices all to be the same vendor/device,
because we don't want to group unrelated devices, but we only check
the iommugroup for the first device, but there is a high chance
that this also changes when somethings off since e.g. SRIOV devices
are most often created at the same time, so when the any has a different
group, the first one will too

Signed-off-by: Dominik Csapak <d.csa...@proxmox.com>
---
 src/PVE/HardwareMap.pm | 68 +++++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 28 deletions(-)

diff --git a/src/PVE/HardwareMap.pm b/src/PVE/HardwareMap.pm
index 7a90220..4a322ff 100644
--- a/src/PVE/HardwareMap.pm
+++ b/src/PVE/HardwareMap.pm
@@ -84,9 +84,11 @@ my $format = {
        },
        path => {
            description => "The path to the device. If the function is omitted, 
the whole device is"
-               ." mapped. In that case use the attributes of the first 
device.",
+               ." mapped. In that case use the attributes of the first device. 
You can give"
+               ." multiple paths as a semicolon seperated list, the first 
available will then"
+               ." be chosen on guest start.",
            type => 'string',
-           pattern => "${PCI_RE}",
+           pattern => "(?:${PCI_RE};)*${PCI_RE}",
        },
        mdev => {
            description => "The Device supports mediated devices.",
@@ -212,37 +214,47 @@ sub write_hardware_map {
 my $pci_valid = sub {
     my ($cfg) = @_;
 
-    if ($path !~ m/\.[a-f0-9]/i) {
-       # whole device, add .0 (must exist)
-       $path = "$path.0";
-    }
+    my @paths = split(';', $cfg->{path} // '');
 
-    my $info = PVE::SysFSTools::pci_device_info($path, 1);
-    die "pci device '$path' not found\n" if !defined($info);
 
-    my $correct_props = {
-       vendor => $info->{vendor},
-       device => $info->{device},
-       'subsystem-vendor' => $info->{'subsystem_vendor'},
-       'subsystem-device' => $info->{'subsystem_device'},
-       mdev => $info->{mdev},
-       iommugroup => $info->{iommugroup},
-    };
+    my $idx = 0;
+    for my $path (@paths) {
 
-    for my $prop (sort keys %$correct_props) {
-       next if !defined($correct_props->{$prop}) && !defined($cfg->{$prop});
-       die "no '$prop' for device '$path'\n"
-           if defined($correct_props->{$prop}) && !defined($cfg->{$prop});
-       die "'$prop' configured but should not be\n"
-           if !defined($correct_props->{$prop}) && defined($cfg->{$prop});
+       if ($path !~ m/\.[a-f0-9]/i) {
+           # whole device, add .0 (must exist)
+           $path = "$path.0";
+       }
 
-       my $correct_prop = $correct_props->{$prop};
-       $correct_prop =~ s/^0x//;
-       my $configured_prop = $cfg->{$prop};
-       $configured_prop =~ s/^0x//;
+       my $info = PVE::SysFSTools::pci_device_info($path, 1);
+       die "pci device '$path' not found\n" if !defined($info);
+
+       my $correct_props = {
+           vendor => $info->{vendor},
+           device => $info->{device},
+           'subsystem-vendor' => $info->{'subsystem_vendor'},
+           'subsystem-device' => $info->{'subsystem_device'},
+           mdev => $info->{mdev},
+           iommugroup => $info->{iommugroup},
+       };
 
-       die "'$prop' does not match for '$cfg->{name}' ($correct_prop != 
$configured_prop)\n"
-           if $correct_prop ne $configured_prop;
+       for my $prop (sort keys %$correct_props) {
+           next if $prop eq 'iommugroup' && $idx > 0; # check iommu only on 
the first device
+
+           next if !defined($correct_props->{$prop}) && 
!defined($cfg->{$prop});
+           die "no '$prop' for device '$path'\n"
+               if defined($correct_props->{$prop}) && !defined($cfg->{$prop});
+           die "'$prop' configured but should not be\n"
+               if !defined($correct_props->{$prop}) && defined($cfg->{$prop});
+
+           my $correct_prop = $correct_props->{$prop};
+           $correct_prop =~ s/^0x//;
+           my $configured_prop = $cfg->{$prop};
+           $configured_prop =~ s/^0x//;
+
+           die "'$prop' does not match for '$cfg->{name}' ($correct_prop != 
$configured_prop)\n"
+               if $correct_prop ne $configured_prop;
+       }
+       $idx++;
     }
 
     return 1;
-- 
2.30.2



_______________________________________________
pve-devel mailing list
pve-devel@lists.proxmox.com
https://lists.proxmox.com/cgi-bin/mailman/listinfo/pve-devel

Reply via email to