From 32c2f2c589c1a3ccf5dd9117538aafc6f3e0194e Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Wed, 26 Oct 2011 07:12:31 +0200 Subject: Improvements of DMA engine --- cli.c | 120 ++++++++++++++++++++++++++++++++++++------ dma.c | 30 +++++++++-- dma.h | 8 ++- dma/nwl.c | 6 ++- dma/nwl.h | 4 +- dma/nwl_dma.h | 2 +- dma/nwl_engine.c | 45 +++++++++------- dma/nwl_engine.h | 2 + dma/nwl_engine_buffers.h | 85 +++++++----------------------- dma/nwl_irq.c | 2 +- dma/nwl_loopback.c | 132 +++++++++++++++++++++++++++-------------------- dma/nwl_register.c | 6 ++- dma/nwl_register.h | 8 --- error.h | 3 +- pcilib.h | 27 ++++++++-- 15 files changed, 298 insertions(+), 182 deletions(-) diff --git a/cli.c b/cli.c index 53c8f75..e07a470 100644 --- a/cli.c +++ b/cli.c @@ -73,6 +73,11 @@ typedef enum { ACCESS_FIFO } ACCESS_MODE; +typedef enum { + FLAG_MULTIPACKET = 1, + FLAG_WAIT = 2 +} FLAGS; + typedef enum { OPT_DEVICE = 'd', OPT_MODEL = 'm', @@ -101,7 +106,9 @@ typedef enum { OPT_LIST_KMEM, OPT_FREE_KMEM, OPT_READ_KMEM, - OPT_FORCE + OPT_FORCE, + OPT_WAIT, + OPT_MULTIPACKET } OPTIONS; static struct option long_options[] = { @@ -132,6 +139,8 @@ static struct option long_options[] = { {"free-kernel-memory", required_argument, 0, OPT_FREE_KMEM }, {"quiete", no_argument, 0, OPT_QUIETE }, {"force", no_argument, 0, OPT_FORCE }, + {"multipacket", no_argument, 0, OPT_MULTIPACKET }, + {"wait", no_argument, 0, OPT_WAIT }, {"help", no_argument, 0, OPT_HELP }, { 0, 0, 0, 0 } }; @@ -194,6 +203,10 @@ void Usage(int argc, char *argv[], const char *format, ...) { " -o - Append output to file (default: stdout)\n" " -t - Timeout in microseconds\n" "\n" +" DMA Options:\n" +" --multipacket - Read multiple packets\n" +" --wait - Wait until data arrives\n" +"\n" " Information:\n" " -q - Quiete mode (suppress warnings)\n" "\n" @@ -393,8 +406,8 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, } for (size = min_size; size <= max_size; size *= 4) { - mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_FROM_DEVICE); - mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_TO_DEVICE); + mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_FROM_DEVICE); + mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_TO_DEVICE); mbs = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_BIDIRECTIONAL); err = pcilib_wait_irq(handle, 0, 0, &irqs); if (err) irqs = 0; @@ -571,15 +584,45 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, #define pci2host16(endianess, value) endianess? +/* +typedef struct { + size_t size; + void *data; + size_t pos; + + int multi_mode; +} DMACallbackContext; + +static int DMACallback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { + DMACallbackContext *ctx = (DMACallbackContext*)arg; + + if ((ctx->pos + bufsize > ctx->size)||(!ctx->data)) { + ctx->size *= 2; + ctx->data = realloc(ctx->data, ctx->size); + if (!ctx->data) { + Error("Allocation of %i bytes of memory have failed", ctx->size); + return 0; + } + } + + memcpy(ctx->data + ctx->pos, buf, bufsize); + ctx->pos += bufsize; + + if (flags & PCILIB_DMA_FLAG_EOP) return 0; + return 1; +} +*/ + -int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, FILE *o) { +int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, size_t timeout, FILE *o) { void *buf; int i, err; - size_t ret; + size_t ret, bytes; int size = n * abs(access); int block_width, blocks_per_line; int numbers_per_block, numbers_per_line; pcilib_dma_engine_t dmaid; + pcilib_dma_flags_t dma_flags = 0; numbers_per_block = BLOCK_SIZE / access; @@ -588,18 +631,45 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, p if ((blocks_per_line > 1)&&(blocks_per_line % 2)) --blocks_per_line; numbers_per_line = blocks_per_line * numbers_per_block; -// buf = alloca(size); - err = posix_memalign( (void**)&buf, 256, size ); - if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size); + if (size) { + buf = malloc(size); + if (!buf) Error("Allocation of %i bytes of memory have failed", size); + } else { + buf = NULL; + } switch (mode) { case ACCESS_DMA: + if (timeout == (size_t)-1) timeout = PCILIB_DMA_TIMEOUT; + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); - err = pcilib_read_dma(handle, dmaid, addr, size, buf, &ret); - if ((err)||(ret <= 0)) Error("No data is returned by DMA engine"); - size = ret; - n = ret / abs(access); + + if (flags&FLAG_MULTIPACKET) dma_flags |= PCILIB_DMA_FLAG_MULTIPACKET; + if (flags&FLAG_WAIT) dma_flags |= PCILIB_DMA_FLAG_WAIT; + + if (size) { + err = pcilib_read_dma_custom(handle, dmaid, addr, size, dma_flags, timeout, buf, &bytes); + if (err) Error("Error (%i) is reported by DMA engine", err); + } else { + dma_flags |= PCILIB_DMA_FLAG_IGNORE_ERRORS; + + size = 2048; bytes = 0; + do { + size *= 2; + buf = realloc(buf, size); + err = pcilib_read_dma_custom(handle, dmaid, addr, size - bytes, dma_flags, timeout, buf + bytes, &ret); + bytes += ret; + + if ((!err)&&(flags&FLAG_MULTIPACKET)) { + err = PCILIB_ERROR_TOOBIG; + if ((flags&FLAG_WAIT)==0) timeout = 0; + } + } while (err == PCILIB_ERROR_TOOBIG); + } + if (bytes <= 0) Error("No data is returned by DMA engine"); + size = bytes; + n = bytes / abs(access); addr = 0; break; case ACCESS_FIFO: @@ -639,6 +709,7 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, p free(buf); + return 0; } @@ -703,6 +774,8 @@ int ReadRegister(pcilib_t *handle, pcilib_model_description_t *model_info, const } printf("\n"); } + + return 0; } #define WRITE_REGVAL(buf, n, access, o) {\ @@ -818,12 +891,14 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, if ((read_back)&&(memcmp(buf, check, size))) { printf("Write failed: the data written and read differ, the foolowing is read back:\n"); if (endianess) pcilib_swap(check, check, abs(access), n); - ReadData(handle, mode, dma, bar, addr, n, access, endianess, NULL); + ReadData(handle, mode, 0, dma, bar, addr, n, access, endianess, (size_t)-1, NULL); exit(-1); } free(check); free(buf); + + return 0; } int WriteRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, const char *bank, uintptr_t addr, size_t n, char ** data) { @@ -856,6 +931,8 @@ int WriteRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, free(check); free(buf); + + return 0; } @@ -1412,6 +1489,7 @@ int main(int argc, char **argv) { pcilib_model_t model = PCILIB_MODEL_DETECT; pcilib_model_description_t *model_info; MODE mode = MODE_INVALID; + FLAGS flags = 0; const char *type = NULL; ACCESS_MODE amode = ACCESS_BAR; const char *fpga_device = DEFAULT_FPGA_DEVICE; @@ -1442,7 +1520,7 @@ int main(int argc, char **argv) { pcilib_t *handle; int size_set = 0; - + int timeout_set = 0; while ((c = getopt_long(argc, argv, "hqilr::w::g::d:m:t:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) { extern int optind; @@ -1645,6 +1723,7 @@ int main(int argc, char **argv) { case OPT_TIMEOUT: if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1)) Usage(argc, argv, "Invalid timeout is specified (%s)", optarg); + timeout_set = 1; break; case OPT_OUTPUT: output = optarg; @@ -1652,7 +1731,6 @@ int main(int argc, char **argv) { case OPT_ITERATIONS: if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &iterations) != 1)) Usage(argc, argv, "Invalid number of iterations is specified (%s)", optarg); - size_set = 1; break; case OPT_QUIETE: quiete = 1; @@ -1660,6 +1738,12 @@ int main(int argc, char **argv) { case OPT_FORCE: force = 1; break; + case OPT_MULTIPACKET: + flags |= FLAG_MULTIPACKET; + break; + case OPT_WAIT: + flags |= FLAG_WAIT; + break; default: Usage(argc, argv, "Unknown option (%s) with argument (%s)", optarg?argv[optind-2]:argv[optind-1], optarg?optarg:"(null)"); } @@ -1823,8 +1907,10 @@ int main(int argc, char **argv) { Benchmark(handle, amode, dma, bar, start, size_set?size:0, access, iterations); break; case MODE_READ: - if ((addr)||(amode == ACCESS_DMA)) { - ReadData(handle, amode, dma, bar, start, size, access, endianess, ofile); + if (amode == ACCESS_DMA) { + ReadData(handle, amode, flags, dma, bar, start, size_set?size:0, access, endianess, timeout_set?timeout:(size_t)-1, ofile); + } else if (addr) { + ReadData(handle, amode, flags, dma, bar, start, size, access, endianess, (size_t)-1, ofile); } else { Error("Address to read is not specified"); } diff --git a/dma.c b/dma.c index 9527c0b..216aa60 100644 --- a/dma.c +++ b/dma.c @@ -168,20 +168,29 @@ typedef struct { size_t size; void *data; size_t pos; + + pcilib_dma_flags_t flags; } pcilib_dma_read_callback_context_t; static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg; if (ctx->pos + bufsize > ctx->size) { - pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); - return PCILIB_ERROR_INVALID_DATA; + if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0) + pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); + return -PCILIB_ERROR_TOOBIG; } memcpy(ctx->data + ctx->pos, buf, bufsize); ctx->pos += bufsize; - if (flags & PCILIB_DMA_FLAG_EOP) return 0; + if (flags & PCILIB_DMA_FLAG_EOP) { + if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) { + if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return 2; + else return 3; + } + return 0; + } return 1; } @@ -229,11 +238,23 @@ int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, si return ctx->model_info.dma_api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr); } +int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) { + int err; + + pcilib_dma_read_callback_context_t opts = { + size, buf, 0, flags + }; + + err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts); + if (read_bytes) *read_bytes = opts.pos; + return err; +} + int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) { int err; pcilib_dma_read_callback_context_t opts = { - size, buf, 0 + size, buf, 0, 0 }; err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts); @@ -241,6 +262,7 @@ int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size return err; } + int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) { int err; struct timeval tv, cur; diff --git a/dma.h b/dma.h index 8da1c96..375763f 100644 --- a/dma.h +++ b/dma.h @@ -6,7 +6,6 @@ typedef uint32_t pcilib_dma_modification_t; - typedef struct { int started; size_t ring_size, buffer_size; @@ -25,7 +24,7 @@ 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 (*status)(pcilib_dma_context_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); @@ -40,6 +39,11 @@ struct pcilib_dma_api_description_s { double (*benchmark)(pcilib_dma_context_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); }; +struct pcilib_dma_context_s { + int ignore_eop; +}; + + 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); diff --git a/dma/nwl.c b/dma/nwl.c index 7d2c964..cc03687 100644 --- a/dma/nwl.c +++ b/dma/nwl.c @@ -88,6 +88,10 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib, pcilib_dma_modification_t t ctx->pcilib = pcilib; ctx->type = type; + if (type == PCILIB_NWL_MODIFICATION_IPECAMERA) { + ctx->dmactx.ignore_eop = 1; + } + pcilib_register_bank_t dma_bank = pcilib_find_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA); if (dma_bank == PCILIB_REGISTER_BANK_INVALID) { free(ctx); @@ -132,7 +136,7 @@ void dma_nwl_free(pcilib_dma_context_t *vctx) { if (ctx) { if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); dma_nwl_free_irq(ctx); - dma_nwl_stop(ctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT); + dma_nwl_stop(vctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT); free(ctx); } diff --git a/dma/nwl.h b/dma/nwl.h index db48fdc..0e4b5ae 100644 --- a/dma/nwl.h +++ b/dma/nwl.h @@ -8,7 +8,7 @@ typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t; #define NWL_XAUI_ENGINE 0 #define NWL_XRAWDATA_ENGINE 1 -#define NWL_FIX_EOP_FOR_BIG_PACKETS // requires precise sizes in read requests +#define NWL_MAX_PACKET_SIZE 4096 //16384 //#define NWL_GENERATE_DMA_IRQ #define PCILIB_NWL_ALIGNMENT 64 // in bytes @@ -44,6 +44,8 @@ struct pcilib_nwl_engine_description_s { struct nwl_dma_s { + struct pcilib_dma_context_s dmactx; + pcilib_t *pcilib; pcilib_dma_modification_t type; diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h index f87c68f..f9873f7 100644 --- a/dma/nwl_dma.h +++ b/dma/nwl_dma.h @@ -9,7 +9,7 @@ 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_get_status(pcilib_dma_context_t *vctx, 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); diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index 037ab02..806173d 100644 --- a/dma/nwl_engine.c +++ b/dma/nwl_engine.c @@ -77,7 +77,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { if (info->reused) { info->preserve = 1; - dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma); + dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma); #ifdef NWL_GENERATE_DMA_IRQ dma_nwl_enable_engine_irq(ctx, dma); @@ -126,7 +126,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { return PCILIB_ERROR_TIMEOUT; } - dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma); + dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma); ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring); nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD); @@ -198,7 +198,7 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { } } - dma_nwl_acknowledge_irq(ctx, PCILIB_DMA_IRQ, dma); + dma_nwl_acknowledge_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, dma); if (info->preserve) { flags = PCILIB_KMEM_FLAG_REUSE; @@ -228,7 +228,7 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_nwl_engine_description_t *info = ctx->engines + dma; - err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT); + err = dma_nwl_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT); if (err) return err; if (data) { @@ -266,7 +266,7 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, } int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) { - int err, ret; + int err, ret = 1; size_t res = 0; size_t bufnum; size_t bufsize; @@ -277,28 +277,31 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin pcilib_nwl_engine_description_t *info = ctx->engines + dma; - err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT); + err = dma_nwl_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT); if (err) return err; - + do { - bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, timeout); - if (bufnum == PCILIB_DMA_BUFFER_INVALID) return PCILIB_ERROR_TIMEOUT; - -#ifdef NWL_FIX_EOP_FOR_BIG_PACKETS - if (size > 65536) { -// printf("%i %i\n", res + bufsize, size); - if ((res+bufsize) < size) eop = 0; - else if ((res+bufsize) == size) eop = 1; + if (ret > 2) { + bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, 0); + if (bufnum == PCILIB_DMA_BUFFER_INVALID) return 0; + } else { + bufnum = dma_nwl_wait_buffer(ctx, info, &bufsize, &eop, timeout); + if (bufnum == PCILIB_DMA_BUFFER_INVALID) { + if (ret == 1) return PCILIB_ERROR_TIMEOUT; + return 0; + } } -#endif /* NWL_FIX_EOP_FOR_BIG_PACKETS */ + + // EOP is not respected in IPE Camera + if (ctx->dmactx.ignore_eop) eop = 1; pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_FROMDEVICE, bufnum); void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, info->pages, bufnum); - ret = cb(cbattr, eop?PCILIB_DMA_FLAG_EOP:0, bufsize, buf); + ret = cb(cbattr, (eop?PCILIB_DMA_FLAG_EOP:0), bufsize, buf); // DS: Fixme, it looks like we can avoid calling this for the sake of performance // pcilib_kmem_sync_block(ctx->pcilib, info->pages, PCILIB_KMEM_SYNC_TODEVICE, bufnum); + if (ret < 0) return -ret; dma_nwl_return_buffer(ctx, info); - res += bufsize; @@ -306,3 +309,9 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin return 0; } + +int dma_nwl_wait_completion(nwl_dma_t * ctx, pcilib_dma_engine_t dma, pcilib_timeout_t timeout) { + if (dma_nwl_get_next_buffer(ctx, ctx->engines + dma, PCILIB_NWL_DMA_PAGES - 1, PCILIB_DMA_TIMEOUT) == (PCILIB_NWL_DMA_PAGES - 1)) return 0; + else return PCILIB_ERROR_TIMEOUT; +} + diff --git a/dma/nwl_engine.h b/dma/nwl_engine.h index 176eaeb..f9f3f60 100644 --- a/dma/nwl_engine.h +++ b/dma/nwl_engine.h @@ -5,6 +5,8 @@ int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t * int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma); int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma); +int dma_nwl_wait_completion(nwl_dma_t * ctx, pcilib_dma_engine_t dma, pcilib_timeout_t timeout); + #endif /* _PCILIB_DMA_NWL_ENGINE_H */ diff --git a/dma/nwl_engine_buffers.h b/dma/nwl_engine_buffers.h index 8f31bb6..b97e469 100644 --- a/dma/nwl_engine_buffers.h +++ b/dma/nwl_engine_buffers.h @@ -276,13 +276,6 @@ static int dma_nwl_push_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t * val = ring_pa + info->head * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; nwl_write_register(val, ctx, info->base_addr, REG_SW_NEXT_BD); -// nwl_read_register(val, ctx, info->base_addr, 0x18); - -// usleep(10000); - -// nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_LAST_BD); -// printf("Last BD(Write): %lx %lx\n", ring, val); - return 0; } @@ -293,27 +286,16 @@ static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_ struct timeval start, cur; uint32_t status_size, status, control; -// usleep(10000); - unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); -// status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); -// printf("Status0: %lx\n", status_size); - ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; gettimeofday(&start, NULL); -// printf("Waiting %li\n", info->tail); -// nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_LAST_BD); -// printf("Last BD(Read): %lx %lx\n", ring, val); - do { status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); status = status_size & DMA_BD_STATUS_MASK; -// printf("%i: %lx\n", info->tail, status_size); - if (status & DMA_BD_ERROR_MASK) { pcilib_error("NWL DMA Engine reported error in ring descriptor"); return (size_t)-1; @@ -322,10 +304,17 @@ static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_ if (status & DMA_BD_COMP_MASK) { if (status & DMA_BD_EOP_MASK) *eop = 1; else *eop = 0; - + *size = status_size & DMA_BD_BUFL_MASK; + +/* + if (mrd) { + if ((info->tail + 1) == info->ring_size) ring -= info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; + else ring += PCILIB_NWL_DMA_DESCRIPTOR_SIZE; + *mrd = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET)&DMA_BD_COMP_MASK; + } +*/ -// printf("Status: %lx\n", status_size); return info->tail; } @@ -333,11 +322,19 @@ static size_t dma_nwl_wait_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_ gettimeofday(&cur, NULL); } while ((timeout == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < timeout)); -// printf("Final status: %lx\n", status_size); - return (size_t)-1; } +static int dma_nwl_is_overflown(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) { + uint32_t status; + unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); + if (info->tail > 0) ring += (info->tail - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; + else ring += (info->ring_size - 1) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; + + status = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); + return status&DMA_BD_COMP_MASK?1:0; +} + static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info) { uint32_t val; @@ -346,7 +343,6 @@ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t size_t bufsz = pcilib_kmem_get_block_size(ctx->pcilib, info->pages, info->tail); ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; -// printf("Returning: %i\n", info->tail); #ifdef NWL_GENERATE_DMA_IRQ NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, bufsz | DMA_BD_INT_ERROR_MASK | DMA_BD_INT_COMP_MASK); @@ -358,13 +354,12 @@ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t val = ring_pa + info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; nwl_write_register(val, ctx, info->base_addr, REG_SW_NEXT_BD); -// nwl_read_register(val, ctx, info->base_addr, 0x18); 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) { +int dma_nwl_get_status(pcilib_dma_context_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; uint32_t bstatus; nwl_dma_t *ctx = (nwl_dma_t*)vctx; @@ -410,43 +405,3 @@ int dma_nwl_get_status(pcilib_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engin return 0; } - -/* - unsigned char *ring = pcilib_kmem_get_ua(ctx->pcilib, info->ring); - -// status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); -// printf("Status0: %lx\n", status_size); - - ring += info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE; - - gettimeofday(&start, NULL); - -// printf("Waiting %li\n", info->tail); -// nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_LAST_BD); -// printf("Last BD(Read): %lx %lx\n", ring, val); - - do { - status_size = NWL_RING_GET(ring, DMA_BD_BUFL_STATUS_OFFSET); - status = status_size & DMA_BD_STATUS_MASK; - -// printf("%i: %lx\n", info->tail, status_size); - - if (status & DMA_BD_ERROR_MASK) { - pcilib_error("NWL DMA Engine reported error in ring descriptor"); - return (size_t)-1; - } - - if (status & DMA_BD_COMP_MASK) { - if (status & DMA_BD_EOP_MASK) *eop = 1; - else *eop = 0; - - *size = status_size & DMA_BD_BUFL_MASK; - -// printf("Status: %lx\n", status_size); - return info->tail; - } - - usleep(10); - gettimeofday(&cur, NULL); - } while ((timeout == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < timeout)); -*/ \ No newline at end of file diff --git a/dma/nwl_irq.c b/dma/nwl_irq.c index ae4aacc..ee5f520 100644 --- a/dma/nwl_irq.c +++ b/dma/nwl_irq.c @@ -81,7 +81,7 @@ int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags) { int dma_nwl_enable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { uint32_t val; - dma_nwl_enable_irq(ctx, PCILIB_DMA_IRQ, 0); + dma_nwl_enable_irq((pcilib_dma_context_t*)ctx, PCILIB_DMA_IRQ, 0); nwl_read_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS); val |= (DMA_ENG_INT_ENABLE); diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c index a87c109..11f7f34 100644 --- a/dma/nwl_loopback.c +++ b/dma/nwl_loopback.c @@ -13,6 +13,8 @@ #include "nwl_defines.h" +#define NWL_BUG_EXTRA_DATA + int dma_nwl_start_loopback(nwl_dma_t *ctx, pcilib_dma_direction_t direction, size_t packet_size) { uint32_t val; @@ -66,11 +68,12 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm int iter, i; int res; int err; - size_t bytes; + size_t bytes, rbytes; uint32_t val; uint32_t *buf, *cmp; const char *error = NULL; pcilib_register_value_t regval; + size_t packet_size, blocks; size_t us = 0; struct timeval start, cur; @@ -87,8 +90,10 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm else size /= sizeof(uint32_t); // Not supported - if (direction == PCILIB_DMA_TO_DEVICE) return -1.; - else if ((direction == PCILIB_DMA_FROM_DEVICE)&&(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) return -1.; + if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) { + if (direction == PCILIB_DMA_TO_DEVICE) return -1.; + } +// else if ((direction == PCILIB_DMA_FROM_DEVICE)&&(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) return -1.; // Stop Generators and drain old data if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); @@ -107,63 +112,107 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm dma_nwl_enable_engine_irq(ctx, writeid); #endif /* NWL_GENERATE_DMA_IRQ */ - dma_nwl_start_loopback(ctx, direction, size * sizeof(uint32_t)); + if (size * sizeof(uint32_t) > NWL_MAX_PACKET_SIZE) { + packet_size = NWL_MAX_PACKET_SIZE; + blocks = (size * sizeof(uint32_t)) / packet_size + (((size*sizeof(uint32_t))%packet_size)?1:0); + } else { + packet_size = size * sizeof(uint32_t); + blocks = 1; + } + + dma_nwl_start_loopback(ctx, direction, packet_size); // Allocate memory and prepare data - buf = malloc(size * sizeof(uint32_t)); - cmp = malloc(size * sizeof(uint32_t)); + buf = malloc(blocks * packet_size * sizeof(uint32_t)); + cmp = malloc(blocks * packet_size * sizeof(uint32_t)); if ((!buf)||(!cmp)) { if (buf) free(buf); if (cmp) free(cmp); return -1; } -//#ifdef DEBUG_HARDWARE if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e5); usleep(100000); pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); + + // This way causes more problems with garbage + //pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1); } -//#endif /* DEBUG_HARDWARE */ // Benchmark for (iter = 0; iter < iterations; iter++) { memset(cmp, 0x13 + iter, size * sizeof(uint32_t)); -//#ifdef DEBUG_HARDWARE if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); } -//#endif /* DEBUG_HARDWARE */ - gettimeofday(&start, NULL); - if (direction&PCILIB_DMA_TO_DEVICE) { + if ((direction&PCILIB_DMA_TO_DEVICE)||(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) { memcpy(buf, cmp, size * sizeof(uint32_t)); + if (direction&PCILIB_DMA_TO_DEVICE) { + gettimeofday(&start, NULL); + } + err = pcilib_write_dma(ctx->pcilib, writeid, addr, size * sizeof(uint32_t), buf, &bytes); if ((err)||(bytes != size * sizeof(uint32_t))) { error = "Write failed"; - break; + break; + } + + if (direction&PCILIB_DMA_TO_DEVICE) { + // wait written + if (direction == PCILIB_DMA_TO_DEVICE) { + dma_nwl_wait_completion(ctx, writeid, PCILIB_DMA_TIMEOUT); + } + gettimeofday(&cur, NULL); + us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)); } } -//#ifdef DEBUG_HARDWARE if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1); } -//#endif /* DEBUG_HARDWARE */ memset(buf, 0, size * sizeof(uint32_t)); - - err = pcilib_read_dma(ctx->pcilib, readid, addr, size * sizeof(uint32_t), buf, &bytes); - gettimeofday(&cur, NULL); - us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)); + if (direction&PCILIB_DMA_FROM_DEVICE) { + gettimeofday(&start, NULL); + } + + for (i = 0, bytes = 0; i < blocks; i++) { +#ifdef NWL_BUG_EXTRA_DATA + retry: +#endif + + err = pcilib_read_dma(ctx->pcilib, readid, addr, packet_size * sizeof(uint32_t), buf + (bytes>>2), &rbytes); + if ((err)||(rbytes%sizeof(uint32_t))) { + break; + } +#ifdef NWL_BUG_EXTRA_DATA + else if (rbytes == 8) { + goto retry; + } +#endif + bytes += rbytes; + } + + if (direction&PCILIB_DMA_FROM_DEVICE) { + gettimeofday(&cur, NULL); + us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)); + } +#ifdef NWL_BUG_EXTRA_DATA + if ((err)||((bytes != size * sizeof(uint32_t))&&((bytes - 8) != size * sizeof(uint32_t)))) { +#else if ((err)||(bytes != size * sizeof(uint32_t))) { - error = "Read failed"; - break; +#endif + printf("Expected: %zu bytes, but %zu read, error: %i\n", size * sizeof(uint32_t), bytes, err); + error = "Read failed"; + break; } +#ifndef NWL_BUG_EXTRA_DATA if (direction == PCILIB_DMA_BIDIRECTIONAL) { res = memcmp(buf, cmp, size * sizeof(uint32_t)); if (res) { @@ -171,7 +220,7 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm if (buf[i] != cmp[i]) break; bytes = i; - printf("Expected: *%lx, Written at position %lu:", 0x13 + iter, bytes); + printf("Expected: *0x%lx, Written at dword %lu:", 0x13 + iter, bytes); for (; (i < size)&&(i < (bytes + 16)); i++) { if (((i - bytes)%8)==0) printf("\n"); printf("% 10lx", buf[i]); @@ -182,41 +231,12 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm break; } } - -#ifdef DEBUG_HARDWARE - puts("===================================="); - - err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); - printf("Status1: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); - printf("Start address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); - printf("End address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); - printf("Status2: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); - printf("Status3: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); - printf("Add_rd_ddr: %i 0x%lx\n", err, regval); -#endif /* DEBUG_HARDWARE */ - +#endif } -#ifdef DEBUG_HARDWARE - puts("------------------------------------------------"); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); - printf("Status1: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); - printf("Start address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); - printf("End address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); - printf("Status2: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); - printf("Status3: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); - printf("Add_rd_ddr: %i 0x%lx\n", err, regval); -#endif /* DEBUG_HARDWARE */ + if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { + pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); + } if (error) { pcilib_warning("%s at iteration %i, error: %i, bytes: %zu", error, iter, err, bytes); @@ -238,5 +258,5 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm free(cmp); free(buf); - return error?-1:(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us); + return /*error?-1:*/(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us); } diff --git a/dma/nwl_register.c b/dma/nwl_register.c index 5bb6e16..95b981a 100644 --- a/dma/nwl_register.c +++ b/dma/nwl_register.c @@ -26,8 +26,10 @@ int nwl_add_registers(nwl_dma_t *ctx) { err = pcilib_add_registers(ctx->pcilib, 0, nwl_dma_registers); if (err) return err; - err = pcilib_add_registers(ctx->pcilib, 0, nwl_xrawdata_registers); - if (err) return err; + if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) { + err = pcilib_add_registers(ctx->pcilib, 0, nwl_xrawdata_registers); + if (err) return err; + } for (n = 0; nwl_dma_engine_registers[n].bits; n++) { diff --git a/dma/nwl_register.h b/dma/nwl_register.h index 89a8632..2f465bd 100644 --- a/dma/nwl_register.h +++ b/dma/nwl_register.h @@ -86,14 +86,6 @@ static pcilib_register_description_t nwl_xrawdata_registers[] = { {0x9108, 0, 1, 0, 0x00000003, PCILIB_REGISTER_RW, PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "xrawdata_enable_checker", ""}, {0x9108, 1, 1, 0, 0x00000003, PCILIB_REGISTER_RW, PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "xrawdata_enable_loopback", ""}, {0x910C, 0, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "xrawdata_data_mistmatch", ""}, -#ifdef DEBUG_HARDWARE - {0x9050, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9050", ""}, - {0x9080, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9080", ""}, - {0x9090, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9090", ""}, - {0x9100, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9100", ""}, - {0x9110, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9110", ""}, - {0x9160, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "reg9160", ""}, -#endif /* DEBUG_HARDWARE */ {0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL} }; diff --git a/error.h b/error.h index 568ef18..5b46ae5 100644 --- a/error.h +++ b/error.h @@ -16,7 +16,8 @@ enum { PCILIB_ERROR_NOTFOUND, PCILIB_ERROR_OUTOFRANGE, PCILIB_ERROR_NOTAVAILABLE, - PCILIB_ERROR_NOTINITIALIZED + PCILIB_ERROR_NOTINITIALIZED, + PCILIB_ERROR_TOOBIG } pcilib_errot_t; diff --git a/pcilib.h b/pcilib.h index a38fcc9..ee5323e 100644 --- a/pcilib.h +++ b/pcilib.h @@ -11,7 +11,8 @@ typedef struct pcilib_s pcilib_t; typedef void pcilib_context_t; -typedef void pcilib_dma_context_t; +typedef struct pcilib_dma_context_s pcilib_dma_context_t; + typedef struct pcilib_dma_api_description_s pcilib_dma_api_description_t; typedef struct pcilib_event_api_description_s pcilib_event_api_description_t; @@ -63,9 +64,11 @@ typedef enum { typedef enum { PCILIB_DMA_FLAGS_DEFAULT = 0, - PCILIB_DMA_FLAG_EOP = 1, - PCILIB_DMA_FLAG_WAIT = 2, - PCILIB_DMA_FLAG_PERSISTENT = 4 + PCILIB_DMA_FLAG_EOP = 1, /**< last buffer of the packet */ + PCILIB_DMA_FLAG_WAIT = 2, /**< wait completion of write operation / wait for data during read operation */ + PCILIB_DMA_FLAG_MULTIPACKET = 4, /**< read multiple packets */ + PCILIB_DMA_FLAG_PERSISTENT = 8, /**< do not stop DMA engine on application termination / permanently close DMA engine on dma_stop */ + PCILIB_DMA_FLAG_IGNORE_ERRORS = 16 /**< do not crash on errors, but return appropriate error codes */ } pcilib_dma_flags_t; typedef enum { @@ -102,7 +105,20 @@ typedef enum { #define PCILIB_TIMEOUT_TRIGGER 0 #define PCILIB_IRQ_SOURCE_DEFAULT 0 -typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf); +/**< + * Callback function called when new data is read by DMA streaming function + * @ctx - DMA Engine context + * @flags - DMA Flags + * @bufsize - size of data in bytes + * @buf - data + * @returns + * <0 - error, stop streaming (the value is negative error code) + * 0 - stop streaming + * 1 - wait & read next buffer, fail if no data + * 2 - wait & read next buffer, but don't fail if timeout expired + * 3 - read next buffer if available (don't wait), don't fail + */ +typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf); typedef int (*pcilib_event_callback_t)(pcilib_event_t event, pcilib_event_id_t event_id, void *user); typedef struct { @@ -237,6 +253,7 @@ int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma); int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written_bytes); int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes); +int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes); int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes); double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); -- cgit v1.2.3