diff options
| -rw-r--r-- | NOTES | 9 | ||||
| -rw-r--r-- | ToDo | 3 | ||||
| -rw-r--r-- | dma.c | 3 | ||||
| -rw-r--r-- | dma/nwl_buffers.h | 22 | ||||
| -rw-r--r-- | dma/nwl_engine.c | 2 | ||||
| -rw-r--r-- | driver/common.h | 2 | ||||
| -rw-r--r-- | driver/kmem.c | 36 | ||||
| -rw-r--r-- | kmem.c | 3 | 
8 files changed, 52 insertions, 28 deletions
| @@ -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: @@ -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?) @@ -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) { @@ -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"; | 
