add pci multifunction support

multifunction device should be define without the .function

hostpci0: 00:00

example
-------
if 00:00.0
   00:00.1
   00:00.2

exists,

then we generate the multifunction devices

-device (pci-assign|vfio-pci),host=00:00.0,id=hostpci0.0,bus=...,addr=0x0.0,multifunction=on
-device (pci-assign|vfio-pci),host=00:00.1,id=hostpci0.1,bus=...,addr=0x0.1
-device (pci-assign|vfio-pci),host=00:00.2,id=hostpci0.2,bus=...,addr=0x0.2

Signed-off-by: Alexandre Derumier <aderumier@odiso.com>
This commit is contained in:
Alexandre Derumier 2014-06-23 17:41:54 +02:00 committed by Dietmar Maurer
parent 2e3b7e2a3a
commit 4543ecf07f

View File

@ -22,7 +22,7 @@ use PVE::SafeSyslog;
use Storable qw(dclone); use Storable qw(dclone);
use PVE::Exception qw(raise raise_param_exc); use PVE::Exception qw(raise raise_param_exc);
use PVE::Storage; use PVE::Storage;
use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline); use PVE::Tools qw(run_command lock_file lock_file_full file_read_firstline dir_glob_foreach);
use PVE::JSONSchema qw(get_standard_option); use PVE::JSONSchema qw(get_standard_option);
use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file); use PVE::Cluster qw(cfs_register_file cfs_read_file cfs_write_file cfs_lock_file);
use PVE::INotify; use PVE::INotify;
@ -1267,9 +1267,15 @@ sub parse_hostpci {
my $res = {}; my $res = {};
foreach my $kv (@list) { foreach my $kv (@list) {
if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2}\.[a-f0-9])$/) { if ($kv =~ m/^(host=)?([a-f0-9]{2}:[a-f0-9]{2})(\.([a-f0-9]))?$/) {
$found = 1; $found = 1;
$res->{pciid} = $2; if(defined($4)){
push @{$res->{pciid}}, { id => $2 , function => $4};
}else{
my $pcidevices = lspci($2);
$res->{pciid} = $pcidevices->{$2};
}
} elsif ($kv =~ m/^driver=(kvm|vfio)$/) { } elsif ($kv =~ m/^driver=(kvm|vfio)$/) {
$res->{driver} = $1; $res->{driver} = $1;
} elsif ($kv =~ m/^rombar=(on|off)$/) { } elsif ($kv =~ m/^rombar=(on|off)$/) {
@ -2430,9 +2436,26 @@ sub config_to_command {
my $driver = $d->{driver} && $d->{driver} eq 'vfio' ? "vfio-pci" : "pci-assign"; my $driver = $d->{driver} && $d->{driver} eq 'vfio' ? "vfio-pci" : "pci-assign";
my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ? ",x-vga=on" : ""; my $xvga = $d->{'x-vga'} && $d->{'x-vga'} eq 'on' ? ",x-vga=on" : "";
$driver = "vfio-pci" if $xvga ne ''; $driver = "vfio-pci" if $xvga ne '';
my $pcidevices = $d->{pciid};
my $multifunction = 1 if @$pcidevices > 1;
push @$devices, '-device', "$driver,host=$d->{pciid},id=hostpci$i$pciaddr$rombar$xvga"; my $j=0;
foreach my $pcidevice (@$pcidevices) {
my $id = "hostpci$i";
$id .= ".$j" if $multifunction;
my $addr = $pciaddr;
$addr .= ".$j" if $multifunction;
my $devicestr = "$driver,host=$pcidevice->{id}.$pcidevice->{function},id=$id$addr";
if($j == 0){
$devicestr .= "$rombar$xvga";
$devicestr .= ",multifunction=on" if $multifunction;
}
push @$devices, '-device', $devicestr;
$j++;
}
} }
# usb devices # usb devices
@ -5167,4 +5190,17 @@ sub get_current_qemu_machine {
return $current || $default || 'pc'; return $current || $default || 'pc';
} }
sub lspci {
my $devices = {};
dir_glob_foreach("$pcisysfs/devices", '[a-f0-9]{4}:([a-f0-9]{2}:[a-f0-9]{2})\.([0-9])', sub {
my (undef, $id, $function) = @_;
my $res = { id => $id, function => $function};
push @{$devices->{$id}}, $res;
});
return $devices;
}
1; 1;