summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 21:28:53 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 21:28:53 +0200
commit2c52de4f914806c040f62d9fc3ee88081a7aa56b (patch)
treee40aa496fe958e313e082340c4d1689e56143f2f
parent8ad813673ae155ce0e601ae864466a59ce7afa95 (diff)
downloadipecamera-2c52de4f914806c040f62d9fc3ee88081a7aa56b.tar.gz
ipecamera-2c52de4f914806c040f62d9fc3ee88081a7aa56b.tar.bz2
ipecamera-2c52de4f914806c040f62d9fc3ee88081a7aa56b.tar.xz
ipecamera-2c52de4f914806c040f62d9fc3ee88081a7aa56b.zip
List kernel buffers
-rw-r--r--ToDo10
-rw-r--r--cli.c216
-rw-r--r--driver/common.h7
-rw-r--r--driver/sysfs.c2
-rw-r--r--pcilib_types.h8
5 files changed, 205 insertions, 38 deletions
diff --git a/ToDo b/ToDo
index 8a9eca0..328eb41 100644
--- a/ToDo
+++ b/ToDo
@@ -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)
============
diff --git a/cli.c b/cli.c
index 8cdab0c..5deee17 100644
--- a/cli.c
+++ b/cli.c
@@ -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,