pci: add a helper to lookup a pci_device by string This is for #device code that often wants to find a pci_device that userspace specified by string. The string is of the form 00:00.0. You can skip leading zeros. This one throws on error, since the intent is that user-interface code will use it. The older match_tbdf() is used in a few internal places, with a custom format for the int argument (MKBUS()). Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/arch/x86/pci.c b/kern/arch/x86/pci.c index 58f16e8..a3057d3 100644 --- a/kern/arch/x86/pci.c +++ b/kern/arch/x86/pci.c
@@ -632,14 +632,9 @@ spin_unlock_irqsave(&pcidev->lock); } -struct pci_device *pci_match_tbdf(int tbdf) +static struct pci_device *pci_match_bus_dev_func(int bus, int dev, int func) { struct pci_device *search; - int bus, dev, func; - - bus = BUSBNO(tbdf); - dev = BUSDNO(tbdf); - func = BUSFNO(tbdf); STAILQ_FOREACH(search, &pci_devices, all_dev) { if ((search->bus == bus) && @@ -650,6 +645,30 @@ return NULL; } +struct pci_device *pci_match_tbdf(int tbdf) +{ + return pci_match_bus_dev_func(BUSBNO(tbdf), BUSDNO(tbdf), BUSFNO(tbdf)); +} + +/* Throws on error */ +struct pci_device *pci_match_string(const char *bdf) +{ + struct pci_device *pdev; + int bus, dev, func, ret; + + ret = sscanf(bdf, "%x:%x.%x", &bus, &dev, &func); + if (ret != 3) + error(EINVAL, "Bad BDF format %s", bdf); + if ((bus != (bus & 0xff)) || + (dev != (dev & 0x1f)) || + (func != (func & 0x07))) + error(EINVAL, "BDF %s out of range", bdf); + pdev = pci_match_tbdf(MKBUS(BusPCI, bus, dev, func)); + if (!pdev) + error(ENOENT, "No BDF %s", bdf); + return pdev; +} + /* Helper to get the membar value for BAR index bir */ uintptr_t pci_get_membar(struct pci_device *pcidev, int bir) {
diff --git a/kern/arch/x86/pci.h b/kern/arch/x86/pci.h index 86b9793..9040623 100644 --- a/kern/arch/x86/pci.h +++ b/kern/arch/x86/pci.h
@@ -300,6 +300,7 @@ void pci_set_bus_master(struct pci_device *pcidev); void pci_clr_bus_master(struct pci_device *pcidev); struct pci_device *pci_match_tbdf(int tbdf); +struct pci_device *pci_match_string(const char *bdf); uintptr_t pci_get_membar(struct pci_device *pcidev, int bir); uintptr_t pci_get_iobar(struct pci_device *pcidev, int bir); bool pci_bar_is_mem32(struct pci_device *pdev, int bar);