From ad820a3618c819463b89f4fe40a710edc4081694 Mon Sep 17 00:00:00 2001 From: Daniel Krebs Date: Tue, 15 May 2018 15:11:47 +0200 Subject: [PATCH] kernel/pci: parse BAR regions --- fpga/include/villas/kernel/pci.h | 10 +++++ fpga/lib/kernel/pci.c | 67 ++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/fpga/include/villas/kernel/pci.h b/fpga/include/villas/kernel/pci.h index 10fd86ef6..3cd9565ed 100644 --- a/fpga/include/villas/kernel/pci.h +++ b/fpga/include/villas/kernel/pci.h @@ -9,6 +9,7 @@ #pragma once +#include #include "list.h" #define PCI_SLOT(devfn) (((devfn) >> 3) & 0x1f) @@ -33,6 +34,13 @@ struct pci_device { } slot; /**< Bus, Device, Function (BDF) */ }; +struct pci_region { + int num; + uintptr_t start; + uintptr_t end; + unsigned long long flags; +}; + struct pci { struct list devices; /**< List of available PCI devices in the system (struct pci_device) */ }; @@ -66,6 +74,8 @@ int pci_attach_driver(const struct pci_device *d, const char *driver); /** Return the IOMMU group of this PCI device or -1 if the device is not in a group. */ int pci_get_iommu_group(const struct pci_device *d); +size_t pci_get_regions(const struct pci_device *d, struct pci_region** regions); + #ifdef __cplusplus } #endif diff --git a/fpga/lib/kernel/pci.c b/fpga/lib/kernel/pci.c index 1f7336742..f920ea6d5 100644 --- a/fpga/lib/kernel/pci.c +++ b/fpga/lib/kernel/pci.c @@ -254,6 +254,73 @@ struct pci_device * pci_lookup_device(struct pci *p, struct pci_device *f) return list_search(&p->devices, (cmp_cb_t) pci_device_compare, (void *) f); } +size_t pci_get_regions(const struct pci_device *d, struct pci_region** regions) +{ + FILE* f; + char sysfs[1024]; + + assert(regions != NULL); + + snprintf(sysfs, sizeof(sysfs), "%s/bus/pci/devices/%04x:%02x:%02x.%x/resource", + SYSFS_PATH, d->slot.domain, d->slot.bus, d->slot.device, d->slot.function); + + f = fopen(sysfs, "r"); + if (!f) + serror("Failed to open resource mapping %s", sysfs); + + struct pci_region _regions[8]; + struct pci_region* cur_region = _regions; + size_t valid_regions = 0; + + ssize_t bytesRead; + char* line = NULL; + size_t len = 0; + + int region = 0; + // cap to 8 regions, just because we don't know how many may exist + while(region < 8 && (bytesRead = getline(&line, &len, f)) != -1) { + unsigned long long tokens[3]; + char* s = line; + for(int i = 0; i < 3; i++) { + char* end; + tokens[i] = strtoull(s, &end, 16); + if(s == end) { + printf("Error parsing line %d of %s\n", region + 1, sysfs); + tokens[0] = tokens[1] = 0; // mark invalid + break; + } + s = end; + } + + free(line); + + // required for getline() to allocate a new buffer on the next iteration + line = NULL; + len = 0; + + if(tokens[0] != tokens[1]) { + // this is a valid region + cur_region->num = region; + cur_region->start = tokens[0]; + cur_region->end = tokens[1]; + cur_region->flags = tokens[2]; + cur_region++; + valid_regions++; + } + + region++; + } + + if(valid_regions > 0) { + const size_t len = valid_regions * sizeof (struct pci_region); + *regions = malloc(len); + memcpy(*regions, _regions, len); + } + + return valid_regions; +} + + int pci_get_driver(const struct pci_device *d, char *buf, size_t buflen) { int ret;