X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=src%2FPVE%2FSysFSTools.pm;h=2da3a38894268cb33acd2ad3b4414fb16888cb39;hb=5c1556cd27c93705eef1d02f2d09e0c245212e67;hp=b0a025f28ea051847b41938776fcdc53c5327b16;hpb=44a4db5b60b8a69e28d764682ffdb9874e67aba3;p=pve-common.git diff --git a/src/PVE/SysFSTools.pm b/src/PVE/SysFSTools.pm index b0a025f..2da3a38 100644 --- a/src/PVE/SysFSTools.pm +++ b/src/PVE/SysFSTools.pm @@ -10,29 +10,141 @@ 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; +}; + +# returns a list of pci devices +# +# filter is either a string (then it tries to match to the id) +# or a sub ref (then it adds the device if the sub returns truthy) +# +# verbose also returns iommu groups, subvendor/device and the +# human readable names from /usr/share/misc/pci.ids +# +# return format: +# [ +# { +# id => '00:00.0', +# vendor => '0xabab', +# device => '0xefef', +# class => '0x012345', +# +# # optional +# iommugroup => '14', +# mdev => 1, +# vendor_name => 'Foo Inc.', +# device_name => 'Bar 9000AF', +# subsystem_vendor => '0xacac', +# subsystem_device => '0xfefe', +# subsystem_vendor_name => 'Foo Europe GmbH', +# subsystem_device_name => 'Bar 9001AF OC', +# }, +# ... +# ] +# sub lspci { - my ($id_filter) = @_; + my ($filter, $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 ($fullid, $domain, $bus, $slot, $function) = @_; + my $id = "$bus:$slot.$function"; - my $id = "$bus:$slot"; - return if defined($id_filter) && $id_filter ne $id; + if (defined($filter) && !ref($filter) && $id !~ m/^\Q$filter\E/) { + return; # filter ids early + } + + my $devdir = "$pcisysfs/devices/$fullid"; + + my $vendor = file_read_firstline("$devdir/vendor"); + my $device = file_read_firstline("$devdir/device"); + my $class = file_read_firstline("$devdir/class"); + + my $res = { + id => $id, + vendor => $vendor, + device => $device, + class => $class, + }; - push @{$devices->{$id}}, { id => $id, function => $function }; + if (defined($filter) && ref($filter) eq 'CODE' && !$filter->($res)) { + return; + } + + if ($verbose) { + $res->{iommugroup} = -1; + if (-e "$devdir/iommu_group") { + my ($iommugroup) = (readlink("$devdir/iommu_group") =~ m/\/(\d+)$/); + $res->{iommugroup} = int($iommugroup); + } + + if (-d "$devdir/mdev_supported_types") { + $res->{mdev} = 1; + } + + my $device_hash = $ids->{$vendor}->{devices}->{$device} // {}; + + my $sub_vendor = file_read_firstline("$devdir/subsystem_vendor"); + my $sub_device = file_read_firstline("$devdir/subsystem_device"); + + my $vendor_name = $ids->{$vendor}->{name}; + my $device_name = $device_hash->{name}; + my $sub_vendor_name = $ids->{$sub_vendor}->{name}; + my $sub_device_name = $device_hash->{subs}->{$sub_vendor}->{$sub_device}; + + $res->{vendor_name} = $vendor_name if defined($vendor_name); + $res->{device_name} = $device_name if defined($device_name); + $res->{subsystem_vendor} = $sub_vendor if defined($sub_vendor); + $res->{subsystem_device} = $sub_device if defined($sub_device); + $res->{subsystem_vendor_name} = $sub_vendor_name if defined($sub_vendor_name); + $res->{subsystem_device_name} = $sub_device_name if defined($sub_device_name); + } + + 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; } +# +# return format: +# [ +# { +# type => 'FooType_1', +# description => "a longer description with custom format\nand newlines", +# available => 5, +# }, +# ... +# ] +# sub get_mdev_types { my ($id) = @_;