On 11/13/18 3:18 PM, Dominik Csapak wrote: > and refactor the pci regex in lspci and pci_device_info
do this in two steps please, 1. move only 2. refactor way easier to see what's going on... and you need to send a v2 anyway, as you notified me off-list, so this could be included there. > > Signed-off-by: Dominik Csapak <[email protected]> > --- > PVE/QemuServer.pm | 157 > +++----------------------------------------------- > PVE/QemuServer/PCI.pm | 148 +++++++++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 155 insertions(+), 150 deletions(-) > > diff --git a/PVE/QemuServer.pm b/PVE/QemuServer.pm > index bf1a1fb..71ef81c 100644 > --- a/PVE/QemuServer.pm > +++ b/PVE/QemuServer.pm > @@ -2078,7 +2078,7 @@ sub parse_hostpci { > if (defined($2)) { > push @{$res->{pciid}}, { id => $1, function => $2 }; > } else { > - my $pcidevices = lspci($1); > + my $pcidevices = PVE::QemuServer::PCI::lspci($1); > $res->{pciid} = $pcidevices->{$1}; > } > } else { > @@ -2427,15 +2427,6 @@ sub check_type { > } > } > > -sub check_iommu_support{ > - #fixme : need to check IOMMU support > - #http://www.linux-kvm.org/page/How_to_assign_devices_with_VT-d_in_KVM > - > - my $iommu=1; > - return $iommu; > - > -} > - > sub touch_config { > my ($vmid) = @_; > > @@ -5033,11 +5024,13 @@ sub vm_start { > foreach my $pcidevice (@$pcidevices) { > my $pciid = $pcidevice->{id}.".".$pcidevice->{function}; > > - my $info = pci_device_info("0000:$pciid"); > - die "IOMMU not present\n" if !check_iommu_support(); > + my $info = PVE::QemuServer::PCI::pci_device_info("0000:$pciid"); > + die "IOMMU not present\n" if > !PVE::QemuServer::PCI::check_iommu_support(); > die "no pci device info for device '$pciid'\n" if !$info; > - die "can't unbind/bind pci group to vfio '$pciid'\n" if > !pci_dev_group_bind_to_vfio($pciid); > - die "can't reset pci device '$pciid'\n" if > $info->{has_fl_reset} and !pci_dev_reset($info); > + die "can't unbind/bind pci group to vfio '$pciid'\n" > + if > !PVE::QemuServer::PCI::pci_dev_group_bind_to_vfio($pciid); > + die "can't reset pci device '$pciid'\n" > + if $info->{has_fl_reset} and > !PVE::QemuServer::PCI::pci_dev_reset($info); > } > } > > @@ -5442,123 +5435,6 @@ sub vm_destroy { > }); > } > > -# pci helpers > - > -sub file_write { > - my ($filename, $buf) = @_; > - > - my $fh = IO::File->new($filename, "w"); > - return undef if !$fh; > - > - my $res = print $fh $buf; > - > - $fh->close(); > - > - return $res; > -} > - > -sub pci_device_info { > - my ($name) = @_; > - > - my $res; > - > - return undef if $name !~ > m/^([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])$/; > - my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4); > - > - my $irq = file_read_firstline("$pcisysfs/devices/$name/irq"); > - return undef if !defined($irq) || $irq !~ m/^\d+$/; > - > - my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor"); > - return undef if !defined($vendor) || $vendor !~ s/^0x//; > - > - my $product = file_read_firstline("$pcisysfs/devices/$name/device"); > - return undef if !defined($product) || $product !~ s/^0x//; > - > - $res = { > - name => $name, > - vendor => $vendor, > - product => $product, > - domain => $domain, > - bus => $bus, > - slot => $slot, > - func => $func, > - irq => $irq, > - has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0, > - }; > - > - return $res; > -} > - > -sub pci_dev_reset { > - my ($dev) = @_; > - > - my $name = $dev->{name}; > - > - my $fn = "$pcisysfs/devices/$name/reset"; > - > - return file_write($fn, "1"); > -} > - > -sub pci_dev_bind_to_vfio { > - my ($dev) = @_; > - > - my $name = $dev->{name}; > - > - my $vfio_basedir = "$pcisysfs/drivers/vfio-pci"; > - > - if (!-d $vfio_basedir) { > - system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null"); > - } > - die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir; > - > - my $testdir = "$vfio_basedir/$name"; > - return 1 if -d $testdir; > - > - my $data = "$dev->{vendor} $dev->{product}"; > - return undef if !file_write("$vfio_basedir/new_id", $data); > - > - my $fn = "$pcisysfs/devices/$name/driver/unbind"; > - if (!file_write($fn, $name)) { > - return undef if -f $fn; > - } > - > - $fn = "$vfio_basedir/bind"; > - if (! -d $testdir) { > - return undef if !file_write($fn, $name); > - } > - > - return -d $testdir; > -} > - > -sub pci_dev_group_bind_to_vfio { > - my ($pciid) = @_; > - > - my $vfio_basedir = "$pcisysfs/drivers/vfio-pci"; > - > - if (!-d $vfio_basedir) { > - system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null"); > - } > - die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir; > - > - # get IOMMU group devices > - opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || > die "Cannot open iommu_group: $!\n"; > - my @devs = grep /^0000:/, readdir($D); > - closedir($D); > - > - foreach my $pciid (@devs) { > - $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n"; > - > - # pci bridges, switches or root ports are not supported > - # they have a pci_bus subdirectory so skip them > - next if (-e "$pcisysfs/devices/$pciid/pci_bus"); > - > - my $info = pci_device_info($1); > - pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n"; > - } > - > - return 1; > -} > - > # vzdump restore implementaion > > sub tar_archive_read_firstfile { > @@ -6761,25 +6637,6 @@ sub create_efidisk { > return ($volid, $vars_size); > } > > -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; > - }); > - > - # Entries should be sorted by functions. > - foreach my $id (keys %$devices) { > - my $dev = $devices->{$id}; > - $devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ]; > - } > - > - return $devices; > -} > - > sub vm_iothreads_list { > my ($vmid) = @_; > > diff --git a/PVE/QemuServer/PCI.pm b/PVE/QemuServer/PCI.pm > index 5ddda4f..ab534f4 100644 > --- a/PVE/QemuServer/PCI.pm > +++ b/PVE/QemuServer/PCI.pm > @@ -1,5 +1,7 @@ > package PVE::QemuServer::PCI; > > +use PVE::Tools qw(file_read_firstline dir_glob_foreach); > + > use base 'Exporter'; > > our @EXPORT_OK = qw( > @@ -145,3 +147,149 @@ sub print_pcie_addr { > return $res; > > } > + > +my $pcisysfs = "/sys/bus/pci"; > +my $pciregex = > "([a-fA-F0-9]{4}):([a-fA-F0-9]{2}):([a-fA-F0-9]{2})\.([a-fA-F0-9])"; > + > +sub lspci { > + > + my $devices = {}; > + > + dir_glob_foreach("$pcisysfs/devices", '${pciregex}', sub { > + my (undef, $domain, $bus, $slot, $function) = @_; > + my $id = "$bus:$slot"; > + my $res = { id => $id, function => $function }; > + push @{$devices->{$id}}, $res; > + }); > + > + # Entries should be sorted by functions. > + foreach my $id (keys %$devices) { > + my $dev = $devices->{$id}; > + $devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ]; > + } > + > + return $devices; > +} > + > + > +sub check_iommu_support{ > + my $entry = PVE::Tools::dir_glob_regex('/sys/class/iommu/', '[^\.].*'); > + return defined($entry); > +} > + > +sub file_write { > + my ($filename, $buf) = @_; > + > + my $fh = IO::File->new($filename, "w"); > + return undef if !$fh; > + > + my $res = print $fh $buf; > + > + $fh->close(); > + > + return $res; > +} > + > +sub pci_device_info { > + my ($name) = @_; > + > + my $res; > + > + return undef if $name !~ m/^${pciregex}$/; > + my ($domain, $bus, $slot, $func) = ($1, $2, $3, $4); > + > + my $irq = file_read_firstline("$pcisysfs/devices/$name/irq"); > + return undef if !defined($irq) || $irq !~ m/^\d+$/; > + > + my $vendor = file_read_firstline("$pcisysfs/devices/$name/vendor"); > + return undef if !defined($vendor) || $vendor !~ s/^0x//; > + > + my $product = file_read_firstline("$pcisysfs/devices/$name/device"); > + return undef if !defined($product) || $product !~ s/^0x//; > + > + $res = { > + name => $name, > + vendor => $vendor, > + product => $product, > + domain => $domain, > + bus => $bus, > + slot => $slot, > + func => $func, > + irq => $irq, > + has_fl_reset => -f "$pcisysfs/devices/$name/reset" || 0, > + }; > + > + return $res; > +} > + > +sub pci_dev_reset { > + my ($dev) = @_; > + > + my $name = $dev->{name}; > + > + my $fn = "$pcisysfs/devices/$name/reset"; > + > + return file_write($fn, "1"); > +} > + > +sub pci_dev_bind_to_vfio { > + my ($dev) = @_; > + > + my $name = $dev->{name}; > + > + my $vfio_basedir = "$pcisysfs/drivers/vfio-pci"; > + > + if (!-d $vfio_basedir) { > + system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null"); > + } > + die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir; > + > + my $testdir = "$vfio_basedir/$name"; > + return 1 if -d $testdir; > + > + my $data = "$dev->{vendor} $dev->{product}"; > + return undef if !file_write("$vfio_basedir/new_id", $data); > + > + my $fn = "$pcisysfs/devices/$name/driver/unbind"; > + if (!file_write($fn, $name)) { > + return undef if -f $fn; > + } > + > + $fn = "$vfio_basedir/bind"; > + if (! -d $testdir) { > + return undef if !file_write($fn, $name); > + } > + > + return -d $testdir; > +} > + > +sub pci_dev_group_bind_to_vfio { > + my ($pciid) = @_; > + > + my $vfio_basedir = "$pcisysfs/drivers/vfio-pci"; > + > + if (!-d $vfio_basedir) { > + system("/sbin/modprobe vfio-pci >/dev/null 2>/dev/null"); > + } > + die "Cannot find vfio-pci module!\n" if !-d $vfio_basedir; > + > + # get IOMMU group devices > + opendir(my $D, "$pcisysfs/devices/0000:$pciid/iommu_group/devices/") || > die "Cannot open iommu_group: $!\n"; > + my @devs = grep /^0000:/, readdir($D); > + closedir($D); > + > + foreach my $pciid (@devs) { > + $pciid =~ m/^([:\.\da-f]+)$/ or die "PCI ID $pciid not valid!\n"; > + > + # pci bridges, switches or root ports are not supported > + # they have a pci_bus subdirectory so skip them > + next if (-e "$pcisysfs/devices/$pciid/pci_bus"); > + > + my $info = pci_device_info($1); > + pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n"; > + } > + > + return 1; > +} > + > +1; > _______________________________________________ pve-devel mailing list [email protected] https://pve.proxmox.com/cgi-bin/mailman/listinfo/pve-devel
