From f0765c717400f2e566dd6026e3257a8b1e0b1f02 Mon Sep 17 00:00:00 2001 From: Dominik Csapak Date: Fri, 16 Nov 2018 16:17:46 +0100 Subject: [PATCH] introduce SysFSTools initially, copy pci related subs from PVE::QemuServer we want to have it in common, so we can maybe reuse them later, also the code is not really qemu-server related Signed-off-by: Dominik Csapak Signed-off-by: Thomas Lamprecht --- src/Makefile | 1 + src/PVE/SysFSTools.pm | 155 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 156 insertions(+) create mode 100644 src/PVE/SysFSTools.pm diff --git a/src/Makefile b/src/Makefile index 3d9bdb8..02f1f56 100644 --- a/src/Makefile +++ b/src/Makefile @@ -30,6 +30,7 @@ LIB_SOURCES = \ SectionConfig.pm \ Subscription.pm \ Syscall.pm \ + SysFSTools.pm \ Systemd.pm \ Ticket.pm \ Tools.pm diff --git a/src/PVE/SysFSTools.pm b/src/PVE/SysFSTools.pm new file mode 100644 index 0000000..8906f19 --- /dev/null +++ b/src/PVE/SysFSTools.pm @@ -0,0 +1,155 @@ +package PVE::SysFSTools; + +use strict; +use warnings; + +use IO::File; + +use PVE::Tools qw(file_read_firstline dir_glob_foreach); + +my $pcisysfs = "/sys/bus/pci"; + +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 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 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; +} + +1; -- 2.39.2