summaryrefslogtreecommitdiffstats
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
parent02924fc49641ca9c000054a7a540b6f1eaa0e8f8 (diff)
downloadipecamera-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.gz
ipecamera-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.bz2
ipecamera-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.tar.xz
ipecamera-c095f06560a0efacc7a34ea4e7f1e69c1faab0cf.zip
IRQ support in NWL DMA engine
-rw-r--r--Makefile2
-rw-r--r--cli.c8
-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
-rw-r--r--driver/common.h2
-rw-r--r--driver/config.h2
-rw-r--r--driver/int.c71
-rw-r--r--driver/ioctl.c26
-rw-r--r--driver/pciDriver.h9
-rw-r--r--pci.c11
-rw-r--r--pci.h1
-rw-r--r--pcilib.h5
-rw-r--r--register.c2
18 files changed, 306 insertions, 206 deletions
diff --git a/Makefile b/Makefile
index 6779487..3722a6e 100644
--- a/Makefile
+++ b/Makefile
@@ -14,7 +14,7 @@ include common.mk
###############################################################
# Target definitions
-OBJECTS = pci.o register.o kmem.o dma.o event.o default.o tools.o dma/nwl.o ipecamera/model.o ipecamera/image.o
+OBJECTS = pci.o register.o kmem.o irq.o dma.o event.o default.o tools.o dma/nwl.o dma/nwl_register.o dma/nwl_irq.o ipecamera/model.o ipecamera/image.o
libpcilib.so: $(OBJECTS)
echo -e "LD \t$@"
diff --git a/cli.c b/cli.c
index f4758e7..e6f0d7b 100644
--- a/cli.c
+++ b/cli.c
@@ -328,6 +328,7 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma,
unsigned long time;
size_t size, min_size, max_size;
double mbs_in, mbs_out, mbs;
+ size_t irqs;
const pcilib_board_info_t *board_info = pcilib_get_board_info(handle);
@@ -344,6 +345,9 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma,
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 = pcilib_benchmark_dma(handle, dma, addr, size, BENCHMARK_ITERATIONS, PCILIB_DMA_BIDIRECTIONAL);
+ err = pcilib_wait_irq(handle, 0, 0, &irqs);
+ if (err) irqs = 0;
+
printf("%8i KB - ", size / 1024);
printf("RW: ");
@@ -357,6 +361,10 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma,
printf(", W: ");
if (mbs_out < 0) printf("failed ... ");
else printf("%8.2lf MB/s", mbs_out);
+
+ if (irqs) {
+ printf(", IRQs: %lu", irqs);
+ }
printf("\n");
}
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 */
diff --git a/driver/common.h b/driver/common.h
index 6036b0c..3bc27d8 100644
--- a/driver/common.h
+++ b/driver/common.h
@@ -60,7 +60,7 @@ typedef struct {
struct list_head umem_list; /* List of 'umem_list_entry's associated with this device */
atomic_t umem_count; /* id for next umem entry */
-
+ int msi_mode;
} pcidriver_privdata_t;
diff --git a/driver/config.h b/driver/config.h
index a2b6946..c217afd 100644
--- a/driver/config.h
+++ b/driver/config.h
@@ -3,7 +3,7 @@
/*******************************/
/* Debug messages */
-#define DEBUG
+//#define DEBUG
/* Enable/disable IRQ handling */
#define ENABLE_IRQ
diff --git a/driver/int.c b/driver/int.c
index 285aa0e..5dbcb7f 100644
--- a/driver/int.c
+++ b/driver/int.c
@@ -162,6 +162,10 @@ int pcidriver_probe_irq(pcidriver_privdata_t *privdata)
return 0;
}
+ /* Enable interrupts using MSI mode */
+ if (!pci_enable_msi(privdata->pdev))
+ privdata->msi_mode = 1;
+
/* register interrupt handler */
if ((err = request_irq(privdata->pdev->irq, pcidriver_irq_handler, MODNAME, privdata)) != 0) {
mod_info("Error registering the interrupt handler. Disabling interrupts for this device\n");
@@ -184,6 +188,11 @@ void pcidriver_remove_irq(pcidriver_privdata_t *privdata)
/* Release the IRQ handler */
if (privdata->irq_enabled != 0)
free_irq(privdata->pdev->irq, privdata);
+
+ if (privdata->msi_mode) {
+ pci_disable_msi(privdata->pdev);
+ privdata->msi_mode = 0;
+ }
pcidriver_irq_unmap_bars(privdata);
}
@@ -208,29 +217,6 @@ void pcidriver_irq_unmap_bars(pcidriver_privdata_t *privdata)
/**
*
- * Acknowledge the interrupt by ACKing the interrupt generator.
- *
- * @returns true if the channel was acknowledged and the interrupt handler is done
- *
- */
-static bool check_acknowlegde_channel(pcidriver_privdata_t *privdata, int interrupt,
- int channel, volatile unsigned int *bar)
-{
- if (!(bar[ABB_INT_STAT] & interrupt))
- return false;
-
- bar[ABB_INT_ENABLE] &= !interrupt;
- if (interrupt == ABB_INT_IG)
- bar[ABB_IG_CTRL] = ABB_IG_ACK;
-
- /* Wake up the waiting loop in ioctl.c:ioctl_wait_interrupt() */
- atomic_inc(&(privdata->irq_outstanding[channel]));
- wake_up_interruptible(&(privdata->irq_queues[channel]));
- return true;
-}
-
-/**
- *
* Acknowledges the receival of an interrupt to the card.
*
* @returns true if the card was acknowledget
@@ -241,38 +227,15 @@ static bool check_acknowlegde_channel(pcidriver_privdata_t *privdata, int interr
*/
static bool pcidriver_irq_acknowledge(pcidriver_privdata_t *privdata)
{
- volatile unsigned int *bar;
+ int channel = 0;
+// volatile unsigned int *bar;
+// bar = privdata->bars_kmapped[0];
+// mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]);
- /* TODO: add subvendor / subsystem ids */
- /* FIXME: guillermo: which ones? all? */
-
- /* Test if we have to handle this interrupt */
- return false; // The device is not supported any more
-
- /* Acknowledge the device */
- /* this is for ABB / wenxue DMA engine */
- bar = privdata->bars_kmapped[0];
-
- mod_info_dbg("interrupt registers. ISR: %x, IER: %x\n", bar[ABB_INT_STAT], bar[ABB_INT_ENABLE]);
-
- if (check_acknowlegde_channel(privdata, ABB_INT_CH0, ABB_IRQ_CH0, bar))
- return true;
-
- if (check_acknowlegde_channel(privdata, ABB_INT_CH1, ABB_IRQ_CH1, bar))
- return true;
-
- if (check_acknowlegde_channel(privdata, ABB_INT_IG, ABB_IRQ_IG, bar))
- return true;
-
- if (check_acknowlegde_channel(privdata, ABB_INT_CH0_TIMEOUT, ABB_IRQ_CH0, bar))
- return true;
-
- if (check_acknowlegde_channel(privdata, ABB_INT_CH1_TIMEOUT, ABB_IRQ_CH1, bar))
- return true;
-
- mod_info_dbg("err: interrupt registers. ISR: %x, IER: %x\n", bar[ ABB_INT_STAT ], bar[ ABB_INT_ENABLE ] );
-
- return false;
+ atomic_inc(&(privdata->irq_outstanding[channel]));
+ wake_up_interruptible(&(privdata->irq_queues[channel]));
+
+ return true;
}
/**
diff --git a/driver/ioctl.c b/driver/ioctl.c
index 64985e8..0059833 100644
--- a/driver/ioctl.c
+++ b/driver/ioctl.c
@@ -335,18 +335,23 @@ static int ioctl_umem_sync(pcidriver_privdata_t *privdata, unsigned long arg)
static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long arg)
{
#ifdef ENABLE_IRQ
+ int ret;
+ unsigned long timeout;
unsigned int irq_source;
- int temp;
+ unsigned long temp = 0;
- if (arg >= PCIDRIVER_INT_MAXSOURCES)
+ READ_FROM_USER(interrupt_wait_t, irq_handle);
+
+ irq_source = irq_handle.source;
+
+ if (irq_source >= PCIDRIVER_INT_MAXSOURCES)
return -EFAULT; /* User tried to overrun the IRQ_SOURCES array */
- irq_source = arg;
+ timeout = jiffies + (irq_handle.timeout * HZ / 1000000);
/* Thanks to Joern for the correction and tips! */
/* done this way to avoid wrong behaviour (endless loop) of the compiler in AMD platforms */
- temp=1;
- while (temp) {
+ do {
/* We wait here with an interruptible timeout. This will be interrupted
* by int.c:check_acknowledge_channel() as soon as in interrupt for
* the specified source arrives. */
@@ -355,8 +360,17 @@ static int ioctl_wait_interrupt(pcidriver_privdata_t *privdata, unsigned long ar
if (atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source])) )
atomic_inc( &(privdata->irq_outstanding[irq_source]) );
else
- temp =0;
+ temp = 1;
+ } while ((!temp)&&(jiffies < timeout));
+
+ if ((temp)&&(irq_handle.count)) {
+ while (!atomic_add_negative( -1, &(privdata->irq_outstanding[irq_source]))) temp++;
+ atomic_inc( &(privdata->irq_outstanding[irq_source]) );
}
+
+ irq_handle.count = temp;
+
+ WRITE_TO_USER(interrupt_wait_t, irq_handle);
return 0;
#else
diff --git a/driver/pciDriver.h b/driver/pciDriver.h
index 94c98e7..2704ab5 100644
--- a/driver/pciDriver.h
+++ b/driver/pciDriver.h
@@ -64,8 +64,8 @@
#define PCIE_ML605_DEVICE_ID 0x04a0
/* Identifies the PCI-E IPE Camera */
-#define PCIE_IPECAMERA_DEVICE_ID 0x6081
-//#define PCIE_IPECAMERA_DEVICE_ID 0x6018
+//#define PCIE_IPECAMERA_DEVICE_ID 0x6081
+#define PCIE_IPECAMERA_DEVICE_ID 0x6018
/* Possible values for ioctl commands */
@@ -133,6 +133,11 @@ typedef struct {
int dir;
} kmem_sync_t;
+typedef struct {
+ unsigned long count;
+ unsigned long timeout; // microseconds
+ unsigned int source;
+} interrupt_wait_t;
typedef struct {
int size;
diff --git a/pci.c b/pci.c
index 807e799..3846235 100644
--- a/pci.c
+++ b/pci.c
@@ -93,17 +93,6 @@ const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) {
}
-int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, unsigned long timeout) {
- int err;
-
- err = ioctl(ctx->handle, PCIDRIVER_IOC_WAITI, source);
- if (err) {
- pcilib_error("PCIDRIVER_IOC_WAITI ioctl have failed");
- return PCILIB_ERROR_FAILED;
- }
-
- return 0;
-}
pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) {
return ctx->event_ctx;
diff --git a/pci.h b/pci.h
index 98176ad..2115134 100644
--- a/pci.h
+++ b/pci.h
@@ -10,6 +10,7 @@
#include "pcilib.h"
#include "register.h"
#include "kmem.h"
+#include "irq.h"
#include "dma.h"
#include "event.h"
diff --git a/pcilib.h b/pcilib.h
index 6f831fa..8e1a7ec 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -24,7 +24,7 @@ typedef void 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;
typedef struct pcilib_protocol_description_s pcilib_protocol_description_t;
-typedef unsigned long pcilib_irq_source_t;
+typedef unsigned int pcilib_irq_source_t;
typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */
typedef uint8_t pcilib_register_t; /**< Type holding the register ID within the Bank */
@@ -198,6 +198,9 @@ pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx);
pcilib_t *pcilib_open(const char *device, pcilib_model_t model);
void pcilib_close(pcilib_t *ctx);
+int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_source_t source);
+int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_source_t source, size_t timeout, size_t *count);
+
void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar);
void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data);
char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr); // addr is offset if bar is specified
diff --git a/register.c b/register.c
index 1960e18..580a164 100644
--- a/register.c
+++ b/register.c
@@ -26,6 +26,8 @@ int pcilib_add_registers(pcilib_t *ctx, size_t n, pcilib_register_description_t
}
+ if (pcilib_model[ctx->model].registers)
+
if (ctx->model_info.registers == pcilib_model[ctx->model].registers) {
for (n_present = 0; ctx->model_info.registers[n_present].bits; n_present++);
for (size = 1024; size < 2 * (n + n_present + 1); size<<=1);