]> git.ipfire.org Git - thirdparty/pciutils.git/commitdiff
Created a generic interface for device properties
authorMartin Mares <mj@ucw.cz>
Tue, 26 Jun 2018 10:08:37 +0000 (12:08 +0200)
committerMartin Mares <mj@ucw.cz>
Tue, 26 Jun 2018 10:08:37 +0000 (12:08 +0200)
Introduction of device tree node properties broke library ABI.

I gave up on creating new symbol versions whenever we add a new
device property, so I introduced a generic property interface
with which new string properties can be added while keeping ABI
compatibility.

lib/access.c
lib/internal.h
lib/libpci.ver
lib/pci.h
lib/sysfs.c
lspci.c

index 9475a84286f6d0ba265bc35f4ebfd6b69338d994..52f1432915a798899108b54e5e55bb3bb511152a 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The PCI Library -- User Access
  *
- *     Copyright (c) 1997--2014 Martin Mares <mj@ucw.cz>
+ *     Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
@@ -67,15 +67,30 @@ pci_get_dev(struct pci_access *a, int domain, int bus, int dev, int func)
   return d;
 }
 
+static void
+pci_free_properties(struct pci_dev *d)
+{
+  struct pci_property *p;
+
+  while (p = d->properties)
+    {
+      d->properties = p->next;
+      pci_mfree(p);
+    }
+}
+
 void pci_free_dev(struct pci_dev *d)
 {
   if (d->methods->cleanup_dev)
     d->methods->cleanup_dev(d);
+
   pci_free_caps(d);
+  pci_free_properties(d);
+
   pci_mfree(d->module_alias);
   pci_mfree(d->label);
   pci_mfree(d->phy_slot);
-  pci_mfree(d->dt_node);
+
   pci_mfree(d);
 }
 
@@ -167,14 +182,21 @@ pci_write_block(struct pci_dev *d, int pos, byte *buf, int len)
   return d->methods->write(d, pos, buf, len);
 }
 
+static void
+pci_reset_properties(struct pci_dev *d)
+{
+  d->known_fields = 0;
+  pci_free_caps(d);
+  pci_free_properties(d);
+}
+
 int
 pci_fill_info_v35(struct pci_dev *d, int flags)
 {
   if (flags & PCI_FILL_RESCAN)
     {
       flags &= ~PCI_FILL_RESCAN;
-      d->known_fields = 0;
-      pci_free_caps(d);
+      pci_reset_properties(d);
     }
   if (flags & ~d->known_fields)
     d->known_fields |= d->methods->fill_info(d, flags & ~d->known_fields);
@@ -202,3 +224,44 @@ pci_setup_cache(struct pci_dev *d, byte *cache, int len)
   d->cache = cache;
   d->cache_len = len;
 }
+
+char *
+pci_set_property(struct pci_dev *d, u32 key, char *value)
+{
+  struct pci_property *p;
+  struct pci_property **pp = &d->properties;
+
+  while (p = *pp)
+    {
+      if (p->key == key)
+       {
+         *pp = p->next;
+         pci_mfree(p);
+       }
+      else
+       pp = &p->next;
+    }
+
+  if (!value)
+    return NULL;
+
+  p = pci_malloc(d->access, sizeof(*p) + strlen(value));
+  *pp = p;
+  p->next = NULL;
+  p->key = key;
+  strcpy(p->value, value);
+
+  return p->value;
+}
+
+char *
+pci_get_string_property(struct pci_dev *d, u32 prop)
+{
+  struct pci_property *p;
+
+  for (p = d->properties; p; p = p->next)
+    if (p->key == prop)
+      return p->value;
+
+  return NULL;
+}
index 09c171d7783cdf76459d341baa1187cda854431b..aaa121a36316dacf77beeb4442fe276d7801f889 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     The PCI Library -- Internal Stuff
  *
- *     Copyright (c) 1997--2014 Martin Mares <mj@ucw.cz>
+ *     Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
@@ -75,6 +75,14 @@ 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;
 
+struct pci_property {
+  struct pci_property *next;
+  u32 key;
+  char value[1];
+};
+
+char *pci_set_property(struct pci_dev *d, u32 key, char *value);
+
 /* params.c */
 void pci_define_param(struct pci_access *acc, char *param, char *val, char *help);
 int pci_set_param_internal(struct pci_access *acc, char *param, char *val, int copy);
index d9bfb34f7cf7bfd3b299254e03974ca26cd94fe8..d15e678cbfc6018bf5aeba362fe70b17632efeb1 100644 (file)
@@ -72,3 +72,8 @@ LIBPCI_3.5 {
                pci_init;
                pci_fill_info;
 };
+
+LIBPCI_3.6 {
+       global:
+               pci_get_string_property;
+};
index 3abb5d5cc9f0d441db2b3fd9bfd014b2e36fbe35..8cf9c4c4201000c218de1b9e958b18fbde78f371 100644 (file)
--- a/lib/pci.h
+++ b/lib/pci.h
@@ -1,7 +1,7 @@
 /*
  *     The PCI Library
  *
- *     Copyright (c) 1997--2017 Martin Mares <mj@ucw.cz>
+ *     Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
  *
  *     Can be freely distributed and used under the terms of the GNU GPL.
  */
@@ -137,19 +137,19 @@ struct pci_dev {
   char *phy_slot;                      /* Physical slot */
   char *module_alias;                  /* Linux kernel module alias */
   char *label;                         /* Device name as exported by BIOS */
-  char *dt_node;                       /* Path to the device-tree node for this device */
   int numa_node;                       /* NUMA node */
   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) */
 
-  /* Fields used internally: */
+  /* Fields used internally */
   struct pci_access *access;
   struct pci_methods *methods;
   u8 *cache;                           /* Cached config registers */
   int cache_len;
   int hdrtype;                         /* Cached low 7 bits of header type, -1 if unknown */
   void *aux;                           /* Auxiliary data */
+  struct pci_property *properties;     /* A linked list of extra properties */
 };
 
 #define PCI_ADDR_IO_MASK (~(pciaddr_t) 0x3)
@@ -166,7 +166,17 @@ int pci_write_word(struct pci_dev *, int pos, u16 data) PCI_ABI;
 int pci_write_long(struct pci_dev *, int pos, u32 data) PCI_ABI;
 int pci_write_block(struct pci_dev *, int pos, u8 *buf, int len) PCI_ABI;
 
-int pci_fill_info(struct pci_dev *, int flags) PCI_ABI; /* Fill in device information */
+/*
+ * Most device properties take some effort to obtain, so libpci does not
+ * initialize them during default bus scan. Instead, you have to call
+ * pci_fill_info() with the proper PCI_FILL_xxx constants OR'ed together.
+ *
+ * Some properties are stored directly in the pci_dev structure.
+ * The remaining ones can be accessed through pci_get_string_property().
+ */
+
+int pci_fill_info(struct pci_dev *, int flags) PCI_ABI;
+char *pci_get_string_property(struct pci_dev *d, u32 prop) PCI_ABI;
 
 #define PCI_FILL_IDENT         0x0001
 #define PCI_FILL_IRQ           0x0002
@@ -181,7 +191,7 @@ int pci_fill_info(struct pci_dev *, int flags) PCI_ABI; /* Fill in device inform
 #define PCI_FILL_LABEL         0x0400
 #define PCI_FILL_NUMA_NODE     0x0800
 #define PCI_FILL_IO_FLAGS      0x1000
-#define PCI_FILL_DT_NODE       0x2000
+#define PCI_FILL_DT_NODE       0x2000          /* Device tree node */
 #define PCI_FILL_RESCAN                0x00010000
 
 void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI;
index 9eba5c50ca9a763b24ca41cd60d1a24f03999166..b826e97ccf8fbbd87695ea12f1e883e002b33780 100644 (file)
@@ -329,7 +329,7 @@ sysfs_fill_info(struct pci_dev *d, int flags)
     d->numa_node = sysfs_get_value(d, "numa_node", 0);
 
   if ((flags & PCI_FILL_DT_NODE) && !(d->known_fields & PCI_FILL_DT_NODE))
-      d->dt_node = sysfs_deref_link(d, "of_node");
+    pci_set_property(d, PCI_FILL_DT_NODE, sysfs_deref_link(d, "of_node"));
 
   return pci_generic_fill_info(d, flags);
 }
diff --git a/lspci.c b/lspci.c
index e207e03e366e4d4a8bd46042a4e4ef7425dfe1e3..241b57a5739c78d8e37418de3f1883f72888bbe9 100644 (file)
--- a/lspci.c
+++ b/lspci.c
@@ -682,6 +682,7 @@ show_verbose(struct device *d)
   byte max_lat, min_gnt;
   byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
   unsigned int irq;
+  char *dt_node;
 
   show_terse(d);
 
@@ -715,10 +716,11 @@ show_verbose(struct device *d)
   if (p->phy_slot)
     printf("\tPhysical Slot: %s\n", p->phy_slot);
 
+  if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
+    printf("\tDevice tree node: %s\n", dt_node);
+
   if (verbose > 1)
     {
-      if (p->dt_node)
-        printf("\tDT Node: %s\n", p->dt_node);
       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",
             FLAG(cmd, PCI_COMMAND_IO),
             FLAG(cmd, PCI_COMMAND_MEMORY),
@@ -772,8 +774,6 @@ show_verbose(struct device *d)
     }
   else
     {
-      if (p->dt_node)
-        printf("\tDT Node: %s\n", p->dt_node);
       printf("\tFlags: ");
       if (cmd & PCI_COMMAND_MASTER)
        printf("bus master, ");
@@ -867,6 +867,7 @@ show_machine(struct device *d)
   int c;
   word sv_id, sd_id;
   char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
+  char *dt_node;
 
   get_subid(d, &sv_id, &sd_id);
 
@@ -899,8 +900,8 @@ show_machine(struct device *d)
        show_kernel_machine(d);
       if (p->numa_node != -1)
        printf("NUMANode:\t%d\n", p->numa_node);
-      if (p->dt_node)
-        printf("DTNode:\t%s\n", p->dt_node);
+      if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE))
+        printf("DTNode:\t%s\n", dt_node);
     }
   else
     {