From: Martin Mares Date: Tue, 26 Jun 2018 10:08:37 +0000 (+0200) Subject: Created a generic interface for device properties X-Git-Tag: v3.6.0~3 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=c02d903c2a8971718c7dea482075f4ddb8e3c1fe;p=pciutils.git 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. --- 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 + * Copyright (c) 1997--2018 Martin Mares * * 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 + * Copyright (c) 1997--2018 Martin Mares * * 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 + * Copyright (c) 1997--2018 Martin Mares * * 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 {