]> mj.ucw.cz Git - pciutils.git/commitdiff
Display physical slot information in lspci -v
authorAlex Chiang <achiang@hp.com>
Wed, 3 Dec 2008 19:30:21 +0000 (12:30 -0700)
committerMartin Mares <mj@ucw.cz>
Fri, 12 Dec 2008 23:13:15 +0000 (00:13 +0100)
We've been exposing slot information in /sys/bus/pci/slots for a
long time now (as long as a hotplug driver or slot detection
driver like pci_slot is loaded).

Let's make life better for our users and display that information
in lspci. If slot entries appear in /sys/bus/pci/slots/,
correlate them to PCI devices, and display the information when
lspci -v is issued.

If no slot entries appear in sysfs (due to no modules loaded), do
nothing.

Now you'll see sample output like the following:

23:01.1 Class 0c04: Device 10df:fd00 (rev 01)
Subsystem: Device 10df:fd00
Physical Slot: 3
Flags: bus master, 66MHz, medium devsel, latency 248, IRQ 60
...

Signed-off-by: Alex Chiang <achiang@hp.com>
lib/access.c
lib/pci.h
lib/sysfs.c
lspci.c
lspci.man

index 23a821c1af7f82a17ed61ec7d0747200a739a653..691df39c30b607047696f6d15d6474544e3de3df 100644 (file)
@@ -59,6 +59,7 @@ void pci_free_dev(struct pci_dev *d)
   if (d->methods->cleanup_dev)
     d->methods->cleanup_dev(d);
   pci_free_caps(d);
+  pci_mfree(d->phy_slot);
   pci_mfree(d);
 }
 
index 452e1d81c394c092051d046e08f9b89c90b0af9e..1453f751cc8f9e90420f9e2eccb591d67aaf6250 100644 (file)
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -129,6 +129,7 @@ struct pci_dev {
   pciaddr_t rom_base_addr;             /* Expansion ROM base address */
   pciaddr_t rom_size;                  /* Expansion ROM size */
   struct pci_cap *first_cap;           /* List of capabilities */
+  char *phy_slot;                      /* Physical slot */
 
   /* Fields used internally: */
   struct pci_access *access;
@@ -162,6 +163,7 @@ int pci_fill_info(struct pci_dev *, int flags) PCI_ABI; /* Fill in device inform
 #define PCI_FILL_CLASS         32
 #define PCI_FILL_CAPS          64
 #define PCI_FILL_EXT_CAPS      128
+#define PCI_FILL_PHYS_SLOT     256
 #define PCI_FILL_RESCAN                0x10000
 
 void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;
index ca4356239d644953c20202f81a4250b6ca6a65b7..5949ff1f87b67ab56424caa9b172ae2fbb139622 100644 (file)
@@ -177,6 +177,68 @@ static void sysfs_scan(struct pci_access *a)
   closedir(dir);
 }
 
+static void
+sysfs_fill_slots(struct pci_dev *d)
+{
+  struct pci_access *a = d->access;
+  char dirname[1024];
+  DIR *dir;
+  struct dirent *entry;
+  int n;
+
+  n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
+  if (n < 0 || n >= (int) sizeof(dirname))
+    a->error("Directory name too long");
+  dir = opendir(dirname);
+  if (!dir)
+    a->error("Cannot open %s", dirname);
+  while ((entry = readdir(dir)))
+    {
+      char namebuf[OBJNAMELEN], buf[16];
+      FILE *file;
+      unsigned int dom, bus, dev;
+      struct pci_dev *pd;
+      int n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
+
+      /* ".", ".." or a special non-device perhaps */
+      if (entry->d_name[0] == '.')
+       continue;
+
+      if (n < 0 || n >= OBJNAMELEN)
+       d->access->error("File name too long");
+      file = fopen(namebuf, "r");
+      if (!file)
+       a->error("Cannot open %s: %s", namebuf, strerror(errno));
+      if (!fgets(buf, sizeof(buf), file))
+       break;
+      if (sscanf(buf, "%x:%x:%x", &dom, &bus, &dev) < 3)
+       a->error("sysfs_scan: Couldn't parse entry address %s", buf);
+      for (pd = a->devices; pd; pd = pd->next)
+       {
+         if (dom == pd->domain && bus == pd->bus && dev == pd->dev && !pd->phy_slot)
+           {
+             pd->phy_slot = pci_malloc(a, strlen(entry->d_name) + 1);
+             sprintf(pd->phy_slot, "%s", entry->d_name);
+           }
+         pd->known_fields |= PCI_FILL_PHYS_SLOT;
+       }
+      fclose(file);
+    }
+  closedir(dir);
+}
+
+static int
+sysfs_fill_info(struct pci_dev *d, int flags)
+{
+  int ret;
+
+  ret = pci_generic_fill_info(d, flags);
+  if (flags & PCI_FILL_PHYS_SLOT && !(d->known_fields & PCI_FILL_PHYS_SLOT))
+    sysfs_fill_slots(d);
+
+  return ret;
+}
+
 /* Intent of the sysfs_setup() caller */
 enum
   {
@@ -306,7 +368,7 @@ struct pci_methods pm_linux_sysfs = {
   sysfs_init,
   sysfs_cleanup,
   sysfs_scan,
-  pci_generic_fill_info,
+  sysfs_fill_info,
   sysfs_read,
   sysfs_write,
   sysfs_read_vpd,
diff --git a/lspci.c b/lspci.c
index d872c75192041bb114f1afeda5fc923c4c8f9282..9958ef6b7b12061778208c017d6d616faeae3716 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -140,7 +140,7 @@ scan_device(struct pci_dev *p)
        d->config_cached += 64;
     }
   pci_setup_cache(p, d->config, d->config_cached);
-  pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES);
+  pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_PHYS_SLOT);
   return d;
 }
 
@@ -685,6 +685,9 @@ show_verbose(struct device *d)
       return;
     }
 
+  if (p->phy_slot)
+    printf("\tPhysical Slot: %s\n", p->phy_slot);
+
   if (verbose > 1)
     {
       printf("\tControl: I/O%c Mem%c BusMaster%c SpecCycle%c MemWINV%c VGASnoop%c ParErr%c Stepping%c SERR%c FastB2B%c DisINTx%c\n",
@@ -850,6 +853,8 @@ show_machine(struct device *d)
          printf("SDevice:\t%s\n",
                 pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
        }
+      if (p->phy_slot)
+       printf("PhySlot:\t%s\n", p->phy_slot);
       if (c = get_conf_byte(d, PCI_REVISION_ID))
        printf("Rev:\t%02x\n", c);
       if (c = get_conf_byte(d, PCI_CLASS_PROG))
index dfddacd3d6b6f7af0770fc70ffdea96989e64531..441bc2bc791b2a2aed0abaf9e870b084fd396c81 100644 (file)
--- a/lspci.man
+++ b/lspci.man
@@ -285,6 +285,10 @@ Name of the subsystem vendor (optional).
 .B SDevice
 Name of the subsystem (optional).
 
+.TP
+.B PhySlot
+The physical slot where the device resides (optional, Linux only).
+
 .TP
 .B Rev
 Revision number (optional).