Luc Verhaegen has uploaded this change for review. ( https://review.coreboot.org/29078
Change subject: add newer pci infrastructure ......................................................................
add newer pci infrastructure
This code does not negatively affect existing pci support and existing pci devices, it introduces parallel infrastructure which: - allows users to define a private which could be device specific. This avoids doing multiple lookups, which massively helps the ati spi driver which will support hundreds of devices. - uses linux sysfs pci infrastructure for enable/disable and mapping resources. This circumvents the security restrictions surrounding /dev/mem, but means that support for other operating systems still needs to be cobbled together. - looks up device names through libpci, keeping us from maintaining a separate names list.
Change-Id: I59af37cba5cb78014e0714c654db2501151f605e Signed-off-by: Luc Verhaegen libv@skynet.be --- M pcidev.c M programmer.h 2 files changed, 157 insertions(+), 0 deletions(-)
git pull ssh://review.coreboot.org:29418/flashrom refs/changes/78/29078/1
diff --git a/pcidev.c b/pcidev.c index f5ad819..837b028 100644 --- a/pcidev.c +++ b/pcidev.c @@ -3,6 +3,7 @@ * * Copyright (C) 2009 Uwe Hermann uwe@hermann-uwe.de * Copyright (C) 2010, 2011 Carl-Daniel Hailfinger + * Copyright (C) 2018 Luc Verhaegen libv@skynet.be * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -333,3 +334,134 @@ register_undo_pci_write_long(dev, reg); return pci_write_long(dev, reg, data); } + +/* + * This is reinvented pci device matching and access infrastructure which: + * - allows users to define a private which could be device specific. + * This avoids doing multiple lookups, which massively helps the ati spi + * driver which will support hundreds of devices. + * - uses linux sysfs pci infrastructure for enable/disable and mapping + * resources. This circumvents the security restrictions surrounding + * /dev/mem, but means that support for other operating systems still + * needs to be cobbled together. + * - looks up device names through libpci, keeping us from maintaining a + * separate names list. + * + */ + +/* + * + */ +static int +flashrom_pci_device_shutdown(void *data) +{ + struct flashrom_pci_device *device = data; + + if (!device->sysfs_path) { + msg_perr("%s: Tried to cleanup an invalid pci_device!\n" + "Please report a bug at flashrom@flashrom.org\n", __func__); + return 1; + } + + free(device->sysfs_path); + device->sysfs_path = NULL; + + free(device->name); + device->name = NULL; + + device->private = NULL; + free(device); + + return 0; +} + +/* + * + */ +struct flashrom_pci_device * +flashrom_pci_init(const struct flashrom_pci_match *matches) +{ + struct flashrom_pci_device *device; + struct pci_filter filter; + struct pci_dev *dev, *found_dev = NULL; + const struct flashrom_pci_match *found_match = NULL; + char *pcidev_bdf; + char buffer[1024], *name = NULL; + int i, found = 0; + + if (pci_init_common()) + return NULL; + + pci_filter_init(pacc, &filter); + + /* Filter by bb:dd.f (if supplied by the user). */ + pcidev_bdf = extract_programmer_param("pci"); + if (pcidev_bdf) { + char *msg; + + if ((msg = pci_filter_parse_slot(&filter, pcidev_bdf))) { + msg_perr("Error: %s\n", msg); + return NULL; + } + + free(pcidev_bdf); + } + + for (dev = pacc->devices; dev; dev = dev->next) + if (pci_filter_match(&filter, dev)) { + for (i = 0; matches[i].vendor_id ; i++) + if ((dev->vendor_id == matches[i].vendor_id) && + (dev->device_id == matches[i].device_id)) + break; + + if (!matches[i].vendor_id) + continue; + + + name = pci_lookup_name(pacc, buffer, sizeof(buffer), + PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE, + dev->vendor_id, dev->device_id); + if (name) + msg_pinfo("Detected %04x:%04x@%02x:%02x.%x "%s"\n", + dev->vendor_id, dev->device_id, + dev->bus, dev->dev, dev->func, name); + else + msg_pinfo("Detected %04x:%04x@%02x:%02x.%x "%s"\n", + dev->vendor_id, dev->device_id, + dev->bus, dev->dev, dev->func, + "<unknown pciids>"); + found_dev = dev; + found_match = &matches[i]; + found++; + } + + /* Only continue if exactly one supported PCI dev has been found. */ + if (!found) { + msg_perr("Error: No supported PCI device found.\n"); + return NULL; + } else if (found > 1) { + msg_perr("Error: Multiple supported PCI devices found. Use 'flashrom -p xxxx:pci=bb:dd.f'\n" + "to explicitly select the card with the given BDF (PCI bus, device, function).\n"); + return NULL; + } + + device = calloc(1, sizeof(*device)); + + device->name = strdup(name); + + device->device_id = found_dev->device_id; + device->vendor_id = found_dev->vendor_id; + + device->pci = found_dev; + + snprintf(buffer, sizeof(buffer) - 1, + "/sys/bus/pci/devices/%04x:%02x:%02x.%01x/", + 0, found_dev->bus, found_dev->dev, found_dev->func); + device->sysfs_path = strdup(buffer); + + device->private = found_match->private; + + register_shutdown(flashrom_pci_device_shutdown, device); + + return device; +} diff --git a/programmer.h b/programmer.h index 311992a..0a445fa 100644 --- a/programmer.h +++ b/programmer.h @@ -849,4 +849,29 @@ struct libusb_device_handle *usb_dev_get_by_vid_pid_number( struct libusb_context *usb_ctx, uint16_t vid, uint16_t pid, unsigned int num);
+#if NEED_PCI == 1 +struct flashrom_pci_match { + uint16_t vendor_id; + uint16_t device_id; + const enum test_state status; + const void *private; /* programmer specific */ +}; + +struct flashrom_pci_device { + char *name; /* created from pci info */ + + /* convenience copies */ + uint16_t vendor_id; + uint16_t device_id; + + struct pci_dev *pci; + + char *sysfs_path; /* linux only, of course */ + + const void *private; /* programmer specific hook */ +}; + +struct flashrom_pci_device *flashrom_pci_init(const struct flashrom_pci_match *matches); +#endif /* NEED_PCI */ + #endif /* !__PROGRAMMER_H__ */