summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2014-04-03 00:37:21 +0200
committerSuren A. Chilingaryan <csa@suren.me>2014-04-03 00:37:21 +0200
commita1925232b26bc0d9801d7c1dcd58301841877af1 (patch)
tree8da70a5e091d5400fd063c385ec473d17b708583
parentd8c13eb6ff5a1c9cc28617d83dbde454c7222be4 (diff)
parentc57db04f528e671040256d322bb8f21a8d8e9ac1 (diff)
downloadpcitool-a1925232b26bc0d9801d7c1dcd58301841877af1.tar.gz
pcitool-a1925232b26bc0d9801d7c1dcd58301841877af1.tar.bz2
pcitool-a1925232b26bc0d9801d7c1dcd58301841877af1.tar.xz
pcitool-a1925232b26bc0d9801d7c1dcd58301841877af1.zip
Merge changes from xilinx_dma branch providing support of multipage kmem allocations and mapping memory regions reserved with memmap boot option
-rw-r--r--.bzrignore5
-rw-r--r--apps/xilinx.c76
-rw-r--r--driver/kmem.c43
-rw-r--r--ipecamera/ipecamera.c31
-rw-r--r--kmem.c10
-rw-r--r--pci.c2
-rw-r--r--pci.h1
-rw-r--r--pcilib_types.h5
-rwxr-xr-xtests/dma/xilinx/xilinx_dma_static_mem.sh117
9 files changed, 254 insertions, 36 deletions
diff --git a/.bzrignore b/.bzrignore
index 590038e..4cbe2d8 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -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);
diff --git a/kmem.c b/kmem.c
index d693b60..64f593a 100644
--- a/kmem.c
+++ b/kmem.c
@@ -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) {
diff --git a/pci.c b/pci.c
index 5164111..62536ea 100644
--- a/pci.c
+++ b/pci.c
@@ -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;
diff --git a/pci.h b/pci.h
index bdd34a7..b25aeec 100644
--- a/pci.h
+++ b/pci.h
@@ -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