diff options
| author | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2013-06-20 19:15:55 +0200 | 
|---|---|---|
| committer | Suren A. Chilingaryan <csa@dside.dyndns.org> | 2013-06-20 19:15:55 +0200 | 
| commit | 7ec4581ad37b88bbb300ac00850603433a8cdfe9 (patch) | |
| tree | 6c78a5a4f876469226b54a9f9e4d7b749bebb3f9 | |
| parent | 0444091c36134f176738393b659ea60e09dda423 (diff) | |
| download | ipecamera-7ec4581ad37b88bbb300ac00850603433a8cdfe9.tar.gz ipecamera-7ec4581ad37b88bbb300ac00850603433a8cdfe9.tar.bz2 ipecamera-7ec4581ad37b88bbb300ac00850603433a8cdfe9.tar.xz ipecamera-7ec4581ad37b88bbb300ac00850603433a8cdfe9.zip  | |
Multipage DMA tests for Xilinx
| -rw-r--r-- | .bzrignore | 2 | ||||
| -rw-r--r-- | apps/CMakeLists.txt | 3 | ||||
| -rwxr-xr-x | apps/load.sh | 3 | ||||
| -rw-r--r-- | apps/xilinx2.c | 179 | ||||
| -rw-r--r-- | driver/kmem.c | 19 | ||||
| -rw-r--r-- | ipecamera/ipecamera.c | 3 | ||||
| -rw-r--r-- | ipecamera/model.h | 2 | 
7 files changed, 202 insertions, 9 deletions
@@ -19,3 +19,5 @@ Makefile  *.so.*  install_manifest.txt  ./xilinx +apps/xilinx +apps/xilinx2 diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 2f882a3..80a506f 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -6,3 +6,6 @@ link_directories(${UFODECODE_LIBRARY_DIRS})  add_executable(xilinx xilinx.c)  target_link_libraries(xilinx pcilib rt) + +add_executable(xilinx2 xilinx2.c) +target_link_libraries(xilinx2 pcilib rt) diff --git a/apps/load.sh b/apps/load.sh new file mode 100755 index 0000000..6456c63 --- /dev/null +++ b/apps/load.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +echo "10ee 6028" >   /sys/bus/pci/drivers/pciDriver/new_id diff --git a/apps/xilinx2.c b/apps/xilinx2.c new file mode 100644 index 0000000..6dd1be3 --- /dev/null +++ b/apps/xilinx2.c @@ -0,0 +1,179 @@ +#define _BSD_SOURCE +#define _POSIX_C_SOURCE 199309L +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <stdarg.h> +#include <time.h> +#include <sched.h> +#include <sys/time.h> + +#include "pcilib.h" +#include "irq.h" +#include "kmem.h" + +#define DEVICE "/dev/fpga0" +#define BAR PCILIB_BAR0 +#define USE PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 1) +#define BUFFERS 1 +#define ITERATIONS 16384 +#define HUGE_PAGE 128	// 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 CHECK_READY +//#define REALTIME +//#define ADD_DELAYS + +//#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); } + +static void fail(const char *msg, ...) { +    va_list va; +     +    va_start(va, msg); +    vprintf(msg, va); +    va_end(va); +    printf("\n"); + +    exit(-1); +} + +void hpsleep(size_t ns) { +    struct timespec wait, tv; + +    clock_gettime(CLOCK_REALTIME, &wait); + +    wait.tv_nsec += ns; +    if (wait.tv_nsec > 999999999) { +	wait.tv_sec += 1; +	wait.tv_nsec = 1000000000 - wait.tv_nsec; +    } + +    do { +	clock_gettime(CLOCK_REALTIME, &tv); +    } while ((wait.tv_sec > tv.tv_sec)||((wait.tv_sec == tv.tv_sec)&&(wait.tv_nsec > tv.tv_nsec))); +} + + +int main() { +    int err; +    int i, j; +    pcilib_t *pci; +    pcilib_kmem_handle_t *kbuf; +    uint32_t status; +    struct timeval start, end; +    size_t size, run_time; +    void* volatile bar; +    uintptr_t bus_addr[BUFFERS]; + +    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 * HUGE_PAGE * PAGE_SIZE / (4L * 1024 * 1024 * 1024); +#endif /* ADD_DELAYS */ + +#ifdef REALTIME +    pid_t pid; +    struct sched_param sched = {0}; + +    pid = getpid(); +    sched.sched_priority = sched_get_priority_min(SCHED_FIFO); +    if (sched_setscheduler(pid, SCHED_FIFO, &sched)) +	printf("Warning: not able to get real-time priority\n"); +#endif /* REALTIME */ + +    pci = pcilib_open(DEVICE, PCILIB_MODEL_DETECT); +    if (!pci) fail("pcilib_open"); + +    bar = pcilib_map_bar(pci, BAR); +    if (!bar) { +	pcilib_close(pci); +	fail("map bar"); +    } + +	// 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); + +    kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, BUFFERS, HUGE_PAGE * PAGE_SIZE, 4096, USE, 0); + +    WR(0x04, 0) +    WR(0x0C, 0x20) +    WR(0x10, (HUGE_PAGE * (PAGE_SIZE / 0x80))) +    WR(0x14, 0x13131313) + +    for (j = 0; j < BUFFERS; j++ ) { +        bus_addr[j] = pcilib_kmem_get_block_ba(pci, kbuf, j); +    } + +    gettimeofday(&start, NULL); + +    for (i = 0; i < ITERATIONS; i++) { +	for (j = 0; j < BUFFERS; j++ ) { +//	    uintptr_t ba = pcilib_kmem_get_block_ba(pci, kbuf, j); +//	    WR(0x08, ba) +	    WR(0x08, bus_addr[j]); +	    WR(0x04, 0x01) + +#ifdef USE_IRQ +	    err = pcilib_wait_irq(pci, PCILIB_IRQ_SOURCE_DEFAULT, TIMEOUT, NULL); +	    if (err) printf("Timeout waiting for IRQ, err: %i\n", err); + +	    RD(0x04, status); +	    if ((status&0xFFFF) != 0x101) printf("Invalid status %x\n", status); +//	    WR(0x04, 0x00); +#else /* USE_IRQ */ +# ifdef ADD_DELAYS +//	    hpsleep(best_time); +	    do { +		rpt++; +		RD(0x04, status); +	    } while (status != 0x101); +# else /* ADD_DELAYS */ +	    do { +		RD(0x04, status); +	    } while (status != 0x101); +# endif /* ADD_DELAYS */ +#endif /* USE_IRQ */ + +	    WR(0x00, 1) +#ifdef CHECK_READY +	    do { +		rpt2++; +		RD(0x04, status); +	    } while (status != 0); +#endif /* CHECK_READY */ +	    WR(0x00, 0) +	} +    } +    gettimeofday(&end, NULL); + +    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 * 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 37a7368..ee64a78 100644 --- a/driver/kmem.c +++ b/driver/kmem.c @@ -130,23 +130,28 @@ int pcidriver_kmem_alloc(pcidriver_privdata_t *privdata, kmem_handle_t *kmem_han  	    retptr = pci_alloc_consistent( privdata->pdev, kmem_handle->size, &(kmem_entry->dma_handle) );  	    break;  	 case PCILIB_KMEM_TYPE_PAGE: -	    retptr = (void*)__get_free_pages(GFP_KERNEL, 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(GFP_KERNEL|__GFP_DMA, get_order(kmem_handle->size));  	    kmem_entry->dma_handle = 0; -	    kmem_handle->size = PAGE_SIZE; +	    kmem_handle->size = kmem_handle->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;  		    } @@ -435,7 +440,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;  	} diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c index 27bea77..b4bbeb8 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); +	    ;  	}  #ifdef IPECAMERA_BUG_POSTPONED_READ diff --git a/ipecamera/model.h b/ipecamera/model.h index 4c527df..37f9096 100644 --- a/ipecamera/model.h +++ b/ipecamera/model.h @@ -8,7 +8,7 @@  //#define IPECAMERA_DEBUG -#define IPECAMERA_DMA_R3 +//#define IPECAMERA_DMA_R3  #define IPECAMERA_DMA_ADDRESS 1  #define IPECAMERA_DMA_PACKET_LENGTH 4096  | 
