(Apologies to "mj" for duplicate send, the mailing list subscription was
finally sorted out.)
The attached perl script tries to use lspci -n and the information in
/sys/devices and /lib/modules/$kernel/modules.alias to describe the PCI
devices on the system. I'm trying to make it tease out what drivers are
built in (from /sys/devices) and which are loaded as modules (from
/lib/modules). While overall this resembles the output of "lspci -k"
there are a few differences I cannot explain yet.
On an old IBM server the outputs are:
lspci -k
00:01.0 PCI bridge: Broadcom BCM5785 [HT1000] PCI/PCI-X Bridge
Kernel modules: shpchp
00:02.0 Host bridge: Broadcom BCM5785 [HT1000] Legacy South Bridge
Subsystem: IBM BCM5785 [HT1000] Legacy South Bridge
Kernel driver in use: piix4_smbus
Kernel modules: i2c_piix4
00:02.1 IDE interface: Broadcom BCM5785 [HT1000] IDE
Subsystem: IBM BCM5785 [HT1000] IDE
Kernel driver in use: pata_serverworks
Kernel modules: pata_serverworks, pata_acpi
00:02.2 ISA bridge: Broadcom BCM5785 [HT1000] LPC
Subsystem: IBM BCM5785 [HT1000] LPC
00:03.0 USB controller: Broadcom BCM5785 [HT1000] USB (rev 01)
Subsystem: IBM BCM5785 [HT1000] USB
Kernel driver in use: ohci-pci
00:03.1 USB controller: Broadcom BCM5785 [HT1000] USB (rev 01)
Subsystem: IBM BCM5785 [HT1000] USB
Kernel driver in use: ohci-pci
00:03.2 USB controller: Broadcom BCM5785 [HT1000] USB (rev 01)
Subsystem: IBM BCM5785 [HT1000] USB
Kernel driver in use: ehci-pci
00:05.0 VGA compatible controller: Advanced Micro Devices, Inc.
[AMD/ATI] ES1000 (rev 02)
Subsystem: IBM ES1000
Kernel driver in use: radeon
Kernel modules: radeonfb, radeon
00:06.0 PCI bridge: Broadcom HT2100 PCI-Express Bridge (rev a2)
Kernel driver in use: pcieport
Kernel modules: shpchp
00:07.0 PCI bridge: Broadcom HT2100 PCI-Express Bridge (rev a2)
Kernel driver in use: pcieport
Kernel modules: shpchp
00:08.0 PCI bridge: Broadcom HT2100 PCI-Express Bridge (rev a2)
Kernel driver in use: pcieport
Kernel modules: shpchp
00:09.0 PCI bridge: Broadcom HT2100 PCI-Express Bridge (rev a2)
Kernel driver in use: pcieport
Kernel modules: shpchp
00:0a.0 PCI bridge: Broadcom HT2100 PCI-Express Bridge (rev a2)
Kernel driver in use: pcieport
Kernel modules: shpchp
00:18.0 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] HyperTransport Technology Configuration
00:18.1 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] Address Map
00:18.2 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] DRAM Controller
00:18.3 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] Miscellaneous Control
Kernel driver in use: k8temp
Kernel modules: k8temp
00:19.0 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] HyperTransport Technology Configuration
00:19.1 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] Address Map
00:19.2 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] DRAM Controller
00:19.3 Host bridge: Advanced Micro Devices, Inc. [AMD] K8
[Athlon64/Opteron] Miscellaneous Control
Kernel driver in use: k8temp
Kernel modules: k8temp
01:0d.0 PCI bridge: Broadcom BCM5785 [HT1000] PCI/PCI-X Bridge (rev c0)
Kernel modules: shpchp
01:0e.0 RAID bus controller: Broadcom BCM5785 [HT1000] SATA (Native SATA
Mode)
Subsystem: IBM BCM5785 [HT1000] SATA (Native SATA Mode)
Kernel driver in use: sata_svw
Kernel modules: sata_svw
02:01.0 Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme
BCM5704 Gigabit Ethernet (rev 10)
Subsystem: IBM NetXtreme BCM5704 Gigabit Ethernet
Kernel driver in use: tg3
Kernel modules: tg3
02:01.1 Ethernet controller: Broadcom Inc. and subsidiaries NetXtreme
BCM5704 Gigabit Ethernet (rev 10)
Subsystem: IBM NetXtreme BCM5704 Gigabit Ethernet
Kernel driver in use: tg3
Kernel modules: tg3
03:00.0 Mass storage controller: Silicon Image, Inc. SiI 3132 Serial ATA
Raid II Controller (rev 01)
Subsystem: Silicon Image, Inc. SiI 3132 Serial ATA Raid II
Controller
Kernel driver in use: sata_sil24
Kernel modules: sata_sil24
06:00.0 Ethernet controller: Intel Corporation 82572EI Gigabit Ethernet
Controller (Copper) (rev 06)
Subsystem: Intel Corporation PRO/1000 PT Desktop Adapter
Kernel driver in use: e1000e
Kernel modules: e1000e
root@keyserver3:/tmp# lspci -k | head
00:01.0 PCI bridge: Broadcom BCM5785 [HT1000] PCI/PCI-X Bridge
Kernel modules: shpchp
00:02.0 Host bridge: Broadcom BCM5785 [HT1000] Legacy South Bridge
Subsystem: IBM BCM5785 [HT1000] Legacy South Bridge
Kernel driver in use: piix4_smbus
Kernel modules: i2c_piix4
00:02.1 IDE interface: Broadcom BCM5785 [HT1000] IDE
Subsystem: IBM BCM5785 [HT1000] IDE
Kernel driver in use: pata_serverworks
Kernel modules: pata_serverworks, pata_acpi
vs.
./map_hardware_to_drivers.pl /tmp/pci.ids
Checking this machine for drivers
Getting Device ID list from https://pci-ids.ucw.cz/v2.2/pci.ids
Getting PCI ID to builtin mappings from /sys/bus/pci/drivers
Getting PCI ID to kernel module name mappingsChecking pci and device IDs
from lspci -n
pci_id dev_id driver description
00:01.0 1166:0036 <none> "BCM5785 [HT1000] PCI/PCI-X Bridge"
00:02.0 1166:0205 i2c_piix4(module)/piix4_smbus(builtin) "BCM5785
[HT1000] Legacy South Bridge"
00:02.1 1166:0214 pata_serverworks(module)/pata_serverworks(builtin)
"BCM5785 [HT1000] IDE"
00:02.2 1166:0234 <none> "BCM5785 [HT1000] LPC"
00:03.0 1166:0223 ohci-pci(builtin) "BCM5785 [HT1000] USB"
00:03.1 1166:0223 ohci-pci(builtin) "BCM5785 [HT1000] USB"
00:03.2 1166:0223 ehci-pci(builtin) "BCM5785 [HT1000] USB"
00:05.0 1002:515E radeonfb(module)/radeon(builtin) "ES1000"
00:06.0 1166:0140 pcieport(builtin) "HT2100 PCI-Express Bridge"
00:07.0 1166:0142 pcieport(builtin) "HT2100 PCI-Express Bridge"
00:08.0 1166:0144 pcieport(builtin) "HT2100 PCI-Express Bridge"
00:09.0 1166:0142 pcieport(builtin) "HT2100 PCI-Express Bridge"
00:0a.0 1166:0144 <none> "HT2100 PCI-Express Bridge"
00:18.0 1022:1100 <none> "K8 [Athlon64/Opteron] HyperTransport
Technology Configuration"
00:18.1 1022:1101 <none> "K8 [Athlon64/Opteron] Address Map"
00:18.2 1022:1102 <none> "K8 [Athlon64/Opteron] DRAM Controller"
00:18.3 1022:1103 k8temp(module)/k8temp(builtin) "K8 [Athlon64/Opteron]
Miscellaneous Control"
00:19.0 1022:1100 <none> "K8 [Athlon64/Opteron] HyperTransport
Technology Configuration"
00:19.1 1022:1101 <none> "K8 [Athlon64/Opteron] Address Map"
00:19.2 1022:1102 <none> "K8 [Athlon64/Opteron] DRAM Controller"
00:19.3 1022:1103 k8temp(module)/k8temp(builtin) "K8 [Athlon64/Opteron]
Miscellaneous Control"
01:0d.0 1166:0104 <none> "BCM5785 [HT1000] PCI/PCI-X Bridge"
01:0e.0 1166:024A sata_svw(module) "BCM5785 [HT1000] SATA (Native SATA
Mode)"
02:01.0 14E4:1648 tg3(module)/tg3(builtin) "NetXtreme BCM5704 Gigabit
Ethernet"
02:01.1 14E4:1648 tg3(module)/tg3(builtin) "NetXtreme BCM5704 Gigabit
Ethernet"
03:00.0 1095:3132 sata_sil24(module)/sata_sil24(builtin) "SiI 3132
Serial ATA Raid II Controller"
06:00.0 8086:10B9 e1000e(module)/e1000e(builtin) "82572EI Gigabit
Ethernet Controller (Copper)"
Done
Things I do not understand:
1. Devices 00:01.0 and 01:0d.0 show "Kernel modules: shpchp" in "lspci
-k".
Where is "lspci -k" getting that information?
"ls /sys/module/shpch" does not indicate any links to those devices, nor
do those devices have any links to that module/driver. The others
devices do link to their
drivers (and vice versa), for instance:
ls -al /sys/devices/pci0000:00/0000:00:02.1 | grep drivers
lrwxrwxrwx 1 root root 0 Mar 16 13:47 driver ->
../../../bus/pci/drivers/pata_serverworks
ls -al /sys/bus/pci/drivers/pata_serverworks | grep devices
lrwxrwxrwx 1 root root 0 Mar 16 13:48 0000:00:02.1 ->
../../../../devices/pci0000:00/0000:00:02.1
2. I describe the /sys/module heirarchy as "builtin", assuming that all
the drivers in it are compiled into the running kernel. Is that
actually true or will modules from /lib/modules/<kernel> show up in
there too when they are loaded? If the latter is the case, how does one
determine what is actually built into the kernel and what was added
later?
3. lsmod shows which modules are loaded. Is there anything similar to
show which builtin kernel drivers are being used? Or is deterimining
which driver is in use an either/or sort of thing. For instance, for
06:00.0 the driver is e1000e for both builtin and module, and lsmod
shows e1000e, so that is the module and not the builtin in use. If
lsmod did not show it then it would be the builtin. That seems to be
the case for these two:
00:03.1 1166:0223 ohci-pci(builtin) "BCM5785 [HT1000] USB"
00:03.2 1166:0223 ehci-pci(builtin) "BCM5785 [HT1000] USB"
Thank you,
David Mathog
mathog@xxxxxxxxxxx
Manager, Sequence Analysis Facility, Biology Division, Caltech
#!/usr/bin/perl
#Name: map_hardware_to_drivers.pl
#version: 1.0.0
#Date: 2020-03-12
#Author: David Mathog
#
# Map the pci hardware list to drivers for the running kernel
#
# assumes wget, lspci, and access to the internet are available
# If access is not available specify one parameter to the already downloaded
# PCI IDs file.
#
#
use strict;
use warnings;
my $IDLIST="https://pci-ids.ucw.cz/v2.2/pci.ids";
my $real_filename="/tmp/pci.ids";
my $kernel=`uname -r`;
chomp $kernel;
my $MODALIAS="/lib/modules/$kernel/modules.alias";
my %dev_hash_longname;
my %dev_hash_module;
my %pci_hash_builtin;
my $count=0;
my $vendor="";
my $device="";
my $long_name="";
my $module_name="";
my $pci_id;
my $dev_id;
my $ignore;
my $num_args = $#ARGV;
if ($num_args != 0) {
print
"Usage: map_hardware_to_drivers.pl PciIDsFile\n\n",
"If internet access is available let PciIDsFile = \"-\" and it will be downloaded\n",
"automatically. Otherwise on some machine do:\n\n",
" wget -O PciIDsFile $IDLIST\n\n",
"Then copy that file by some means to the target and specify\n",
"the file name on the command line.\n";
exit;
}
my $filename=$ARGV[0];
if($filename eq '-'){
my $messages = `wget -q -O $real_filename $IDLIST 2>/dev/null`;
if($messages){
print
"Some problem running:\n\n",
" wget -q -O $real_filename 2>/dev/null\n\n",
"returned:\n",
"$messages\n";
exit;
}
}
else {
$real_filename = $filename;
}
#######################
open(FH, $real_filename) or die "could not open file $real_filename";
print "Checking this machine for drivers\n";
print "Getting Device ID list from $IDLIST\n";
# Syntax in this file:
# #comment line
# <blank lines>
# vendor vendor_name
# device device_name <-- single tab
# subvendor subdevice subsystem_name <-- two tabs
# Only the vendor and device lines are retained
#(This will obtain all PCI ID -> long name mappings even if the current kernel does
#not have the information.)
while (my $line = <FH>){
chomp $line;
if(! $line){ next; }
if(substr($line,0,1) eq "#"){ next; }
if(substr($line,0,2) eq "\t\t"){ next; }
if(substr($line,0,1) eq "\t"){ #device line
$device = substr($line,1,4);
$long_name = substr($line,7);
$dev_id = $vendor . ":" . uc $device;
$dev_hash_longname{$dev_id} = $long_name;
}
else { #vendor line
$vendor = uc substr($line,0,4);
}
}
close(FH);
# my ($dev_type, $dev_id, $dev_driver) = split(/\s+/,$line);
#print "Getting pci IDs and long names from lspci\n";
#foreach my $line (`lspci`){
# chomp $line;
# my $starts = index($line," ");
# my $pci_id = uc substr($line,0,$starts);
# my $ln = substr($line,$starts+1);
# $dev_hash_longname{$pci_id}=$ln;
#}
#######################
# get all the PCI ID to builtin mappings.
print "Getting PCI ID to builtin mappings from /sys/bus/pci/drivers\n";
foreach my $line (`find /sys/bus/pci/drivers`){
chomp $line;
my $starts = index($line,"/0000:");
if($starts != -1){
my $pci_id = uc substr($line,$starts + 6);
my $delim = rindex(substr($line,0,$starts-1),"/");
my $driver= substr($line,$delim+1,$starts - $delim -1);
# print "pci_id >$pci_id< driver >$driver<\n";
$pci_hash_builtin{$pci_id}=$driver . "(builtin)";
}
}
#######################
# get all the PCI ID to module name mappings. Ignore subvendor and subdevice information.
# This uses the "alias pci:" lines which have the syntax:
# alias pci:vVENDORdDEVICEsvSUBVENDORsdSUBDEVICEscIGNOREiIGNORE module_name
# extract the VENDOR and DEVICE files to construct a PCI ID like 1234:ABCD
# Use that to store the module_name value in a hash.
#
open(FH, $MODALIAS) or die "could not open file $MODALIAS";
print "Getting PCI ID to kernel module name mappings";
my $next_delim;
while (my $line = <FH>){
chomp $line;
if(substr($line,0,10) eq 'alias pci:'){
# print "line: $line\n";
if(substr($line,11,1) eq "*"){ next; }
$next_delim=index($line,"d",11);
if($next_delim == -1){ die "File $MODALIAS has pci: line with unexpected syntax: $line"; }
$vendor = substr($line,15,4);
$next_delim=index($line,"sv",20);
if($next_delim == -1){ die("File $MODALIAS has pci: line with unexpected syntax: $line"); }
$device = substr($line,24,4);
$dev_id = $vendor . ":" . $device;
$next_delim=index($line," ",28);
if($next_delim == -1){ die "File $MODALIAS has pci: line with unexpected syntax: $line"; }
$module_name = substr($line,$next_delim + 1);
if(defined($dev_hash_module{$dev_id})){ next; } #subvendor/subdevice lines
$dev_hash_module{$dev_id} = $module_name . "(module)";
$count++;
# print " parsed $dev_id $module_name\n";
}
}
close(FH);
print "Checking pci and device IDs from lspci -n\n";
print "pci_id dev_id driver description\n";
foreach my $line (`lspci -n`){
chomp $line;
($pci_id, $ignore, $dev_id)= split /\s/,$line;
$dev_id = uc $dev_id;
my $description = (defined($dev_hash_longname{$dev_id}) ? $dev_hash_longname{$dev_id} : "unknown");
my $module = (defined($dev_hash_module{$dev_id}) ? $dev_hash_module{$dev_id} : "");
my $builtin = (defined($pci_hash_builtin{$pci_id}) ? $pci_hash_builtin{$pci_id} : "");
if(!$module){
if($builtin){
$module = $builtin;
}
else {
$module = "<none>";
}
}
else {
if($builtin){
$module .= "/" . $builtin;
}
}
print "$pci_id $dev_id $module \"$description\"\n";
}
if($filename eq "-"){
unlink($real_filename);
}
print "Done\n";