diff options
author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-07-14 06:01:27 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2011-07-14 06:01:27 +0200 |
commit | f4ad2df2209acac66f3df47d847f1f714283feab (patch) | |
tree | 23da0368acbb6c15cdebd2a35808cd6bbe99b8ae | |
parent | b492b1aac3d12683ccbc973b08b023ba0466cbec (diff) | |
download | ipecamera-f4ad2df2209acac66f3df47d847f1f714283feab.tar.gz ipecamera-f4ad2df2209acac66f3df47d847f1f714283feab.tar.bz2 ipecamera-f4ad2df2209acac66f3df47d847f1f714283feab.tar.xz ipecamera-f4ad2df2209acac66f3df47d847f1f714283feab.zip |
First iteration of work to preserve DMA state between executions
-rw-r--r-- | cli.c | 3 | ||||
-rw-r--r-- | dma/nwl.c | 185 | ||||
-rw-r--r-- | dma/nwl.h | 3 | ||||
-rw-r--r-- | dma/nwl_buffers.h | 22 | ||||
-rw-r--r-- | dma/nwl_engine.c | 42 | ||||
-rw-r--r-- | dma/nwl_loopback.c | 173 | ||||
-rw-r--r-- | dma/nwl_register.h | 4 | ||||
-rw-r--r-- | driver/base.c | 2 | ||||
-rw-r--r-- | driver/common.h | 5 | ||||
-rw-r--r-- | driver/kmem.c | 56 | ||||
-rw-r--r-- | driver/kmem.h | 1 | ||||
-rw-r--r-- | driver/pciDriver.h | 2 | ||||
-rw-r--r-- | driver/sysfs.c | 9 | ||||
-rw-r--r-- | kmem.c | 27 | ||||
-rw-r--r-- | kmem.h | 16 | ||||
-rw-r--r-- | pci.c | 8 | ||||
-rw-r--r-- | pcilib_types.h | 4 |
17 files changed, 347 insertions, 215 deletions
@@ -146,6 +146,7 @@ void Usage(int argc, char *argv[], const char *format, ...) { " --start-dma <num>[r|w] - Start specified DMA engine\n" " --stop-dma [num][r|w] - Stop specified engine or DMA subsystem\n" " --wait-irq <source> - Wait for IRQ\n" +" --clean-kernel-memory - Cleans lost kernel space buffers (DANGEROUS)\n" "\n" " Addressing:\n" " -d <device> - FPGA device (/dev/fpga0)\n" @@ -334,7 +335,7 @@ void Info(pcilib_t *handle, pcilib_model_description_t *model_info) { } -#define BENCH_MAX_DMA_SIZE 16 * 1024 * 1024 +#define BENCH_MAX_DMA_SIZE 4 * 1024 * 1024 #define BENCH_MAX_FIFO_SIZE 1024 * 1024 int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, size_t iterations) { @@ -1,6 +1,5 @@ #define _PCILIB_DMA_NWL_C #define _BSD_SOURCE -//#define DEBUG_HARDWARE #include <stdio.h> #include <stdlib.h> @@ -47,10 +46,9 @@ int dma_nwl_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma } if (ctx->engines[dma].preserve) preserving = 1; - else { - err = dma_nwl_stop_engine(ctx, dma); - if (err) return err; - } + + err = dma_nwl_stop_engine(ctx, dma); + if (err) return err; } // global cleanup, should we do anything? @@ -68,9 +66,6 @@ int dma_nwl_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma ctx->engines[dma].preserve = 0; } - // Do not close DMA if preservation mode is set - if (ctx->engines[dma].preserve) return 0; - return dma_nwl_stop_engine(ctx, dma); } @@ -138,177 +133,3 @@ void dma_nwl_free(pcilib_dma_context_t *vctx) { free(ctx); } } - - -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; - int err; - size_t bytes; - uint32_t val; - uint32_t *buf, *cmp; - const char *error = NULL; - pcilib_register_value_t regval; - - size_t us = 0; - struct timeval start, cur; - - nwl_dma_t *ctx = (nwl_dma_t*)vctx; - - 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); - - // Not supported - if (direction == PCILIB_DMA_TO_DEVICE) return -1.; - else if ((direction == PCILIB_DMA_FROM_DEVICE)&&(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) return -1.; - - // Stop Generators and drain old data - if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); -// dma_nwl_stop_engine(ctx, readid); // DS: replace with something better - - __sync_synchronize(); - - err = pcilib_skip_dma(ctx->pcilib, readid); - if (err) { - pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine"); - return err; - } - -#ifdef NWL_GENERATE_DMA_IRQ - dma_nwl_enable_engine_irq(ctx, readid); - dma_nwl_enable_engine_irq(ctx, writeid); -#endif /* NWL_GENERATE_DMA_IRQ */ - - - if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) { - dma_nwl_start_loopback(ctx, direction, size * sizeof(uint32_t)); - } - - // Allocate memory and prepare data - buf = malloc(size * sizeof(uint32_t)); - cmp = malloc(size * sizeof(uint32_t)); - if ((!buf)||(!cmp)) { - if (buf) free(buf); - if (cmp) free(cmp); - return -1; - } - - memset(cmp, 0x13, size * sizeof(uint32_t)); - - -#ifdef DEBUG_HARDWARE - if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { - pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e5); - usleep(100000); - pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); - } -#endif /* DEBUG_HARDWARE */ - - // Benchmark - for (i = 0; i < iterations; i++) { -#ifdef DEBUG_HARDWARE - if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { - pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); - } -#endif /* DEBUG_HARDWARE */ - - gettimeofday(&start, NULL); - if (direction&PCILIB_DMA_TO_DEVICE) { - memcpy(buf, cmp, size * sizeof(uint32_t)); - - err = pcilib_write_dma(ctx->pcilib, writeid, addr, size * sizeof(uint32_t), buf, &bytes); - if ((err)||(bytes != size * sizeof(uint32_t))) { - error = "Write failed"; - break; - } - } - -#ifdef DEBUG_HARDWARE - if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { - //usleep(1000000); - pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1); - } - - memset(buf, 0, size * sizeof(uint32_t)); -#endif /* DEBUG_HARDWARE */ - - err = pcilib_read_dma(ctx->pcilib, readid, addr, size * sizeof(uint32_t), buf, &bytes); - gettimeofday(&cur, NULL); - us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)); - - if ((err)||(bytes != size * sizeof(uint32_t))) { - error = "Read failed"; - break; - } - - if (direction == PCILIB_DMA_BIDIRECTIONAL) { - res = memcmp(buf, cmp, size * sizeof(uint32_t)); - if (res) { - error = "Written and read values does not match"; - break; - } - } - -#ifdef DEBUG_HARDWARE - puts("===================================="); - - err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); - printf("Status1: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); - printf("Start address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); - printf("End address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); - printf("Status2: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); - printf("Status3: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); - printf("Add_rd_ddr: %i 0x%lx\n", err, regval); -#endif /* DEBUG_HARDWARE */ - - } - -#ifdef DEBUG_HARDWARE - puts("------------------------------------------------"); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); - printf("Status1: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); - printf("Start address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); - printf("End address: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); - printf("Status2: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); - printf("Status3: %i 0x%lx\n", err, regval); - err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); - printf("Add_rd_ddr: %i 0x%lx\n", err, regval); -#endif /* DEBUG_HARDWARE */ - - if (error) { - pcilib_warning("%s at iteration %i, error: %i, bytes: %zu", error, i, err, bytes); - } - -#ifdef NWL_GENERATE_DMA_IRQ - dma_nwl_disable_engine_irq(ctx, writeid); - dma_nwl_disable_engine_irq(ctx, readid); -#endif /* NWL_GENERATE_DMA_IRQ */ - - if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); - - __sync_synchronize(); - - if (direction == PCILIB_DMA_FROM_DEVICE) { - pcilib_skip_dma(ctx->pcilib, readid); - } - - free(cmp); - free(buf); - - return error?-1:(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us); -} @@ -15,6 +15,9 @@ typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t; #define PCILIB_NWL_DMA_DESCRIPTOR_SIZE 64 // in bytes #define PCILIB_NWL_DMA_PAGES 512 // 1024 +//#define DEBUG_HARDWARE + + #include "nwl_dma.h" #include "nwl_irq.h" #include "nwl_register.h" diff --git a/dma/nwl_buffers.h b/dma/nwl_buffers.h index 565eccf..e0df2d0 100644 --- a/dma/nwl_buffers.h +++ b/dma/nwl_buffers.h @@ -17,26 +17,36 @@ int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_descriptio int err = 0; int i; + uint16_t sub_use; uint32_t val; uint32_t buf_sz; uint64_t buf_pa; + pcilib_kmem_reuse_t reuse_ring, reuse_pages; char *base = info->base_addr; if (info->pages) return 0; - - 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, info->desc.addr), 0); - pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_PAGE, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA, info->desc.addr), 0); + + // Or bidirectional specified by 0x0|addr, or read 0x0|addr and write 0x80|addr + sub_use = info->desc.addr|(info->desc.direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00; + 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), PCILIB_KMEM_FLAG_REUSE); + pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_PAGE, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, sub_use), PCILIB_KMEM_FLAG_REUSE); if ((ring)&&(pages)) err = dma_nwl_sync_buffers(ctx, info, pages); else err = PCILIB_ERROR_FAILED; - if (err) { - if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages); - if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring); + if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0); + if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring, 0); return err; } + +/* + reuse_ring = pcilib_kmem_is_reused(ctx->pcilib, ring); + reuse_pages = pcilib_kmem_is_reused(ctx->pcilib, pages); + if ((reuse_ring == PCILIB_KMEM_REUSE_REUSED)&&(reuse_pages == PCILIB_KMEM_REUSE_REUSED)) info->preserve = 1; + else if (reuse_ring||reuse_pages) pcilib_warning("Inconsistent buffers in the kernel module are detected"); +*/ unsigned char *data = (unsigned char*)pcilib_kmem_get_ua(ctx->pcilib, ring); uint32_t ring_pa = pcilib_kmem_get_pa(ctx->pcilib, ring); diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index 11137b9..59e9b93 100644 --- a/dma/nwl_engine.c +++ b/dma/nwl_engine.c @@ -65,6 +65,24 @@ int dma_nwl_start_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { if (info->started) return 0; + // This will only successed if there are no parallel access to DMA engine + err = dma_nwl_allocate_engine_buffers(ctx, info); + if (err) return err; + + // Check if DMA engine is enabled + nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS); + if (val&DMA_ENG_RUNNING) { +// info->preserve = 1; + + // We need to positionate buffers correctly (both read and write) + //DSS info->tail, info->head + +// pcilib_error("Not implemented"); + +// info->started = 1; +// return 0; + } + // Disable IRQs err = dma_nwl_disable_engine_irq(ctx, dma); if (err) return err; @@ -104,9 +122,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_allocate_engine_buffers(ctx, info); - if (err) return err; - ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring); nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD); nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD); @@ -154,13 +169,16 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { err = dma_nwl_disable_engine_irq(ctx, dma); if (err) return err; - val = DMA_ENG_DISABLE; - nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); + if (!info->preserve) { + // Stopping DMA is not enough reset is required + val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET|DMA_ENG_RESET; + nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS); - if (info->ring) { - ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring); - nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD); - nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD); + if (info->ring) { + ring_pa = pcilib_kmem_get_pa(ctx->pcilib, info->ring); + nwl_write_register(ring_pa, ctx, info->base_addr, REG_DMA_ENG_NEXT_BD); + nwl_write_register(ring_pa, ctx, info->base_addr, REG_SW_NEXT_BD); + } } // Acknowledge asserted engine interrupts @@ -171,15 +189,17 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) { // Clean buffers if (info->ring) { - pcilib_free_kernel_memory(ctx->pcilib, info->ring); + pcilib_free_kernel_memory(ctx->pcilib, info->ring, info->preserve?PCILIB_KMEM_FLAG_REUSE:0); info->ring = NULL; } if (info->pages) { - pcilib_free_kernel_memory(ctx->pcilib, info->pages); + pcilib_free_kernel_memory(ctx->pcilib, info->pages, info->preserve?PCILIB_KMEM_FLAG_REUSE:0); info->pages = NULL; } + nwl_read_register(val, ctx, info->base_addr, REG_DMA_ENG_CTRL_STATUS); + return 0; } diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c index a31bd08..3c2c124 100644 --- a/dma/nwl_loopback.c +++ b/dma/nwl_loopback.c @@ -52,3 +52,176 @@ int dma_nwl_stop_loopback(nwl_dma_t *ctx) { return 0; } + +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; + int err; + size_t bytes; + uint32_t val; + uint32_t *buf, *cmp; + const char *error = NULL; + pcilib_register_value_t regval; + + size_t us = 0; + struct timeval start, cur; + + nwl_dma_t *ctx = (nwl_dma_t*)vctx; + + 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); + + // Not supported + if (direction == PCILIB_DMA_TO_DEVICE) return -1.; + else if ((direction == PCILIB_DMA_FROM_DEVICE)&&(ctx->type != PCILIB_DMA_MODIFICATION_DEFAULT)) return -1.; + + // Stop Generators and drain old data + if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); +// dma_nwl_stop_engine(ctx, readid); // DS: replace with something better + + __sync_synchronize(); + + err = pcilib_skip_dma(ctx->pcilib, readid); + if (err) { + pcilib_error("Can't start benchmark, devices continuously writes unexpected data using DMA engine"); + return err; + } + +#ifdef NWL_GENERATE_DMA_IRQ + dma_nwl_enable_engine_irq(ctx, readid); + dma_nwl_enable_engine_irq(ctx, writeid); +#endif /* NWL_GENERATE_DMA_IRQ */ + + + if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) { + dma_nwl_start_loopback(ctx, direction, size * sizeof(uint32_t)); + } + + // Allocate memory and prepare data + buf = malloc(size * sizeof(uint32_t)); + cmp = malloc(size * sizeof(uint32_t)); + if ((!buf)||(!cmp)) { + if (buf) free(buf); + if (cmp) free(cmp); + return -1; + } + + memset(cmp, 0x13, size * sizeof(uint32_t)); + + +#ifdef DEBUG_HARDWARE + if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { + pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e5); + usleep(100000); + pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); + } +#endif /* DEBUG_HARDWARE */ + + // Benchmark + for (i = 0; i < iterations; i++) { +#ifdef DEBUG_HARDWARE + if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { + pcilib_write_register(ctx->pcilib, NULL, "control", 0x1e1); + } +#endif /* DEBUG_HARDWARE */ + + gettimeofday(&start, NULL); + if (direction&PCILIB_DMA_TO_DEVICE) { + memcpy(buf, cmp, size * sizeof(uint32_t)); + + err = pcilib_write_dma(ctx->pcilib, writeid, addr, size * sizeof(uint32_t), buf, &bytes); + if ((err)||(bytes != size * sizeof(uint32_t))) { + error = "Write failed"; + break; + } + } + +#ifdef DEBUG_HARDWARE + if (ctx->type == PCILIB_NWL_MODIFICATION_IPECAMERA) { + //usleep(1000000); + pcilib_write_register(ctx->pcilib, NULL, "control", 0x3e1); + } + + memset(buf, 0, size * sizeof(uint32_t)); +#endif /* DEBUG_HARDWARE */ + + err = pcilib_read_dma(ctx->pcilib, readid, addr, size * sizeof(uint32_t), buf, &bytes); + gettimeofday(&cur, NULL); + us += ((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)); + + if ((err)||(bytes != size * sizeof(uint32_t))) { + error = "Read failed"; + break; + } + + if (direction == PCILIB_DMA_BIDIRECTIONAL) { + res = memcmp(buf, cmp, size * sizeof(uint32_t)); + if (res) { + error = "Written and read values does not match"; + break; + } + } + +#ifdef DEBUG_HARDWARE + puts("===================================="); + + err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); + printf("Status1: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); + printf("Start address: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); + printf("End address: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); + printf("Status2: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); + printf("Status3: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); + printf("Add_rd_ddr: %i 0x%lx\n", err, regval); +#endif /* DEBUG_HARDWARE */ + + } + +#ifdef DEBUG_HARDWARE + puts("------------------------------------------------"); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9050", ®val); + printf("Status1: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", ®val); + printf("Start address: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", ®val); + printf("End address: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", ®val); + printf("Status2: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", ®val); + printf("Status3: %i 0x%lx\n", err, regval); + err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", ®val); + printf("Add_rd_ddr: %i 0x%lx\n", err, regval); +#endif /* DEBUG_HARDWARE */ + + if (error) { + pcilib_warning("%s at iteration %i, error: %i, bytes: %zu", error, i, err, bytes); + } + +#ifdef NWL_GENERATE_DMA_IRQ + dma_nwl_disable_engine_irq(ctx, writeid); + dma_nwl_disable_engine_irq(ctx, readid); +#endif /* NWL_GENERATE_DMA_IRQ */ + + if (ctx->type == PCILIB_DMA_MODIFICATION_DEFAULT) dma_nwl_stop_loopback(ctx); + + __sync_synchronize(); + + if (direction == PCILIB_DMA_FROM_DEVICE) { + pcilib_skip_dma(ctx->pcilib, readid); + } + + free(cmp); + free(buf); + + return error?-1:(1. * size * sizeof(uint32_t) * iterations * 1000000) / (1024. * 1024. * us); +} diff --git a/dma/nwl_register.h b/dma/nwl_register.h index df479e9..926f093 100644 --- a/dma/nwl_register.h +++ b/dma/nwl_register.h @@ -56,8 +56,8 @@ static pcilib_register_description_t nwl_dma_engine_registers[] = { {0x0004, 4, 1, 0, 0x0000C100, PCILIB_REGISTER_RW1C, PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_descriptor_fetch_error", ""}, {0x0004, 5, 1, 0, 0x0000C100, PCILIB_REGISTER_RW1C, PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_sw_abort_error", ""}, {0x0004, 8, 1, 0, 0x0000C100, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_enable", ""}, - {0x0004, 9, 1, 0, 0x0000C100, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_running", ""}, - {0x0004, 10, 1, 0, 0x0000C100, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_waiting", ""}, + {0x0004, 10, 1, 0, 0x0000C100, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_running", ""}, + {0x0004, 11, 1, 0, 0x0000C100, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_waiting", ""}, {0x0004, 14, 1, 0, 0x0000C100, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_reset_request", ""}, {0x0004, 15, 1, 0, 0x0000C100, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_reset", ""}, {0x0008, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dma%0*u%s_next_descriptor", ""}, diff --git a/driver/base.c b/driver/base.c index 2c3ff23..37102d8 100644 --- a/driver/base.c +++ b/driver/base.c @@ -352,6 +352,8 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi INIT_LIST_HEAD(&(privdata->kmem_list)); spin_lock_init(&(privdata->kmemlist_lock)); atomic_set(&privdata->kmem_count, 0); + + privdata->kmem_cur = NULL; INIT_LIST_HEAD(&(privdata->umem_list)); spin_lock_init(&(privdata->umemlist_lock)); diff --git a/driver/common.h b/driver/common.h index 3bc27d8..e45ae25 100644 --- a/driver/common.h +++ b/driver/common.h @@ -16,6 +16,7 @@ typedef struct { unsigned long size; unsigned long type; unsigned long use; + unsigned long item; struct class_device_attribute sysfs_attr; /* initialized when adding the entry */ } pcidriver_kmem_entry_t; @@ -56,11 +57,13 @@ typedef struct { struct list_head kmem_list; /* List of 'kmem_list_entry's associated with this device */ atomic_t kmem_count; /* id for next kmem entry */ + pcidriver_kmem_entry_t *kmem_cur; /* Currently selected kmem buffer, for mmap */ + spinlock_t umemlist_lock; /* Spinlock to lock umem list operations */ 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; + int msi_mode; /* Flag specifying if interrupt have been initialized in MSI mode */ } pcidriver_privdata_t; diff --git a/driver/kmem.c b/driver/kmem.c index 95a5487..ed2a2af 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -35,6 +35,26 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han pcidriver_kmem_entry_t *kmem_entry; void *retptr; + privdata->kmem_cur = NULL; + + if (kmem_handle->reuse) { +/* kmem_entry = pcidriver_kmem_find_entry_use(privdata, kmem_handle->use, kmem_handle->item); + if (kmem_entry) { + if (kmem_handle->type != kmem_entry->type) return EINVAL; + + if (kmem_handle->type == PCILIB_KMEM_TYPE_PAGE) kmem_handle->size = kmem_entry->size; + else if (kmem_handle->size != kmem_entry->size) return EINVAL; + + kmem_handle->handle_id = kmem_entry->id; + kmem_handle->pa = (unsigned long)(kmem_entry->dma_handle); + + privdata->kmem_cur = kmem_entry; + + return 0; + }*/ + kmem_handle->reuse = 0; + } + /* First, allocate zeroed memory for the kmem_entry */ if ((kmem_entry = kcalloc(1, sizeof(pcidriver_kmem_entry_t), GFP_KERNEL)) == NULL) goto kmem_alloc_entry_fail; @@ -42,6 +62,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han /* Initialize the kmem_entry */ kmem_entry->id = atomic_inc_return(&privdata->kmem_count) - 1; kmem_entry->use = kmem_handle->use; + kmem_entry->item = kmem_handle->item; kmem_entry->type = kmem_handle->type; kmem_handle->handle_id = kmem_entry->id; @@ -102,6 +123,11 @@ int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han { pcidriver_kmem_entry_t *kmem_entry; + if (kmem_handle->reuse) { + // just mark free + return 0; + } + /* Find the associated kmem_entry for this buffer */ if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL) return -EINVAL; /* kmem_handle is not valid */ @@ -193,6 +219,8 @@ int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync */ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry) { + privdata->kmem_cur = NULL; + pcidriver_sysfs_remove(privdata, &(kmem_entry->sysfs_attr)); /* Go over the pages of the kmem buffer, and mark them as not reserved */ @@ -299,6 +327,31 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id(pcidriver_privdata_t *privd /** * + * find the corresponding kmem_entry for the given use and item. + * + */ +pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_use(pcidriver_privdata_t *privdata, unsigned long use, unsigned long item) +{ + struct list_head *ptr; + pcidriver_kmem_entry_t *entry, *result = NULL; + + spin_lock(&(privdata->kmemlist_lock)); + list_for_each(ptr, &(privdata->kmem_list)) { + entry = list_entry(ptr, pcidriver_kmem_entry_t, list); + + if ((entry->use == use)&&(entry->item == item)) { + result = entry; + break; + } + } + + spin_unlock(&(privdata->kmemlist_lock)); + return result; +} + + +/** + * * mmap() kernel memory to userspace. * */ @@ -318,7 +371,8 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v mod_info("Trying to mmap a kernel memory buffer without creating it first!\n"); return -EFAULT; } - kmem_entry = list_entry(privdata->kmem_list.prev, pcidriver_kmem_entry_t, list); + if (privdata->kmem_cur) kmem_entry = privdata->kmem_cur; + else kmem_entry = list_entry(privdata->kmem_list.prev, pcidriver_kmem_entry_t, list); spin_unlock(&(privdata->kmemlist_lock)); mod_info_dbg("Got kmem_entry with id: %d\n", kmem_entry->id); diff --git a/driver/kmem.h b/driver/kmem.h index c9e2fb9..ee12855 100644 --- a/driver/kmem.h +++ b/driver/kmem.h @@ -4,4 +4,5 @@ int pcidriver_kmem_sync( pcidriver_privdata_t *privdata, kmem_sync_t *kmem_sync int pcidriver_kmem_free_all( pcidriver_privdata_t *privdata ); pcidriver_kmem_entry_t *pcidriver_kmem_find_entry( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_handle ); pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_id( pcidriver_privdata_t *privdata, int id ); +pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_use(pcidriver_privdata_t *privdata, unsigned long use, unsigned long item); int pcidriver_kmem_free_entry( pcidriver_privdata_t *privdata, pcidriver_kmem_entry_t *kmem_entry ); diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 74eacaf..3ff3357 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -106,6 +106,8 @@ typedef struct { unsigned long size; unsigned long align; unsigned long use; + unsigned long item; + int reuse; int handle_id; } kmem_handle_t; diff --git a/driver/sysfs.c b/driver/sysfs.c index b082d3c..0653aef 100644 --- a/driver/sysfs.c +++ b/driver/sysfs.c @@ -90,14 +90,17 @@ void pcidriver_sysfs_remove(pcidriver_privdata_t *privdata, struct class_device_ static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) { #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,13) -// pcidriver_privdata_t *privdata = (pcidriver_privdata_t *)cls->class_data; + pcidriver_privdata_t *privdata = SYSFS_GET_PRIVDATA; /* As we can be sure that attr.name contains a filename which we * created (see _pcidriver_sysfs_initialize), we do not need to have * sanity checks but can directly call simple_strtol() */ int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); - - return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); + pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); + if (entry) + return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lu\nuse: 0x%lx\nitem: %lu\nsize: %lu\n", id, entry->type, entry->use, entry->item, entry->size); + else + return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); #else return 0; #endif @@ -21,6 +21,8 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type int ret; int i; void *addr; + + pcilib_kmem_reuse_t reuse = PCILIB_KMEM_REUSE_ALLOCATED; kmem_handle_t kh = {0}; @@ -49,10 +51,13 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type } for ( i = 0; i < nmemb; i++) { + kh.item = i; + kh.reuse = PCILIB_KMEM_FLAG_REUSE?1:0; + ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh); if (ret) { kbuf->buf.n_blocks = i; - pcilib_free_kernel_memory(ctx, kbuf); + pcilib_free_kernel_memory(ctx, kbuf, 0); pcilib_error("PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed"); return NULL; } @@ -60,6 +65,15 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type kbuf->buf.blocks[i].handle_id = kh.handle_id; kbuf->buf.blocks[i].pa = kh.pa; kbuf->buf.blocks[i].size = kh.size; + kbuf->buf.blocks[i].reused = kh.reuse; + + if (reuse) { + // if already reused, set to partial + if (!kh.reuse) reuse = PCILIB_KMEM_REUSE_PARTIAL; + } else if (kh.reuse) { + if (i) reuse = PCILIB_KMEM_REUSE_PARTIAL; + else reuse = PCILIB_KMEM_REUSE_REUSED; + } if ((alignment)&&(type != PCILIB_KMEM_TYPE_PAGE)) { if (kh.pa % alignment) kbuf->buf.blocks[i].alignment_offset = alignment - kh.pa % alignment; @@ -69,7 +83,7 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type addr = mmap( 0, kh.size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 ); if ((!addr)||(addr == MAP_FAILED)) { kbuf->buf.n_blocks = i + 1; - pcilib_free_kernel_memory(ctx, kbuf); + pcilib_free_kernel_memory(ctx, kbuf, 0); pcilib_error("Failed to mmap allocated kernel memory"); return NULL; } @@ -83,6 +97,7 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t)); } + kbuf->buf.reuse = reuse; kbuf->buf.n_blocks = nmemb; kbuf->prev = NULL; @@ -93,7 +108,7 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type return (pcilib_kmem_handle_t*)kbuf; } -void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k) { +void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags) { int ret, err = 0; int i; kmem_handle_t kh = {0}; @@ -109,6 +124,7 @@ void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k) { kh.handle_id = kbuf->buf.blocks[i].handle_id; kh.pa = kbuf->buf.blocks[i].pa; + kh.reuse = ((flags&PCILIB_KMEM_FLAG_REUSE)||(kbuf->buf.blocks[i].reused)); ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); if ((ret)&&(!err)) err = ret; } @@ -170,3 +186,8 @@ size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; return kbuf->buf.blocks[block].size; } + +pcilib_kmem_reuse_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k) { + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + return kbuf->buf.reuse; +} @@ -3,10 +3,20 @@ #include "pcilib.h" -typedef int pcilib_kmem_flags_t; +typedef enum { + PCILIB_KMEM_FLAG_REUSE = 1, /**< Try to reuse buffers on alloc and only unmap non-reused buffers on free (reused are freed only if FORCE flag is specified) */ +// PCILIB_KMEM_FLAG_FORCE = 2 /**< Force buffer +} pcilib_kmem_flags_t; + +typedef enum { + PCILIB_KMEM_REUSE_ALLOCATED = 0, + PCILIB_KMEM_REUSE_PARTIAL = 1, + PCILIB_KMEM_REUSE_REUSED = 2 +} pcilib_kmem_reuse_t; typedef struct { int handle_id; + int reused; uintptr_t pa; // uintptr_t va; void *ua; @@ -23,6 +33,7 @@ typedef struct { */ typedef struct { pcilib_kmem_addr_t addr; + pcilib_kmem_reuse_t reuse; size_t n_blocks; pcilib_kmem_addr_t blocks[]; @@ -39,12 +50,13 @@ struct pcilib_kmem_list_s { }; pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags); -void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k); +void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags); int pcilib_sync_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir); void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k); uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k); void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); +pcilib_kmem_reuse_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k); #endif /* _PCILIB_KMEM_H */ @@ -401,8 +401,12 @@ void pcilib_close(pcilib_t *ctx) { ctx->model_info.registers = pcilib_model[ctx->model].registers; } - while (ctx->kmem_list) { - pcilib_free_kernel_memory(ctx, ctx->kmem_list); + if (ctx->kmem_list) { + pcilib_warning("Not all kernel buffers are properly cleaned"); + + while (ctx->kmem_list) { + pcilib_free_kernel_memory(ctx, ctx->kmem_list, 0); + } } for (i = 0; i < PCILIB_MAX_BANKS; i++) { diff --git a/pcilib_types.h b/pcilib_types.h index f8c1c79..237f1db 100644 --- a/pcilib_types.h +++ b/pcilib_types.h @@ -7,7 +7,9 @@ typedef enum { } pcilib_kmem_type_t; typedef enum { - PCILIB_KMEM_USE_DMA = 1, + PCILIB_KMEM_USE_STANDARD = 0, + PCILIB_KMEM_USE_DMA_RING = 1, + PCILIB_KMEM_USE_DMA_PAGES = 2 } pcilib_kmem_use_t; typedef enum { |