summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 14:22:32 +0200
committerSuren A. Chilingaryan <csa@dside.dyndns.org>2011-07-17 14:22:32 +0200
commit06b3e35cc964d4735bd62d293b9d51f689545f97 (patch)
tree6011078f428ec1b3c2506643529c3d00cfd29c28
parentec5fd54c7559392139fa704a57185f4d4244dfde (diff)
downloadipecamera-06b3e35cc964d4735bd62d293b9d51f689545f97.tar.gz
ipecamera-06b3e35cc964d4735bd62d293b9d51f689545f97.tar.bz2
ipecamera-06b3e35cc964d4735bd62d293b9d51f689545f97.tar.xz
ipecamera-06b3e35cc964d4735bd62d293b9d51f689545f97.zip
Handle correctly reference counting in the driver
-rw-r--r--NOTES9
-rw-r--r--ToDo3
-rw-r--r--dma.c3
-rw-r--r--dma/nwl_buffers.h22
-rw-r--r--dma/nwl_engine.c2
-rw-r--r--driver/common.h2
-rw-r--r--driver/kmem.c36
-rw-r--r--kmem.c3
8 files changed, 52 insertions, 28 deletions
diff --git a/NOTES b/NOTES
index 4efca52..3f1eadb 100644
--- a/NOTES
+++ b/NOTES
@@ -1,3 +1,12 @@
+Memory Addressing
+=================
+ There is 3 types of addresses: virtual, physical, and bus. For DMA a bus
+ address is used. However, on x86 physical and bus addresses are the same (on
+ other architectures it is not guaranteed). Anyway, this assumption is still
+ used by xdma driver, it uses phiscal address for DMA access. I have ported
+ in the same way. Now, we need to provide additionaly bus-addresses in kmem
+ abstraction and use it in NWL DMA implementation.
+
DMA Access Synchronization
==========================
- At driver level, few types of buffers are supported:
diff --git a/ToDo b/ToDo
index ee40fd8..8a9eca0 100644
--- a/ToDo
+++ b/ToDo
@@ -9,7 +9,8 @@ Normal Priority (it would make just few things a bit easier)
1. Implement software registers (stored in kernel-memory)
2. Support FIFO reads/writes from/to registers
3. Provide OR and AND operations on registers in cli
-
+ 4. Use bus-addresses instead of physcial addresses for DMA
+
Low Priority (only as generalization for other projects)
============
1. XML configurations describing registers (and DMA engines?)
diff --git a/dma.c b/dma.c
index db7625c..7ae56f7 100644
--- a/dma.c
+++ b/dma.c
@@ -96,9 +96,6 @@ int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t f
return 0;
}
-
- printf("stop dma: %li\n", dma);
-
return ctx->model_info.dma_api->stop_dma(ctx->dma_ctx, dma, flags);
}
diff --git a/dma/nwl_buffers.h b/dma/nwl_buffers.h
index c298612..130c189 100644
--- a/dma/nwl_buffers.h
+++ b/dma/nwl_buffers.h
@@ -21,25 +21,27 @@ static int dma_nwl_compute_read_s2c_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_d
nwl_read_register(val, ctx, base, REG_SW_NEXT_BD);
if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_SW_NEXT_BD register out of range)");
+ if (val < ring_pa) pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%lx) is below start of ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
+ else pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
return PCILIB_ERROR_INVALID_STATE;
}
info->head = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
if (info->head >= PCILIB_NWL_DMA_PAGES) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_SW_NEXT_BD register out of range)");
+ pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu) out of range)", info->head);
return PCILIB_ERROR_INVALID_STATE;
}
nwl_read_register(val, ctx, base, REG_DMA_ENG_NEXT_BD);
if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register out of range)");
+ if (val < ring_pa) pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%lx) is below start of ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
+ else pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
return PCILIB_ERROR_INVALID_STATE;
}
info->tail = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
if (info->tail >= PCILIB_NWL_DMA_PAGES) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register out of range)");
+ pcilib_warning("Inconsistent S2C DMA Ring buffer is found (REG_DMA_ENG_NEXT_BD register value (%zu) out of range)", info->tail);
return PCILIB_ERROR_INVALID_STATE;
}
@@ -56,13 +58,14 @@ static int dma_nwl_compute_read_c2s_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_d
nwl_read_register(val, ctx, base, REG_SW_NEXT_BD);
if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_SW_NEXT_BD register out of range)");
+ if (val < ring_pa) pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%lx) is below start of the ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
+ else pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
return PCILIB_ERROR_INVALID_STATE;
}
info->head = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
if (info->head >= PCILIB_NWL_DMA_PAGES) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_SW_NEXT_BD register out of range)");
+ pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_SW_NEXT_BD register value (%zu) out of range)", info->head);
return PCILIB_ERROR_INVALID_STATE;
}
@@ -72,13 +75,14 @@ static int dma_nwl_compute_read_c2s_pointers(nwl_dma_t *ctx, pcilib_nwl_engine_d
// Last read BD
nwl_read_register(val, ctx, base, REG_DMA_ENG_LAST_BD);
if ((val < ring_pa)||((val - ring_pa) % PCILIB_NWL_DMA_DESCRIPTOR_SIZE)) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_DMA_ENG_LAST_BD register out of range)");
+ if (val < ring_pa) pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_DMA_ENG_LAST_BD register value (%lx) is below start of ring [%lx,%lx])", val, ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
+ else pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_DMA_ENG_LAST_BD register value (%zu / %u) is fractal)", val - ring_pa, PCILIB_NWL_DMA_DESCRIPTOR_SIZE);
return PCILIB_ERROR_INVALID_STATE;
}
prev = (val - ring_pa) / PCILIB_NWL_DMA_DESCRIPTOR_SIZE;
if (prev >= PCILIB_NWL_DMA_PAGES) {
- pcilib_warning("Inconsistent DMA Ring buffer is found (REG_DMA_ENG_LAST_BD register out of range)");
+ pcilib_warning("Inconsistent C2S DMA Ring buffer is found (REG_DMA_ENG_LAST_BD register value (%zu) out of range)", prev);
return PCILIB_ERROR_INVALID_STATE;
}
@@ -115,7 +119,7 @@ static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_des
if (info->pages) return 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;
+ sub_use = info->desc.addr|((info->desc.direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00);
flags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(info->preserve?PCILIB_KMEM_FLAG_PERSISTENT: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_RING, sub_use), flags);
diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c
index 68e1805..f5ca30e 100644
--- a/dma/nwl_engine.c
+++ b/dma/nwl_engine.c
@@ -202,8 +202,6 @@ int dma_nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_engine_t dma) {
flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT;
}
-
- printf("%lx %i\n", flags, info->preserve);
// Clean buffers
if (info->ring) {
pcilib_free_kernel_memory(ctx->pcilib, info->ring, flags);
diff --git a/driver/common.h b/driver/common.h
index b79d5ec..5787618 100644
--- a/driver/common.h
+++ b/driver/common.h
@@ -7,7 +7,7 @@
/* Private data types and structures */
#define KMEM_REF_HW 0x80000000 /**< Special reference to indicate hardware access */
-#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap) */
+#define KMEM_REF_COUNT 0x0FFFFFFF /**< Mask of reference counter (mmap/munmap), couting in mmaped memory pages */
#define KMEM_MODE_REUSABLE 0x80000000 /**< Indicates reusable buffer */
#define KMEM_MODE_EXCLUSIVE 0x40000000 /**< Only a single process is allowed to mmap the buffer */
diff --git a/driver/kmem.c b/driver/kmem.c
index a7180f8..90ae5ba 100644
--- a/driver/kmem.c
+++ b/driver/kmem.c
@@ -36,7 +36,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
void *retptr;
if (kmem_handle->flags&KMEM_FLAG_REUSE) {
-/* kmem_entry = pcidriver_kmem_find_entry_use(privdata, kmem_handle->use, kmem_handle->item);
+ kmem_entry = pcidriver_kmem_find_entry_use(privdata, kmem_handle->use, kmem_handle->item);
if (kmem_entry) {
unsigned long flags = kmem_handle->flags;
@@ -76,7 +76,7 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
privdata->kmem_cur_id = kmem_entry->id;
return 0;
- }*/
+ }
}
/* First, allocate zeroed memory for the kmem_entry */
@@ -165,7 +165,8 @@ int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
if ((kmem_entry = pcidriver_kmem_find_entry(privdata, kmem_handle)) == NULL)
return -EINVAL; /* kmem_handle is not valid */
- mod_info("1: %x %lx %lx\n", kmem_handle->flags, kmem_entry->refs, kmem_entry->mode);
+// if (kmem_entry->id == 0)
+// mod_info("1: %i %x %lx %lx\n", kmem_entry->id, kmem_handle->flags, kmem_entry->refs, kmem_entry->mode);
if (kmem_entry->mode&KMEM_MODE_COUNT)
kmem_entry->mode -= 1;
@@ -176,7 +177,8 @@ int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
if (kmem_handle->flags&KMEM_FLAG_PERSISTENT)
kmem_entry->mode &= ~KMEM_MODE_PERSISTENT;
- mod_info("2: %x %lx %lx\n", kmem_handle->flags, kmem_entry->refs, kmem_entry->mode);
+// if (kmem_entry->id == 0)
+// mod_info("2: %i %x %lx %lx\n", kmem_entry->id, kmem_handle->flags, kmem_entry->refs, kmem_entry->mode);
if (kmem_handle->flags&KMEM_FLAG_REUSE)
return 0;
@@ -196,7 +198,8 @@ int pcidriver_kmem_free( pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han
return 0;
- mod_info("cleaned %i\n", kmem_entry->id);
+// if (kmem_entry->id == 0)
+// mod_info("cleaned %i\n", kmem_entry->id);
return pcidriver_kmem_free_entry(privdata, kmem_entry);
}
@@ -424,8 +427,21 @@ pcidriver_kmem_entry_t *pcidriver_kmem_find_entry_use(pcidriver_privdata_t *priv
void pcidriver_kmem_mmap_close(struct vm_area_struct *vma) {
+ unsigned long vma_size;
pcidriver_kmem_entry_t *kmem_entry = (pcidriver_kmem_entry_t*)vma->vm_private_data;
- if (kmem_entry) kmem_entry->refs -= 1;
+ if (kmem_entry) {
+/*
+ if (kmem_entry->id == 0) {
+ mod_info("refs: %p %p %lx\n", vma, vma->vm_private_data, kmem_entry->refs);
+ mod_info("kmem_size: %lu vma_size: %lu, s: %lx, e: %lx\n", kmem_entry->size, (vma->vm_end - vma->vm_start), vma->vm_start, vma->vm_end);
+ }
+*/
+
+ vma_size = (vma->vm_end - vma->vm_start);
+
+ if (kmem_entry->refs&KMEM_REF_COUNT)
+ kmem_entry->refs -= vma_size / PAGE_SIZE;
+ }
}
static struct vm_operations_struct pcidriver_kmem_mmap_ops = {
@@ -458,7 +474,7 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v
/* Check sizes */
vma_size = (vma->vm_end - vma->vm_start);
- if ((vma_size != kmem_entry->size) &&
+ if ((vma_size > kmem_entry->size) &&
((kmem_entry->size < PAGE_SIZE) && (vma_size != PAGE_SIZE))) {
mod_info("kem_entry size(%lu) and vma size do not match(%lu)\n", kmem_entry->size, vma_size);
return -EINVAL;
@@ -469,11 +485,11 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v
mod_info("can't make second mmaping for exclusive kmem_entry\n");
return -EBUSY;
}
- if ((kmem_entry->refs&KMEM_REF_COUNT)==KMEM_REF_COUNT) {
+ if (((kmem_entry->refs&KMEM_REF_COUNT) + (vma_size / PAGE_SIZE)) > KMEM_REF_COUNT) {
mod_info("maximal amount of references is reached by kmem_entry\n");
return -EBUSY;
}
- kmem_entry->refs += 1;
+ kmem_entry->refs += vma_size / PAGE_SIZE;
vma->vm_flags |= (VM_RESERVED);
@@ -490,7 +506,7 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v
vma,
vma->vm_start,
kmem_entry->cpua,
- kmem_entry->size,
+ (vma_size < kmem_entry->size)?vma_size:kmem_entry->size,
vma->vm_page_prot );
if (ret) {
diff --git a/kmem.c b/kmem.c
index 5511b7a..0ad9b39 100644
--- a/kmem.c
+++ b/kmem.c
@@ -87,7 +87,6 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type
kh.size += alignment;
}
- printf("KMEM Flags: %lx\n", flags);
for ( i = 0; i < nmemb; i++) {
kh.item = i;
kh.flags = flags;
@@ -141,7 +140,7 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type
kbuf->buf.blocks[i].size -= alignment;
}
- addr = mmap( 0, kh.size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 );
+ addr = mmap( 0, kbuf->buf.blocks[i].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;
error = "Failed to mmap allocated kernel memory";