diff options
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | dma.c | 46 | ||||
-rw-r--r-- | dma/nwl.c | 108 | ||||
-rw-r--r-- | dma/nwl.h | 6 | ||||
-rw-r--r-- | dma/nwl_dma.h | 7 | ||||
-rw-r--r-- | dma/nwl_engine.c | 15 | ||||
-rw-r--r-- | dma/nwl_engine.h | 3 | ||||
-rw-r--r-- | dma/nwl_irq.c | 14 | ||||
-rw-r--r-- | dma/nwl_loopback.c | 53 | ||||
-rw-r--r-- | dma/nwl_loopback.h | 7 | ||||
-rw-r--r-- | pcilib.h | 2 |
11 files changed, 181 insertions, 82 deletions
@@ -14,7 +14,7 @@ include common.mk ############################################################### # Target definitions -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 dma/nwl_engine.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 dma/nwl_engine.o dma/nwl_loopback.o ipecamera/model.o ipecamera/image.o libpcilib.so: $(OBJECTS) echo -e "LD \t$@" @@ -55,9 +55,47 @@ int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, } int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + int err; + + const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!ctx->model_info.dma_api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!ctx->model_info.dma_api->start_dma) { + //pcilib_error("The IRQs are not supported by configured DMA engine"); + return 0; + } + + return ctx->model_info.dma_api->start_dma(ctx->dma_ctx, dma, flags); } int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + int err; + + const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!ctx->model_info.dma_api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!ctx->model_info.dma_api->stop_dma) { + //pcilib_error("The IRQs are not supported by configured DMA engine"); + return 0; + } + + return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags); } int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) { @@ -75,8 +113,8 @@ int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flag } if (!ctx->model_info.dma_api->enable_irq) { - pcilib_error("The IRQs are not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; + //pcilib_error("The IRQs are not supported by configured DMA engine"); + return 0; } return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags); @@ -97,8 +135,8 @@ int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) { } if (!ctx->model_info.dma_api->disable_irq) { - pcilib_error("The IRQs are not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; + //pcilib_error("The IRQs are not supported by configured DMA engine"); + return 0; } return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags); @@ -15,73 +15,62 @@ #include "nwl_defines.h" +int dma_nwl_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + nwl_dma_t *ctx = (nwl_dma_t*)vctx; - -int dma_nwl_start_loopback(nwl_dma_t *ctx, pcilib_dma_direction_t direction, size_t packet_size) { - uint32_t val; - - val = packet_size; - nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS); - - switch (direction) { - case PCILIB_DMA_BIDIRECTIONAL: - val = LOOPBACK; - break; - case PCILIB_DMA_TO_DEVICE: - return -1; - case PCILIB_DMA_FROM_DEVICE: - val = PKTGENR; - break; + if (!ctx->started) { + // global initialization, should we do anything? + ctx->started = 1; } - nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS); - nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS); - - return 0; -} - -int dma_nwl_stop_loopback(nwl_dma_t *ctx) { - uint32_t val; - - val = 0; - nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS); - nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS); - - return 0; -} - - -int dma_nwl_start(nwl_dma_t *ctx) { - if (ctx->started) return 0; - -#ifdef NWL_GENERATE_DMA_IRQ - dma_nwl_enable_irq(ctx, PCILIB_DMA_IRQ, 0); -#endif /* NWL_GENERATE_DMA_IRQ */ - - ctx->started = 1; + if (dma == PCILIB_DMA_ENGINE_INVALID) return 0; + else if (dma > ctx->n_engines) return PCILIB_ERROR_INVALID_BANK; - return 0; + if (flags&PCILIB_DMA_FLAG_PERMANENT) ctx->engines[dma].preserve = 1; + return dma_nwl_start_engine(ctx, dma); } -int dma_nwl_stop(nwl_dma_t *ctx) { +int dma_nwl_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { int err; + int preserving = 0; - pcilib_dma_engine_t i; + nwl_dma_t *ctx = (nwl_dma_t*)vctx; - ctx->started = 0; + if (!ctx->started) return 0; - err = dma_nwl_free_irq(ctx); - if (err) return err; + // stop everything + if (dma == PCILIB_DMA_ENGINE_INVALID) { + for (dma = 0; dma < ctx->n_engines; dma++) { + if (flags&PCILIB_DMA_FLAG_PERMANENT) { + ctx->engines[dma].preserve = 0; + } + + if (ctx->engines[dma].preserve) preserving = 1; + else { + err = dma_nwl_stop_engine(ctx, dma); + if (err) return err; + } + } + + // global cleanup, should we do anything? + if (!preserving) { + ctx->started = 0; + } + + return 0; + } - err = dma_nwl_stop_loopback(ctx); - if (err) return err; + if (dma > ctx->n_engines) return PCILIB_ERROR_INVALID_BANK; - for (i = 0; i < ctx->n_engines; i++) { - err = dma_nwl_stop_engine(ctx, i); - if (err) return err; + // ignorign previous setting if flag specified + if (flags&PCILIB_DMA_FLAG_PERMANENT) { + ctx->engines[dma].preserve = 0; } - return 0; + // Do not close DMA if preservation mode is set + if (ctx->engines[dma].preserve) return 0; + + return dma_nwl_stop_engine(ctx, dma); } @@ -134,13 +123,16 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) { } void dma_nwl_free(pcilib_dma_context_t *vctx) { + int err; + pcilib_dma_engine_t i; nwl_dma_t *ctx = (nwl_dma_t*)vctx; - if (ctx) { - for (i = 0; i < ctx->n_engines; i++) dma_nwl_stop_engine(ctx, i); - dma_nwl_stop(ctx); - free(ctx); - } + + dma_nwl_stop_loopback(ctx); + dma_nwl_free_irq(ctx); + dma_nwl_stop(ctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT); + + free(ctx); } @@ -19,6 +19,7 @@ typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t; #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) @@ -44,11 +45,12 @@ struct nwl_dma_s { pcilib_register_bank_description_t *dma_bank; char *base_addr; - int irq_init; /**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */ 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]; }; diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h index 0ed8158..883dc29 100644 --- a/dma/nwl_dma.h +++ b/dma/nwl_dma.h @@ -10,6 +10,9 @@ void dma_nwl_free(pcilib_dma_context_t *vctx); 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_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); @@ -21,8 +24,8 @@ pcilib_dma_api_description_t nwl_dma_api = { dma_nwl_free, dma_nwl_enable_irq, dma_nwl_disable_irq, - NULL, - NULL, + dma_nwl_start, + dma_nwl_stop, dma_nwl_write_fragment, dma_nwl_stream_read, dma_nwl_benchmark diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index 3258da6..11137b9 100644 --- a/dma/nwl_engine.c +++ b/dma/nwl_engine.c @@ -1,3 +1,5 @@ +#define _BSD_SOURCE + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -12,6 +14,8 @@ #include "nwl_defines.h" +#include "nwl_buffers.h" + int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) { uint32_t val; @@ -58,7 +62,7 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { pcilib_nwl_engine_description_t *info = ctx->engines + dma; char *base = ctx->engines[dma].base_addr; - + if (info->started) return 0; // Disable IRQs @@ -100,9 +104,6 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); } - err = dma_nwl_start(ctx); - if (err) return err; - err = dma_nwl_allocate_engine_buffers(ctx, info); if (err) return err; @@ -182,8 +183,6 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { return 0; } -#include "nwl_buffers.h" - 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 err; size_t pos; @@ -192,7 +191,7 @@ int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_nwl_engine_description_t *info = ctx->engines + dma; - err = dma_nwl_start_engine(ctx, dma); + err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT); if (err) return err; if (data) { @@ -238,7 +237,7 @@ int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin pcilib_nwl_engine_description_t *info = ctx->engines + dma; - err = dma_nwl_start_engine(ctx, dma); + err = dma_nwl_start(ctx, dma, PCILIB_DMA_FLAGS_DEFAULT); if (err) return err; do { diff --git a/dma/nwl_engine.h b/dma/nwl_engine.h index 778dc8a..176eaeb 100644 --- a/dma/nwl_engine.h +++ b/dma/nwl_engine.h @@ -2,6 +2,9 @@ #define _PCILIB_DMA_NWL_ENGINE_H int dma_nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base); +int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma); +int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma); + #endif /* _PCILIB_DMA_NWL_ENGINE_H */ diff --git a/dma/nwl_irq.c b/dma/nwl_irq.c index 04ac908..3a9d9a2 100644 --- a/dma/nwl_irq.c +++ b/dma/nwl_irq.c @@ -19,16 +19,16 @@ int dma_nwl_init_irq(nwl_dma_t *ctx, uint32_t val) { if (val&DMA_USER_INT_ENABLE) ctx->irq_preserve |= PCILIB_EVENT_IRQ; } - ctx->irq_init = 1; + ctx->irq_started = 1; return 0; } int dma_nwl_free_irq(nwl_dma_t *ctx) { - if (ctx->irq_init) { + if (ctx->irq_started) { dma_nwl_disable_irq((pcilib_dma_context_t*)ctx, 0); if (ctx->irq_preserve) dma_nwl_enable_irq((pcilib_dma_context_t*)ctx, ctx->irq_preserve, 0); ctx->irq_enabled = 0; - ctx->irq_init = 0; + ctx->irq_started = 0; } return 0; } @@ -39,12 +39,12 @@ int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcili if (flags&PCILIB_DMA_FLAG_PERMANENT) ctx->irq_preserve |= type; - if (ctx->irq_enabled == type) return 0; + if ((ctx->irq_enabled&type) == type) return 0; type |= ctx->irq_enabled; nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS); - if (!ctx->irq_init) dma_nwl_init_irq(ctx, val); + if (!ctx->irq_started) dma_nwl_init_irq(ctx, val); val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE); nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS); @@ -68,7 +68,7 @@ int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags) { ctx->irq_enabled = 0; nwl_read_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS); - if (!ctx->irq_init) dma_nwl_init_irq(ctx, val); + if (!ctx->irq_started) dma_nwl_init_irq(ctx, val); val &= ~(DMA_INT_ENABLE|DMA_USER_INT_ENABLE); nwl_write_register(val, ctx, ctx->base_addr, REG_DMA_CTRL_STATUS); @@ -81,7 +81,7 @@ int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags) { int dma_nwl_enable_engine_irq(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { uint32_t val; - dma_nwl_enable_irq(ctx, ctx->irq_enabled|PCILIB_DMA_IRQ, 0); + dma_nwl_enable_irq(ctx, PCILIB_DMA_IRQ, 0); nwl_read_register(val, ctx, ctx->engines[dma].base_addr, REG_DMA_ENG_CTRL_STATUS); val |= (DMA_ENG_INT_ENABLE); diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c new file mode 100644 index 0000000..9c74b14 --- /dev/null +++ b/dma/nwl_loopback.c @@ -0,0 +1,53 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> + +#include "pci.h" +#include "pcilib.h" +#include "error.h" +#include "tools.h" +#include "nwl.h" + +#include "nwl_defines.h" + + +int dma_nwl_start_loopback(nwl_dma_t *ctx, pcilib_dma_direction_t direction, size_t packet_size) { + uint32_t val; + + // Re-initializing always + + val = packet_size; + nwl_write_register(val, ctx, ctx->base_addr, PKT_SIZE_ADDRESS); + + switch (direction) { + case PCILIB_DMA_BIDIRECTIONAL: + val = LOOPBACK; + break; + case PCILIB_DMA_TO_DEVICE: + return -1; + case PCILIB_DMA_FROM_DEVICE: + val = PKTGENR; + break; + } + + nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS); + nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS); + + ctx->loopback_started = 1; + + return 0; +} + +int dma_nwl_stop_loopback(nwl_dma_t *ctx) { + uint32_t val = 0; + + if (ctx->loopback_started) { + nwl_write_register(val, ctx, ctx->base_addr, TX_CONFIG_ADDRESS); + nwl_write_register(val, ctx, ctx->base_addr, RX_CONFIG_ADDRESS); + ctx->loopback_started = 0; + } + + return 0; +} diff --git a/dma/nwl_loopback.h b/dma/nwl_loopback.h new file mode 100644 index 0000000..63c8446 --- /dev/null +++ b/dma/nwl_loopback.h @@ -0,0 +1,7 @@ +#ifndef _PCILIB_NWL_LOOPBACK_H +#define _PCILIB_NWL_LOOPBACK_H + +int dma_nwl_start_loopback(nwl_dma_t *ctx, pcilib_dma_direction_t direction, size_t packet_size); +int dma_nwl_stop_loopback(nwl_dma_t *ctx); + +#endif /* _PCILIB_NWL_LOOPBACK_H */ @@ -86,6 +86,8 @@ typedef enum { #define PCILIB_BAR0 0 #define PCILIB_BAR1 1 #define PCILIB_DMA_ENGINE_INVALID ((pcilib_dma_engine_t)-1) +#define PCILIB_DMA_ENGINE_ALL ((pcilib_dma_engine_t)-1) +#define PCILIB_DMA_FLAGS_DEFAULT ((pcilib_dma_flags_t)0) #define PCILIB_DMA_ENGINE_ADDR_INVALID ((pcilib_dma_engine_addr_t)-1) #define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1) #define PCILIB_ADDRESS_INVALID ((uintptr_t)-1) |