diff options
| -rw-r--r-- | .bzrignore | 5 | ||||
| -rw-r--r-- | apps/xilinx.c | 76 | ||||
| -rw-r--r-- | driver/kmem.c | 43 | ||||
| -rw-r--r-- | ipecamera/ipecamera.c | 31 | ||||
| -rw-r--r-- | kmem.c | 10 | ||||
| -rw-r--r-- | pci.c | 2 | ||||
| -rw-r--r-- | pci.h | 1 | ||||
| -rw-r--r-- | pcilib_types.h | 5 | ||||
| -rwxr-xr-x | tests/dma/xilinx/xilinx_dma_static_mem.sh | 117 | 
9 files changed, 254 insertions, 36 deletions
| @@ -18,9 +18,8 @@ cmake_install.cmake  Makefile  *.so.*  install_manifest.txt -./xilinx +apps/xilinx  apps/pio_test  apps/compare_to_value -*.out -apps/xilinx  apps/heb_strip_bad_values +*.out diff --git a/apps/xilinx.c b/apps/xilinx.c index 1ec31d7..757c388 100644 --- a/apps/xilinx.c +++ b/apps/xilinx.c @@ -2,6 +2,7 @@  #define _POSIX_C_SOURCE 199309L  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <unistd.h>  #include <stdarg.h>  #include <time.h> @@ -15,23 +16,27 @@  #define DEVICE "/dev/fpga0"  #define BAR PCILIB_BAR0  #define USE PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 1) -#define BUFFERS 16 -#define ITERATIONS 16384 +#define STATIC_REGION 0x80000000 //  to reserve 512 MB at the specified address, add "memmap=512M$2G" to kernel parameters +#define BUFFERS 1 +#define ITERATIONS 100 +#define TLP_SIZE 64 +#define HUGE_PAGE 4096	// number of pages per huge page  #define PAGE_SIZE 4096	// other values are not supported in the kernel  #define TIMEOUT 100000  /* IRQs are slow for some reason. REALTIME mode is slower. Adding delays does not really help,  otherall we have only 3 checks in average. Check ready seems to be not needed and adds quite   much extra time */ -//#define USE_IRQ +#define USE_IRQ  //#define CHECK_READY  //#define REALTIME  //#define ADD_DELAYS +#define CHECK_RESULT  //#define WR(addr, value) { val = value; pcilib_write(pci, BAR, addr, sizeof(val), &val); }  //#define RD(addr, value) { pcilib_read(pci, BAR, addr, sizeof(val), &val); value = val; } -#define WR(addr, value) { *(uint32_t*)(bar + addr) = value; } -#define RD(addr, value) { value = *(uint32_t*)(bar + addr); } +#define WR(addr, value) { *(uint32_t*)(bar + addr + offset) = value; } +#define RD(addr, value) { value = *(uint32_t*)(bar + addr + offset); }  static void fail(const char *msg, ...) {      va_list va; @@ -63,7 +68,7 @@ void hpsleep(size_t ns) {  int main() {      int err; -    int i, j; +    long i, j;      pcilib_t *pci;      pcilib_kmem_handle_t *kbuf;      uint32_t status; @@ -72,12 +77,15 @@ int main() {      void* volatile bar;      uintptr_t bus_addr[BUFFERS]; +    pcilib_bar_t bar_tmp = BAR;  +    uintptr_t offset = 0; +      pcilib_kmem_flags_t clean_flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT|PCILIB_KMEM_FLAG_EXCLUSIVE;  #ifdef ADD_DELAYS      long rpt = 0, rpt2 = 0;      size_t best_time; -    best_time = 1000000000L * PAGE_SIZE / (4L * 1024 * 1024 * 1024); +    best_time = 1000000000L * HUGE_PAGE * PAGE_SIZE / (4L * 1024 * 1024 * 1024);  #endif /* ADD_DELAYS */  #ifdef REALTIME @@ -99,22 +107,46 @@ int main() {  	fail("map bar");      } +    pcilib_detect_address(pci, &bar_tmp, &offset, 1); + +	// Reset +    WR(0x00, 1) +    usleep(1000); +    WR(0x00, 0) +      pcilib_enable_irq(pci, PCILIB_IRQ_TYPE_ALL, 0);      pcilib_clear_irq(pci, PCILIB_IRQ_SOURCE_DEFAULT);      pcilib_clean_kernel_memory(pci, USE, clean_flags); +#ifdef STATIC_REGION +    kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_REGION_C2S, BUFFERS, HUGE_PAGE * PAGE_SIZE, STATIC_REGION, USE, 0); +#else /* STATIC_REGION */ +    kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, BUFFERS, HUGE_PAGE * PAGE_SIZE, 4096, USE, 0); +#endif /* STATIC_REGION */ -    kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, BUFFERS, PAGE_SIZE, 4096, USE, 0); +    if (!kbuf) { +	printf("KMem allocation failed\n"); +	exit(0); +    } + + +#ifdef CHECK_RESULT     +    volatile uint32_t *ptr0 = pcilib_kmem_get_block_ua(pci, kbuf, 0); +    memset((void*)ptr0, 0, (HUGE_PAGE * PAGE_SIZE)); -    WR(0x00, 1) -    usleep(1000); -    WR(0x00, 0) +    for (i = 0; i < (HUGE_PAGE * PAGE_SIZE / 4); i++) { +	if (ptr0[i] != 0) break; +    } +    if (i < (HUGE_PAGE * PAGE_SIZE / 4)) { +	printf("Initialization error in position %lu, value = %x\n", i * 4, ptr0[i]); +    } +#endif /* CHECK_RESULT */ +      WR(0x04, 0) -     -    WR(0x0C, 0x20) -    WR(0x10, (PAGE_SIZE / 0x80)) +    WR(0x0C, TLP_SIZE) +    WR(0x10, (HUGE_PAGE * (PAGE_SIZE / (4 * TLP_SIZE))))      WR(0x14, 0x13131313)      for (j = 0; j < BUFFERS; j++ ) { @@ -163,17 +195,31 @@ int main() {      }      gettimeofday(&end, NULL); +#ifdef CHECK_RESULT     +    pcilib_kmem_sync_block(pci, kbuf, PCILIB_KMEM_SYNC_FROMDEVICE, 0); + +    for (i = 0; i < (HUGE_PAGE * PAGE_SIZE / 4); i++) { +//	printf("%lx ", ptr0[i]); +	if (ptr0[i] != 0x13131313) break; +    } +    if (i < (HUGE_PAGE * PAGE_SIZE / 4)) { +	printf("Error in position %lu, value = %x\n", i * 4, ptr0[i]); +    } +#endif /* CHECK_RESULT */ +      pcilib_free_kernel_memory(pci, kbuf,  0);      pcilib_disable_irq(pci, 0);      pcilib_unmap_bar(pci, BAR, bar);      pcilib_close(pci);      run_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); -    size = (long long int)ITERATIONS * BUFFERS * PAGE_SIZE; +    size = (long long int)ITERATIONS * BUFFERS * HUGE_PAGE * PAGE_SIZE;      printf("%.3lf GB/s: transfered %zu bytes in %zu us using %u buffers\n", 1000000. * size / run_time / 1024 / 1024 / 1024, size, run_time, BUFFERS);  # ifdef ADD_DELAYS      printf("Repeats: %lf, %lf\n",1. * rpt / (ITERATIONS * BUFFERS), 1. * rpt2 / (ITERATIONS * BUFFERS));  #endif /* USE_IRQ */	     + +  } diff --git a/driver/kmem.c b/driver/kmem.c index f6e22a1..4f36e79 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -135,29 +135,42 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han  	 case PCILIB_KMEM_TYPE_CONSISTENT:  	    retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );  	    break; +	 case PCILIB_KMEM_TYPE_REGION: +	    retptr = ioremap(kmem_handle->pa,  kmem_handle->size); +	    kmem_entry->dma_handle = kmem_handle->pa; +	    if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_S2C) { +		kmem_entry->direction = PCI_DMA_TODEVICE; +	    } else if (kmem_entry->type == PCILIB_KMEM_TYPE_REGION_C2S) { +		kmem_entry->direction = PCI_DMA_FROMDEVICE; +	    } +	    break;  	 case PCILIB_KMEM_TYPE_PAGE:  	    flags = GFP_KERNEL; -	     +  	    if ((kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE)||(kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE))  		flags |= __GFP_DMA; -	    retptr = (void*)__get_free_pages(flags, get_order(PAGE_SIZE)); +	    if (kmem_handle->size == 0) +		kmem_handle->size = PAGE_SIZE; +	    else if (kmem_handle->size%PAGE_SIZE) +		goto kmem_alloc_mem_fail; +	 +	    retptr = (void*)__get_free_pages(flags, get_order(kmem_handle->size));  	    kmem_entry->dma_handle = 0; -	    kmem_handle->size = PAGE_SIZE;  	    if (retptr) {  	        if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) {  		    kmem_entry->direction = PCI_DMA_TODEVICE; -    		    kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, PAGE_SIZE, PCI_DMA_TODEVICE); +    		    kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_TODEVICE);  		    if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) { -			free_page((unsigned long)retptr); +			free_pages((unsigned long)retptr, get_order(kmem_handle->size));  			goto kmem_alloc_mem_fail;  		    }  		} else if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_C2S_PAGE) {  		    kmem_entry->direction = PCI_DMA_FROMDEVICE; -    		    kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, PAGE_SIZE, PCI_DMA_FROMDEVICE); +    		    kmem_entry->dma_handle = pci_map_single(privdata->pdev, retptr, kmem_handle->size, PCI_DMA_FROMDEVICE);  		    if (pci_dma_mapping_error(privdata->pdev, kmem_entry->dma_handle)) { -			free_page((unsigned long)retptr); +			free_pages((unsigned long)retptr, get_order(kmem_handle->size));  			goto kmem_alloc_mem_fail;  		    } @@ -438,6 +451,9 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent  	 case PCILIB_KMEM_TYPE_CONSISTENT:  	    pci_free_consistent( privdata->pdev, kmem_entry->size, (void *)(kmem_entry->cpua), kmem_entry->dma_handle );  	    break; +	 case PCILIB_KMEM_TYPE_REGION: +	    iounmap((void *)(kmem_entry->cpua)); +	    break;  	 case PCILIB_KMEM_TYPE_PAGE:  	    if (kmem_entry->dma_handle) {  		if (kmem_entry->type == PCILIB_KMEM_TYPE_DMA_S2C_PAGE) { @@ -446,7 +462,7 @@ int pcidriver_kmem_free_entry(pcidriver_privdata_t *privdata, pcidriver_kmem_ent  		    pci_unmap_single(privdata->pdev, kmem_entry->dma_handle, kmem_entry->size, PCI_DMA_FROMDEVICE);  		}  	    } -	    free_page((unsigned long)kmem_entry->cpua); +	    free_pages((unsigned long)kmem_entry->cpua, get_order(kmem_entry->size));  	    break;  	} @@ -615,12 +631,21 @@ int pcidriver_mmap_kmem(pcidriver_privdata_t *privdata, struct vm_area_struct *v  			virt_to_phys((void*)kmem_entry->cpua),  			page_to_pfn(virt_to_page((void*)kmem_entry->cpua))); -	ret = remap_pfn_range_cpua_compat( +	 if ((kmem_entry->type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { +		ret = remap_pfn_range_compat( +					vma, +					vma->vm_start, +					kmem_entry->dma_handle, +					(vma_size < kmem_entry->size)?vma_size:kmem_entry->size, +					vma->vm_page_prot); +	 } else { +		ret = remap_pfn_range_cpua_compat(  					vma,  					vma->vm_start,  					kmem_entry->cpua,  					(vma_size < kmem_entry->size)?vma_size:kmem_entry->size,  					vma->vm_page_prot ); +	}  	if (ret) {  		mod_info("kmem remap failed: %d (%lx)\n", ret,kmem_entry->cpua); diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c index 605d733..1681f7c 100644 --- a/ipecamera/ipecamera.c +++ b/ipecamera/ipecamera.c @@ -123,7 +123,8 @@ pcilib_context_t *ipecamera_init(pcilib_t *pcilib) {  	    ctx->firmware = value;  	    break;  	 default: -    	    pcilib_error("Unsupported version of firmware (%lu)", value); +//    	    pcilib_error("Unsupported version of firmware (%lu)", value); +	    ctx->firmware = 0;  	}  #ifdef IPECAMERA_BUG_POSTPONED_READ @@ -155,7 +156,9 @@ void ipecamera_free(pcilib_context_t *vctx) {  }  pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) { -//    ipecamera_t *ctx = (ipecamera_t*)vctx; +#ifdef IPECAMERA_DMA_R3 +    ipecamera_t *ctx = (ipecamera_t*)vctx; +#endif      pcilib_model_description_t *model_info = pcilib_get_model_description(vctx->pcilib);      if ((!model_info->dma_api)||(!model_info->dma_api->init)) { @@ -165,7 +168,11 @@ pcilib_dma_context_t *ipecamera_init_dma(pcilib_context_t *vctx) {  #ifdef IPECAMERA_DMA_R3 -    return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); +    if (ctx->firmware) { +	return model_info->dma_api->init(vctx->pcilib, PCILIB_NWL_MODIFICATION_IPECAMERA, NULL); +    } else { +	return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); +    }  #else      return model_info->dma_api->init(vctx->pcilib, PCILIB_DMA_MODIFICATION_DEFAULT, NULL);  #endif @@ -204,6 +211,11 @@ int ipecamera_reset(pcilib_context_t *vctx) {  	pcilib_error("IPECamera imaging is not initialized");  	return PCILIB_ERROR_NOTINITIALIZED;      } +     +    if (!ctx->firmware) { +	pcilib_warning("Unsupported version of firmware (%lu)", ctx->firmware); +	return 0; +    }      pcilib = vctx->pcilib;      control = ctx->control_reg; @@ -278,13 +290,17 @@ int ipecamera_start(pcilib_context_t *vctx, pcilib_event_t event_mask, pcilib_ev  	pcilib_error("IPECamera imaging is not initialized");  	return PCILIB_ERROR_NOTINITIALIZED;      } + +    if (!ctx->firmware) { +	pcilib_error("Unsupported version of firmware (%lu)", ctx->firmware); +	return PCILIB_ERROR_INVALID_REQUEST; +    }      if (ctx->started) {  	pcilib_error("IPECamera grabbing is already started");  	return PCILIB_ERROR_INVALID_REQUEST;      } -  	// Allow readout and clean the FRAME_REQUEST mode if set for some reason      GET_REG(control_reg, value);      SET_REG(control_reg, value|IPECAMERA_READOUT_FLAG); @@ -634,7 +650,12 @@ int ipecamera_trigger(pcilib_context_t *vctx, pcilib_event_t event, size_t trigg  	pcilib_error("IPECamera imaging is not initialized");  	return PCILIB_ERROR_NOTINITIALIZED;      } -     + +    if (!ctx->firmware) { +	pcilib_error("Unsupported version of firmware (%lu)", ctx->firmware); +	return PCILIB_ERROR_INVALID_REQUEST; +    } +      pcilib_sleep_until_deadline(&ctx->next_trigger);      GET_REG(num_frames_reg, value); @@ -91,13 +91,19 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type      kh.align = alignment;      kh.use = use; -    if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) { +    if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { +	kh.align = 0; +    } else if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) {  	kh.size += alignment;      } -     +      for ( i = 0; i < nmemb; i++) {  	kh.item = i;  	kh.flags = flags; + +	if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { +	    kh.pa = alignment + i * size; +	}          ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh);  	if (ret) { @@ -116,7 +116,7 @@ static pcilib_bar_t pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size      return PCILIB_BAR_INVALID;  } -static int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) { +int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) {      const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx);      if (!board_info) return PCILIB_ERROR_NOTFOUND; @@ -76,6 +76,7 @@ const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx);  int pcilib_map_register_space(pcilib_t *ctx);  int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr); +int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size);  #endif /* _PCITOOL_PCI_H */ diff --git a/pcilib_types.h b/pcilib_types.h index f4f8f20..52c0879 100644 --- a/pcilib_types.h +++ b/pcilib_types.h @@ -15,7 +15,10 @@ typedef enum {      PCILIB_KMEM_TYPE_CONSISTENT = 0x00000,      PCILIB_KMEM_TYPE_PAGE = 0x10000,      PCILIB_KMEM_TYPE_DMA_S2C_PAGE = 0x10001, -    PCILIB_KMEM_TYPE_DMA_C2S_PAGE = 0x10002 +    PCILIB_KMEM_TYPE_DMA_C2S_PAGE = 0x10002, +    PCILIB_KMEM_TYPE_REGION = 0x20000, +    PCILIB_KMEM_TYPE_REGION_S2C = 0x20001, +    PCILIB_KMEM_TYPE_REGION_C2S = 0x20002  } pcilib_kmem_type_t;  typedef enum { diff --git a/tests/dma/xilinx/xilinx_dma_static_mem.sh b/tests/dma/xilinx/xilinx_dma_static_mem.sh new file mode 100755 index 0000000..e3ba0f5 --- /dev/null +++ b/tests/dma/xilinx/xilinx_dma_static_mem.sh @@ -0,0 +1,117 @@ +#! /bin/bash + +BAR=0 +USE=1 +ITERATIONS=1 +TLP_SIZE=32 +BUFFER_SIZE=8 + +function pci { +    PCILIB_PATH=`pwd`/.. +    LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* +} + + +function reset { +    pci -b $BAR -w 0 1 +    usleep 1000 +    pci -b $BAR -w 0 0 +    pci -b $BAR -w 4 0 +} + +function read_cfg { +#    echo $1 1>&2 +    pci -a config -r 0x$1 | awk '{ print $2; }' +} + +function parse_config { +    info=0x`pci -b $BAR -r 0 | awk '{ print $2; }'` +    model=`printf "%X" $((info>>24))` +    if [ $model -eq 14 ]; then +	model="Xilinx Virtex-6" +    else +	model="Xilinx $model" +    fi +    version=$(((info >> 8) & 0xFF)) +    data_width=$((16 * (2 ** ((info >> 16) & 0xF)))) +     +    echo "$model, build $version, $data_width bits" + + +    next=`read_cfg 34 | cut -c 7-8` + +    while [ $next -ne 0 ]; do +	cap=`read_cfg $next` +	capid=`echo $cap | cut -c 7-8` +	if [ $capid -eq 10 ]; then +	    addr=`printf "%X" $((0x$next + 12))` +	    pcie_link1=`read_cfg $addr` +	    addr=`printf "%X" $((0x$next + 16))` +	    pcie_link2=`read_cfg $addr` + +	    link_speed=$((((0x$pcie_link2 & 0xF0000) >> 16))) +	    link_width=$((((0x$pcie_link2 & 0x3F00000) >> 20))) + +	    dev_link_speed=$((((0x$pcie_link1 & 0xF)))) +	    dev_link_width=$((((0x$pcie_link1 & 0x3F0) >> 4))) +	fi +	next=`echo $cap | cut -c 5-6` +    done + +    echo "Link: PCIe gen$link_speed x$link_width" +    if [ $link_speed -ne $dev_link_speed -o $link_width -ne $dev_link_width ]; then +	echo " * But device capable of gen$dev_link_speed x$dev_link_width" +    fi +     +    info=0x`read_cfg 40` +    max_tlp=$((2 ** (5 + ((info & 0xE0) >> 5)))) +    echo "TLP: 32 dwords (transfering 32 TLP per request)" +    if [ $max_tlp -ne $TLP_SIZE ]; then +	echo " * But device is able to transfer TLP up to $max_tlp bytes" +    fi +     +    # 2500 MT/s, but PCIe gen1 and gen2 uses 10 bit encoding +    speed=$((link_width * link_speed * 2500 / 10)) +} + +reset +parse_config + +pci --enable-irq +pci --acknowledge-irq + +# TLP size +pci -b $BAR -w 0x0C 0x`echo "obase=16; $TLP_SIZE" | bc` +# TLP count +pci -b $BAR -w 0x10 0x`echo "obase=16; $BUFFER_SIZE * 1024 * 1024 / $TLP_SIZE / 4" | bc` +# Data +pci -b $BAR -w 0x14 0x13131313 + +bus="80000000" +dmaperf=0 +for i in `seq 1 $ITERATIONS`; do +  for addr in $bus; do  +    pci -b $BAR -w 0x08 0x$addr + +#Trigger +    pci -b $BAR -w 0x04 0x01 +    pci --wait-irq + +    status=`pci -b $BAR -r 0x04 | awk '{print $2; }' | cut -c 5-8` +    if [ $status != "0101" ]; then +	echo "Read failed, invalid status: $status" +    fi + +    dmaperf=$((dmaperf + 0x`pci -b $BAR -r 0x28 | awk '{print $2}'`)) +    reset +  done +done + +pci --free-kernel-memory $USE +pci --disable-irq + +echo +# Don't ask me about this formula +echo "Performance reported by FPGA: $(($BUFFER_SIZE * 1024 * 1024 * ITERATIONS * $speed / $dmaperf / 8)) MB/s" + +#pci -b $BAR  -r 0 -s 32 | 
