summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-14 06:01:27 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-14 06:01:27 +0200
commitf4ad2df2209acac66f3df47d847f1f714283feab (patch)
tree23da0368acbb6c15cdebd2a35808cd6bbe99b8ae
parentb492b1aac3d12683ccbc973b08b023ba0466cbec (diff)
downloadipecamera-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.c3
-rw-r--r--dma/nwl.c185
-rw-r--r--dma/nwl.h3
-rw-r--r--dma/nwl_buffers.h22
-rw-r--r--dma/nwl_engine.c42
-rw-r--r--dma/nwl_loopback.c173
-rw-r--r--dma/nwl_register.h4
-rw-r--r--driver/base.c2
-rw-r--r--driver/common.h5
-rw-r--r--driver/kmem.c56
-rw-r--r--driver/kmem.h1
-rw-r--r--driver/pciDriver.h2
-rw-r--r--driver/sysfs.c9
-rw-r--r--kmem.c27
-rw-r--r--kmem.h16
-rw-r--r--pci.c8
-rw-r--r--pcilib_types.h4
17 files changed, 347 insertions, 215 deletions
diff --git a/cli.c b/cli.c
index 00b2174..bd5a33a 100644
--- a/cli.c
+++ b/cli.c
@@ -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) {
diff --git a/dma/nwl.c b/dma/nwl.c
index efae205..6bb79c5 100644
--- a/dma/nwl.c
+++ b/dma/nwl.c
@@ -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", &regval);
- printf("Status1: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
- printf("Start address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
- printf("End address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
- printf("Status2: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
- printf("Status3: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
- 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", &regval);
- printf("Status1: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
- printf("Start address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
- printf("End address: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
- printf("Status2: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
- printf("Status3: %i 0x%lx\n", err, regval);
- err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
- 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.h b/dma/nwl.h
index 570b36e..7a04dfa 100644
--- a/dma/nwl.h
+++ b/dma/nwl.h
@@ -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", &regval);
+ printf("Status1: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
+ printf("Start address: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
+ printf("End address: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
+ printf("Status2: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
+ printf("Status3: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
+ 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", &regval);
+ printf("Status1: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9080", &regval);
+ printf("Start address: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9090", &regval);
+ printf("End address: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9100", &regval);
+ printf("Status2: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9110", &regval);
+ printf("Status3: %i 0x%lx\n", err, regval);
+ err = pcilib_read_register(ctx->pcilib, NULL, "reg9160", &regval);
+ 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
diff --git a/kmem.c b/kmem.c
index 10bd88c..df01591 100644
--- a/kmem.c
+++ b/kmem.c
@@ -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;
+}
diff --git a/kmem.h b/kmem.h
index a92d55a..b09424c 100644
--- a/kmem.h
+++ b/kmem.h
@@ -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 */
diff --git a/pci.c b/pci.c
index 3846235..d2d5843 100644
--- a/pci.c
+++ b/pci.c
@@ -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 {