summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-10-22 01:44:28 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-10-22 01:44:28 +0200
commita710557ef4f33bc286d8240fff950b974c9d5b01 (patch)
tree4b119f7df96df3f4583e5c47ce32f86dacea306d
parent32bd82e4b4748cbe7b4734030dfb135feab4dffc (diff)
downloadpcitool-a710557ef4f33bc286d8240fff950b974c9d5b01.tar.gz
pcitool-a710557ef4f33bc286d8240fff950b974c9d5b01.tar.bz2
pcitool-a710557ef4f33bc286d8240fff950b974c9d5b01.tar.xz
pcitool-a710557ef4f33bc286d8240fff950b974c9d5b01.zip
Provide information about active DMA engines & buffers
-rw-r--r--cli.c252
-rw-r--r--dma.c30
-rw-r--r--dma.h17
-rw-r--r--dma/nwl_dma.h3
-rw-r--r--dma/nwl_engine_buffers.h34
5 files changed, 328 insertions, 8 deletions
diff --git a/cli.c b/cli.c
index 8c65830..3c98960 100644
--- a/cli.c
+++ b/cli.c
@@ -58,6 +58,9 @@ typedef enum {
MODE_GRAB,
MODE_START_DMA,
MODE_STOP_DMA,
+ MODE_LIST_DMA,
+ MODE_LIST_DMA_BUFFERS,
+ MODE_READ_DMA_BUFFER,
MODE_WAIT_IRQ,
MODE_LIST_KMEM,
MODE_READ_KMEM,
@@ -85,8 +88,12 @@ typedef enum {
OPT_WRITE = 'w',
OPT_GRAB = 'g',
OPT_QUIETE = 'q',
+ OPT_HELP = 'h',
OPT_RESET = 128,
OPT_BENCHMARK,
+ OPT_LIST_DMA,
+ OPT_LIST_DMA_BUFFERS,
+ OPT_READ_DMA_BUFFER,
OPT_START_DMA,
OPT_STOP_DMA,
OPT_WAIT_IRQ,
@@ -94,8 +101,7 @@ typedef enum {
OPT_LIST_KMEM,
OPT_FREE_KMEM,
OPT_READ_KMEM,
- OPT_FORCE,
- OPT_HELP = 'h',
+ OPT_FORCE
} OPTIONS;
static struct option long_options[] = {
@@ -117,6 +123,9 @@ static struct option long_options[] = {
{"grab", optional_argument, 0, OPT_GRAB },
{"start-dma", required_argument, 0, OPT_START_DMA },
{"stop-dma", optional_argument, 0, OPT_STOP_DMA },
+ {"list-dma-engines", no_argument, 0, OPT_LIST_DMA },
+ {"list-dma-buffers", required_argument, 0, OPT_LIST_DMA_BUFFERS },
+ {"read-dma-buffer", required_argument, 0, OPT_READ_DMA_BUFFER },
{"wait-irq", optional_argument, 0, OPT_WAIT_IRQ },
{"list-kernel-memory", no_argument, 0, OPT_LIST_KMEM },
{"read-kernel-memory", required_argument, 0, OPT_READ_KMEM },
@@ -157,7 +166,10 @@ void Usage(int argc, char *argv[], const char *format, ...) {
"\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"
+" --stop-dma [num[r|w]] - Stop specified engine or DMA subsystem\n"
+" --list-dma-engines - List active DMA engines\n"
+" --list-dma-buffers <dma> - List buffers for specified DMA engine\n"
+" --read-dma-buffer <dma:buf> - Read the specified buffer\n"
" --wait-irq <source> - Wait for IRQ\n"
"\n"
" Kernel Modes:\n"
@@ -1073,7 +1085,7 @@ int ListKMEM(pcilib_t *handle, const char *device) {
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;
@@ -1126,7 +1138,7 @@ int ListKMEM(pcilib_t *handle, const char *device) {
return 0;
}
-int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t block, FILE *o) {
+int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t block, size_t max_size, FILE *o) {
void *data;
size_t size;
pcilib_kmem_handle_t *kbuf;
@@ -1140,6 +1152,7 @@ int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t
data = pcilib_kmem_get_block_ua(handle, kbuf, block);
if (data) {
size = pcilib_kmem_get_block_size(handle, kbuf, block);
+ if ((max_size)&&(size > max_size)) size = max_size;
fwrite(data, 1, size, o?o:stdout);
} else {
printf("The specified block is not existing\n");
@@ -1180,6 +1193,193 @@ int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) {
return 0;
}
+int ListDMA(pcilib_t *handle, const char *device, pcilib_model_description_t *model_info) {
+ int err;
+
+ DIR *dir;
+ struct dirent *entry;
+ const char *pos;
+ char sysdir[256];
+ char fname[256];
+ char info[256];
+ char stmp[256];
+
+ pcilib_dma_engine_t dmaid;
+ pcilib_dma_engine_status_t status;
+
+ 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);
+
+ printf("DMA Engine Status Total Size Buffer Ring\n");
+ printf("--------------------------------------------------------------------------------\n");
+ 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);
+
+ if ((mode&(KMEM_MODE_REUSABLE|KMEM_MODE_PERSISTENT|KMEM_MODE_COUNT)) == 0) continue; // closed
+ if ((use >> 16) != PCILIB_KMEM_USE_DMA_RING) continue;
+
+ if (use&0x80) {
+ dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, use&0x7F);
+ } else {
+ dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, use&0x7F);
+ }
+
+ if (dmaid == PCILIB_DMA_ENGINE_INVALID) continue;
+
+
+ printf("DMA%u %s ", use&0x7F, (use&0x80)?"S2C":"C2S");
+ err = pcilib_start_dma(handle, dmaid, 0);
+ if (err) {
+ printf("-- Wrong state, start is failed\n");
+ continue;
+ }
+
+ err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL);
+ if (err) {
+ printf("-- Wrong state, failed to obtain status\n");
+ pcilib_stop_dma(handle, dmaid, 0);
+ continue;
+ }
+
+ pcilib_stop_dma(handle, dmaid, 0);
+
+ if (status.started) printf("S");
+ else printf(" ");
+
+ if (status.ring_head == status.ring_tail) printf(" ");
+ else printf("D");
+
+ printf(" ");
+ printf("% 10s", PrintSize(stmp, status.ring_size * status.buffer_size));
+
+ printf(" ");
+ printf("%zu - %zu (of %zu)", status.ring_tail, status.ring_head, status.ring_size);
+
+ printf("\n");
+
+ }
+ closedir(dir);
+
+ printf("--------------------------------------------------------------------------------\n");
+ printf("S - Started, D - Data in buffers\n");
+
+ return 0;
+}
+
+int ListBuffers(pcilib_t *handle, const char *device, pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction) {
+ int err;
+ size_t i;
+ pcilib_dma_engine_t dmaid;
+ pcilib_dma_engine_status_t status;
+ pcilib_dma_buffer_status_t *buffer;
+ char stmp[256];
+
+ dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma);
+ if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found");
+
+ err = pcilib_start_dma(handle, dmaid, 0);
+ if (err) Error("Error starting the specified DMA engine");
+
+ err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL);
+ if (err) Error("Failed to obtain status of the specified DMA engine");
+
+ buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t));
+ if (!buffer) Error("Failed to allocate memory for status buffer");
+
+ err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer);
+ if (err) Error("Failed to obtain extended status of the specified DMA engine");
+
+
+ printf("Buffer Status Total Size \n");
+ printf("--------------------------------------------------------------------------------\n");
+
+ for (i = 0; i < status.ring_size; i++) {
+ printf("%8zu ", i);
+ printf("%c%c %c%c ", buffer[i].used?'U':' ', buffer[i].error?'E':' ', buffer[i].first?'F':' ', buffer[i].last?'L':' ');
+ printf("% 10s", PrintSize(stmp, buffer[i].size));
+ printf("\n");
+ }
+
+ printf("--------------------------------------------------------------------------------\n");
+ printf("U - Used, E - Error, F - First block, L - Last Block\n");
+
+ free(buffer);
+
+ pcilib_stop_dma(handle, dmaid, 0);
+
+}
+
+int ReadBuffer(pcilib_t *handle, const char *device, pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, size_t block, FILE *o) {
+ int err;
+ size_t i;
+ pcilib_dma_engine_t dmaid;
+ pcilib_dma_engine_status_t status;
+ pcilib_dma_buffer_status_t *buffer;
+ size_t size;
+ char stmp[256];
+
+ dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma);
+ if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found");
+
+ err = pcilib_start_dma(handle, dmaid, 0);
+ if (err) Error("Error starting the specified DMA engine");
+
+ err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL);
+ if (err) Error("Failed to obtain status of the specified DMA engine");
+
+ buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t));
+ if (!buffer) Error("Failed to allocate memory for status buffer");
+
+ err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer);
+ if (err) Error("Failed to obtain extended status of the specified DMA engine");
+
+ if (block == (size_t)-1) {
+ // get current
+ }
+
+ size = buffer[block].size;
+
+ free(buffer);
+
+ pcilib_stop_dma(handle, dmaid, 0);
+
+
+
+// printf("%i %i\n", dma, buffer);
+// printf("%lx\n", ((dma&0x7F)|((dma_direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00))|(PCILIB_KMEM_USE_DMA_PAGES<<16));
+ return ReadKMEM(handle, device, ((dma&0x7F)|((dma_direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00))|(PCILIB_KMEM_USE_DMA_PAGES<<16), block, size, o);
+}
+
+
+
int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source, pcilib_timeout_t timeout) {
int err;
size_t count;
@@ -1295,6 +1495,33 @@ int main(int argc, char **argv) {
if (optarg) event = optarg;
else if ((optind < argc)&&(argv[optind][0] != '-')) event = argv[optind++];
break;
+ case OPT_LIST_DMA:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+
+ mode = MODE_LIST_DMA;
+ break;
+ case OPT_LIST_DMA_BUFFERS:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+
+ mode = MODE_LIST_DMA_BUFFERS;
+ dma_channel = optarg;
+ break;
+ case OPT_READ_DMA_BUFFER:
+ if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
+
+ mode = MODE_READ_DMA_BUFFER;
+
+ num_offset = strchr(optarg, ':');
+
+ if (num_offset) {
+ if (sscanf(num_offset + 1, "%zu", &block) != 1)
+ Usage(argc, argv, "Invalid buffer is specified (%s)", num_offset + 1);
+
+ *(char*)num_offset = 0;
+ } else block = (size_t)-1;
+
+ dma_channel = optarg;
+ break;
case OPT_START_DMA:
if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported");
@@ -1434,7 +1661,7 @@ int main(int argc, char **argv) {
force = 1;
break;
default:
- Usage(argc, argv, "Unknown option (%s)", argv[optind]);
+ Usage(argc, argv, "Unknown option (%s) with argument (%s)", optarg?argv[optind-2]:argv[optind-1], optarg?optarg:"(null)");
}
}
@@ -1485,6 +1712,8 @@ int main(int argc, char **argv) {
break;
case MODE_START_DMA:
case MODE_STOP_DMA:
+ case MODE_LIST_DMA_BUFFERS:
+ case MODE_READ_DMA_BUFFER:
if ((dma_channel)&&(*dma_channel)) {
itmp = strlen(dma_channel) - 1;
if (dma_channel[itmp] == 'r') dma_direction = PCILIB_DMA_FROM_DEVICE;
@@ -1617,6 +1846,15 @@ int main(int argc, char **argv) {
case MODE_GRAB:
Grab(handle, event, ofile);
break;
+ case MODE_LIST_DMA:
+ ListDMA(handle, fpga_device, model_info);
+ break;
+ case MODE_LIST_DMA_BUFFERS:
+ ListBuffers(handle, fpga_device, model_info, dma, dma_direction);
+ break;
+ case MODE_READ_DMA_BUFFER:
+ ReadBuffer(handle, fpga_device, model_info, dma, dma_direction, block, ofile);
+ break;
case MODE_START_DMA:
StartStopDMA(handle, model_info, dma, dma_direction, 1);
break;
@@ -1630,7 +1868,7 @@ int main(int argc, char **argv) {
ListKMEM(handle, fpga_device);
break;
case MODE_READ_KMEM:
- ReadKMEM(handle, fpga_device, use_id, block, ofile);
+ ReadKMEM(handle, fpga_device, use_id, block, 0, ofile);
break;
case MODE_FREE_KMEM:
FreeKMEM(handle, fpga_device, use, force);
diff --git a/dma.c b/dma.c
index 1bab0f9..9527c0b 100644
--- a/dma.c
+++ b/dma.c
@@ -235,7 +235,7 @@ int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size
pcilib_dma_read_callback_context_t opts = {
size, buf, 0
};
-
+
err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts);
if (read_bytes) *read_bytes = opts.pos;
return err;
@@ -325,3 +325,31 @@ double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr
return ctx->model_info.dma_api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction);
}
+
+int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
+ int err;
+
+ const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
+ if (!info) {
+ pcilib_error("DMA is not supported by the device");
+ return 0;
+ }
+
+ if (!ctx->model_info.dma_api) {
+ pcilib_error("DMA Engine is not configured in the current model");
+ return -1;
+ }
+
+ if (!ctx->model_info.dma_api->status) {
+ memset(status, 0, sizeof(pcilib_dma_engine_status_t));
+ return -1;
+ }
+
+ if (!info->engines[dma]) {
+ pcilib_error("The DMA engine (%i) is not supported by device", dma);
+ return -1;
+ }
+
+ return ctx->model_info.dma_api->status(ctx->dma_ctx, dma, status, n_buffers, buffers);
+
+}
diff --git a/dma.h b/dma.h
index b18ee56..8da1c96 100644
--- a/dma.h
+++ b/dma.h
@@ -7,9 +7,25 @@
typedef uint32_t pcilib_dma_modification_t;
+typedef struct {
+ int started;
+ size_t ring_size, buffer_size;
+ size_t ring_head, ring_tail;
+} pcilib_dma_engine_status_t;
+
+typedef struct {
+ int used;
+ int error;
+ int first;
+ int last;
+ size_t size;
+} pcilib_dma_buffer_status_t;
+
struct pcilib_dma_api_description_s {
pcilib_dma_context_t *(*init)(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg);
void (*free)(pcilib_dma_context_t *ctx);
+
+ int (*status)(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers);
int (*enable_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags);
int (*disable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags);
@@ -25,5 +41,6 @@ struct pcilib_dma_api_description_s {
};
int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc);
+int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers);
#endif /* _PCILIB_DMA_H */
diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h
index d5068e2..f87c68f 100644
--- a/dma/nwl_dma.h
+++ b/dma/nwl_dma.h
@@ -9,6 +9,8 @@
pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg);
void dma_nwl_free(pcilib_dma_context_t *vctx);
+int dma_nwl_get_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers);
+
int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcilib_dma_flags_t flags);
int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags);
int dma_nwl_acknowledge_irq(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source);
@@ -25,6 +27,7 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
pcilib_dma_api_description_t nwl_dma_api = {
dma_nwl_init,
dma_nwl_free,
+ dma_nwl_get_status,
dma_nwl_enable_irq,
dma_nwl_disable_irq,
dma_nwl_acknowledge_irq,
diff --git a/dma/nwl_engine_buffers.h b/dma/nwl_engine_buffers.h
index 77484a2..bbafae4 100644
--- a/dma/nwl_engine_buffers.h
+++ b/dma/nwl_engine_buffers.h
@@ -375,3 +375,37 @@ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t
info->tail++;
if (info->tail == info->ring_size) info->tail = 0;
}
+
+int dma_nwl_get_status(pcilib_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) {
+ size_t i;
+ nwl_dma_t *ctx = (nwl_dma_t*)vctx;
+ pcilib_nwl_engine_description_t *info = ctx->engines + dma;
+ uint32_t bstatus;
+
+ if (!status) return -1;
+
+ status->started = info->started;
+ status->ring_size = info->ring_size;
+ status->buffer_size = info->page_size;
+ status->ring_head = info->head;
+ status->ring_tail = info->tail;
+
+ if (buffers) {
+ unsigned char *ring = (unsigned char*)pcilib_kmem_get_ua(ctx->pcilib, info->ring);
+
+ for (i = 0; (i < info->ring_size)&&(i < n_buffers); i++) {
+ bstatus = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET);
+
+ buffers[i].error = bstatus & (DMA_BD_ERROR_MASK/*|DMA_BD_SHORT_MASK*/);
+ buffers[i].used = bstatus & DMA_BD_COMP_MASK;
+ buffers[i].size = bstatus & DMA_BD_BUFL_MASK;
+ buffers[i].first = bstatus & DMA_BD_SOP_MASK;
+ buffers[i].last = bstatus & DMA_BD_EOP_MASK;
+
+ ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
+ }
+ }
+
+ return 0;
+}
+