From a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f Mon Sep 17 00:00:00 2001
From: "Suren A. Chilingaryan" <csa@suren.me>
Date: Fri, 19 Dec 2014 00:14:21 +0100
Subject: Initial implementation of IPEDMA, dummy driver for KAPTURE, start of
 API changes

---
 dma/CMakeLists.txt       |   4 +-
 dma/ipe.c                | 412 +++++++++++++++++++++++++++++++++++++++++++++++
 dma/ipe.h                |  42 +++++
 dma/ipe_private.h        |  56 +++++++
 dma/ipe_registers.h      |  44 +++++
 dma/nwl.c                |   2 +-
 dma/nwl.h                |  89 ++++------
 dma/nwl_dma.h            |  45 ------
 dma/nwl_engine.c         |   2 +-
 dma/nwl_engine_buffers.h |   6 +-
 dma/nwl_irq.c            |   2 +-
 dma/nwl_loopback.c       |   2 +-
 dma/nwl_private.h        |  67 ++++++++
 dma/nwl_register.c       |   2 +-
 14 files changed, 665 insertions(+), 110 deletions(-)
 create mode 100644 dma/ipe.c
 create mode 100644 dma/ipe.h
 create mode 100644 dma/ipe_private.h
 create mode 100644 dma/ipe_registers.h
 delete mode 100644 dma/nwl_dma.h
 create mode 100644 dma/nwl_private.h

(limited to 'dma')

diff --git a/dma/CMakeLists.txt b/dma/CMakeLists.txt
index 3d4226a..44bf18c 100644
--- a/dma/CMakeLists.txt
+++ b/dma/CMakeLists.txt
@@ -3,7 +3,7 @@ include_directories(
 )
 
 
-set(HEADERS ${HEADERS} nwl.h nwl_dma.h nwl_engine.h nwl_irq.h nwl_loopback.h nwl_register.h)
+set(HEADERS ${HEADERS} nwl.h nwl_private.h nwl_engine.h nwl_irq.h nwl_loopback.h nwl_register.h ipe.h ipe_private.h ipe_registers.h)
 
-add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c nwl_register.c)
+add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c nwl_register.c ipe.c)
 
diff --git a/dma/ipe.c b/dma/ipe.c
new file mode 100644
index 0000000..eb1ad6d
--- /dev/null
+++ b/dma/ipe.c
@@ -0,0 +1,412 @@
+#define _PCILIB_DMA_IPE_C
+#define _BSD_SOURCE
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <arpa/inet.h>
+
+#include "pci.h"
+#include "pcilib.h"
+#include "error.h"
+#include "tools.h"
+
+#include "ipe.h"
+#include "ipe_private.h"
+#include "ipe_registers.h"
+
+
+#define WR(addr, value) { *(uint32_t*)(ctx->base_addr + addr) = value; }
+#define RD(addr, value) { value = *(uint32_t*)(ctx->base_addr + addr); }
+
+
+pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, pcilib_dma_modification_t type, void *arg) {
+    int err = 0;
+    
+    pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib);
+
+    ipe_dma_t *ctx = malloc(sizeof(ipe_dma_t));
+
+    if (ctx) {
+	memset(ctx, 0, sizeof(ipe_dma_t));
+	ctx->pcilib = pcilib;
+	
+	memset(ctx->engine, 0, 2 * sizeof(pcilib_dma_engine_description_t));
+	ctx->engine[0].addr = 0;
+	ctx->engine[0].type = PCILIB_DMA_TYPE_PACKET;
+	ctx->engine[0].direction = PCILIB_DMA_FROM_DEVICE;
+	ctx->engine[0].addr_bits = 32;
+	pcilib_set_dma_engine_description(pcilib, 0, &ctx->engine[0]);
+	pcilib_set_dma_engine_description(pcilib, 1, NULL);
+
+	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);
+	    pcilib_error("DMA Register Bank could not be found");
+	    return NULL;
+	}
+
+	ctx->dma_bank = model_info->banks + dma_bank;
+	ctx->base_addr = pcilib_resolve_register_address(pcilib, ctx->dma_bank->bar, ctx->dma_bank->read_addr);
+
+	err = pcilib_add_registers(ctx->pcilib, 0, ipe_dma_registers);
+	if (err) {
+	    free(ctx);
+	    pcilib_error("Error adding DMA registers");
+	    return NULL;
+	}
+    }
+
+    return (pcilib_dma_context_t*)ctx;
+}
+
+void  dma_ipe_free(pcilib_dma_context_t *vctx) {
+    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
+
+    if (ctx) {
+	dma_ipe_stop(vctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT);
+	free(ctx);
+    }
+}
+
+
+int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+    size_t i;
+
+    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
+
+    int preserve = 0;
+    pcilib_kmem_flags_t kflags;
+    pcilib_kmem_reuse_state_t reuse_desc, reuse_pages;
+
+    volatile void *desc_va;
+    volatile uint32_t *last_written_addr_ptr;
+
+    pcilib_register_value_t value;
+
+    if (dma == PCILIB_DMA_ENGINE_INVALID) return 0;
+    else if (dma > 1) return PCILIB_ERROR_INVALID_BANK;
+
+    if (!ctx->started) ctx->started = 1;
+
+    if (flags&PCILIB_DMA_FLAG_PERSISTENT) ctx->preserve = 1;
+
+    if (ctx->pages) return 0;
+    
+    kflags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ctx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0);
+    pcilib_kmem_handle_t *desc = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags);
+    pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, IPEDMA_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags);
+
+    if (!desc||!pages) {
+	if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0);
+	if (desc) pcilib_free_kernel_memory(ctx->pcilib, desc, 0);
+	return PCILIB_ERROR_MEMORY;
+    }
+    reuse_desc = pcilib_kmem_is_reused(ctx->pcilib, desc);
+    reuse_pages = pcilib_kmem_is_reused(ctx->pcilib, pages);
+
+    if (reuse_desc == reuse_pages) {
+	if (reuse_desc & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing...");
+	else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) {
+	    if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing...");
+	    else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing...");
+	    else {
+#ifndef IPEDMA_BUG_DMARD
+		RD(IPEDMA_REG_PAGE_COUNT, value);
+
+		if ((value + 1) != IPEDMA_DMA_PAGES) pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers does not match current request), reinitializing...");
+		else
+#endif /* IPEDMA_BUG_DMARD */
+		    preserve = 1;
+	    }
+	}
+    } else pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing....");
+
+    desc_va = pcilib_kmem_get_ua(ctx->pcilib, desc);
+    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
+    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
+
+    if (preserve) {
+	ctx->reused = 1;
+	ctx->preserve = 1;
+	
+
+//	usleep(100000);
+
+	    // Detect the current state of DMA engine
+#ifdef IPEDMA_BUG_DMARD
+	FILE *f = fopen("/tmp/pcitool_lastread", "r");
+	if (!f) pcilib_error("Can't read current status");
+	fread(&value, 1, sizeof(pcilib_register_value_t), f);
+	fclose(f);
+#else /* IPEDMA_BUG_DMARD */
+	RD(IPEDMA_REG_LAST_READ, value);
+	if (value == IPEDMA_DMA_PAGES) value = 0;
+#endif /* IPEDMA_BUG_DMARD */
+
+	ctx->last_read = value;
+    } else {
+	ctx->reused = 0;
+
+	    // Disable DMA
+	WR(IPEDMA_REG_CONTROL, 0x0);
+	
+	    // Reset DMA engine
+	WR(IPEDMA_REG_RESET, 0x1);
+	usleep(100000);
+	WR(IPEDMA_REG_RESET, 0x0);
+
+#ifndef IPEDMA_BUG_DMARD
+	    // Verify PCIe link status
+	RD(IPEDMA_REG_RESET, value);
+	if (value != 0x14031700) pcilib_warning("PCIe is not ready");
+#endif /* IPEDMA_BUG_DMARD */
+ 
+	    // Configuring TLP and PACKET sizes (40 bit mode can be used with big pre-allocated buffers later)
+        WR(IPEDMA_REG_TLP_SIZE, IPEDMA_TLP_SIZE);
+        WR(IPEDMA_REG_TLP_COUNT, IPEDMA_PAGE_SIZE / (4 * IPEDMA_TLP_SIZE * IPEDMA_CORES));
+
+	    // Setting progress register threshold
+	WR(IPEDMA_REG_UPDATE_THRESHOLD, IPEDMA_DMA_PROGRESS_THRESHOLD);
+        
+	    // Reseting configured DMA pages
+        WR(IPEDMA_REG_PAGE_COUNT, 0);
+        
+	    // Setting current read position and configuring progress register
+	WR(IPEDMA_REG_LAST_READ, IPEDMA_DMA_PAGES - 2 + 1);
+	WR(IPEDMA_REG_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->pcilib, desc, 0));
+
+	    // Instructing DMA engine that writting should start from the first DMA page
+	*last_written_addr_ptr = 0;//htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, IPEDMA_DMA_PAGES - 1));
+
+	
+	for (i = 0; i < IPEDMA_DMA_PAGES; i++) {
+	    uintptr_t bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, pages, i);
+	    WR(IPEDMA_REG_PAGE_ADDR, bus_addr);
+	    if (bus_addr%4096) printf("Bad address %lu: %lx\n", i, bus_addr);
+	    usleep(1000);
+	}
+	
+	    // Enable DMA
+	WR(IPEDMA_REG_CONTROL, 0x1);
+	
+	ctx->last_read = IPEDMA_DMA_PAGES - 1;
+
+#ifdef IPEDMA_BUG_DMARD
+	FILE *f = fopen("/tmp/pcitool_lastread", "w");
+	if (!f) pcilib_error("Can't write current status");
+	value = ctx->last_read;
+	fwrite(&value, 1, sizeof(pcilib_register_value_t), f);
+	fclose(f);
+#endif /* IPEDMA_BUG_DMARD */
+    }
+
+    ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, ctx->last_read));
+
+
+    ctx->desc = desc;
+    ctx->pages = pages;
+    ctx->page_size = pcilib_kmem_get_block_size(ctx->pcilib, pages, 0);;
+    ctx->ring_size = IPEDMA_DMA_PAGES;
+
+    return 0;
+}
+
+int dma_ipe_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) {
+    pcilib_kmem_flags_t kflags;
+
+    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
+
+    if (!ctx->started) return 0;
+
+    if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return PCILIB_ERROR_INVALID_BANK;
+
+	    // ignoring previous setting if flag specified
+    if (flags&PCILIB_DMA_FLAG_PERSISTENT) {
+	ctx->preserve = 0;
+    }
+
+    if (ctx->preserve) {
+	kflags = PCILIB_KMEM_FLAG_REUSE;
+    } else {
+        kflags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
+
+	ctx->started  = 0;
+
+	    // Disable DMA
+	WR(IPEDMA_REG_CONTROL, 0);
+	
+	    // Reset DMA engine
+	WR(IPEDMA_REG_RESET, 0x1);
+	usleep(100000);
+	WR(IPEDMA_REG_RESET, 0x0);
+
+	    // Reseting configured DMA pages
+        WR(IPEDMA_REG_PAGE_COUNT, 0);
+    }
+
+	// Clean buffers
+    if (ctx->desc) {
+	pcilib_free_kernel_memory(ctx->pcilib, ctx->desc, kflags);
+	ctx->desc = NULL;
+    }
+
+    if (ctx->pages) {
+	pcilib_free_kernel_memory(ctx->pcilib, ctx->pages, kflags);
+	ctx->pages = NULL;
+    }
+
+    return 0;
+}
+
+
+int dma_ipe_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;
+    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
+
+    void *desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc);
+    uint32_t *last_written_addr_ptr;
+    uint32_t last_written_addr;
+    
+
+    if (!status) return -1;
+
+    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
+    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
+
+    last_written_addr = ntohl(*last_written_addr_ptr);
+
+    status->started = ctx->started;
+    status->ring_size = ctx->ring_size;
+    status->buffer_size = ctx->page_size;
+
+    status->ring_tail = ctx->last_read + 1;
+    if (status->ring_tail == status->ring_size) status->ring_tail = 0;
+
+	// Find where the ring head is actually are
+    for (i = 0; i < ctx->ring_size; i++) {
+	uintptr_t bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, i);
+
+	if (bus_addr == last_written_addr) {
+	    status->ring_head = bus_addr;
+	    break;
+	}
+    }
+    
+    if (i == ctx->ring_size) {
+	// ERROR
+    }
+    
+    if (n_buffers > ctx->ring_size) n_buffers = ctx->ring_size;
+
+    memset(buffers, 0, n_buffers * sizeof(pcilib_dma_engine_status_t));
+
+    if (status->ring_head > status->ring_tail) {
+	for (i = status->ring_tail; i <= status->ring_head; i++) {
+	    buffers[i].used = 1;
+	    buffers[i].size = ctx->page_size;
+	    buffers[i].first = 1;
+	    buffers[i].last = 1;
+	}
+    } else {
+	for (i = 0; i <= status->ring_tail; i++) {
+	    buffers[i].used = 1;
+	    buffers[i].size = ctx->page_size;
+	    buffers[i].first = 1;
+	    buffers[i].last = 1;
+	} 
+	
+	for (i = status->ring_head; i < status->ring_size; i++) {
+	    buffers[i].used = 1;
+	    buffers[i].size = ctx->page_size;
+	    buffers[i].first = 1;
+	    buffers[i].last = 1;
+	} 
+    }
+
+    return 0;
+}
+
+int dma_ipe_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 = PCILIB_STREAMING_REQ_PACKET;
+
+    pcilib_register_value_t value;
+
+    pcilib_timeout_t wait = 0;
+    struct timeval start, cur;
+
+    volatile void *desc_va;
+    volatile uint32_t *last_written_addr_ptr;
+    
+    size_t cur_read;
+    
+    ipe_dma_t *ctx = (ipe_dma_t*)vctx;
+
+    err = dma_ipe_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT);
+    if (err) return err;
+
+    desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc);
+
+    if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t);
+    else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t);
+
+    do {
+	switch (ret&PCILIB_STREAMING_TIMEOUT_MASK) {
+	    case PCILIB_STREAMING_CONTINUE: wait = PCILIB_DMA_TIMEOUT; break;
+	    case PCILIB_STREAMING_WAIT: wait = timeout; break;
+//	    case PCILIB_STREAMING_CHECK: wait = 0; break;
+	}
+
+#ifdef IPEDMA_DEBUG
+	printf("Waiting for data: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", ctx->last_read, ctx->last_read_addr, *last_written_addr_ptr);
+#endif /* IPEDMA_DEBUG */
+
+	gettimeofday(&start, NULL);
+	while (((*last_written_addr_ptr == 0)||(ctx->last_read_addr == (*last_written_addr_ptr)))&&((wait == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < wait))) {
+	    usleep(10);
+	    gettimeofday(&cur, NULL);
+	}
+	
+	    // Failing out if we exited on timeout
+	if ((ctx->last_read_addr == (*last_written_addr_ptr))||(*last_written_addr_ptr == 0))
+	    return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0;
+
+	    // Getting next page to read
+	cur_read = ctx->last_read + 1;
+	if (cur_read == ctx->ring_size) cur_read = 0;
+
+#ifdef IPEDMA_DEBUG
+	printf("Reading: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", cur_read, ctx->last_read_addr, *last_written_addr_ptr);
+#endif /* IPEDMA_DEBUG */
+	
+	pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, cur_read);
+        void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, ctx->pages, cur_read);
+	ret = cb(cbattr, PCILIB_DMA_FLAG_EOP, ctx->page_size, buf);
+	if (ret < 0) return -ret;
+	
+//	DS: Fixme, it looks like we can avoid calling this for the sake of performance
+//	pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_TODEVICE, cur_read);
+
+	WR(IPEDMA_REG_LAST_READ, ctx->last_read + 1);
+
+	ctx->last_read = cur_read;
+	ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, cur_read));
+
+#ifdef IPEDMA_BUG_DMARD
+	FILE *f = fopen("/tmp/pcitool_lastread", "w");
+	if (!f) pcilib_error("Can't write current status");
+	value = cur_read;
+	fwrite(&value, 1, sizeof(pcilib_register_value_t), f);
+	fclose(f);
+#endif /* IPEDMA_BUG_DMARD */
+
+    } while (ret);
+
+    return 0;
+}
+
+double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) {
+    return 0;
+}
diff --git a/dma/ipe.h b/dma/ipe.h
new file mode 100644
index 0000000..2c34ff1
--- /dev/null
+++ b/dma/ipe.h
@@ -0,0 +1,42 @@
+#ifndef _PCILIB_DMA_IPE_H
+#define _PCILIB_DMA_IPE_H
+
+#include <stdio.h>
+#include "../pcilib.h"
+
+//#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100
+
+pcilib_dma_context_t *dma_ipe_init(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg);
+void  dma_ipe_free(pcilib_dma_context_t *vctx);
+
+int dma_ipe_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_ipe_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+int dma_ipe_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+
+int dma_ipe_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);
+double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
+
+
+#ifdef _PCILIB_DMA_IPE_C
+pcilib_dma_api_description_t ipe_dma_api = {
+    "ipe_dma",
+    dma_ipe_init,
+    dma_ipe_free,
+    dma_ipe_get_status,
+    NULL,
+    NULL,
+    NULL,
+    dma_ipe_start,
+    dma_ipe_stop,
+    NULL,
+    dma_ipe_stream_read,
+    dma_ipe_benchmark
+};
+#else
+extern pcilib_dma_api_description_t ipe_dma_api;
+#endif
+
+
+#endif /* _PCILIB_DMA_IPE_H */
diff --git a/dma/ipe_private.h b/dma/ipe_private.h
new file mode 100644
index 0000000..e6e70c2
--- /dev/null
+++ b/dma/ipe_private.h
@@ -0,0 +1,56 @@
+#ifndef _PCILIB_DMA_IPE_PRIVATE_H
+#define _PCILIB_DMA_IPE_PRIVATE_H
+
+#define IPEDMA_CORES			1
+#define IPEDMA_TLP_SIZE			32
+#define IPEDMA_PAGE_SIZE		4096
+#define IPEDMA_DMA_PAGES		16		/**< number of DMA pages in the ring buffer to allocate */
+#define IPEDMA_DMA_PROGRESS_THRESHOLD	1		/**< how many pages the DMA engine should fill before reporting progress */
+#define IPEDMA_DESCRIPTOR_SIZE		128
+#define IPEDMA_DESCRIPTOR_ALIGNMENT	64
+
+//#define IPEDMA_DEBUG
+#define IPEDMA_BUG_DMARD				/**< No register read during DMA transfer */
+
+#define IPEDMA_REG_RESET		0x00
+#define IPEDMA_REG_CONTROL		0x04
+#define IPEDMA_REG_TLP_SIZE		0x0C
+#define IPEDMA_REG_TLP_COUNT		0x10
+#define IPEDMA_REG_PAGE_ADDR		0x50
+#define IPEDMA_REG_UPDATE_ADDR		0x54
+#define IPEDMA_REG_LAST_READ		0x58
+#define IPEDMA_REG_PAGE_COUNT		0x5C
+#define IPEDMA_REG_UPDATE_THRESHOLD	0x60
+
+
+
+typedef struct ipe_dma_s ipe_dma_t;
+
+struct ipe_dma_s {
+    struct pcilib_dma_context_s dmactx;
+    pcilib_dma_engine_description_t engine[2];
+
+    pcilib_t *pcilib;
+    
+    pcilib_register_bank_description_t *dma_bank;
+    char *base_addr;
+
+    pcilib_irq_type_t irq_enabled;	/**< indicates that IRQs are enabled */
+    pcilib_irq_type_t irq_preserve;	/**< indicates that IRQs should not be disabled during clean-up */
+    int irq_started;			/**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */    
+
+    int started;			/**< indicates that DMA buffers are initialized and reading is allowed */
+    int writting;			/**< indicates that we are in middle of writting packet */
+    int reused;				/**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */
+    int preserve;			/**< indicates that DMA should not be stopped during clean-up */
+    int mode64;				/**< indicates 64-bit operation mode */
+
+    pcilib_kmem_handle_t *desc;		/**< in-memory status descriptor written by DMA engine upon operation progess */
+    pcilib_kmem_handle_t *pages;	/**< collection of memory-locked pages for DMA operation */
+
+    size_t ring_size, page_size;
+    size_t last_read, last_read_addr, last_written;
+
+};
+
+#endif /* _PCILIB_DMA_IPE_PRIVATE_H */
diff --git a/dma/ipe_registers.h b/dma/ipe_registers.h
new file mode 100644
index 0000000..17fc41a
--- /dev/null
+++ b/dma/ipe_registers.h
@@ -0,0 +1,44 @@
+#ifndef _PCILIB_DMA_IPE_REGISTERS_H
+#define _PCILIB_DMA_IPE_REGISTERS_H 
+
+#ifdef _PCILIB_DMA_IPE_C 
+static pcilib_register_description_t ipe_dma_registers[] = {
+    {0x0000, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dcr",  			"Device Control Status Register"},
+    {0x0000, 	0, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "reset_dma",  			""},
+    {0x0000, 	16, 	4, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "datapath_width",			""},
+    {0x0000, 	24, 	8, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "fpga_family",			""},
+    {0x0004, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "ddmacr",  			"Device DMA Control Status Register"},
+    {0x0004, 	0, 	1, 	0, 	0xFFFFFFFF,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_start",  			"Start writting memory"},
+    {0x0004, 	5, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_relxed_order",  		""},
+    {0x0004, 	6, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_nosnoop",  			""},
+    {0x0004, 	7, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_int_dis",  			""},
+    {0x0004, 	16, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_start",  			""},
+    {0x0004, 	21, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_relaxed_order",  		""},
+    {0x0004, 	22, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_nosnoop",  			""},
+    {0x0004, 	23, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_int_dis",  			""},
+    {0x000C, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_size",  			"DMA TLP size"},
+    {0x000C, 	0, 	16, 	0x20, 	0xFFFFFFFF,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_len",  			"Max TLP size"},
+    {0x000C, 	16, 	3, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_tlp_tc",  			"TC for TLP packets"},
+    {0x000C, 	19, 	1, 	0, 	0xFFFFFFFF,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_64b_en",  			"Enable 64 bit memory addressing"},
+    {0x000C, 	20, 	1, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_phant_func_dis",		"Disable MWR phantom function"},
+    {0x000C, 	24, 	8, 	0, 	0xFFFFFFFF,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_up_addr",  			"Upper address for 64 bit memory addressing"},
+    {0x0010, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_count",  		"Write DMA TLP Count"},
+    {0x0014, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_pattern",  		"DMA generator data pattern"},
+    {0x0028, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_perf",			"MWR Performance"},
+    {0x003C, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "cfg_lnk_width",		"Negotiated and max width of PCIe Link"},
+    {0x003C, 	0, 	6, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_cap_max_lnk_width", 		"Max link width"},
+    {0x003C, 	8, 	6, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_prg_max_lnk_width", 		"Negotiated link width"},
+    {0x0040, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "cfg_payload_size",  		""},
+    {0x0040, 	0, 	4, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_cap_max_payload_size",	"Max payload size"},
+    {0x0040, 	8, 	3, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_prg_max_payload_size",	"Prog max payload size"},
+    {0x0040, 	16, 	3, 	0, 	0x00000000,	PCILIB_REGISTER_R   , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_max_rd_req_size",		"Max read request size"},
+    {0x0050, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_din",  		"Descriptor memory"},
+    {0x0054, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_addr",  		"Address of progress register"},
+    {0x0058, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "last_descriptor_read",	"Last descriptor read by the host"},
+    {0x005C, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_addr", 		"Number of descriptors configured"},
+    {0x0060, 	0, 	32, 	0, 	0x00000000,	PCILIB_REGISTER_RW  , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_thresh",  		"Update threshold of progress register"},
+    {0,		0,	0,	0,	0x00000000,	0,                                           0,                        0, NULL, 			NULL}
+};
+#endif /* _PCILIB_DMA_IPE_C */
+
+#endif /* _PCILIB_DMA_IPE_REGISTERS_H */
diff --git a/dma/nwl.c b/dma/nwl.c
index a638af3..52b46ef 100644
--- a/dma/nwl.c
+++ b/dma/nwl.c
@@ -11,7 +11,7 @@
 #include "pcilib.h"
 #include "error.h"
 #include "tools.h"
-#include "nwl.h"
+#include "nwl_private.h"
 
 #include "nwl_defines.h"
 
diff --git a/dma/nwl.h b/dma/nwl.h
index d295e23..21df94c 100644
--- a/dma/nwl.h
+++ b/dma/nwl.h
@@ -1,67 +1,46 @@
-#ifndef _PCILIB_NWL_H
-#define _PCILIB_NWL_H
+#ifndef _PCILIB_DMA_NWL_H
+#define _PCILIB_DMA_NWL_H
 
-typedef struct nwl_dma_s nwl_dma_t;
-typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t;
+#include <stdio.h>
+#include "../pcilib.h"
 
-#define NWL_DMA_IRQ_SOURCE 0
+#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100
 
-#define NWL_XAUI_ENGINE 0
-#define NWL_XRAWDATA_ENGINE 1
-#define NWL_MAX_PACKET_SIZE 4096 //16384
-//#define NWL_GENERATE_DMA_IRQ
+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);
 
-#define PCILIB_NWL_ALIGNMENT 			64  // in bytes
-#define PCILIB_NWL_DMA_DESCRIPTOR_SIZE		64  // in bytes
-#define PCILIB_NWL_DMA_PAGES			256 // 1024
+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);
 
-//#define DEBUG_HARDWARE
-//#define DEBUG_NWL
+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);
 
-#include "nwl_dma.h"
-#include "nwl_irq.h"
-#include "nwl_register.h"
-#include "nwl_engine.h"
-#include "nwl_loopback.h"
+int dma_nwl_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
+int dma_nwl_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
 
-#define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess)
-#define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess)
+int dma_nwl_write_fragment(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, void *data, size_t *written);
+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);
+double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
 
-struct pcilib_nwl_engine_description_s {
-    pcilib_dma_engine_description_t desc;
-    char *base_addr;
-    
-    size_t ring_size, page_size;
-    size_t head, tail;
-    pcilib_kmem_handle_t *ring;
-    pcilib_kmem_handle_t *pages;
-    
-    int started;			/**< indicates that DMA buffers are initialized and reading is allowed */
-    int writting;			/**< indicates that we are in middle of writting packet */
-    int reused;				/**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */
-    int preserve;			/**< indicates that DMA should not be stopped during clean-up */
-};
-
-
-struct nwl_dma_s {
-    struct pcilib_dma_context_s dmactx;
-    
-    pcilib_t *pcilib;
-    
-    pcilib_dma_modification_t type;
-    
-    pcilib_register_bank_description_t *dma_bank;
-    char *base_addr;
-
-    pcilib_irq_type_t irq_enabled;	/**< indicates that IRQs are enabled */
-    pcilib_irq_type_t irq_preserve;	/**< indicates that IRQs should not be disabled during clean-up */
-    int started;			/**< indicates that DMA subsystem is initialized and DMA engine can start */
-    int irq_started;			/**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */    
-    int loopback_started;		/**< indicates that benchmarking subsystem is initialized */
 
-    pcilib_dma_engine_t n_engines;
-    pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
+#ifdef _PCILIB_DMA_NWL_C
+pcilib_dma_api_description_t nwl_dma_api = {
+    "nwl_dma",
+    dma_nwl_init,
+    dma_nwl_free,
+    dma_nwl_get_status,
+    dma_nwl_enable_irq,
+    dma_nwl_disable_irq,
+    dma_nwl_acknowledge_irq,
+    dma_nwl_start,
+    dma_nwl_stop,
+    dma_nwl_write_fragment,
+    dma_nwl_stream_read,
+    dma_nwl_benchmark
 };
+#else
+extern pcilib_dma_api_description_t nwl_dma_api;
+#endif
 
 
-#endif /* _PCILIB_NWL_H */
+#endif /* _PCILIB_DMA_NWL_H */
diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h
deleted file mode 100644
index cc9e379..0000000
--- a/dma/nwl_dma.h
+++ /dev/null
@@ -1,45 +0,0 @@
-#ifndef _PCILIB_DMA_NWL_H
-#define _PCILIB_DMA_NWL_H
-
-#include <stdio.h>
-#include "../pcilib.h"
-
-#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100
-
-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_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);
-int dma_nwl_acknowledge_irq(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source);
-
-int dma_nwl_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
-int dma_nwl_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags);
-
-int dma_nwl_write_fragment(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, void *data, size_t *written);
-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);
-double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction);
-
-
-#ifdef _PCILIB_DMA_NWL_C
-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,
-    dma_nwl_start,
-    dma_nwl_stop,
-    dma_nwl_write_fragment,
-    dma_nwl_stream_read,
-    dma_nwl_benchmark
-};
-#else
-extern pcilib_dma_api_description_t nwl_dma_api;
-#endif
-
-
-#endif /* _PCILIB_DMA_NWL_H */
diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c
index e4c102d..f541d0b 100644
--- a/dma/nwl_engine.c
+++ b/dma/nwl_engine.c
@@ -10,7 +10,7 @@
 #include "pcilib.h"
 #include "error.h"
 #include "tools.h"
-#include "nwl.h"
+#include "nwl_private.h"
 
 #include "nwl_defines.h"
 
diff --git a/dma/nwl_engine_buffers.h b/dma/nwl_engine_buffers.h
index 826a4d5..c45c3ca 100644
--- a/dma/nwl_engine_buffers.h
+++ b/dma/nwl_engine_buffers.h
@@ -94,10 +94,10 @@ static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_des
     pcilib_kmem_handle_t *ring = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, PCILIB_NWL_DMA_PAGES * PCILIB_NWL_DMA_DESCRIPTOR_SIZE, PCILIB_NWL_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, sub_use), flags);
     pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, type, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, sub_use), flags);
 
-    if (err) {
+    if (!ring||!pages) {
 	if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0);
-	if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring, 0);    
-	return err;
+	if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring, 0);
+	return PCILIB_ERROR_MEMORY;
     }
 
     reuse_ring = pcilib_kmem_is_reused(ctx->pcilib, ring);
diff --git a/dma/nwl_irq.c b/dma/nwl_irq.c
index ee5f520..e71c76a 100644
--- a/dma/nwl_irq.c
+++ b/dma/nwl_irq.c
@@ -10,7 +10,7 @@
 #include "error.h"
 #include "tools.h"
 
-#include "nwl.h"
+#include "nwl_private.h"
 #include "nwl_defines.h"
 
 int dma_nwl_init_irq(nwl_dma_t *ctx, uint32_t val) {
diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c
index ce0844f..53e0d48 100644
--- a/dma/nwl_loopback.c
+++ b/dma/nwl_loopback.c
@@ -9,7 +9,7 @@
 #include "pcilib.h"
 #include "error.h"
 #include "tools.h"
-#include "nwl.h"
+#include "nwl_private.h"
 
 #include "nwl_defines.h"
 
diff --git a/dma/nwl_private.h b/dma/nwl_private.h
new file mode 100644
index 0000000..756e6ca
--- /dev/null
+++ b/dma/nwl_private.h
@@ -0,0 +1,67 @@
+#ifndef _PCILIB_DMA_NWL_PRIVATE_H
+#define _PCILIB_DMA_NWL_PRIVATE_H
+
+typedef struct nwl_dma_s nwl_dma_t;
+typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t;
+
+#define NWL_DMA_IRQ_SOURCE 0
+
+#define NWL_XAUI_ENGINE 0
+#define NWL_XRAWDATA_ENGINE 1
+#define NWL_MAX_PACKET_SIZE 4096 //16384
+//#define NWL_GENERATE_DMA_IRQ
+
+#define PCILIB_NWL_ALIGNMENT 			64  // in bytes
+#define PCILIB_NWL_DMA_DESCRIPTOR_SIZE		64  // in bytes
+#define PCILIB_NWL_DMA_PAGES			256 // 1024
+
+//#define DEBUG_HARDWARE
+//#define DEBUG_NWL
+
+#include "nwl.h"
+#include "nwl_irq.h"
+#include "nwl_register.h"
+#include "nwl_engine.h"
+#include "nwl_loopback.h"
+
+#define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess)
+#define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess)
+
+struct pcilib_nwl_engine_description_s {
+    pcilib_dma_engine_description_t desc;
+    char *base_addr;
+    
+    size_t ring_size, page_size;
+    size_t head, tail;
+    pcilib_kmem_handle_t *ring;
+    pcilib_kmem_handle_t *pages;
+    
+    int started;			/**< indicates that DMA buffers are initialized and reading is allowed */
+    int writting;			/**< indicates that we are in middle of writting packet */
+    int reused;				/**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */
+    int preserve;			/**< indicates that DMA should not be stopped during clean-up */
+};
+
+
+struct nwl_dma_s {
+    struct pcilib_dma_context_s dmactx;
+    
+    pcilib_t *pcilib;
+    
+    pcilib_dma_modification_t type;
+    
+    pcilib_register_bank_description_t *dma_bank;
+    char *base_addr;
+
+    pcilib_irq_type_t irq_enabled;	/**< indicates that IRQs are enabled */
+    pcilib_irq_type_t irq_preserve;	/**< indicates that IRQs should not be disabled during clean-up */
+    int started;			/**< indicates that DMA subsystem is initialized and DMA engine can start */
+    int irq_started;			/**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */    
+    int loopback_started;		/**< indicates that benchmarking subsystem is initialized */
+
+    pcilib_dma_engine_t n_engines;
+    pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
+};
+
+
+#endif /* _PCILIB_DMA_NWL_PRIVATE_H */
diff --git a/dma/nwl_register.c b/dma/nwl_register.c
index 5f94e4d..6a3771a 100644
--- a/dma/nwl_register.c
+++ b/dma/nwl_register.c
@@ -12,7 +12,7 @@
 #include "error.h"
 #include "tools.h"
 
-#include "nwl.h"
+#include "nwl_private.h"
 #include "nwl_register.h"
 
 int nwl_add_registers(nwl_dma_t *ctx) {
-- 
cgit v1.2.3