[PATCH pciutils 3/4] libpci: Add support for filling bridge resources

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

 



Extend libpci API and ABI to fill bridge resources from sysfs.
---
 lib/access.c   | 20 +++++++++++---------
 lib/caps.c     |  2 +-
 lib/filter.c   |  2 +-
 lib/internal.h |  1 +
 lib/libpci.ver |  5 +++++
 lib/pci.h      |  4 ++++
 lib/sysfs.c    | 48 ++++++++++++++++++++++++++++++++++++++++++------
 7 files changed, 65 insertions(+), 17 deletions(-)

diff --git a/lib/access.c b/lib/access.c
index b257849a685e..a33e067e2389 100644
--- a/lib/access.c
+++ b/lib/access.c
@@ -189,7 +189,7 @@ pci_reset_properties(struct pci_dev *d)
 }
 
 int
-pci_fill_info_v35(struct pci_dev *d, int flags)
+pci_fill_info_v38(struct pci_dev *d, int flags)
 {
   unsigned int uflags = flags;
   if (uflags & PCI_FILL_RESCAN)
@@ -203,19 +203,21 @@ pci_fill_info_v35(struct pci_dev *d, int flags)
 }
 
 /* In version 3.1, pci_fill_info got new flags => versioned alias */
-/* In versions 3.2, 3.3, 3.4 and 3.5, the same has happened */
-STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v35(d, flags));
-DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v35);
-DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v35);
-DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v35);
-DEFINE_ALIAS(int pci_fill_info_v33(struct pci_dev *d, int flags), pci_fill_info_v35);
-DEFINE_ALIAS(int pci_fill_info_v34(struct pci_dev *d, int flags), pci_fill_info_v35);
+/* In versions 3.2, 3.3, 3.4, 3.5 and 3.8, the same has happened */
+STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v38(d, flags));
+DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v38);
+DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v38);
+DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v38);
+DEFINE_ALIAS(int pci_fill_info_v33(struct pci_dev *d, int flags), pci_fill_info_v38);
+DEFINE_ALIAS(int pci_fill_info_v34(struct pci_dev *d, int flags), pci_fill_info_v38);
+DEFINE_ALIAS(int pci_fill_info_v35(struct pci_dev *d, int flags), pci_fill_info_v38);
 SYMBOL_VERSION(pci_fill_info_v30, pci_fill_info@LIBPCI_3.0);
 SYMBOL_VERSION(pci_fill_info_v31, pci_fill_info@LIBPCI_3.1);
 SYMBOL_VERSION(pci_fill_info_v32, pci_fill_info@LIBPCI_3.2);
 SYMBOL_VERSION(pci_fill_info_v33, pci_fill_info@LIBPCI_3.3);
 SYMBOL_VERSION(pci_fill_info_v34, pci_fill_info@LIBPCI_3.4);
-SYMBOL_VERSION(pci_fill_info_v35, pci_fill_info@@LIBPCI_3.5);
+SYMBOL_VERSION(pci_fill_info_v35, pci_fill_info@LIBPCI_3.5);
+SYMBOL_VERSION(pci_fill_info_v38, pci_fill_info@@LIBPCI_3.8);
 
 void
 pci_setup_cache(struct pci_dev *d, byte *cache, int len)
diff --git a/lib/caps.c b/lib/caps.c
index c3b918059fe1..70a41b836e31 100644
--- a/lib/caps.c
+++ b/lib/caps.c
@@ -129,7 +129,7 @@ pci_find_cap_nr(struct pci_dev *d, unsigned int id, unsigned int type,
   unsigned int target = (cap_number ? *cap_number : 0);
   unsigned int index = 0;
 
-  pci_fill_info_v35(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS));
+  pci_fill_info_v38(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS));
 
   for (c=d->first_cap; c; c=c->next)
     {
diff --git a/lib/filter.c b/lib/filter.c
index 573fb2810363..195f813193c4 100644
--- a/lib/filter.c
+++ b/lib/filter.c
@@ -129,7 +129,7 @@ pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d)
     return 0;
   if (f->device >= 0 || f->vendor >= 0)
     {
-      pci_fill_info_v35(d, PCI_FILL_IDENT);
+      pci_fill_info_v38(d, PCI_FILL_IDENT);
       if ((f->device >= 0 && f->device != d->device_id) ||
 	  (f->vendor >= 0 && f->vendor != d->vendor_id))
 	return 0;
diff --git a/lib/internal.h b/lib/internal.h
index 17c27e194a29..4df8dd70c2c6 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -74,6 +74,7 @@ int pci_fill_info_v32(struct pci_dev *, int flags) VERSIONED_ABI;
 int pci_fill_info_v33(struct pci_dev *, int flags) VERSIONED_ABI;
 int pci_fill_info_v34(struct pci_dev *, int flags) VERSIONED_ABI;
 int pci_fill_info_v35(struct pci_dev *, int flags) VERSIONED_ABI;
+int pci_fill_info_v38(struct pci_dev *, int flags) VERSIONED_ABI;
 
 struct pci_property {
   struct pci_property *next;
diff --git a/lib/libpci.ver b/lib/libpci.ver
index e20c3f581c71..73f7fa71e357 100644
--- a/lib/libpci.ver
+++ b/lib/libpci.ver
@@ -82,3 +82,8 @@ LIBPCI_3.7 {
 	global:
 		pci_find_cap_nr;
 };
+
+LIBPCI_3.8 {
+	global:
+		pci_fill_info;
+};
diff --git a/lib/pci.h b/lib/pci.h
index 814247691086..0ec7f211ca24 100644
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -142,6 +142,9 @@ struct pci_dev {
   pciaddr_t flags[6];			/* PCI_IORESOURCE_* flags for regions */
   pciaddr_t rom_flags;			/* PCI_IORESOURCE_* flags for expansion ROM */
   int domain;				/* PCI domain (host bridge) */
+  pciaddr_t bridge_base_addr[4];	/* Bridge base addresses (without flags) */
+  pciaddr_t bridge_size[4];		/* Bridge sizes */
+  pciaddr_t bridge_flags[4];		/* PCI_IORESOURCE_* flags for bridge addresses */
 
   /* Fields used internally */
   struct pci_access *access;
@@ -205,6 +208,7 @@ char *pci_get_string_property(struct pci_dev *d, u32 prop) PCI_ABI;
 #define PCI_FILL_IO_FLAGS	0x1000
 #define PCI_FILL_DT_NODE	0x2000		/* Device tree node */
 #define PCI_FILL_IOMMU_GROUP	0x4000
+#define PCI_FILL_BRIDGE_BASES	0x8000
 #define PCI_FILL_RESCAN		0x00010000
 
 void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;
diff --git a/lib/sysfs.c b/lib/sysfs.c
index fb6424105e84..7c157a2688ad 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -148,19 +148,22 @@ sysfs_get_value(struct pci_dev *d, char *object, int mandatory)
     return -1;
 }
 
-static void
+static unsigned int
 sysfs_get_resources(struct pci_dev *d)
 {
   struct pci_access *a = d->access;
   char namebuf[OBJNAMELEN], buf[256];
+  struct { pciaddr_t flags, base_addr, size; } lines[10];
+  unsigned int done;
   FILE *file;
   int i;
 
+  done = 0;
   sysfs_obj_name(d, "resource", namebuf);
   file = fopen(namebuf, "r");
   if (!file)
     a->error("Cannot open %s: %s", namebuf, strerror(errno));
-  for (i = 0; i < 7; i++)
+  for (i = 0; i < 7+6+4+1; i++)
     {
       unsigned long long start, end, size, flags;
       if (!fgets(buf, sizeof(buf), file))
@@ -177,16 +180,50 @@ sysfs_get_resources(struct pci_dev *d)
 	  flags &= PCI_ADDR_FLAG_MASK;
 	  d->base_addr[i] = start | flags;
 	  d->size[i] = size;
+	  done |= PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS;
 	}
-      else
+      else if (i == 6)
 	{
 	  d->rom_flags = flags;
 	  flags &= PCI_ADDR_FLAG_MASK;
 	  d->rom_base_addr = start | flags;
 	  d->rom_size = size;
+	  done |= PCI_FILL_ROM_BASE;
 	}
+      else if (i < 7+6+4)
+        {
+          /*
+           * If kernel was compiled without CONFIG_PCI_IOV option then after
+           * the ROM line for configured bridge device (that which had set
+           * subordinary bus number to non-zero value) are four additional lines
+           * which describe resources behind bridge. For PCI-to-PCI bridges they
+           * are: IO, MEM, PREFMEM and empty. For CardBus bridges they are: IO0,
+           * IO1, MEM0 and MEM1. For unconfigured bridges and other devices
+           * there is no additional line after the ROM line. If kernel was
+           * compiled with CONFIG_PCI_IOV option then after the ROM line and
+           * before the first bridge resource line are six additional lines
+           * which describe IOV resources. Read all remaining lines in resource
+           * file and based on the number of remaining lines (0, 4, 6, 10) parse
+           * resources behind bridge.
+           */
+          lines[i-7].flags = flags;
+          lines[i-7].base_addr = start;
+          lines[i-7].size = size;
+        }
+    }
+  if (i == 7+4 || i == 7+6+4)
+    {
+      int offset = (i == 7+6+4) ? 6 : 0;
+      for (i = 0; i < 4; i++)
+        {
+          d->bridge_flags[i] = lines[offset+i].flags;
+          d->bridge_base_addr[i] = lines[offset+i].base_addr;
+          d->bridge_size[i] = lines[offset+i].size;
+        }
+      done |= PCI_FILL_BRIDGE_BASES;
     }
   fclose(file);
+  return done;
 }
 
 static void sysfs_scan(struct pci_access *a)
@@ -316,10 +353,9 @@ sysfs_fill_info(struct pci_dev *d, unsigned int flags)
 	  d->irq = sysfs_get_value(d, "irq", 1);
 	  done |= PCI_FILL_IRQ;
 	}
-      if (flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS))
+      if (flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS | PCI_FILL_BRIDGE_BASES))
 	{
-	  sysfs_get_resources(d);
-	  done |= PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS;
+	  done |= sysfs_get_resources(d);
 	}
     }
 
-- 
2.20.1




[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