From c095f06560a0efacc7a34ea4e7f1e69c1faab0cf Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Mon, 11 Jul 2011 01:37:54 +0200 Subject: IRQ support in NWL DMA engine --- Makefile | 2 +- cli.c | 8 ++++ dma/nwl.c | 119 ++++++++++++----------------------------------------- dma/nwl.h | 61 +++++++++++++-------------- dma/nwl_dma.h | 32 ++++++++++++++ dma/nwl_irq.c | 68 ++++++++++++++++++++++++++++++ dma/nwl_irq.h | 9 ++++ dma/nwl_register.c | 73 ++++++++++++++++++++++++++++++++ dma/nwl_register.h | 11 +++-- driver/common.h | 2 +- driver/config.h | 2 +- driver/int.c | 71 ++++++++------------------------ driver/ioctl.c | 26 +++++++++--- driver/pciDriver.h | 9 +++- pci.c | 11 ----- pci.h | 1 + pcilib.h | 5 ++- register.c | 2 + 18 files changed, 306 insertions(+), 206 deletions(-) create mode 100644 dma/nwl_dma.h create mode 100644 dma/nwl_irq.c create mode 100644 dma/nwl_irq.h create mode 100644 dma/nwl_register.c 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 -#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 +#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 +#include +#include +#include +#include + +#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 +#include +#include +#include +#include + +#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); } @@ -206,29 +215,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. @@ -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); -- cgit v1.2.3