[pve-devel] [PATCH common 2/2] SysFSTools.pm: improve and extend lspci

Dominik Csapak d.csapak at proxmox.com
Fri Nov 16 16:29:48 CET 2018


this implements following improvements and optimizations for lspci

* removes the unecessary split between id and function
  since everywhere we need that information, we stitch them together
  anyway. to preserve ordering, simply order by id with string
  comparison 'cmp' (this is important for the shorthand syntax '00:01' in
  the config)
* returns now a list directly, instead of an hash with lists
* filter now does not have to be an exact match, only the beginning has
  to match, this is not a problem for parse_hostpci, as we check
  the syntax there explicitely
* adds a filterunusable flag, which filters not pass-throughable
  devices, such as memory controllers, processors, etc.
  the pci classes are documented [1]
* adds a verbose flag to include more information about the device,
  such as device/vendor, iommu-group, mdev support, etc.
  this will be used for the pci scan api call for the gui

1: https://pci-ids.ucw.cz/read/PD/

Signed-off-by: Dominik Csapak <d.csapak at proxmox.com>
---
 src/PVE/SysFSTools.pm | 94 ++++++++++++++++++++++++++++++++++++++++++++-------
 1 file changed, 82 insertions(+), 12 deletions(-)

diff --git a/src/PVE/SysFSTools.pm b/src/PVE/SysFSTools.pm
index a031713..5d3aea4 100644
--- a/src/PVE/SysFSTools.pm
+++ b/src/PVE/SysFSTools.pm
@@ -10,24 +10,94 @@ use PVE::Tools qw(file_read_firstline dir_glob_foreach);
 my $pcisysfs = "/sys/bus/pci";
 my $pciregex = "([a-f0-9]{4}):([a-f0-9]{2}):([a-f0-9]{2})\.([a-f0-9])";
 
+my $parse_pci_ids = sub {
+    my $ids = {};
+
+    open(my $fh, '<', "/usr/share/misc/pci.ids")
+	or return $ids;
+
+    my $curvendor;
+    my $curdevice;
+    while (my $line = <$fh>) {
+	if ($line =~ m/^([0-9a-fA-F]{4})\s+(.*)$/) {
+	    $curvendor = ($ids->{"0x$1"} = {});
+	    $curvendor->{name} = $2;
+	} elsif ($line =~ m/^\t([0-9a-fA-F]{4})\s+(.*)$/) {
+	    $curdevice = ($curvendor->{devices}->{"0x$1"} = {});
+	    $curdevice->{name} = $2;
+	} elsif ($line =~ m/^\t\t([0-9a-fA-F]{4}) ([0-9a-fA-F]{4})\s+(.*)$/) {
+	    $curdevice->{subs}->{"0x$1"}->{"0x$2"} = $3;
+	}
+    }
+
+    return $ids;
+};
+
 sub lspci {
-    my ($filter) = @_;
+    my ($filter, $filterunusable, $verbose) = @_;
 
-    my $devices = {};
+    my $devices = [];
+    my $ids = {};
+    if ($verbose) {
+	$ids = $parse_pci_ids->();
+    }
 
     dir_glob_foreach("$pcisysfs/devices", $pciregex, sub {
-            my (undef, undef, $bus, $slot, $function) = @_;
-	    my $id = "$bus:$slot";
-	    return if defined($filter) && $id ne $filter;
-	    my $res = { id => $id, function => $function};
-	    push @{$devices->{$id}}, $res;
+	    my ($fullid, $domain, $bus, $slot, $function) = @_;
+	    my $id = "$bus:$slot.$function";
+	    return if defined($filter) && $id !~ m/^\Q$filter\E/;
+	    my $res = { id => $id, };
+
+	    my $devdir = "$pcisysfs/devices/$fullid";
+
+	    if ($filterunusable) {
+		my $class = substr(file_read_firstline("$devdir/class"), 2, 2);
+		# skips:
+		# 05 - Memory Controller
+		# 06 - Bridge
+		# 08 - Generic system peripheral
+		# 0b - Processor
+		return if $class =~ m/^05|06|08|0b$/;
+	    }
+
+	    if ($verbose) {
+		my $vendorid = file_read_firstline("$devdir/vendor");
+		my $deviceid = file_read_firstline("$devdir/device");
+		my $svendorid = file_read_firstline("$devdir/subsystem_vendor");
+		my $sdeviceid = file_read_firstline("$devdir/subsystem_device");
+
+		my $iommugroup = -1;
+		if (-e "$devdir/iommu_group") {
+		    ($iommugroup) = (readlink("$devdir/iommu_group") =~ m/\/(\d+)$/);
+		    $iommugroup = int($iommugroup);
+		}
+
+		my $vendor = $ids->{$vendorid}->{name};
+		my $device = $ids->{$vendorid}->{devices}->{$deviceid}->{name};
+		my $svendor = $ids->{$svendorid}->{name};
+		my $sdevice = $ids->{$vendorid}->{devices}->{$deviceid}->{subs}->{$svendorid}->{$sdeviceid};
+
+		$res->{vendorid} = $vendorid;
+		$res->{deviceid} = $deviceid;
+
+		if (-d "$devdir/mdev_supported_types") {
+		    $res->{mdev} = 1;
+		}
+
+		$res->{vendor} = $vendor if defined($vendor);
+		$res->{device} = $device if defined($device);
+		$res->{subsystem_vendorid} = $svendorid if defined($svendorid);
+		$res->{subsystem_vendor} = $svendor if defined($svendor);
+		$res->{subsystem_deviceid} = $sdeviceid if defined($sdeviceid);
+		$res->{subsystem_device} = $sdevice if defined($sdevice);
+		$res->{iommugroup} = $iommugroup if defined($iommugroup);
+	    }
+
+	    push @$devices, $res;
     });
 
-    # Entries should be sorted by functions.
-    foreach my $id (keys %$devices) {
-	my $dev = $devices->{$id};
-	$devices->{$id} = [ sort { $a->{function} <=> $b->{function} } @$dev ];
-    }
+    # Entries should be sorted by ids
+    $devices = [ sort { $a->{id} cmp $b->{id} } @$devices ];
 
     return $devices;
 }
-- 
2.11.0





More information about the pve-devel mailing list