summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMartin Mares <mj@ucw.cz>2018-06-26 12:08:37 +0200
committerMartin Mares <mj@ucw.cz>2018-06-26 12:08:37 +0200
commitc02d903c2a8971718c7dea482075f4ddb8e3c1fe (patch)
tree2f1e57bbf96b73143739798886ba31c1ec01528b
parent6d701ce33eb2a420ce196be731ddf11d2d1fcc7f (diff)
downloadpciutils-c02d903c2a8971718c7dea482075f4ddb8e3c1fe.tar.gz
Created a generic interface for device properties
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.
-rw-r--r--lib/access.c71
-rw-r--r--lib/internal.h10
-rw-r--r--lib/libpci.ver5
-rw-r--r--lib/pci.h20
-rw-r--r--lib/sysfs.c2
-rw-r--r--lspci.c13
6 files changed, 104 insertions, 17 deletions
diff --git a/lib/access.c b/lib/access.c
index 9475a84..52f1432 100644
--- a/lib/access.c
+++ b/lib/access.c
@@ -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;
+}
diff --git a/lib/internal.h b/lib/internal.h
index 09c171d..aaa121a 100644
--- a/lib/internal.h
+++ b/lib/internal.h
@@ -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);
diff --git a/lib/libpci.ver b/lib/libpci.ver
index d9bfb34..d15e678 100644
--- a/lib/libpci.ver
+++ b/lib/libpci.ver
@@ -72,3 +72,8 @@ LIBPCI_3.5 {
pci_init;
pci_fill_info;
};
+
+LIBPCI_3.6 {
+ global:
+ pci_get_string_property;
+};
diff --git a/lib/pci.h b/lib/pci.h
index 3abb5d5..8cf9c4c 100644
--- 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;
diff --git a/lib/sysfs.c b/lib/sysfs.c
index 9eba5c5..b826e97 100644
--- a/lib/sysfs.c
+++ b/lib/sysfs.c
@@ -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 e207e03..241b57a 100644
--- 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
{