+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";
+ my $info = pci_device_info($1);
+ pci_dev_bind_to_vfio($info) || die "Cannot bind $pciid to vfio\n";
+ }
+
+ return 1;
+}
+