[PATCH v3] pciutils: Display physical slot information in lspci -v

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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@xxxxxx>
---
v2 -> v3:
	- fixed indentation / style issues
	- fixed another memory leak
	- move pci_mfree(d->phy_slot) to more obvious location
	- set PCI_FILL_PHYS_SLOT for all devices after looking
	  for slot info
	
v1-> v2:
	- sysfs-specific fill_info
	- fix memory leak
	- document in man page

 lib/access.c |    1 
 lib/pci.h    |    2 +
 lib/sysfs.c  |   64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 lspci.c      |    7 +++++-
 lspci.man    |    4 +++
 5 files changed, 76 insertions(+), 2 deletions(-)
---
diff --git a/lib/access.c b/lib/access.c
index 23a821c..691df39 100644
--- a/lib/access.c
+++ b/lib/access.c
@@ -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);
 }
 
diff --git a/lib/pci.h b/lib/pci.h
index 452e1d8..be62297 100644
--- 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;
diff --git a/lib/sysfs.c b/lib/sysfs.c
index ca43562..5949ff1 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -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 d872c75..9958ef6 100644
--- 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))
diff --git a/lspci.man b/lspci.man
index dfddacd..441bc2b 100644
--- a/lspci.man
+++ b/lspci.man
@@ -286,6 +286,10 @@ Name of the subsystem vendor (optional).
 Name of the subsystem (optional).
 
 .TP
+.B PhySlot
+The physical slot where the device resides (optional, Linux only).
+
+.TP
 .B Rev
 Revision number (optional).
 
--
To unsubscribe from this list: send the line "unsubscribe linux-pci" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [DMA Engine]     [Linux Coverity]     [Linux USB]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Greybus]

  Powered by Linux