diff options
-rw-r--r-- | ToDo | 10 | ||||
-rw-r--r-- | cli.c | 216 | ||||
-rw-r--r-- | driver/common.h | 7 | ||||
-rw-r--r-- | driver/sysfs.c | 2 | ||||
-rw-r--r-- | pcilib_types.h | 8 |
5 files changed, 205 insertions, 38 deletions
@@ -1,15 +1,21 @@ +Bugs +==== + 1. For IPECamera, shall we limit DMA packet size to xdma_packet_lenght register + additionally to size of memory page? + High Priority (we would need it for IPE Camera) ============= 1. Serialize access to the registers across applications 2. Protect kmem_entries in the driver using spinlock - 3. CMake build system + 3. Use bus-addresses instead of physcial addresses for DMA + 4. CMake build system Normal Priority (it would make just few things a bit easier) =============== 1. Implement software registers (stored in kernel-memory) 2. Support FIFO reads/writes from/to registers 3. Provide OR and AND operations on registers in cli - 4. Use bus-addresses instead of physcial addresses for DMA + 4. Support writting a data from binary file in cli Low Priority (only as generalization for other projects) ============ @@ -14,6 +14,8 @@ #include <errno.h> #include <alloca.h> #include <arpa/inet.h> +#include <sys/types.h> +#include <dirent.h> #include <getopt.h> @@ -56,7 +58,9 @@ typedef enum { MODE_GRAB, MODE_START_DMA, MODE_STOP_DMA, - MODE_WAIT_IRQ + MODE_WAIT_IRQ, + MODE_LIST_KMEM, + MODE_FREE_KMEM } MODE; typedef enum { @@ -82,10 +86,12 @@ typedef enum { OPT_GRAB = 'g', OPT_QUIETE = 'q', OPT_RESET = 128, - OPT_START_DMA = 129, - OPT_STOP_DMA = 130, - OPT_WAIT_IRQ = 131, - OPT_ITERATIONS = 132, + OPT_START_DMA, + OPT_STOP_DMA, + OPT_WAIT_IRQ, + OPT_ITERATIONS, + OPT_LIST_KMEM, + OPT_FREE_KMEM, OPT_HELP = 'h', } OPTIONS; @@ -109,6 +115,8 @@ static struct option long_options[] = { {"start-dma", required_argument, 0, OPT_START_DMA }, {"stop-dma", optional_argument, 0, OPT_STOP_DMA }, {"wait-irq", optional_argument, 0, OPT_WAIT_IRQ }, + {"list-kernel-memory", no_argument, 0, OPT_LIST_KMEM }, + {"free-kernel-memory", optional_argument, 0, OPT_FREE_KMEM }, {"quiete", no_argument, 0, OPT_QUIETE }, {"help", no_argument, 0, OPT_HELP }, { 0, 0, 0, 0 } @@ -133,37 +141,40 @@ void Usage(int argc, char *argv[], const char *format, ...) { "Usage:\n" " %s <mode> [options] [hex data]\n" " Modes:\n" -" -i - Device Info\n" -" -l[l] - List (detailed) Data Banks & Registers\n" -" -p <barX|dmaX> - Performance Evaluation\n" -" -r <addr|reg|dmaX> - Read Data/Register\n" -" -w <addr|reg|dmaX> - Write Data/Register\n" -" -g [event] - Grab Event\n" -" --reset - Reset board\n" -" --help - Help message\n" +" -i - Device Info\n" +" -l[l] - List (detailed) Data Banks & Registers\n" +" -p <barX|dmaX> - Performance Evaluation\n" +" -r <addr|reg|dmaX> - Read Data/Register\n" +" -w <addr|reg|dmaX> - Write Data/Register\n" +" -g [event] - Grab Event\n" +" --reset - Reset board\n" +" --help - Help message\n" "\n" " DMA Modes:\n" -" --start-dma <num>[r|w] - Start specified DMA engine\n" -" --stop-dma [num][r|w] - Stop specified engine or DMA subsystem\n" -" --wait-irq <source> - Wait for IRQ\n" -" --clean-kernel-memory - Cleans lost kernel space buffers (DANGEROUS)\n" +" --start-dma <num>[r|w] - Start specified DMA engine\n" +" --stop-dma [num][r|w] - Stop specified engine or DMA subsystem\n" +" --wait-irq <source> - Wait for IRQ\n" +"\n" +" Kernel Modes:\n" +" --list-kernel-memory - List kernel buffers\n" +" --free-kernel-memory [use] - Cleans lost kernel space buffers (DANGEROUS)\n" "\n" " Addressing:\n" -" -d <device> - FPGA device (/dev/fpga0)\n" -" -m <model> - Memory model (autodetected)\n" -" pci - Plain\n" -" ipecamera - IPE Camera\n" -" -b <bank> - PCI bar, Register bank, or DMA channel\n" +" -d <device> - FPGA device (/dev/fpga0)\n" +" -m <model> - Memory model (autodetected)\n" +" pci - Plain\n" +" ipecamera - IPE Camera\n" +" -b <bank> - PCI bar, Register bank, or DMA channel\n" "\n" " Options:\n" -" -s <size> - Number of words (default: 1)\n" -" -a [fifo|dma]<bits> - Access type and bits per word (default: 32)\n" -" -e <l|b> - Endianess Little/Big (default: host)\n" -" -o <file> - Output to file (default: stdout)\n" -" -t <timeout> - Timeout in microseconds\n" +" -s <size> - Number of words (default: 1)\n" +" -a [fifo|dma]<bits> - Access type and bits per word (default: 32)\n" +" -e <l|b> - Endianess Little/Big (default: host)\n" +" -o <file> - Output to file (default: stdout)\n" +" -t <timeout> - Timeout in microseconds\n" "\n" " Information:\n" -" -q - Quiete mode (suppress warnings)\n" +" -q - Quiete mode (suppress warnings)\n" "\n" " Data:\n" " Data can be specified as sequence of hexdecimal number or\n" @@ -942,6 +953,140 @@ int StartStopDMA(pcilib_t *handle, pcilib_model_description_t *model_info, pcil return 0; } + +typedef struct { + unsigned long use; + + int referenced; + int hw_lock; + int reusable; + int persistent; + int open; + + size_t count; + size_t size; +} kmem_use_info_t; + +#define MAX_USES 64 + +size_t FindUse(size_t *n_uses, kmem_use_info_t *uses, unsigned long use) { + size_t i, n = *n_uses; + + if (uses[n - 1].use == use) return n - 1; + + for (i = 1; i < (n - 1); i++) { + if (uses[i].use == use) return i; + } + + if (n == MAX_USES) return 0; + + uses[n].use = use; + return (*n_uses)++; +} + +char *PrintSize(char *str, size_t size) { + if (size >= 1073741824) sprintf(str, "%.1lf GB", 1.*size / 1073741824); + else if (size >= 1048576) sprintf(str, "%.1lf MB", 1.*size / 1048576); + else if (size >= 1024) sprintf(str, "%lu KB", size / 1024); + else sprintf(str, "%lu B ", size); + + return str; +} + +int ListKMEM(pcilib_t *handle, const char *device) { + DIR *dir; + struct dirent *entry; + const char *pos; + char sysdir[256]; + char fname[256]; + char info[256]; + char stmp[256]; + + size_t useid, i, n_uses = 1; // Use 0 is for others + kmem_use_info_t uses[MAX_USES]; + + memset(uses, 0, sizeof(uses)); + + pos = strrchr(device, '/'); + if (pos) ++pos; + else pos = device; + + snprintf(sysdir, 255, "/sys/class/fpga/%s", pos); + + dir = opendir(sysdir); + if (!dir) Error("Can't open directory (%s)", sysdir); + + while ((entry = readdir(dir)) != NULL) { + FILE *f; + unsigned long use; + unsigned long size; + unsigned long refs; + unsigned long mode; + unsigned long hwref; + + if (strncmp(entry->d_name, "kbuf", 4)) continue; + if (!isnumber(entry->d_name+4)) continue; + + snprintf(fname, 255, "%s/%s", sysdir, entry->d_name); + f = fopen(fname, "r"); + if (!f) Error("Can't access file (%s)", fname); + + while(!feof(f)) { + fgets(info, 256, f); + if (!strncmp(info, "use:", 4)) use = strtoul(info+4, NULL, 16); + if (!strncmp(info, "size:", 5)) size = strtoul(info+5, NULL, 10); + if (!strncmp(info, "refs:", 5)) refs = strtoul(info+5, NULL, 10); + if (!strncmp(info, "mode:", 5)) mode = strtoul(info+5, NULL, 16); + if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); + } + fclose(f); + + useid = FindUse(&n_uses, uses, use); + uses[useid].count++; + uses[useid].size += size; + if (refs) uses[useid].referenced = 1; + if (hwref) uses[useid].hw_lock = 1; + if (mode&KMEM_MODE_REUSABLE) uses[useid].reusable = 1; + if (mode&KMEM_MODE_PERSISTENT) uses[useid].persistent = 1; + if (mode&KMEM_MODE_COUNT) uses[useid].open = 1; + } + closedir(dir); + + printf("Use Type Count Total Size REF Mode \n"); + printf("--------------------------------------------------------------------------------\n"); + for (useid = 0; useid < n_uses; useid++) { + if (useid + 1 == n_uses) { + if (!uses[0].count) continue; + i = 0; + } else i = useid + 1; + + if (!i) printf("0x%08lx Others", 0); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%u %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"C2S":"S2C")); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%u %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"C2S":"S2C")); + else printf("0x%08lx ", uses[i].use); + printf(" "); + printf("% 9lu", uses[i].count); + printf(" "); + printf("% 12s", PrintSize(stmp, uses[i].size)); + printf(" "); + if (uses[i].referenced&&uses[i].hw_lock) printf("HW+SW"); + else if (uses[i].referenced) printf(" SW"); + else if (uses[i].hw_lock) printf("HW "); + else printf(" - "); + printf(" "); + if (uses[i].persistent) printf("Persistent"); + else if (uses[i].open) printf("Open "); + else if (uses[i].reusable) printf("Reusable "); + else printf("Closed "); + printf("\n"); + } + printf("--------------------------------------------------------------------------------\n"); + printf("REF - Software/Hardware Reference, MODE - Reusable/Persistent/Open\n"); + + + return 0; +} + int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_source_t irq_source, pcilib_timeout_t timeout) { int err; size_t count; @@ -982,6 +1127,7 @@ int main(int argc, char **argv) { char **data = NULL; const char *event = NULL; const char *dma_channel = NULL; + const char *use = NULL; pcilib_irq_source_t irq_source; pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL; @@ -1077,6 +1223,17 @@ int main(int argc, char **argv) { irq_source = itmp; break; + case OPT_LIST_KMEM: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + mode = MODE_LIST_KMEM; + break; + case OPT_FREE_KMEM: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + mode = MODE_FREE_KMEM; + + if (optarg) use = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++]; + break; case OPT_DEVICE: fpga_device = optarg; break; @@ -1334,6 +1491,9 @@ int main(int argc, char **argv) { case MODE_WAIT_IRQ: WaitIRQ(handle, model_info, irq_source, timeout); break; + case MODE_LIST_KMEM: + ListKMEM(handle, fpga_device); + break; } pcilib_close(handle); diff --git a/driver/common.h b/driver/common.h index 5787618..3d26a97 100644 --- a/driver/common.h +++ b/driver/common.h @@ -6,13 +6,6 @@ /*************************************************************************/ /* Private data types and structures */ -#define KMEM_REF_HW 0x80000000 /**< Special reference to indicate hardware access */ -#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap), couting in mmaped memory pages */ - -#define KMEM_MODE_REUSABLE 0x80000000 /**< Indicates reusable buffer */ -#define KMEM_MODE_EXCLUSIVE 0x40000000 /**< Only a single process is allowed to mmap the buffer */ -#define KMEM_MODE_PERSISTENT 0x20000000 /**< Persistent mode instructs kmem_free to preserve buffer in memory */ -#define KMEM_MODE_COUNT 0x0FFFFFFF /**< Mask of reuse counter (alloc/free) */ /* Define an entry in the kmem list (this list is per device) */ /* This list keeps references to the allocated kernel buffers */ diff --git a/driver/sysfs.c b/driver/sysfs.c index ab0925c..59536ab 100644 --- a/driver/sysfs.c +++ b/driver/sysfs.c @@ -98,7 +98,7 @@ static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); if (entry) - return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lu\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: %lx\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); + return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lu\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); else return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); #else diff --git a/pcilib_types.h b/pcilib_types.h index 237f1db..d8dd6f5 100644 --- a/pcilib_types.h +++ b/pcilib_types.h @@ -1,6 +1,14 @@ #ifndef _PCILIB_TYPES_H #define _PCILIB_TYPES_H +#define KMEM_REF_HW 0x80000000 /**< Special reference to indicate hardware access */ +#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap), couting in mmaped memory pages */ + +#define KMEM_MODE_REUSABLE 0x80000000 /**< Indicates reusable buffer */ +#define KMEM_MODE_EXCLUSIVE 0x40000000 /**< Only a single process is allowed to mmap the buffer */ +#define KMEM_MODE_PERSISTENT 0x20000000 /**< Persistent mode instructs kmem_free to preserve buffer in memory */ +#define KMEM_MODE_COUNT 0x0FFFFFFF /**< Mask of reuse counter (alloc/free) */ + typedef enum { PCILIB_KMEM_TYPE_CONSISTENT = 0, PCILIB_KMEM_TYPE_PAGE, |