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.
/*
* 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.
*/
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);
}
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);
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;
+}
/*
* 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.
*/
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);
pci_init;
pci_fill_info;
};
+
+LIBPCI_3.6 {
+ global:
+ pci_get_string_property;
+};
/*
* 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.
*/
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)
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
#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;
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);
}
byte max_lat, min_gnt;
byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
unsigned int irq;
+ char *dt_node;
show_terse(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),
}
else
{
- if (p->dt_node)
- printf("\tDT Node: %s\n", p->dt_node);
printf("\tFlags: ");
if (cmd & PCI_COMMAND_MASTER)
printf("bus master, ");
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);
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
{