summaryrefslogtreecommitdiffstats
path: root/dma
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-11 01:37:54 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-11 01:37:54 +0200
commitc095f06560a0efacc7a34ea4e7f1e69c1faab0cf (patch)
treec005686153325eadb3d5c97617154f0acba75fbb /dma
parent02924fc49641ca9c000054a7a540b6f1eaa0e8f8 (diff)
downloadpcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.gz
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.bz2
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.xz
pcitool-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.zip
IRQ support in NWL DMA engine
Diffstat (limited to 'dma')
-rw-r--r--dma/nwl.c119
-rw-r--r--dma/nwl.h61
-rw-r--r--dma/nwl_dma.h32
-rw-r--r--dma/nwl_irq.c68
-rw-r--r--dma/nwl_irq.h9
-rw-r--r--dma/nwl_register.c73
-rw-r--r--dma/nwl_register.h11
7 files changed, 244 insertions, 129 deletions
diff --git a/dma/nwl.c b/dma/nwl.c
index 9d05cd7..0ef69a4 100644
--- a/dma/nwl.c
+++ b/dma/nwl.c
@@ -21,93 +21,9 @@
#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_GENERATE_DMA_IRQ
-typedef struct {
- 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 if DMA buffers are initialized and reading is allowed
- int writting; // indicates if we are in middle of writting packet
-
-} pcilib_nwl_engine_description_t;
-
-
-struct nwl_dma_s {
- pcilib_t *pcilib;
-
- pcilib_register_bank_description_t *dma_bank;
- char *base_addr;
-
- pcilib_dma_engine_t n_engines;
- pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
-};
-
-#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)
-
-static int nwl_add_registers(nwl_dma_t *ctx) {
- int err;
- size_t n, i, j;
- int length;
- const char *names[NWL_MAX_DMA_ENGINE_REGISTERS];
- uintptr_t addr[NWL_MAX_DMA_ENGINE_REGISTERS];
-
- // We don't want DMA registers
- if (pcilib_find_bank_by_addr(ctx->pcilib, PCILIB_REGISTER_BANK_DMA) == PCILIB_REGISTER_BANK_INVALID) return 0;
-
- 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;
-
- for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
- names[n] = nwl_dma_engine_registers[n].name;
- addr[n] = nwl_dma_engine_registers[n].addr;
- }
-
- if (ctx->n_engines > 9) length = 2;
- else length = 1;
-
- for (i = 0; i < ctx->n_engines; i++) {
- for (j = 0; nwl_dma_engine_registers[j].bits; j++) {
- const char *direction;
- nwl_dma_engine_registers[j].name = nwl_dma_engine_register_names[i * NWL_MAX_DMA_ENGINE_REGISTERS + j];
- nwl_dma_engine_registers[j].addr = addr[j] + (ctx->engines[i].base_addr - ctx->base_addr);
-// printf("%lx %lx\n", (ctx->engines[i].base_addr - ctx->base_addr), nwl_dma_engine_registers[j].addr);
-
- switch (ctx->engines[i].desc.direction) {
- case PCILIB_DMA_FROM_DEVICE:
- direction = "r";
- break;
- case PCILIB_DMA_TO_DEVICE:
- direction = "w";
- break;
- default:
- direction = "";
- }
-
- sprintf((char*)nwl_dma_engine_registers[j].name, names[j], length, ctx->engines[i].desc.addr, direction);
- }
-
- err = pcilib_add_registers(ctx->pcilib, n, nwl_dma_engine_registers);
- if (err) return err;
- }
-
- for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
- nwl_dma_engine_registers[n].name = names[n];
- nwl_dma_engine_registers[n].addr = addr[n];
- }
-
- return 0;
-}
-
static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {
uint32_t val;
@@ -144,7 +60,8 @@ static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_
return 0;
}
-static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
+
+int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
uint32_t val;
struct timeval start, cur;
@@ -218,6 +135,7 @@ static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
return 0;
}
+
pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {
int i;
int err;
@@ -339,12 +257,11 @@ int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_descriptio
NWL_RING_SET(data, DMA_BD_NDESC_OFFSET, ring_pa + ((i + 1) % PCILIB_NWL_DMA_PAGES) * PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
NWL_RING_SET(data, DMA_BD_BUFAL_OFFSET, buf_pa&0xFFFFFFFF);
NWL_RING_SET(data, DMA_BD_BUFAH_OFFSET, buf_pa>>32);
+#ifdef NWL_GENERATE_DMA_IRQ
+ NWL_RING_SET(data, DMA_BD_BUFL_CTRL_OFFSET, buf_sz | DMA_BD_INT_ERROR_MASK | DMA_BD_INT_COMP_MASK);
+#else /* NWL_GENERATE_DMA_IRQ */
NWL_RING_SET(data, DMA_BD_BUFL_CTRL_OFFSET, buf_sz);
-/*
- if (info->desc.direction == PCILIB_DMA_TO_DEVICE) {
- NWL_RING_SET(data, DMA_BD_BUFL_STATUS_OFFSET, buf_sz);
- }
-*/
+#endif /* NWL_GENERATE_DMA_IRQ */
}
val = ring_pa;
@@ -577,7 +494,12 @@ static int dma_nwl_return_buffer(nwl_dma_t *ctx, pcilib_nwl_engine_description_t
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);
+#else /* NWL_GENERATE_DMA_IRQ */
NWL_RING_SET(ring, DMA_BD_BUFL_CTRL_OFFSET, bufsz);
+#endif /* NWL_GENERATE_DMA_IRQ */
+
NWL_RING_SET(ring, DMA_BD_BUFL_STATUS_OFFSET, 0);
val = ring_pa + info->tail * PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
@@ -657,6 +579,8 @@ size_t dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma,
return res;
}
+
+
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) {
int i;
int res;
@@ -674,6 +598,9 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
pcilib_dma_engine_t readid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_FROM_DEVICE, dma);
pcilib_dma_engine_t writeid = pcilib_find_dma_by_addr(ctx->pcilib, PCILIB_DMA_TO_DEVICE, dma);
+ char *read_base = ctx->engines[readid].base_addr;
+ char *write_base = ctx->engines[writeid].base_addr;
+
if (size%sizeof(uint32_t)) size = 1 + size / sizeof(uint32_t);
else size /= sizeof(uint32_t);
@@ -701,7 +628,10 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
pcilib_skip_dma(ctx->pcilib, readid);
-
+#ifdef NWL_GENERATE_DMA_IRQ
+ dma_nwl_enable_engine_irq(ctx, readid);
+#endif /* NWL_GENERATE_DMA_IRQ */
+
// Set size and required mode
val = size * sizeof(uint32_t);
nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS);
@@ -755,7 +685,7 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
if (bytes != size * sizeof(uint32_t)) {
- printf("RF: %li %li\n", bytes, size * 4);
+// printf("RF: %li %li\n", bytes, size * 4);
error = "Read failed";
break;
}
@@ -770,6 +700,9 @@ double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dm
}
+#ifdef NWL_GENERATE_DMA_IRQ
+ dma_nwl_disable_irq(ctx);
+#endif /* NWL_GENERATE_DMA_IRQ */
// Stop Generators and drain data if necessary
nwl_read_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS);
diff --git a/dma/nwl.h b/dma/nwl.h
index 8902a75..3802511 100644
--- a/dma/nwl.h
+++ b/dma/nwl.h
@@ -1,37 +1,38 @@
-#ifndef _PCILIB_DMA_NWL_H
-#define _PCILIB_DMA_NWL_H
+#ifndef _PCILIB_NWL_H
+#define _PCILIB_NWL_H
-#include <stdio.h>
-#include "pcilib.h"
+#include "nwl_dma.h"
+#include "nwl_irq.h"
+#include "nwl_register.h"
-typedef struct nwl_dma_s nwl_dma_t;
+#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)
-/*
typedef struct {
- pcilib_dma_engine_info_t info;
- // offset
-} pcilib_dma_engine_info_t;
-*/
-
-
-pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx);
-void dma_nwl_free(pcilib_dma_context_t *vctx);
-
-size_t 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, size_t timeout, void *data);
-size_t 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, size_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_write_fragment,
- dma_nwl_stream_read,
- dma_nwl_benchmark
+ 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 if DMA buffers are initialized and reading is allowed
+ int writting; // indicates if we are in middle of writting packet
+} pcilib_nwl_engine_description_t;
+
+
+struct nwl_dma_s {
+ pcilib_t *pcilib;
+
+ pcilib_register_bank_description_t *dma_bank;
+ char *base_addr;
+
+ pcilib_irq_type_t irq_enabled;
+
+ pcilib_dma_engine_t n_engines;
+ pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
};
-#else
-extern pcilib_dma_api_description_t nwl_dma_api;
-#endif
-#endif /* _PCILIB_DMA_NWL_H */
+#endif /* _PCILIB_NWL_H */
diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h
new file mode 100644
index 0000000..8468f52
--- /dev/null
+++ b/dma/nwl_dma.h
@@ -0,0 +1,32 @@
+#ifndef _PCILIB_DMA_NWL_H
+#define _PCILIB_DMA_NWL_H
+
+#include <stdio.h>
+#include "pcilib.h"
+
+#define NWL_DMA_IRQ_SOURCE 0
+
+typedef struct nwl_dma_s nwl_dma_t;
+
+pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx);
+void dma_nwl_free(pcilib_dma_context_t *vctx);
+
+size_t 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, size_t timeout, void *data);
+size_t 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, size_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_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_irq.c b/dma/nwl_irq.c
new file mode 100644
index 0000000..45564bc
--- /dev/null
+++ b/dma/nwl_irq.c
@@ -0,0 +1,68 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "pcilib.h"
+
+#include "pci.h"
+#include "error.h"
+#include "tools.h"
+
+#include "nwl.h"
+#include "nwl_defines.h"
+
+int dma_nwl_enable_irq(nwl_dma_t *ctx, pcilib_irq_type_t type) {
+ uint32_t val;
+
+ if (ctx->irq_enabled == type) return 0;
+
+ nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
+ val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE);
+ nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
+
+ pcilib_clear_irq(ctx->pcilib, NWL_DMA_IRQ_SOURCE);
+
+ if (type & PCILIB_DMA_IRQ) val |= DMA_INT_ENABLE;
+ if (type & PCILIB_EVENT_IRQ) val |= DMA_USER_INT_ENABLE;
+ nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
+
+ ctx->irq_enabled = type;
+
+ return 0;
+}
+
+int dma_nwl_disable_irq(nwl_dma_t *ctx) {
+ uint32_t val;
+
+ ctx->irq_enabled = 0;
+
+ nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
+ val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE);
+ nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS);
+
+ return 0;
+}
+
+int dma_nwl_enable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
+ uint32_t val;
+
+ dma_nwl_enable_irq(ctx, ctx->irq_enabled|PCILIB_DMA_IRQ);
+
+ nwl_read_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS);
+ val |= (DMA_ENG_INT_ENABLE);
+ nwl_write_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS);
+
+ return 0;
+}
+
+int dma_nwl_disable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
+ uint32_t val;
+
+ nwl_read_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS);
+ val &= ~(DMA_ENG_INT_ENABLE);
+ nwl_write_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS);
+
+ return 0;
+}
diff --git a/dma/nwl_irq.h b/dma/nwl_irq.h
new file mode 100644
index 0000000..685d74c
--- /dev/null
+++ b/dma/nwl_irq.h
@@ -0,0 +1,9 @@
+#ifndef _PCILIB_NWL_IRQ_H
+#define _PCILIB_NWL_IRQ_H
+
+int dma_nwl_enable_irq(nwl_dma_t *ctx, pcilib_irq_type_t type);
+int dma_nwl_disable_irq(nwl_dma_t *ctx);
+int dma_nwl_enable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma);
+int dma_nwl_disable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma);
+
+#endif /* _PCILIB_NWL_IRQ_H */
diff --git a/dma/nwl_register.c b/dma/nwl_register.c
new file mode 100644
index 0000000..5bb6e16
--- /dev/null
+++ b/dma/nwl_register.c
@@ -0,0 +1,73 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+#include "pcilib.h"
+
+#include "pci.h"
+#include "error.h"
+#include "tools.h"
+
+#include "nwl.h"
+#include "nwl_register.h"
+
+int nwl_add_registers(nwl_dma_t *ctx) {
+ int err;
+ size_t n, i, j;
+ int length;
+ const char *names[NWL_MAX_DMA_ENGINE_REGISTERS];
+ uintptr_t addr[NWL_MAX_DMA_ENGINE_REGISTERS];
+
+ // We don't want DMA registers
+ if (pcilib_find_bank_by_addr(ctx->pcilib, PCILIB_REGISTER_BANK_DMA) == PCILIB_REGISTER_BANK_INVALID) return 0;
+
+ 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;
+
+
+ for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
+ names[n] = nwl_dma_engine_registers[n].name;
+ addr[n] = nwl_dma_engine_registers[n].addr;
+ }
+
+ if (ctx->n_engines > 9) length = 2;
+ else length = 1;
+
+
+ for (i = 0; i < ctx->n_engines; i++) {
+ for (j = 0; nwl_dma_engine_registers[j].bits; j++) {
+ const char *direction;
+ nwl_dma_engine_registers[j].name = nwl_dma_engine_register_names[i * NWL_MAX_DMA_ENGINE_REGISTERS + j];
+ nwl_dma_engine_registers[j].addr = addr[j] + (ctx->engines[i].base_addr - ctx->base_addr);
+// printf("%lx %lx\n", (ctx->engines[i].base_addr - ctx->base_addr), nwl_dma_engine_registers[j].addr);
+
+ switch (ctx->engines[i].desc.direction) {
+ case PCILIB_DMA_FROM_DEVICE:
+ direction = "r";
+ break;
+ case PCILIB_DMA_TO_DEVICE:
+ direction = "w";
+ break;
+ default:
+ direction = "";
+ }
+
+ sprintf((char*)nwl_dma_engine_registers[j].name, names[j], length, ctx->engines[i].desc.addr, direction);
+ }
+
+ err = pcilib_add_registers(ctx->pcilib, n, nwl_dma_engine_registers);
+ if (err) return err;
+ }
+
+ for (n = 0; nwl_dma_engine_registers[n].bits; n++) {
+ nwl_dma_engine_registers[n].name = names[n];
+ nwl_dma_engine_registers[n].addr = addr[n];
+ }
+
+ return 0;
+}
diff --git a/dma/nwl_register.h b/dma/nwl_register.h
index 86515cc..bffc1bf 100644
--- a/dma/nwl_register.h
+++ b/dma/nwl_register.h
@@ -1,9 +1,5 @@
-/*
-pcilib_register_bank_description_t ipecamera_register_banks[] = {
- { PCILIB_REGISTER_DMABANK0, PCILIB_BAR0, 128, PCILIB_DEFAULT_PROTOCOL, DMA_NWL_OFFSET, DMA_NWL_OFFSET, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "%lx", "dma", "NorthWest Logick DMA Engine" },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL }
-};
-*/
+#ifndef _PCILIB_NWL_REGISTERS_H
+#define _PCILIB_NWL_REGISTERS_H
// DMA
static pcilib_register_description_t nwl_dma_registers[] = {
@@ -92,3 +88,6 @@ static pcilib_register_description_t nwl_xrawdata_registers[] = {
{0x910C, 0, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "xrawdata_data_mistmatch", ""},
{0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL}
};
+
+int nwl_add_registers(nwl_dma_t *ctx);
+#endif /* _PCILIB_NWL_REGISTERS_H */