diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2014-12-19 00:14:21 +0100 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2014-12-19 00:14:21 +0100 |
commit | a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f (patch) | |
tree | 7a6b899c130510e3cca87c23b26a5a1ffc033f20 /dma | |
parent | 0e16eeef08ed9b27f0fbc7f02a562a81e10c4119 (diff) | |
download | ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.gz ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.bz2 ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.xz ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.zip |
Initial implementation of IPEDMA, dummy driver for KAPTURE, start of API changes
Diffstat (limited to 'dma')
-rw-r--r-- | dma/CMakeLists.txt | 4 | ||||
-rw-r--r-- | dma/ipe.c | 412 | ||||
-rw-r--r-- | dma/ipe.h | 42 | ||||
-rw-r--r-- | dma/ipe_private.h | 56 | ||||
-rw-r--r-- | dma/ipe_registers.h | 44 | ||||
-rw-r--r-- | dma/nwl.c | 2 | ||||
-rw-r--r-- | dma/nwl.h | 89 | ||||
-rw-r--r-- | dma/nwl_dma.h | 45 | ||||
-rw-r--r-- | dma/nwl_engine.c | 2 | ||||
-rw-r--r-- | dma/nwl_engine_buffers.h | 6 | ||||
-rw-r--r-- | dma/nwl_irq.c | 2 | ||||
-rw-r--r-- | dma/nwl_loopback.c | 2 | ||||
-rw-r--r-- | dma/nwl_private.h | 67 | ||||
-rw-r--r-- | dma/nwl_register.c | 2 |
14 files changed, 665 insertions, 110 deletions
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 */ @@ -11,7 +11,7 @@ #include "pcilib.h" #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_defines.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) { |