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);