diff options
Diffstat (limited to 'dma/ipe.c')
-rw-r--r-- | dma/ipe.c | 126 |
1 files changed, 70 insertions, 56 deletions
@@ -110,6 +110,24 @@ void dma_ipe_free(pcilib_dma_context_t *vctx) { } +static void dma_ipe_disable(ipe_dma_t *ctx) { + // Disable DMA + WR(IPEDMA_REG_CONTROL, 0x0); + usleep(IPEDMA_RESET_DELAY); + + // Reset DMA engine + WR(IPEDMA_REG_RESET, 0x1); + usleep(IPEDMA_RESET_DELAY); + WR(IPEDMA_REG_RESET, 0x0); + usleep(IPEDMA_RESET_DELAY); + + // Reseting configured DMA pages + if (ctx->version < 3) { + WR(IPEDMA_REG2_PAGE_COUNT, 0); + } + usleep(IPEDMA_RESET_DELAY); +} + int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { int err; int mask = 32; @@ -169,10 +187,10 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm } else ctx->page_size = IPEDMA_PAGE_SIZE; - if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_pages", &value)) - ctx->dma_pages = value; + if ((!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "dma_pages", &value))&&(value > 0)) + ctx->ring_size = value; else - ctx->dma_pages = IPEDMA_DMA_PAGES; + ctx->ring_size = IPEDMA_DMA_PAGES; if (!pcilib_read_register(ctx->dmactx.pcilib, "dmaconf", "ipedma_flags", &value)) ctx->dma_flags = value; @@ -191,35 +209,56 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm 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->dmactx.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->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, IPEDMA_DMA_PAGES, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags); + pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags); if (!desc||!pages) { - if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, 0); - if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, 0); + if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE); + if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE); + printf("%lu\n", IPEDMA_DESCRIPTOR_SIZE); + pcilib_error("Can't allocate required kernel memory for IPEDMA engine (%lu pages of %lu bytes + %lu byte descriptor)", ctx->ring_size, ctx->page_size, (unsigned long)IPEDMA_DESCRIPTOR_SIZE); return PCILIB_ERROR_MEMORY; } reuse_desc = pcilib_kmem_is_reused(ctx->dmactx.pcilib, desc); reuse_pages = pcilib_kmem_is_reused(ctx->dmactx.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..."); + if ((reuse_pages & PCILIB_KMEM_REUSE_PARTIAL)||(reuse_desc & PCILIB_KMEM_REUSE_PARTIAL)) { + dma_ipe_disable(ctx); + + pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE); + pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE); + + if ((flags&PCILIB_DMA_FLAG_STOP) == 0) { + pcilib_error("Inconsistent DMA buffers are found (buffers are only partially re-used). This is very wrong, please stop DMA engine and correct configuration..."); + return PCILIB_ERROR_INVALID_STATE; + } + + pcilib_warning("Inconsistent DMA buffers are found (buffers are only partially re-used), reinitializing..."); + desc = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags|PCILIB_KMEM_FLAG_MASS); + pages = pcilib_alloc_kernel_memory(ctx->dmactx.pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, ctx->ring_size, ctx->page_size, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags|PCILIB_KMEM_FLAG_MASS); + + if (!desc||!pages) { + if (pages) pcilib_free_kernel_memory(ctx->dmactx.pcilib, pages, KMEM_FLAG_REUSE); + if (desc) pcilib_free_kernel_memory(ctx->dmactx.pcilib, desc, KMEM_FLAG_REUSE); + return PCILIB_ERROR_MEMORY; + } + } else if (reuse_desc != reuse_pages) { + pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), 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 { + if (ctx->streaming) + preserve = 1; else { - if (ctx->streaming) + RD(IPEDMA_REG2_PAGE_COUNT, value); + + if (value != ctx->ring_size) + pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES); + else preserve = 1; - else { - RD(IPEDMA_REG2_PAGE_COUNT, value); - - if (value != IPEDMA_DMA_PAGES) - pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers (%lu) does not match current request (%lu)), reinitializing...", value + 1, IPEDMA_DMA_PAGES); - else - 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->dmactx.pcilib, desc); if (ctx->version < 3) { @@ -242,7 +281,7 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm RD(ctx->reg_last_read, value); // Numbered from 1 in FPGA # ifdef IPEDMA_BUG_LAST_READ - if (value == IPEDMA_DMA_PAGES) + if (value == ctx->ring_size) value = 0; # else /* IPEDMA_BUG_LAST_READ */ value--; @@ -251,16 +290,8 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm ctx->last_read = value; } else { ctx->reused = 0; - - // Disable DMA - WR(IPEDMA_REG_CONTROL, 0x0); - usleep(IPEDMA_RESET_DELAY); - // Reset DMA engine - WR(IPEDMA_REG_RESET, 0x1); - usleep(IPEDMA_RESET_DELAY); - WR(IPEDMA_REG_RESET, 0x0); - usleep(IPEDMA_RESET_DELAY); + dma_ipe_disable(ctx); // Verify PCIe link status RD(IPEDMA_REG_RESET, value); @@ -284,9 +315,9 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm // Setting current read position and configuring progress register #ifdef IPEDMA_BUG_LAST_READ - WR(ctx->reg_last_read, IPEDMA_DMA_PAGES - 1); + WR(ctx->reg_last_read, ctx->ring_size - 1); #else /* IPEDMA_BUG_LAST_READ */ - WR(ctx->reg_last_read, IPEDMA_DMA_PAGES); + WR(ctx->reg_last_read, ctx->ring_size); #endif /* IPEDMA_BUG_LAST_READ */ if (ctx->version < 3) { @@ -304,7 +335,7 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm // In ring buffer mode, the hardware taking care to preserve an empty buffer to help distinguish between // completely empty and completely full cases. In streaming mode, it is our responsibility to track this // information. Therefore, we always keep the last buffer free - num_pages = IPEDMA_DMA_PAGES; + num_pages = ctx->ring_size; if (ctx->streaming) num_pages--; for (i = 0; i < num_pages; i++) { @@ -330,7 +361,7 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm // Enable DMA WR(IPEDMA_REG_CONTROL, 0x1); - ctx->last_read = IPEDMA_DMA_PAGES - 1; + ctx->last_read = ctx->ring_size - 1; } ctx->last_read_addr = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, pages, ctx->last_read); @@ -338,8 +369,6 @@ int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dm ctx->desc = desc; ctx->pages = pages; - ctx->ring_size = IPEDMA_DMA_PAGES; - return 0; } @@ -364,22 +393,7 @@ int dma_ipe_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma ctx->started = 0; - // Disable DMA - WR(IPEDMA_REG_CONTROL, 0); - usleep(IPEDMA_RESET_DELAY); - - // Reset DMA engine - WR(IPEDMA_REG_RESET, 0x1); - usleep(IPEDMA_RESET_DELAY); - WR(IPEDMA_REG_RESET, 0x0); - usleep(IPEDMA_RESET_DELAY); - - // Reseting configured DMA pages - if (ctx->version < 3) { - WR(IPEDMA_REG2_PAGE_COUNT, 0); - } - - usleep(IPEDMA_RESET_DELAY); + dma_ipe_disable(ctx); } // Clean buffers @@ -633,7 +647,7 @@ int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin size_t last_free; // We always keep 1 buffer free to distinguish between completely full and empty cases if (cur_read) last_free = cur_read - 1; - else last_free = IPEDMA_DMA_PAGES - 1; + else last_free = ctx->ring_size - 1; uintptr_t buf_ba = pcilib_kmem_get_block_ba(ctx->dmactx.pcilib, ctx->pages, last_free); if (ctx->version < 3) { @@ -651,7 +665,7 @@ int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uin // Numbered from 1 #ifdef IPEDMA_BUG_LAST_READ - WR(ctx->reg_last_read, cur_read?cur_read:IPEDMA_DMA_PAGES); + WR(ctx->reg_last_read, cur_read?cur_read:ctx->ring_size); #else /* IPEDMA_BUG_LAST_READ */ WR(ctx->reg_last_read, cur_read + 1); #endif /* IPEDMA_BUG_LAST_READ */ |