Переглянути джерело

Improvements of DMA engine

Suren A. Chilingaryan 12 роки тому
батько
коміт
32c2f2c589
15 змінених файлів з 298 додано та 182 видалено
  1. 103 17
      cli.c
  2. 26 4
      dma.c
  3. 6 2
      dma.h
  4. 5 1
      dma/nwl.c
  5. 3 1
      dma/nwl.h
  6. 1 1
      dma/nwl_dma.h
  7. 27 18
      dma/nwl_engine.c
  8. 2 0
      dma/nwl_engine.h
  9. 20 65
      dma/nwl_engine_buffers.h
  10. 1 1
      dma/nwl_irq.c
  11. 76 56
      dma/nwl_loopback.c
  12. 4 2
      dma/nwl_register.c
  13. 0 8
      dma/nwl_register.h
  14. 2 1
      error.h
  15. 22 5
      pcilib.h

+ 103 - 17
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 <file>			- Append output to file (default: stdout)\n"
 "   -t <timeout> 		- 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");
 	}

+ 26 - 4
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;

+ 6 - 2
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);
 

+ 5 - 1
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);
     }

+ 3 - 1
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;

+ 1 - 1
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);

+ 27 - 18
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;
+}
+

+ 2 - 0
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 */
 

+ 20 - 65
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));
-*/

+ 1 - 1
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);

+ 76 - 56
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", &regval);
-	printf("Status1: %i 0x%lx\n", err, regval);
-	err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
-	printf("Start address: %i 0x%lx\n", err,  regval);
-	err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
-	printf("End address: %i 0x%lx\n", err,  regval);
-	err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
-	printf("Status2: %i 0x%lx\n", err,  regval);
-	err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
-	printf("Status3: %i 0x%lx\n", err,  regval);
-	err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
-	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", &regval);
-    printf("Status1: %i 0x%lx\n", err, regval);
-    err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
-    printf("Start address: %i 0x%lx\n", err,  regval);
-    err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
-    printf("End address: %i 0x%lx\n", err,  regval);
-    err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
-    printf("Status2: %i 0x%lx\n", err,  regval);
-    err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
-    printf("Status3: %i 0x%lx\n", err,  regval);
-    err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
-    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);
 }

+ 4 - 2
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++) {

+ 0 - 8
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}
 };
 

+ 2 - 1
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;
 
 

+ 22 - 5
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);