]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
pciutils: Add support for 32-bit PCI domains
authorKeith Busch <keith.busch@intel.com>
Thu, 17 Mar 2016 19:19:17 +0000 (13:19 -0600)
committerMartin Mares <mj@ucw.cz>
Sat, 14 May 2016 09:47:29 +0000 (11:47 +0200)
This adds support for new host bridges that may create PCI domain number
values requiring more than 16 bits. The new domain 32-bit integer is
signed to allow -1 for "any", and is sufficient as the domain number
will never require the full 32-bits.

The domain field is appended at the end of struct pci_dev, and the
current location of the 16-bit domain remains for compatibility. The
domain number is truncated and copied into the legacy domain location
so existing applications linking to the library will continue to work
without modification. We accept that these applications may not work
correctly on machines with host bridges exporting 32-bit domains.

In order to force new programs to link to the new ABI, the pci_init
function call is versioned in this commit.

Signed-off-by: Keith Busch <keith.busch@intel.com>
lib/filter.c
lib/init.c
lib/internal.h
lib/pci.h
lib/sysfs.c
ls-tree.c

index d4254a02383bd5aae3902eb610f647aafdee5e14..73a51def8c6c14744e855459fc5db2a324a5aaed 100644 (file)
@@ -45,7 +45,7 @@ pci_filter_parse_slot_v33(struct pci_filter *f, char *str)
          if (str[0] && strcmp(str, "*"))
            {
              long int x = strtol(str, &e, 16);
-             if ((e && *e) || (x < 0 || x > 0xffff))
+             if ((e && *e) || (x < 0 || x > 0x7fffffff))
                return "Invalid domain number";
              f->domain = x;
            }
index 064c9324a4e3f49cdfbc7cb3ba202f61912a6d68..b0a9accbd98a39f8b92e68b989b1b0a538ea0580 100644 (file)
@@ -173,7 +173,7 @@ pci_alloc(void)
 }
 
 void
-pci_init(struct pci_access *a)
+pci_init_v34(struct pci_access *a)
 {
   if (!a->error)
     a->error = pci_generic_error;
@@ -213,6 +213,9 @@ pci_init(struct pci_access *a)
   a->methods->init(a);
 }
 
+STATIC_ALIAS(void pci_init(struct pci_access *a), pci_init_v34(a));
+SYMBOL_VERSION(pci_init_v34, pci_init@@LIBPCI_3.4);
+
 void
 pci_cleanup(struct pci_access *a)
 {
index 7e101aba8b36d8749d6fccadab6a5b691d102c3c..bfb05bf82bee5ab526457c9897a7d40fe2005c90 100644 (file)
@@ -61,6 +61,8 @@ void *pci_malloc(struct pci_access *, int);
 void pci_mfree(void *);
 char *pci_strdup(struct pci_access *a, const char *s);
 
+void pci_init_v34(struct pci_access *a) VERSIONED_ABI;
+
 /* access.c */
 struct pci_dev *pci_alloc_dev(struct pci_access *);
 int pci_link_dev(struct pci_access *, struct pci_dev *);
index 9c1e2810cb2e3d3a01b2bfb36e150dadfb7543b2..545cefeb5d809afa9b8f8b47ad04bf5e47366661 100644 (file)
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -119,7 +119,7 @@ struct pci_param *pci_walk_params(struct pci_access *acc, struct pci_param *prev
 
 struct pci_dev {
   struct pci_dev *next;                        /* Next device in the chain */
-  u16 domain;                          /* PCI domain (host bridge) */
+  u16 domain_16;                       /* 16-bit PCI domain (host bridge) */
   u8 bus, dev, func;                   /* Bus inside domain, device and function */
 
   /* These fields are set by pci_fill_info() */
@@ -136,6 +136,7 @@ struct pci_dev {
   char *module_alias;                  /* Linux kernel module alias */
   char *label;                         /* Device name as exported by BIOS */
   int numa_node;                       /* NUMA node */
+  int domain;                          /* 32-bit PCI domain (host bridge) */
 
   /* Fields used internally: */
   struct pci_access *access;
index 986ecc93185aec0429961e4c8fedc815855c19f5..164d6da89dbec182649eb002f5647833c93c13d8 100644 (file)
@@ -193,6 +193,19 @@ static void sysfs_scan(struct pci_access *a)
       d = pci_alloc_dev(a);
       if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
        a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
+
+      /* Ensure kernel provided domain that fits in a signed integer */
+      if (dom > 0x7fffffff)
+       a->error("sysfs_scan: invalid domain:%x", dom);
+
+      /*
+       * The domain value is truncated to 16 bits and stored in the pci_dev
+       * structure's legacy 16-bit domain offset for compatibility with
+       * applications compiled with libpci pre-32 bit domains. Such
+       * applications may not work as expected if they are on a machine
+       * utilizing PCI domain numbers requiring more than 16 bits.
+       */
+      d->domain_16 = dom;
       d->domain = dom;
       d->bus = bus;
       d->dev = dev;
@@ -267,7 +280,7 @@ sysfs_fill_slots(struct pci_access *a)
       else
        {
          for (d = a->devices; d; d = d->next)
-           if (dom == d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
+           if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
              d->phy_slot = pci_strdup(a, entry->d_name);
        }
       fclose(file);
index 4c5b8532d332384d799435e6cff260a5bf4cba59..add5b7ec63ea5921716f3a38c7111c265446627b 100644 (file)
--- a/ls-tree.c
+++ b/ls-tree.c
@@ -63,7 +63,7 @@ insert_dev(struct device *d, struct bridge *b)
     {
       struct bridge *c;
       for (c=b->child; c; c=c->next)
-       if (c->domain == p->domain && c->secondary <= p->bus && p->bus <= c->subordinate)
+       if (c->domain == (unsigned)p->domain && c->secondary <= p->bus && p->bus <= c->subordinate)
           {
             insert_dev(d, c);
             return;