diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2014-12-19 00:14:21 +0100 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2014-12-19 00:14:21 +0100 |
commit | a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f (patch) | |
tree | 7a6b899c130510e3cca87c23b26a5a1ffc033f20 | |
parent | 0e16eeef08ed9b27f0fbc7f02a562a81e10c4119 (diff) | |
download | ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.gz ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.bz2 ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.tar.xz ipecamera-a640c40c6bcf4bad0b78e0ea6ea04f2a5f3f877f.zip |
Initial implementation of IPEDMA, dummy driver for KAPTURE, start of API changes
-rw-r--r-- | .bzrignore | 2 | ||||
-rw-r--r-- | CMakeLists.txt | 7 | ||||
-rw-r--r-- | apps/CMakeLists.txt | 4 | ||||
-rw-r--r-- | apps/check_counter.c | 45 | ||||
-rw-r--r-- | apps/lorenzo_ipedma_test.c | 749 | ||||
-rw-r--r-- | cli.c | 1 | ||||
-rw-r--r-- | dma.h | 2 | ||||
-rw-r--r-- | dma/CMakeLists.txt | 4 | ||||
-rw-r--r-- | dma/ipe.c | 412 | ||||
-rw-r--r-- | dma/ipe.h | 42 | ||||
-rw-r--r-- | dma/ipe_private.h | 56 | ||||
-rw-r--r-- | dma/ipe_registers.h | 44 | ||||
-rw-r--r-- | dma/nwl.c | 2 | ||||
-rw-r--r-- | dma/nwl.h | 89 | ||||
-rw-r--r-- | dma/nwl_dma.h | 45 | ||||
-rw-r--r-- | dma/nwl_engine.c | 2 | ||||
-rw-r--r-- | dma/nwl_engine_buffers.h | 6 | ||||
-rw-r--r-- | dma/nwl_irq.c | 2 | ||||
-rw-r--r-- | dma/nwl_loopback.c | 2 | ||||
-rw-r--r-- | dma/nwl_private.h | 67 | ||||
-rw-r--r-- | dma/nwl_register.c | 2 | ||||
-rw-r--r-- | driver/base.c | 2 | ||||
-rw-r--r-- | driver/base.h | 1 | ||||
-rw-r--r-- | driver/pciDriver.h | 1 | ||||
-rw-r--r-- | event.h | 6 | ||||
-rw-r--r-- | ipecamera/ipecamera.c | 4 | ||||
-rw-r--r-- | ipecamera/model.h | 7 | ||||
-rw-r--r-- | kapture/CMakeLists.txt | 9 | ||||
-rw-r--r-- | kapture/kapture.c | 62 | ||||
-rw-r--r-- | kapture/kapture.h | 6 | ||||
-rw-r--r-- | kapture/model.h | 81 | ||||
-rw-r--r-- | kapture/private.h | 10 | ||||
-rw-r--r-- | pci.c | 3 | ||||
-rw-r--r-- | pci.h | 7 | ||||
-rw-r--r-- | pcilib.h | 3 | ||||
-rw-r--r-- | register.c | 1 | ||||
-rwxr-xr-x | tests/dma/ipe/bench.sh | 31 |
37 files changed, 1694 insertions, 125 deletions
@@ -23,3 +23,5 @@ apps/pio_test apps/compare_to_value apps/heb_strip_bad_values *.out +apps/check_counter +apps/lorenzo_ipedma_test diff --git a/CMakeLists.txt b/CMakeLists.txt index b653b09..a761acb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ project(pcitool) -set(PCILIB_VERSION "0.0.1") -set(PCILIB_ABI_VERSION "0") +set(PCILIB_VERSION "0.1.0") +set(PCILIB_ABI_VERSION "1") cmake_minimum_required(VERSION 2.6) @@ -24,6 +24,7 @@ add_definitions("-fPIC --std=c99 -Wall -O2") add_subdirectory(dma) add_subdirectory(ipecamera) +add_subdirectory(kapture) add_subdirectory(pcitool) add_subdirectory(apps) @@ -37,7 +38,7 @@ link_directories( ) add_library(pcilib SHARED pci.c register.c kmem.c irq.c dma.c event.c default.c tools.c error.c) -target_link_libraries(pcilib dma ipecamera ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ) +target_link_libraries(pcilib dma ipecamera kapture ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ) add_dependencies(pcilib dma ipecamera) set_target_properties(pcilib PROPERTIES diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index 85457a1..24457e3 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -7,9 +7,13 @@ link_directories(${UFODECODE_LIBRARY_DIRS}) add_executable(xilinx xilinx.c) target_link_libraries(xilinx pcilib rt) +add_executable(lorenzo_ipedma_test lorenzo_ipedma_test.c) +target_link_libraries(lorenzo_ipedma_test pcilib rt) + add_executable(pio_test pio_test.c) target_link_libraries(pio_test pcilib rt) add_executable(compare_to_value compare_to_value.c) add_executable(heb_strip_bad_values heb_strip_bad_values.c) +add_executable(check_counter check_counter.c) diff --git a/apps/check_counter.c b/apps/check_counter.c new file mode 100644 index 0000000..b19b7d0 --- /dev/null +++ b/apps/check_counter.c @@ -0,0 +1,45 @@ +#include <stdio.h> +#include <stdlib.h> +#include <stdint.h> + +int main(int argc, char *argv[]) { + int block = 0; + uint32_t value = 0; + uint32_t buf[1024]; + + if (argc < 2) { + printf("Usage:\n\t\t%s <file-to-check>\n", argv[0]); + exit(0); + } + + FILE *f = fopen(argv[1], "r"); + if (!f) { + printf("Failed to open file %s\n", argv[1]); + exit(1); + } + + + while (!feof(f)) { + int i, n = fread(buf, 4, 1024, f); + + if (block) i = 0; + else { + i = 1; + value = (buf[0]); + } + + for (; i < n; i++) { + if ((buf[i]) != ++value) { + printf("Pos %lx (Block %i, dword %i) expected %x, but got %x\n", block * 4096 + i * 4, block, i, value, (buf[i])); + exit(1); + } + } + + if (n) block++; + } + + fclose(f); + + printf("Checked %i blocks. All is fine\n", block); + return 0; +} diff --git a/apps/lorenzo_ipedma_test.c b/apps/lorenzo_ipedma_test.c new file mode 100644 index 0000000..3802e78 --- /dev/null +++ b/apps/lorenzo_ipedma_test.c @@ -0,0 +1,749 @@ +#define _POSIX_C_SOURCE 199309L +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <stdarg.h> +#include <time.h> +#include <sched.h> +#include <sys/time.h> +#include <sys/types.h> +#include <arpa/inet.h> +#include <sched.h> +#include <errno.h> + +#include "pcilib.h" +#include "irq.h" +#include "kmem.h" + +//#include <sys/ipc.h> +//#include <sys/shm.h> + + +#define DEVICE "/dev/fpga0" + +#define BAR PCILIB_BAR0 +#define USE_RING PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 1) +#define USE PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER, 2) +//#define STATIC_REGION 0x80000000 // to reserve 512 MB at the specified address, add "memmap=512M$2G" to kernel parameters + +#define BUFFERS 128 +#define ITERATIONS 1000 +#define DESC_THRESHOLD BUFFERS/8 // Lorenzo: after how many desc the FPGA must update the "written descriptor counter" in PC mem + // if set to 0, the update only happens when INT is received + +#define HUGE_PAGE 1 // number of pages per huge page +#define TLP_SIZE 32 // TLP SIZE = 64 for 256B payload, 32 for 128B payload +#define PAGE_SIZE 4096 // other values are not supported in the kernel + +//#define USE_64 // Lorenzo: use 64bit addressing + +//#define DUAL_CORE // Lorenzo: DUAL Core + +//#define SHARED_MEMORY // Lorenzo: Test for fast GUI + +#define CHECK_READY // Lorenzo: Check if PCI-Express is ready by reading 0x0 +#define CHECK_RESULTS // Lorenzo: Check if data received is ok (only for counter!) +//#define PRINT_RESULTS // Lorenzo: Save the received data in "data.out" +//#define EXIT_ON_EMPTY // Lorenzo: Exit if an "empty_detected" signal is received + +//#define HEB // Lorenzo: Testing HEB +//#define SWITCH_GENERATOR // Lorenzo: Testing HEB -> Turn data gen on/off + +//#define TEST_DDR // Lorenzo: Testing DDR + +#define TIMEOUT 1000000 + + + +/* 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 REALTIME +//#define ADD_DELAYS + + +#define FPGA_CLOCK 250 // Lorenzo: in MHz ! + + + +//#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 + offset) = value; } +#define RD(addr, value) { value = *(uint32_t*)(bar + addr + offset); } + +// ************************************************************************************** +// Progress BAR +// Process has done x out of n rounds, +// and we want a bar of width w and resolution r. + static inline void loadBar(int x, int n, int r, int w) + { + // Only update r times. + if ( x % (n/r +1) != 0 ) return; + + // Calculuate the ratio of complete-to-incomplete. + float ratio = x/(float)n; + int c = ratio * w; + + // Show the percentage complete. + printf("%3d%% [", (int)(ratio*100) ); + + // Show the load bar. + for (x=0; x<c; x++) + printf("="); + + for (x=c; x<w; x++) + printf(" "); + + // ANSI Control codes to go back to the + // previous line and clear it. + printf("]\n\033[F\033[J"); + } +// ************************************************************************************** + + + 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; + long i, j, k; + int mem_diff; + pcilib_t *pci; + pcilib_kmem_handle_t *kdesc; + pcilib_kmem_handle_t *kbuf; + struct timeval start, end; + size_t run_time, size; + long long int size_mb; + void* volatile bar; + uintptr_t bus_addr[BUFFERS]; + uintptr_t kdesc_bus; + volatile uint32_t *desc; + typedef volatile uint32_t *Tbuf; + Tbuf ptr[BUFFERS]; + int switch_generator = 0; + + float performance, perf_counter; + pcilib_bar_t bar_tmp = BAR; + uintptr_t offset = 0; + + unsigned int temp; + int iterations_completed, buffers_filled; + + +// int shmid; + + + printf("\n\n**** **** **** KIT-DMA TEST **** **** ****\n\n"); + + size = ITERATIONS * BUFFERS * HUGE_PAGE * PAGE_SIZE; + size_mb = ITERATIONS * BUFFERS * HUGE_PAGE * 4 / 1024; + printf("Total size of memory buffer: \t %.3lf GBytes\n", (float)size_mb/1024 ); + printf("Using %d Buffers with %d iterations\n\n", BUFFERS, ITERATIONS ); + +#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 */ + + + pcilib_kmem_flags_t flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT|PCILIB_KMEM_FLAG_EXCLUSIVE/*|PCILIB_KMEM_FLAG_REUSE*/; // Lorenzo: if REUSE = 1, the re-allocation fails! + pcilib_kmem_flags_t free_flags = PCILIB_KMEM_FLAG_HARDWARE/*|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_REUSE*/; + pcilib_kmem_flags_t clean_flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT|PCILIB_KMEM_FLAG_EXCLUSIVE; + + 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"); + } + + pcilib_detect_address(pci, &bar_tmp, &offset, 1); + + 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); + pcilib_clean_kernel_memory(pci, USE_RING, clean_flags); + + kdesc = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_CONSISTENT, 1, 128, 4096, USE_RING, flags); + kdesc_bus = pcilib_kmem_get_block_ba(pci, kdesc, 0); + desc = (uint32_t*)pcilib_kmem_get_block_ua(pci, kdesc, 0); + memset((void*)desc, 0, 5*sizeof(uint32_t)); + +#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 */ + + // ****************************************************************** + // **** MEM: check 4k boundary ***** + // ****************************************************************** + + do { + printf("* Allocating KMem, "); +#ifdef STATIC_REGION + kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_REGION_C2S, BUFFERS, HUGE_PAGE * PAGE_SIZE, STATIC_REGION, USE, flags); +#else + kbuf = pcilib_alloc_kernel_memory(pci, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, BUFFERS, HUGE_PAGE * PAGE_SIZE, 4096, USE, flags); +#endif + + if (!kbuf) { + printf("KMem allocation failed\n"); + exit(0); + } + + // Pointers for Virtualized Mem + for (j = 0; j < BUFFERS; j++) { + ptr[j] = (volatile uint32_t*)pcilib_kmem_get_block_ua(pci, kbuf, j); + memset((ptr[j]), 0, HUGE_PAGE * PAGE_SIZE); + } + + err = 0; + + // Check if HW addresses satisfy 4k boundary condition, if not -> free (!!) and reallocate memory + printf("4k boundary test: "); + for (j = 0; j < BUFFERS; j++) { + temp = (((unsigned int)pcilib_kmem_get_block_ba(pci, kbuf, j)) % 4096); + //printf("%u", temp); + if (temp != 0) { + err = 1; + } + } + if (err == 1) { + pcilib_clean_kernel_memory(pci, USE, clean_flags); + pcilib_clean_kernel_memory(pci, USE_RING, clean_flags); + pcilib_free_kernel_memory(pci, kbuf, free_flags); + printf("failed \xE2\x9C\x98\n"); + } + else printf("passed \xE2\x9C\x93\n"); + + } while (err == 1); + + + // ****************************************************************** + // **** Allocate RAM buffer Memory ***** + // ****************************************************************** + + FILE * Output; + FILE * error_log; + +#ifdef CHECK_RESULTS + + uint32_t *temp_data[ITERATIONS][BUFFERS]; + + for (j=0; j < ITERATIONS; j++) { + for (i=0; i < BUFFERS; i++) { + temp_data[j][i] = (uint32_t *)malloc(HUGE_PAGE*PAGE_SIZE); + if (temp_data[j][i] == 0) { + printf("******* Error: could not allocate memory! ********\n"); + exit(0); + } + memset((void*)(temp_data[j][i]), 0, HUGE_PAGE * PAGE_SIZE); + } + } +#endif + +#ifdef SHARED_MEMORY + // give your shared memory an id, anything will do + key_t key = 123456; + char *shared_memory; + + // Setup shared memory, 11 is the size +/* if ((shmid = shmget(key, HUGE_PAGE*PAGE_SIZE, IPC_CREAT | 0666)) < 0) + { + printf("Error getting shared memory id"); + exit(1); + } + + // Attached shared memory + if ((shared_memory = shmat(shmid, NULL, 0)) == (char *) -1) + { + printf("Error attaching shared memory id"); + exit(1); + } + printf("* Shared memory created... Id:\t %d\n", key); + //////////////// SHARED MEMORY TEST */ +#endif + + Output = fopen ("data.out", "w"); + fclose(Output); + + error_log = fopen ("error_log.txt", "w"); + fclose(error_log); + + // ************************************* + Output = fopen("data.txt", "w"); + fclose(Output); + + // ****************************************************************** + // **** PCIe TEST ***** + // ****************************************************************** + + // Reset DMA + printf("* DMA: Reset...\n"); + WR(0x00, 0x1); + usleep(100000); + WR(0x00, 0x0); + usleep(100000); + +#ifdef CHECK_READY + printf("* PCIe: Testing..."); + RD(0x0, err); + if (err != 335746816) { + printf("\xE2\x9C\x98\n PCIe not ready!\n"); + exit(0); + } else { + printf("\xE2\x9C\x93 \n"); + } +#endif + + + // ****************************************************************** + // **** DMA CONFIGURATION ***** + // ****************************************************************** + + + printf("* DMA: Start Data Generator...\n"); + WR(0x04, 0x10) // Start data generator + + printf("* DMA: Send Data Fill Pattern 55aa55aa\n"); + WR(0x14, 0xbeef); + + printf("* DMA: Send Data Amount\n"); +#ifdef DUAL_CORE + WR(0x10, (HUGE_PAGE * (PAGE_SIZE / (4 * TLP_SIZE)))/2); +#else + WR(0x10, (HUGE_PAGE * (PAGE_SIZE / (4 * TLP_SIZE)))); +#endif + + printf("* DMA: Running mode: "); +#ifdef USE_64 + if (TLP_SIZE == 64) + { + WR(0x0C, 0x80040); + printf ("64bit - 256B Payload\n"); + } + else if (TLP_SIZE == 32) + { + WR(0x0C, 0x80020); + printf ("64bit - 128B Payload\n"); + } +#else + if (TLP_SIZE == 64) + { + WR(0x0C, 0x0040); + printf ("32bit - 256B Payload\n"); + } + else if (TLP_SIZE == 32) + { + WR(0x0C, 0x0020); + printf ("32bit - 128B Payload\n"); + } +#endif + + printf("* DMA: Reset Desc Memory...\n"); + WR(0x5C, 0x00); // RST Desc Memory + + //printf("Writing SW Read Descriptor\n"); + WR(0x58, BUFFERS-1); + //WR(0x58, 0x01); + + //printf("Writing the Descriptor Threshold\n"); + WR(0x60, DESC_THRESHOLD); + + //printf("Writing HW write Descriptor Address: %lx\n", kdesc_bus); + WR(0x54, kdesc_bus); + usleep(100000); + + printf("* DMA: Writing Descriptors\n"); + for (j = 0; j < BUFFERS; j++ ) { + bus_addr[j] = pcilib_kmem_get_block_ba(pci, kbuf, j); + // LEAVE THIS DELAY???!?!?!?! + usleep(1000); + printf("Writing descriptor num. %ld: \t %08lx \r", j, bus_addr[j]); + WR(0x50, bus_addr[j]); + } + + // ****************************************************************** + // **** HEB CONFIGURATION ***** + // ****************************************************************** +#ifdef HEB + + + printf("* DDR REGISTERS: AXI_BUF_SIZE \n"); + WR(0x9130, 0x1000); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x00000001); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x00000004); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x00000000); + + usleep(100000); + + printf("* HEB: Writing Total Orbit Num\n"); + WR(0x9020, 0x2000); + + printf("* HEB: Orbit Skip Num h9028\n"); + WR(0x9028, 0x4); + + //printf("* HEB: LVDS_DELAY h9080\n"); + //WR(0x9080, 0x10101010); + + //printf("* HEB: Delay ADCs \n"); + //WR(0x9088, 0x001); + //WR(0x9090, 0x001); + //WR(0x9094, 0x001); + //WR(0x9098, 0x001); + + //printf("* HEB: Delay TH \n"); + //WR(0x90a0, 0x005); + + //printf("* HEB: Delay_FPGA_reg \n"); + //WR(0x90a8, 0x006); + + //printf("* HEB: Control \n"); + //WR(0x9040, 0x40000000); + + //usleep(1000000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x40000bf0); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x400003f0); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x480007F0); + + usleep(100000); + + printf("* HEB: Control \n"); + WR(0x9040, 0x48000FF0); + + +#endif + + // ****************************************************************** + // **** TEST DDR conf ***** + // ****************************************************************** +#ifdef TEST_DDR + + + printf("* DDR: AXI_BUF_SIZE_ADDR: 4k\n"); + WR(0x9010, 0x04000); + + printf("* DDR: Control \n"); + WR(0x9000, 0x000000F); + + usleep(100000); + WR(0x9000, 0x00000008); + usleep(100000); + WR(0x9000, 0x08000008); + + usleep(50000); + + printf("* DDR: Control \n"); + WR(0x9000, 0x08000208); + + +#endif + + // ****************************************************************** + // **** START DMA ***** + // ****************************************************************** + + //printf ("\n ---- Press ENTER to start DMA ---- \n"); + //getchar(); + + printf("* DMA: Start \n"); + WR(0x04, 0x1f); + gettimeofday(&start, NULL); + + // ****************************************************************** + // **** Handshaking DMA ***** + // ****************************************************************** + + uint32_t curptr = 0, hwptr; + uint32_t curbuf = 0; + int empty = 0; + i = 0; + + + while (i < ITERATIONS) { + j = 0; + // printf("\ndesc0: %lx", htonl(desc[0])); + // printf("\ndesc1: %lx", htonl(desc[1])); + // printf("\ndesc2: %lx", htonl(desc[2])); + // printf("\ndesc3: %lx", htonl(desc[3])); + // printf("\ndesc4: %lx", htonl(desc[4])); + // printf("\ndesc5: %lx", htonl(desc[5])); + //printf("Iteration: %li of %li \r", i+1, ITERATIONS); + //loadBar(i+1, ITERATIONS, ITERATIONS, 30); + // printf("\nhwptr: %zu", hwptr); + // printf("\ncurptr: %zu", curptr); + + do { +#ifdef USE_64 + hwptr = htonl(desc[3]); +#else // 32-bit + hwptr = htonl(desc[4]); +#endif + j++; + //printf("\rcurptr: %lx \t \t hwptr: %lx", curptr, hwptr); + } while (hwptr == curptr); + + do { + pcilib_kmem_sync_block(pci, kbuf, PCILIB_KMEM_SYNC_FROMDEVICE, curbuf); +#ifdef CHECK_RESULTS + memcpy(temp_data[i][curbuf], ptr[curbuf], 4096); +#endif +#ifdef SHARED_MEMORY + memcpy(shared_memory, ptr[curbuf], 4096); +#endif + //printf("\ncurbuf: %08x", curbuf); + //printf("\nbus_addr[curbuf]\n: %08x",bus_addr[curbuf]); + // for (k = 0; k < 63; k++){ + // if (k%16 == 0) printf("\n# %d # :", k); + // printf(" %08x", ptr[curbuf][k]); + // } + //pcilib_kmem_sync_block(pci, kbuf, PCILIB_KMEM_SYNC_TODEVICE, curbuf); + curbuf++; + if (curbuf == BUFFERS) { + i++; + curbuf = 0; +#ifdef SWITCH_GENERATOR + if (switch_generator == 1) { + switch_generator = 0; + WR(0x9040, 0x100007F0); + } else { + WR(0x9040, 0x180007F0); + switch_generator = 1; + } +#endif + if (i >= ITERATIONS) break; + //if (i >= (ITERATIONS - 4) ) WR(0x04, 0x0f); + } + } while (bus_addr[curbuf] != hwptr); + +#ifdef EXIT_ON_EMPTY +#ifdef USE_64 + if (desc[1] != 0) +#else // 32bit + if (desc[2] != 0) +#endif + { + if (bus_addr[curbuf] == hwptr) { + empty = 1; + break; + } + } +#endif + + WR(0x58, curbuf + 1); + //printf("WR %d\n", curbuf + 1); + //printf("%u (%lu)\n", curbuf, j); + curptr = hwptr; + + } + + + + // ****************************************************************** + // **** Read performance and stop DMA ******* + // ****************************************************************** + + gettimeofday(&end, NULL); + WR(0x04, 0x00); + WR(0x01, 0x00); + RD(0x28, perf_counter); + + + + iterations_completed = i; + buffers_filled = curbuf; + if (empty) printf("* DMA: Empty FIFO! Last iteration: %li of %li\n", i+1, ITERATIONS); + printf ("* DMA: Stop\n\n"); + +#ifdef CHECK_RESULTS + printf ("First value:\t %08x\n", temp_data[0][0][0]); + printf ("Last value:\t %08x\n\n", temp_data[ITERATIONS-1][BUFFERS-1][(PAGE_SIZE/4)-4]); +#endif + + // ****************************************************************** + // **** Performance ******* + // ****************************************************************** + printf("Iterations done: %d\n", iterations_completed); + printf("Buffers filled on last iteration: %d\n", buffers_filled); + + + run_time = (end.tv_sec - start.tv_sec) * 1000000 + (end.tv_usec - start.tv_usec); + size = (long long int) (( BUFFERS * (iterations_completed) + buffers_filled) * HUGE_PAGE * PAGE_SIZE); + size_mb = (long long int) (( BUFFERS * (iterations_completed) + buffers_filled) * HUGE_PAGE * 4 / 1024); + printf("Performance: transfered %zu Mbytes in %zu us using %d buffers\n", (size_mb), run_time, BUFFERS); + //printf("Buffers: \t %d \n", BUFFERS); + //printf("Buf_Size: \t %d \n", PAGE_SIZE); + //printf("Perf_counter: \t %f \n", perf_counter); + performance = ((size_mb * FPGA_CLOCK * 1000000)/(perf_counter*256)); + printf("DMA perf counter:\t%d\n", (int)perf_counter); + printf("DMA side:\t\t%.3lf MB/s\n", performance); + printf("PC side:\t\t%.3lf MB/s\n\n", 1000000. * size_mb / run_time ); + + // ****************************************************************** + // **** Read Data ******* + // ****************************************************************** + + + #ifdef PRINT_RESULTS + printf("Writing Data to HDD... \n"); + for (i=0; i < iterations_completed; i++) { + for (j=0; j < BUFFERS; j++) + { + Output = fopen("data.out", "a"); + fwrite(temp_data[i][j], 4096, 1, Output); + fclose(Output); + } + loadBar(i+1, ITERATIONS, ITERATIONS, 30); + } + // Save last partially filled iteration + for (j=0; j < buffers_filled; j++) + { + Output = fopen("data.out", "a"); + fwrite(temp_data[iterations_completed][j], 4096, 1, Output); + fclose(Output); + } + printf("Data saved in data.out. \n"); + #endif + + #ifdef CHECK_RESULTS + err = 0; + error_log = fopen ("error_log.txt", "a"); + printf("\nChecking data ...\n"); + for (i=0; i < iterations_completed; i++) { + for (j = 0; j < BUFFERS; j++) { + for (k = 0; k < 1024 ; k++) + { + mem_diff = ((uint32_t)temp_data[i][j][k] - (uint32_t)temp_data[i][j][k+1]); + //if ((mem_diff == 1) || (mem_diff == (-7)) || (k == 1023) ) + if ((mem_diff == -1) || (k == 1023) ) + {;} + else { + fprintf(error_log, "Error in: \t IT %li \t BUF : %li \t OFFSET: %li \t | %08x --> %08x - DIFF: %d \n", i, j, k, temp_data[i][j][k], temp_data[i][j][k+1], mem_diff); + err++; + } + } + if (j != BUFFERS-1) { + // Check first and Last + mem_diff = (uint32_t)(temp_data[i][j+1][0] - temp_data[i][j][1023]); + if (mem_diff == (1)) + {;} + else { + fprintf(error_log, "Error_2 in: \t IT %li \t BUF : %li \t OFFSET: %li \t | %08x --> %08x - DIFF: %d \n", i, j, k, temp_data[i][j+1][0], temp_data[i][j][1023], mem_diff); + err++; + } + } + + } + loadBar(i+1, ITERATIONS, ITERATIONS, 30); + } + for (j = 0; j < buffers_filled; j++) { + for (k = 0; k < 1024 ; k++) + { + mem_diff = ((uint32_t)temp_data[iterations_completed][j][k] - (uint32_t)temp_data[iterations_completed][j][k+1]); + if ((mem_diff == -1) || (k == 1023) ) + {;} + else { + fprintf(error_log, "Error in: \t IT %li \t BUF : %li \t OFFSET: %li \t | %08x --> %08x - DIFF: %d \n", iterations_completed, j, k, temp_data[iterations_completed][j][k], temp_data[iterations_completed][j][k+1], mem_diff); + err++; + } + } + if (j != buffers_filled-1) { + // Check first and Last + mem_diff = (uint32_t)(temp_data[i][j+1][0] - temp_data[i][j][1023]); + if (mem_diff == (1)) + {;} + else { + fprintf(error_log, "Error_2 in: \t IT %li \t BUF : %li \t OFFSET: %li \t | %08x --> %08x - DIFF: %d \n", iterations_completed, j, k, temp_data[iterations_completed][j+1][0], temp_data[iterations_completed][j][1023], mem_diff); + err++; + } + } + } + if (err != 0) printf("\rChecking data: \xE2\x9C\x98 %d errors found \n See \"error_log.txt\" for details \n\n", err); + else printf("\rChecking data: \xE2\x9C\x93 no errors found \n\n"); + fclose(error_log); + #endif + + + // *********** Free Memory +#ifdef CHECK_RESULTS + for (i=0; i < ITERATIONS; i++) { + for (j=0; j < BUFFERS; j++) + { + free(temp_data[i][j]); + } + } +#endif CHECK_RESULTS + + pcilib_free_kernel_memory(pci, kbuf, free_flags); + pcilib_free_kernel_memory(pci, kdesc, free_flags); + pcilib_disable_irq(pci, 0); + pcilib_unmap_bar(pci, BAR, bar); + pcilib_close(pci); + +// shmdt(shmid); +// shmctl(shmid, IPC_RMID, NULL); + +} @@ -2641,6 +2641,7 @@ int main(int argc, char **argv) { case OPT_MODEL: if (!strcasecmp(optarg, "pci")) model = PCILIB_MODEL_PCI; else if (!strcasecmp(optarg, "ipecamera")) model = PCILIB_MODEL_IPECAMERA; + else if (!strcasecmp(optarg, "kapture")) model = PCILIB_MODEL_KAPTURE; else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg); break; case OPT_BAR: @@ -21,6 +21,8 @@ typedef struct { } pcilib_dma_buffer_status_t; struct pcilib_dma_api_description_s { + const char *title; + pcilib_dma_context_t *(*init)(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg); void (*free)(pcilib_dma_context_t *ctx); diff --git a/dma/CMakeLists.txt b/dma/CMakeLists.txt index 3d4226a..44bf18c 100644 --- a/dma/CMakeLists.txt +++ b/dma/CMakeLists.txt @@ -3,7 +3,7 @@ include_directories( ) -set(HEADERS ${HEADERS} nwl.h nwl_dma.h nwl_engine.h nwl_irq.h nwl_loopback.h nwl_register.h) +set(HEADERS ${HEADERS} nwl.h nwl_private.h nwl_engine.h nwl_irq.h nwl_loopback.h nwl_register.h ipe.h ipe_private.h ipe_registers.h) -add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c nwl_register.c) +add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c nwl_register.c ipe.c) diff --git a/dma/ipe.c b/dma/ipe.c new file mode 100644 index 0000000..eb1ad6d --- /dev/null +++ b/dma/ipe.c @@ -0,0 +1,412 @@ +#define _PCILIB_DMA_IPE_C +#define _BSD_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/time.h> +#include <arpa/inet.h> + +#include "pci.h" +#include "pcilib.h" +#include "error.h" +#include "tools.h" + +#include "ipe.h" +#include "ipe_private.h" +#include "ipe_registers.h" + + +#define WR(addr, value) { *(uint32_t*)(ctx->base_addr + addr) = value; } +#define RD(addr, value) { value = *(uint32_t*)(ctx->base_addr + addr); } + + +pcilib_dma_context_t *dma_ipe_init(pcilib_t *pcilib, pcilib_dma_modification_t type, void *arg) { + int err = 0; + + pcilib_model_description_t *model_info = pcilib_get_model_description(pcilib); + + ipe_dma_t *ctx = malloc(sizeof(ipe_dma_t)); + + if (ctx) { + memset(ctx, 0, sizeof(ipe_dma_t)); + ctx->pcilib = pcilib; + + memset(ctx->engine, 0, 2 * sizeof(pcilib_dma_engine_description_t)); + ctx->engine[0].addr = 0; + ctx->engine[0].type = PCILIB_DMA_TYPE_PACKET; + ctx->engine[0].direction = PCILIB_DMA_FROM_DEVICE; + ctx->engine[0].addr_bits = 32; + pcilib_set_dma_engine_description(pcilib, 0, &ctx->engine[0]); + pcilib_set_dma_engine_description(pcilib, 1, NULL); + + pcilib_register_bank_t dma_bank = pcilib_find_bank_by_addr(pcilib, PCILIB_REGISTER_BANK_DMA); + if (dma_bank == PCILIB_REGISTER_BANK_INVALID) { + free(ctx); + pcilib_error("DMA Register Bank could not be found"); + return NULL; + } + + ctx->dma_bank = model_info->banks + dma_bank; + ctx->base_addr = pcilib_resolve_register_address(pcilib, ctx->dma_bank->bar, ctx->dma_bank->read_addr); + + err = pcilib_add_registers(ctx->pcilib, 0, ipe_dma_registers); + if (err) { + free(ctx); + pcilib_error("Error adding DMA registers"); + return NULL; + } + } + + return (pcilib_dma_context_t*)ctx; +} + +void dma_ipe_free(pcilib_dma_context_t *vctx) { + ipe_dma_t *ctx = (ipe_dma_t*)vctx; + + if (ctx) { + dma_ipe_stop(vctx, PCILIB_DMA_ENGINE_ALL, PCILIB_DMA_FLAGS_DEFAULT); + free(ctx); + } +} + + +int dma_ipe_start(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + size_t i; + + ipe_dma_t *ctx = (ipe_dma_t*)vctx; + + int preserve = 0; + pcilib_kmem_flags_t kflags; + pcilib_kmem_reuse_state_t reuse_desc, reuse_pages; + + volatile void *desc_va; + volatile uint32_t *last_written_addr_ptr; + + pcilib_register_value_t value; + + if (dma == PCILIB_DMA_ENGINE_INVALID) return 0; + else if (dma > 1) return PCILIB_ERROR_INVALID_BANK; + + if (!ctx->started) ctx->started = 1; + + if (flags&PCILIB_DMA_FLAG_PERSISTENT) ctx->preserve = 1; + + if (ctx->pages) return 0; + + kflags = PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_EXCLUSIVE|PCILIB_KMEM_FLAG_HARDWARE|(ctx->preserve?PCILIB_KMEM_FLAG_PERSISTENT:0); + pcilib_kmem_handle_t *desc = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_CONSISTENT, 1, IPEDMA_DESCRIPTOR_SIZE, IPEDMA_DESCRIPTOR_ALIGNMENT, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x00), kflags); + pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, PCILIB_KMEM_TYPE_DMA_C2S_PAGE, IPEDMA_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x00), kflags); + + if (!desc||!pages) { + if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0); + if (desc) pcilib_free_kernel_memory(ctx->pcilib, desc, 0); + return PCILIB_ERROR_MEMORY; + } + reuse_desc = pcilib_kmem_is_reused(ctx->pcilib, desc); + reuse_pages = pcilib_kmem_is_reused(ctx->pcilib, pages); + + if (reuse_desc == reuse_pages) { + if (reuse_desc & PCILIB_KMEM_REUSE_PARTIAL) pcilib_warning("Inconsistent DMA buffers are found (only part of required buffers is available), reinitializing..."); + else if (reuse_desc & PCILIB_KMEM_REUSE_REUSED) { + if ((reuse_desc & PCILIB_KMEM_REUSE_PERSISTENT) == 0) pcilib_warning("Lost DMA buffers are found (non-persistent mode), reinitializing..."); + else if ((reuse_desc & PCILIB_KMEM_REUSE_HARDWARE) == 0) pcilib_warning("Lost DMA buffers are found (missing HW reference), reinitializing..."); + else { +#ifndef IPEDMA_BUG_DMARD + RD(IPEDMA_REG_PAGE_COUNT, value); + + if ((value + 1) != IPEDMA_DMA_PAGES) pcilib_warning("Inconsistent DMA buffers are found (Number of allocated buffers does not match current request), reinitializing..."); + else +#endif /* IPEDMA_BUG_DMARD */ + preserve = 1; + } + } + } else pcilib_warning("Inconsistent DMA buffers (modes of ring and page buffers does not match), reinitializing...."); + + desc_va = pcilib_kmem_get_ua(ctx->pcilib, desc); + if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t); + else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t); + + if (preserve) { + ctx->reused = 1; + ctx->preserve = 1; + + +// usleep(100000); + + // Detect the current state of DMA engine +#ifdef IPEDMA_BUG_DMARD + FILE *f = fopen("/tmp/pcitool_lastread", "r"); + if (!f) pcilib_error("Can't read current status"); + fread(&value, 1, sizeof(pcilib_register_value_t), f); + fclose(f); +#else /* IPEDMA_BUG_DMARD */ + RD(IPEDMA_REG_LAST_READ, value); + if (value == IPEDMA_DMA_PAGES) value = 0; +#endif /* IPEDMA_BUG_DMARD */ + + ctx->last_read = value; + } else { + ctx->reused = 0; + + // Disable DMA + WR(IPEDMA_REG_CONTROL, 0x0); + + // Reset DMA engine + WR(IPEDMA_REG_RESET, 0x1); + usleep(100000); + WR(IPEDMA_REG_RESET, 0x0); + +#ifndef IPEDMA_BUG_DMARD + // Verify PCIe link status + RD(IPEDMA_REG_RESET, value); + if (value != 0x14031700) pcilib_warning("PCIe is not ready"); +#endif /* IPEDMA_BUG_DMARD */ + + // Configuring TLP and PACKET sizes (40 bit mode can be used with big pre-allocated buffers later) + WR(IPEDMA_REG_TLP_SIZE, IPEDMA_TLP_SIZE); + WR(IPEDMA_REG_TLP_COUNT, IPEDMA_PAGE_SIZE / (4 * IPEDMA_TLP_SIZE * IPEDMA_CORES)); + + // Setting progress register threshold + WR(IPEDMA_REG_UPDATE_THRESHOLD, IPEDMA_DMA_PROGRESS_THRESHOLD); + + // Reseting configured DMA pages + WR(IPEDMA_REG_PAGE_COUNT, 0); + + // Setting current read position and configuring progress register + WR(IPEDMA_REG_LAST_READ, IPEDMA_DMA_PAGES - 2 + 1); + WR(IPEDMA_REG_UPDATE_ADDR, pcilib_kmem_get_block_ba(ctx->pcilib, desc, 0)); + + // Instructing DMA engine that writting should start from the first DMA page + *last_written_addr_ptr = 0;//htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, IPEDMA_DMA_PAGES - 1)); + + + for (i = 0; i < IPEDMA_DMA_PAGES; i++) { + uintptr_t bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, pages, i); + WR(IPEDMA_REG_PAGE_ADDR, bus_addr); + if (bus_addr%4096) printf("Bad address %lu: %lx\n", i, bus_addr); + usleep(1000); + } + + // Enable DMA + WR(IPEDMA_REG_CONTROL, 0x1); + + ctx->last_read = IPEDMA_DMA_PAGES - 1; + +#ifdef IPEDMA_BUG_DMARD + FILE *f = fopen("/tmp/pcitool_lastread", "w"); + if (!f) pcilib_error("Can't write current status"); + value = ctx->last_read; + fwrite(&value, 1, sizeof(pcilib_register_value_t), f); + fclose(f); +#endif /* IPEDMA_BUG_DMARD */ + } + + ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, pages, ctx->last_read)); + + + ctx->desc = desc; + ctx->pages = pages; + ctx->page_size = pcilib_kmem_get_block_size(ctx->pcilib, pages, 0);; + ctx->ring_size = IPEDMA_DMA_PAGES; + + return 0; +} + +int dma_ipe_stop(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + pcilib_kmem_flags_t kflags; + + ipe_dma_t *ctx = (ipe_dma_t*)vctx; + + if (!ctx->started) return 0; + + if ((dma != PCILIB_DMA_ENGINE_INVALID)&&(dma > 1)) return PCILIB_ERROR_INVALID_BANK; + + // ignoring previous setting if flag specified + if (flags&PCILIB_DMA_FLAG_PERSISTENT) { + ctx->preserve = 0; + } + + if (ctx->preserve) { + kflags = PCILIB_KMEM_FLAG_REUSE; + } else { + kflags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT; + + ctx->started = 0; + + // Disable DMA + WR(IPEDMA_REG_CONTROL, 0); + + // Reset DMA engine + WR(IPEDMA_REG_RESET, 0x1); + usleep(100000); + WR(IPEDMA_REG_RESET, 0x0); + + // Reseting configured DMA pages + WR(IPEDMA_REG_PAGE_COUNT, 0); + } + + // Clean buffers + if (ctx->desc) { + pcilib_free_kernel_memory(ctx->pcilib, ctx->desc, kflags); + ctx->desc = NULL; + } + + if (ctx->pages) { + pcilib_free_kernel_memory(ctx->pcilib, ctx->pages, kflags); + ctx->pages = NULL; + } + + return 0; +} + + +int dma_ipe_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) { + size_t i; + ipe_dma_t *ctx = (ipe_dma_t*)vctx; + + void *desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc); + uint32_t *last_written_addr_ptr; + uint32_t last_written_addr; + + + if (!status) return -1; + + if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t); + else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t); + + last_written_addr = ntohl(*last_written_addr_ptr); + + status->started = ctx->started; + status->ring_size = ctx->ring_size; + status->buffer_size = ctx->page_size; + + status->ring_tail = ctx->last_read + 1; + if (status->ring_tail == status->ring_size) status->ring_tail = 0; + + // Find where the ring head is actually are + for (i = 0; i < ctx->ring_size; i++) { + uintptr_t bus_addr = pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, i); + + if (bus_addr == last_written_addr) { + status->ring_head = bus_addr; + break; + } + } + + if (i == ctx->ring_size) { + // ERROR + } + + if (n_buffers > ctx->ring_size) n_buffers = ctx->ring_size; + + memset(buffers, 0, n_buffers * sizeof(pcilib_dma_engine_status_t)); + + if (status->ring_head > status->ring_tail) { + for (i = status->ring_tail; i <= status->ring_head; i++) { + buffers[i].used = 1; + buffers[i].size = ctx->page_size; + buffers[i].first = 1; + buffers[i].last = 1; + } + } else { + for (i = 0; i <= status->ring_tail; i++) { + buffers[i].used = 1; + buffers[i].size = ctx->page_size; + buffers[i].first = 1; + buffers[i].last = 1; + } + + for (i = status->ring_head; i < status->ring_size; i++) { + buffers[i].used = 1; + buffers[i].size = ctx->page_size; + buffers[i].first = 1; + buffers[i].last = 1; + } + } + + return 0; +} + +int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) { + int err, ret = PCILIB_STREAMING_REQ_PACKET; + + pcilib_register_value_t value; + + pcilib_timeout_t wait = 0; + struct timeval start, cur; + + volatile void *desc_va; + volatile uint32_t *last_written_addr_ptr; + + size_t cur_read; + + ipe_dma_t *ctx = (ipe_dma_t*)vctx; + + err = dma_ipe_start(vctx, dma, PCILIB_DMA_FLAGS_DEFAULT); + if (err) return err; + + desc_va = (void*)pcilib_kmem_get_ua(ctx->pcilib, ctx->desc); + + if (ctx->mode64) last_written_addr_ptr = desc_va + 3 * sizeof(uint32_t); + else last_written_addr_ptr = desc_va + 4 * sizeof(uint32_t); + + do { + switch (ret&PCILIB_STREAMING_TIMEOUT_MASK) { + case PCILIB_STREAMING_CONTINUE: wait = PCILIB_DMA_TIMEOUT; break; + case PCILIB_STREAMING_WAIT: wait = timeout; break; +// case PCILIB_STREAMING_CHECK: wait = 0; break; + } + +#ifdef IPEDMA_DEBUG + printf("Waiting for data: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", ctx->last_read, ctx->last_read_addr, *last_written_addr_ptr); +#endif /* IPEDMA_DEBUG */ + + gettimeofday(&start, NULL); + while (((*last_written_addr_ptr == 0)||(ctx->last_read_addr == (*last_written_addr_ptr)))&&((wait == PCILIB_TIMEOUT_INFINITE)||(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < wait))) { + usleep(10); + gettimeofday(&cur, NULL); + } + + // Failing out if we exited on timeout + if ((ctx->last_read_addr == (*last_written_addr_ptr))||(*last_written_addr_ptr == 0)) + return (ret&PCILIB_STREAMING_FAIL)?PCILIB_ERROR_TIMEOUT:0; + + // Getting next page to read + cur_read = ctx->last_read + 1; + if (cur_read == ctx->ring_size) cur_read = 0; + +#ifdef IPEDMA_DEBUG + printf("Reading: %u (last read) 0x%x (last read addr) 0x%x (last_written)\n", cur_read, ctx->last_read_addr, *last_written_addr_ptr); +#endif /* IPEDMA_DEBUG */ + + pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_FROMDEVICE, cur_read); + void *buf = pcilib_kmem_get_block_ua(ctx->pcilib, ctx->pages, cur_read); + ret = cb(cbattr, PCILIB_DMA_FLAG_EOP, ctx->page_size, buf); + if (ret < 0) return -ret; + +// DS: Fixme, it looks like we can avoid calling this for the sake of performance +// pcilib_kmem_sync_block(ctx->pcilib, ctx->pages, PCILIB_KMEM_SYNC_TODEVICE, cur_read); + + WR(IPEDMA_REG_LAST_READ, ctx->last_read + 1); + + ctx->last_read = cur_read; + ctx->last_read_addr = htonl(pcilib_kmem_get_block_ba(ctx->pcilib, ctx->pages, cur_read)); + +#ifdef IPEDMA_BUG_DMARD + FILE *f = fopen("/tmp/pcitool_lastread", "w"); + if (!f) pcilib_error("Can't write current status"); + value = cur_read; + fwrite(&value, 1, sizeof(pcilib_register_value_t), f); + fclose(f); +#endif /* IPEDMA_BUG_DMARD */ + + } while (ret); + + return 0; +} + +double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) { + return 0; +} diff --git a/dma/ipe.h b/dma/ipe.h new file mode 100644 index 0000000..2c34ff1 --- /dev/null +++ b/dma/ipe.h @@ -0,0 +1,42 @@ +#ifndef _PCILIB_DMA_IPE_H +#define _PCILIB_DMA_IPE_H + +#include <stdio.h> +#include "../pcilib.h" + +//#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100 + +pcilib_dma_context_t *dma_ipe_init(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg); +void dma_ipe_free(pcilib_dma_context_t *vctx); + +int dma_ipe_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); + + +int dma_ipe_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); +int dma_ipe_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); + +int dma_ipe_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); +double dma_ipe_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); + + +#ifdef _PCILIB_DMA_IPE_C +pcilib_dma_api_description_t ipe_dma_api = { + "ipe_dma", + dma_ipe_init, + dma_ipe_free, + dma_ipe_get_status, + NULL, + NULL, + NULL, + dma_ipe_start, + dma_ipe_stop, + NULL, + dma_ipe_stream_read, + dma_ipe_benchmark +}; +#else +extern pcilib_dma_api_description_t ipe_dma_api; +#endif + + +#endif /* _PCILIB_DMA_IPE_H */ diff --git a/dma/ipe_private.h b/dma/ipe_private.h new file mode 100644 index 0000000..e6e70c2 --- /dev/null +++ b/dma/ipe_private.h @@ -0,0 +1,56 @@ +#ifndef _PCILIB_DMA_IPE_PRIVATE_H +#define _PCILIB_DMA_IPE_PRIVATE_H + +#define IPEDMA_CORES 1 +#define IPEDMA_TLP_SIZE 32 +#define IPEDMA_PAGE_SIZE 4096 +#define IPEDMA_DMA_PAGES 16 /**< number of DMA pages in the ring buffer to allocate */ +#define IPEDMA_DMA_PROGRESS_THRESHOLD 1 /**< how many pages the DMA engine should fill before reporting progress */ +#define IPEDMA_DESCRIPTOR_SIZE 128 +#define IPEDMA_DESCRIPTOR_ALIGNMENT 64 + +//#define IPEDMA_DEBUG +#define IPEDMA_BUG_DMARD /**< No register read during DMA transfer */ + +#define IPEDMA_REG_RESET 0x00 +#define IPEDMA_REG_CONTROL 0x04 +#define IPEDMA_REG_TLP_SIZE 0x0C +#define IPEDMA_REG_TLP_COUNT 0x10 +#define IPEDMA_REG_PAGE_ADDR 0x50 +#define IPEDMA_REG_UPDATE_ADDR 0x54 +#define IPEDMA_REG_LAST_READ 0x58 +#define IPEDMA_REG_PAGE_COUNT 0x5C +#define IPEDMA_REG_UPDATE_THRESHOLD 0x60 + + + +typedef struct ipe_dma_s ipe_dma_t; + +struct ipe_dma_s { + struct pcilib_dma_context_s dmactx; + pcilib_dma_engine_description_t engine[2]; + + pcilib_t *pcilib; + + pcilib_register_bank_description_t *dma_bank; + char *base_addr; + + pcilib_irq_type_t irq_enabled; /**< indicates that IRQs are enabled */ + pcilib_irq_type_t irq_preserve; /**< indicates that IRQs should not be disabled during clean-up */ + int irq_started; /**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */ + + int started; /**< indicates that DMA buffers are initialized and reading is allowed */ + int writting; /**< indicates that we are in middle of writting packet */ + int reused; /**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */ + int preserve; /**< indicates that DMA should not be stopped during clean-up */ + int mode64; /**< indicates 64-bit operation mode */ + + pcilib_kmem_handle_t *desc; /**< in-memory status descriptor written by DMA engine upon operation progess */ + pcilib_kmem_handle_t *pages; /**< collection of memory-locked pages for DMA operation */ + + size_t ring_size, page_size; + size_t last_read, last_read_addr, last_written; + +}; + +#endif /* _PCILIB_DMA_IPE_PRIVATE_H */ diff --git a/dma/ipe_registers.h b/dma/ipe_registers.h new file mode 100644 index 0000000..17fc41a --- /dev/null +++ b/dma/ipe_registers.h @@ -0,0 +1,44 @@ +#ifndef _PCILIB_DMA_IPE_REGISTERS_H +#define _PCILIB_DMA_IPE_REGISTERS_H + +#ifdef _PCILIB_DMA_IPE_C +static pcilib_register_description_t ipe_dma_registers[] = { + {0x0000, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "dcr", "Device Control Status Register"}, + {0x0000, 0, 1, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "reset_dma", ""}, + {0x0000, 16, 4, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "datapath_width", ""}, + {0x0000, 24, 8, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "fpga_family", ""}, + {0x0004, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "ddmacr", "Device DMA Control Status Register"}, + {0x0004, 0, 1, 0, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_start", "Start writting memory"}, + {0x0004, 5, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_relxed_order", ""}, + {0x0004, 6, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_nosnoop", ""}, + {0x0004, 7, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_int_dis", ""}, + {0x0004, 16, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_start", ""}, + {0x0004, 21, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_relaxed_order", ""}, + {0x0004, 22, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_nosnoop", ""}, + {0x0004, 23, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mrd_int_dis", ""}, + {0x000C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_size", "DMA TLP size"}, + {0x000C, 0, 16, 0x20, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_len", "Max TLP size"}, + {0x000C, 16, 3, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_tlp_tc", "TC for TLP packets"}, + {0x000C, 19, 1, 0, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_64b_en", "Enable 64 bit memory addressing"}, + {0x000C, 20, 1, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_phant_func_dis", "Disable MWR phantom function"}, + {0x000C, 24, 8, 0, 0xFFFFFFFF, PCILIB_REGISTER_RW , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "mwr_up_addr", "Upper address for 64 bit memory addressing"}, + {0x0010, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_count", "Write DMA TLP Count"}, + {0x0014, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_pattern", "DMA generator data pattern"}, + {0x0028, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "mwr_perf", "MWR Performance"}, + {0x003C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "cfg_lnk_width", "Negotiated and max width of PCIe Link"}, + {0x003C, 0, 6, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_cap_max_lnk_width", "Max link width"}, + {0x003C, 8, 6, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_prg_max_lnk_width", "Negotiated link width"}, + {0x0040, 0, 32, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "cfg_payload_size", ""}, + {0x0040, 0, 4, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_cap_max_payload_size", "Max payload size"}, + {0x0040, 8, 3, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_prg_max_payload_size", "Prog max payload size"}, + {0x0040, 16, 3, 0, 0x00000000, PCILIB_REGISTER_R , PCILIB_REGISTER_BITS, PCILIB_REGISTER_BANK_DMA, "cfg_max_rd_req_size", "Max read request size"}, + {0x0050, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_din", "Descriptor memory"}, + {0x0054, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_addr", "Address of progress register"}, + {0x0058, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "last_descriptor_read", "Last descriptor read by the host"}, + {0x005C, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "desc_mem_addr", "Number of descriptors configured"}, + {0x0060, 0, 32, 0, 0x00000000, PCILIB_REGISTER_RW , PCILIB_REGISTER_STANDARD, PCILIB_REGISTER_BANK_DMA, "update_thresh", "Update threshold of progress register"}, + {0, 0, 0, 0, 0x00000000, 0, 0, 0, NULL, NULL} +}; +#endif /* _PCILIB_DMA_IPE_C */ + +#endif /* _PCILIB_DMA_IPE_REGISTERS_H */ @@ -11,7 +11,7 @@ #include "pcilib.h" #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_defines.h" @@ -1,67 +1,46 @@ -#ifndef _PCILIB_NWL_H -#define _PCILIB_NWL_H +#ifndef _PCILIB_DMA_NWL_H +#define _PCILIB_DMA_NWL_H -typedef struct nwl_dma_s nwl_dma_t; -typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t; +#include <stdio.h> +#include "../pcilib.h" -#define NWL_DMA_IRQ_SOURCE 0 +#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100 -#define NWL_XAUI_ENGINE 0 -#define NWL_XRAWDATA_ENGINE 1 -#define NWL_MAX_PACKET_SIZE 4096 //16384 -//#define NWL_GENERATE_DMA_IRQ +pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg); +void dma_nwl_free(pcilib_dma_context_t *vctx); -#define PCILIB_NWL_ALIGNMENT 64 // in bytes -#define PCILIB_NWL_DMA_DESCRIPTOR_SIZE 64 // in bytes -#define PCILIB_NWL_DMA_PAGES 256 // 1024 +int dma_nwl_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); -//#define DEBUG_HARDWARE -//#define DEBUG_NWL +int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcilib_dma_flags_t flags); +int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags); +int dma_nwl_acknowledge_irq(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); -#include "nwl_dma.h" -#include "nwl_irq.h" -#include "nwl_register.h" -#include "nwl_engine.h" -#include "nwl_loopback.h" +int dma_nwl_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); +int dma_nwl_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); -#define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess) -#define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess) +int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written); +int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); +double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); -struct pcilib_nwl_engine_description_s { - pcilib_dma_engine_description_t desc; - char *base_addr; - - size_t ring_size, page_size; - size_t head, tail; - pcilib_kmem_handle_t *ring; - pcilib_kmem_handle_t *pages; - - int started; /**< indicates that DMA buffers are initialized and reading is allowed */ - int writting; /**< indicates that we are in middle of writting packet */ - int reused; /**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */ - int preserve; /**< indicates that DMA should not be stopped during clean-up */ -}; - - -struct nwl_dma_s { - struct pcilib_dma_context_s dmactx; - - pcilib_t *pcilib; - - pcilib_dma_modification_t type; - - pcilib_register_bank_description_t *dma_bank; - char *base_addr; - - pcilib_irq_type_t irq_enabled; /**< indicates that IRQs are enabled */ - pcilib_irq_type_t irq_preserve; /**< indicates that IRQs should not be disabled during clean-up */ - int started; /**< indicates that DMA subsystem is initialized and DMA engine can start */ - int irq_started; /**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */ - int loopback_started; /**< indicates that benchmarking subsystem is initialized */ - pcilib_dma_engine_t n_engines; - pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; +#ifdef _PCILIB_DMA_NWL_C +pcilib_dma_api_description_t nwl_dma_api = { + "nwl_dma", + dma_nwl_init, + dma_nwl_free, + dma_nwl_get_status, + dma_nwl_enable_irq, + dma_nwl_disable_irq, + dma_nwl_acknowledge_irq, + dma_nwl_start, + dma_nwl_stop, + dma_nwl_write_fragment, + dma_nwl_stream_read, + dma_nwl_benchmark }; +#else +extern pcilib_dma_api_description_t nwl_dma_api; +#endif -#endif /* _PCILIB_NWL_H */ +#endif /* _PCILIB_DMA_NWL_H */ diff --git a/dma/nwl_dma.h b/dma/nwl_dma.h deleted file mode 100644 index cc9e379..0000000 --- a/dma/nwl_dma.h +++ /dev/null @@ -1,45 +0,0 @@ -#ifndef _PCILIB_DMA_NWL_H -#define _PCILIB_DMA_NWL_H - -#include <stdio.h> -#include "../pcilib.h" - -#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100 - -pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx, pcilib_dma_modification_t type, void *arg); -void dma_nwl_free(pcilib_dma_context_t *vctx); - -int dma_nwl_get_status(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); - -int dma_nwl_enable_irq(pcilib_dma_context_t *vctx, pcilib_irq_type_t type, pcilib_dma_flags_t flags); -int dma_nwl_disable_irq(pcilib_dma_context_t *vctx, pcilib_dma_flags_t flags); -int dma_nwl_acknowledge_irq(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); - -int dma_nwl_start(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); -int dma_nwl_stop(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); - -int dma_nwl_write_fragment(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *data, size_t *written); -int dma_nwl_stream_read(pcilib_dma_context_t *vctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); -double dma_nwl_benchmark(pcilib_dma_context_t *vctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); - - -#ifdef _PCILIB_DMA_NWL_C -pcilib_dma_api_description_t nwl_dma_api = { - dma_nwl_init, - dma_nwl_free, - dma_nwl_get_status, - dma_nwl_enable_irq, - dma_nwl_disable_irq, - dma_nwl_acknowledge_irq, - dma_nwl_start, - dma_nwl_stop, - dma_nwl_write_fragment, - dma_nwl_stream_read, - dma_nwl_benchmark -}; -#else -extern pcilib_dma_api_description_t nwl_dma_api; -#endif - - -#endif /* _PCILIB_DMA_NWL_H */ diff --git a/dma/nwl_engine.c b/dma/nwl_engine.c index e4c102d..f541d0b 100644 --- a/dma/nwl_engine.c +++ b/dma/nwl_engine.c @@ -10,7 +10,7 @@ #include "pcilib.h" #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_defines.h" diff --git a/dma/nwl_engine_buffers.h b/dma/nwl_engine_buffers.h index 826a4d5..c45c3ca 100644 --- a/dma/nwl_engine_buffers.h +++ b/dma/nwl_engine_buffers.h @@ -94,10 +94,10 @@ static int dma_nwl_allocate_engine_buffers(nwl_dma_t *ctx, pcilib_nwl_engine_des 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); pcilib_kmem_handle_t *pages = pcilib_alloc_kernel_memory(ctx->pcilib, type, PCILIB_NWL_DMA_PAGES, 0, 0, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, sub_use), flags); - if (err) { + if (!ring||!pages) { if (pages) pcilib_free_kernel_memory(ctx->pcilib, pages, 0); - if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring, 0); - return err; + if (ring) pcilib_free_kernel_memory(ctx->pcilib, ring, 0); + return PCILIB_ERROR_MEMORY; } reuse_ring = pcilib_kmem_is_reused(ctx->pcilib, ring); diff --git a/dma/nwl_irq.c b/dma/nwl_irq.c index ee5f520..e71c76a 100644 --- a/dma/nwl_irq.c +++ b/dma/nwl_irq.c @@ -10,7 +10,7 @@ #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_defines.h" int dma_nwl_init_irq(nwl_dma_t *ctx, uint32_t val) { diff --git a/dma/nwl_loopback.c b/dma/nwl_loopback.c index ce0844f..53e0d48 100644 --- a/dma/nwl_loopback.c +++ b/dma/nwl_loopback.c @@ -9,7 +9,7 @@ #include "pcilib.h" #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_defines.h" diff --git a/dma/nwl_private.h b/dma/nwl_private.h new file mode 100644 index 0000000..756e6ca --- /dev/null +++ b/dma/nwl_private.h @@ -0,0 +1,67 @@ +#ifndef _PCILIB_DMA_NWL_PRIVATE_H +#define _PCILIB_DMA_NWL_PRIVATE_H + +typedef struct nwl_dma_s nwl_dma_t; +typedef struct pcilib_nwl_engine_description_s pcilib_nwl_engine_description_t; + +#define NWL_DMA_IRQ_SOURCE 0 + +#define NWL_XAUI_ENGINE 0 +#define NWL_XRAWDATA_ENGINE 1 +#define NWL_MAX_PACKET_SIZE 4096 //16384 +//#define NWL_GENERATE_DMA_IRQ + +#define PCILIB_NWL_ALIGNMENT 64 // in bytes +#define PCILIB_NWL_DMA_DESCRIPTOR_SIZE 64 // in bytes +#define PCILIB_NWL_DMA_PAGES 256 // 1024 + +//#define DEBUG_HARDWARE +//#define DEBUG_NWL + +#include "nwl.h" +#include "nwl_irq.h" +#include "nwl_register.h" +#include "nwl_engine.h" +#include "nwl_loopback.h" + +#define nwl_read_register(var, ctx, base, reg) pcilib_datacpy(&var, base + reg, 4, 1, ctx->dma_bank->raw_endianess) +#define nwl_write_register(var, ctx, base, reg) pcilib_datacpy(base + reg, &var, 4, 1, ctx->dma_bank->raw_endianess) + +struct pcilib_nwl_engine_description_s { + pcilib_dma_engine_description_t desc; + char *base_addr; + + size_t ring_size, page_size; + size_t head, tail; + pcilib_kmem_handle_t *ring; + pcilib_kmem_handle_t *pages; + + int started; /**< indicates that DMA buffers are initialized and reading is allowed */ + int writting; /**< indicates that we are in middle of writting packet */ + int reused; /**< indicates that DMA was found intialized, buffers were reused, and no additional initialization is needed */ + int preserve; /**< indicates that DMA should not be stopped during clean-up */ +}; + + +struct nwl_dma_s { + struct pcilib_dma_context_s dmactx; + + pcilib_t *pcilib; + + pcilib_dma_modification_t type; + + pcilib_register_bank_description_t *dma_bank; + char *base_addr; + + pcilib_irq_type_t irq_enabled; /**< indicates that IRQs are enabled */ + pcilib_irq_type_t irq_preserve; /**< indicates that IRQs should not be disabled during clean-up */ + int started; /**< indicates that DMA subsystem is initialized and DMA engine can start */ + int irq_started; /**< indicates that IRQ subsystem is initialized (detecting which types should be preserverd) */ + int loopback_started; /**< indicates that benchmarking subsystem is initialized */ + + pcilib_dma_engine_t n_engines; + pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; +}; + + +#endif /* _PCILIB_DMA_NWL_PRIVATE_H */ diff --git a/dma/nwl_register.c b/dma/nwl_register.c index 5f94e4d..6a3771a 100644 --- a/dma/nwl_register.c +++ b/dma/nwl_register.c @@ -12,7 +12,7 @@ #include "error.h" #include "tools.h" -#include "nwl.h" +#include "nwl_private.h" #include "nwl_register.h" int nwl_add_registers(nwl_dma_t *ctx) { diff --git a/driver/base.c b/driver/base.c index 58eb825..974224d 100644 --- a/driver/base.c +++ b/driver/base.c @@ -307,6 +307,8 @@ static int __devinit pcidriver_probe(struct pci_dev *pdev, const struct pci_devi mod_info("Found ML605 board at %s\n", dev_name(&pdev->dev)); } else if (id->device == PCIE_IPECAMERA_DEVICE_ID) { mod_info("Found IPE Camera at %s\n", dev_name(&pdev->dev)); + } else if (id->device == PCIE_KAPTURE_DEVICE_ID) { + mod_info("Found KAPTURE board at %s\n", dev_name(&pdev->dev)); } else { mod_info("Found unknown Xilinx device (%x) at %s\n", id->device, dev_name(&pdev->dev)); } diff --git a/driver/base.h b/driver/base.h index 84f0aad..9384e2d 100644 --- a/driver/base.h +++ b/driver/base.h @@ -47,6 +47,7 @@ static void pcidriver_exit(void); static const __devinitdata struct pci_device_id pcidriver_ids[] = { { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_ML605_DEVICE_ID ) }, // PCI-E Xilinx ML605 { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_IPECAMERA_DEVICE_ID ) }, // PCI-E IPE Camera + { PCI_DEVICE( PCIE_XILINX_VENDOR_ID, PCIE_KAPTURE_DEVICE_ID ) }, // PCI-E KAPTURE board for HEB {0,0,0,0}, }; diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 8e9c0bc..67a80f2 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -65,6 +65,7 @@ /* Identifies the PCI-E IPE Camera */ #define PCIE_IPECAMERA_DEVICE_ID 0x6081 +#define PCIE_KAPTURE_DEVICE_ID 0x6028 //#define PCIE_IPECAMERA_DEVICE_ID 0x6018 @@ -17,9 +17,13 @@ */ struct pcilib_event_api_description_s { + const char *title; + pcilib_context_t *(*init)(pcilib_t *ctx); void (*free)(pcilib_context_t *ctx); + pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx); + int (*reset)(pcilib_context_t *ctx); int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); @@ -31,8 +35,6 @@ struct pcilib_event_api_description_s { int (*get_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **data); int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); - - pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx); }; diff --git a/ipecamera/ipecamera.c b/ipecamera/ipecamera.c index 1681f7c..fe66948 100644 --- a/ipecamera/ipecamera.c +++ b/ipecamera/ipecamera.c @@ -23,12 +23,8 @@ #include "events.h" #include "data.h" -#include "dma/nwl_dma.h" -#ifdef IPECAMERA_DEBUG #include "dma/nwl.h" -#endif /* IPECAMERA_DEBUG */ - #define FIND_REG(var, bank, name) \ ctx->var = pcilib_find_register(pcilib, bank, name); \ diff --git a/ipecamera/model.h b/ipecamera/model.h index 26505ee..cc47891 100644 --- a/ipecamera/model.h +++ b/ipecamera/model.h @@ -152,9 +152,13 @@ extern pcilib_event_data_type_description_t ipecamera_data_types[]; #ifdef _IPECAMERA_IMAGE_C pcilib_event_api_description_t ipecamera_image_api = { + "ipecamera", + ipecamera_init, ipecamera_free, + ipecamera_init_dma, + ipecamera_reset, ipecamera_start, ipecamera_stop, @@ -163,8 +167,7 @@ pcilib_event_api_description_t ipecamera_image_api = { ipecamera_stream, ipecamera_next_event, ipecamera_get, - ipecamera_return, - ipecamera_init_dma + ipecamera_return }; #else extern pcilib_event_api_description_t ipecamera_image_api; diff --git a/kapture/CMakeLists.txt b/kapture/CMakeLists.txt new file mode 100644 index 0000000..af74edd --- /dev/null +++ b/kapture/CMakeLists.txt @@ -0,0 +1,9 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${UFODECODE_INCLUDE_DIRS} +) + +set(HEADERS ${HEADERS} model.h) + +add_library(kapture STATIC kapture.c) + diff --git a/kapture/kapture.c b/kapture/kapture.c new file mode 100644 index 0000000..4384592 --- /dev/null +++ b/kapture/kapture.c @@ -0,0 +1,62 @@ +#define _KAPTURE_C +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <sys/time.h> +#include <pthread.h> +#include <assert.h> + +#include "../tools.h" +#include "../error.h" +#include "../event.h" + +#include "pcilib.h" +#include "model.h" +#include "kapture.h" +#include "private.h" + + +pcilib_context_t *kapture_init(pcilib_t *vctx) { + kapture_t *ctx = malloc(sizeof(kapture_t)); + + if (ctx) { + memset(ctx, 0, sizeof(kapture_t)); + } + + return ctx; +} + +void kapture_free(pcilib_context_t *vctx) { + if (vctx) { + kapture_t *ctx = (kapture_t*)vctx; + kapture_stop(vctx, PCILIB_EVENT_FLAGS_DEFAULT); + free(ctx); + } +} + +int kapture_reset(pcilib_context_t *ctx) { +} + +int kapture_start(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) { +} + +int kapture_stop(pcilib_context_t *ctx, pcilib_event_flags_t flags) { +} + +int kapture_trigger(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { +} + +int kapture_stream(pcilib_context_t *ctx, pcilib_event_callback_t callback, void *user) { +} + +int kapture_next_event(pcilib_context_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) { +} + +int kapture_get(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **data) { +} + +int kapture_return(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { +} + + diff --git a/kapture/kapture.h b/kapture/kapture.h new file mode 100644 index 0000000..3944b8c --- /dev/null +++ b/kapture/kapture.h @@ -0,0 +1,6 @@ +#ifndef _KAPTURE_H +#define _KAPTURE_H + +typedef struct kapture_s kapture_t; + +#endif /* _KAPTURE_H */ diff --git a/kapture/model.h b/kapture/model.h new file mode 100644 index 0000000..b45969a --- /dev/null +++ b/kapture/model.h @@ -0,0 +1,81 @@ +#ifndef _KAPTURE_MODEL_H +#define _KAPTURE_MODEL_H + +#include <stdio.h> + +#include "../pcilib.h" + + +#define KAPTURE_REGISTER_SPACE 0x9000 + +#ifdef _KAPTURE_C +pcilib_register_bank_description_t kapture_register_banks[] = { +// { PCILIB_REGISTER_BANK0, PCILIB_BAR0, 0x0200, PCILIB_DEFAULT_PROTOCOL , KAPTURE_REGISTER_SPACE, KAPTURE_REGISTER_SPACE, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "fpga", "KAPTURE Registers" }, + { PCILIB_REGISTER_BANK_DMA, PCILIB_BAR0, 0x0200, PCILIB_DEFAULT_PROTOCOL , 0, 0, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, + { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } +}; + +pcilib_register_description_t kapture_registers[] = { +{0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL} +}; + +pcilib_register_range_t kapture_register_ranges[] = { + {0, 0, 0, 0} +}; + +pcilib_event_description_t kapture_events[] = { + {PCILIB_EVENT0, "event", ""}, + {0, NULL, NULL} +}; + +pcilib_event_data_type_description_t kapture_data_types[] = { + {PCILIB_EVENT_RAW_DATA, PCILIB_EVENT0, "raw", "raw data from kapture" }, + {0, 0, NULL, NULL} +}; + +#else +extern pcilib_register_description_t kapture_registers[]; +extern pcilib_register_bank_description_t kapture_register_banks[]; +extern pcilib_register_range_t kapture_register_ranges[]; +extern pcilib_event_description_t kapture_events[]; +extern pcilib_event_data_type_description_t kapture_data_types[]; +#endif + + +pcilib_context_t *kapture_init(pcilib_t *pcilib); +void kapture_free(pcilib_context_t *ctx); + +int kapture_reset(pcilib_context_t *ctx); +int kapture_start(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); +int kapture_stop(pcilib_context_t *ctx, pcilib_event_flags_t flags); +int kapture_trigger(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); +int kapture_stream(pcilib_context_t *vctx, pcilib_event_callback_t callback, void *user); +int kapture_next_event(pcilib_context_t *vctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); +int kapture_get(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **buf); +int kapture_return(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); + +#ifdef _KAPTURE_C +pcilib_event_api_description_t kapture_api = { + "kapture", + + kapture_init, + kapture_free, + + NULL, + + kapture_reset, + kapture_start, + kapture_stop, + kapture_trigger, + + kapture_stream, + kapture_next_event, + kapture_get, + kapture_return +}; +#else +extern pcilib_event_api_description_t kapture_api; +#endif + + +#endif /* _KAPTURE_MODEL_H */ diff --git a/kapture/private.h b/kapture/private.h new file mode 100644 index 0000000..bf084c3 --- /dev/null +++ b/kapture/private.h @@ -0,0 +1,10 @@ +#ifndef _KAPTURE_PRIVATE_H +#define _KAPTURE_PRIVATE_H + +struct kapture_s { + pcilib_context_t event; + +}; + + +#endif /* _KAPTURE_PRIVATE_H */ @@ -22,6 +22,7 @@ #include "error.h" #include "ipecamera/model.h" +#include "kapture/model.h" pcilib_t *pcilib_open(const char *device, pcilib_model_t model) { @@ -88,6 +89,8 @@ pcilib_model_t pcilib_get_model(pcilib_t *ctx) { if ((board_info->vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info->device_id == PCIE_IPECAMERA_DEVICE_ID)) ctx->model = PCILIB_MODEL_IPECAMERA; + else if ((board_info->vendor_id == PCIE_XILINX_VENDOR_ID)&&(board_info->device_id == PCIE_KAPTURE_DEVICE_ID)) + ctx->model = PCILIB_MODEL_KAPTURE; else ctx->model = PCILIB_MODEL_PCI; } @@ -52,13 +52,16 @@ struct pcilib_s { #ifdef _PCILIB_PCI_C # include "ipecamera/model.h" +# include "kapture/model.h" # include "dma/nwl.h" +# include "dma/ipe.h" # include "default.h" -pcilib_model_description_t pcilib_model[3] = { +pcilib_model_description_t pcilib_model[4] = { { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL, NULL }, { 4, PCILIB_HOST_ENDIAN, NULL, NULL, NULL, NULL, NULL, NULL }, - { 4, PCILIB_LITTLE_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, ipecamera_data_types, &nwl_dma_api, &ipecamera_image_api } + { 4, PCILIB_LITTLE_ENDIAN, ipecamera_registers, ipecamera_register_banks, ipecamera_register_ranges, ipecamera_events, ipecamera_data_types, &nwl_dma_api, &ipecamera_image_api }, + { 4, PCILIB_LITTLE_ENDIAN, kapture_registers, kapture_register_banks, kapture_register_ranges, kapture_events, kapture_data_types, &ipe_dma_api, &kapture_api }, }; pcilib_protocol_description_t pcilib_protocol[3] = { @@ -43,7 +43,8 @@ typedef enum { typedef enum { PCILIB_MODEL_DETECT, PCILIB_MODEL_PCI, - PCILIB_MODEL_IPECAMERA + PCILIB_MODEL_IPECAMERA, + PCILIB_MODEL_KAPTURE } pcilib_model_t; typedef enum { @@ -25,7 +25,6 @@ int pcilib_add_registers(pcilib_t *ctx, size_t n, pcilib_register_description_t for (n = 0; registers[n].bits; n++); } - if (ctx->model_info.registers == pcilib_model[ctx->model].registers) { for (n_present = 0; ctx->model_info.registers[n_present].bits; n_present++); for (size = 1024; size < 2 * (n + n_present + 1); size<<=1); diff --git a/tests/dma/ipe/bench.sh b/tests/dma/ipe/bench.sh new file mode 100755 index 0000000..cc32971 --- /dev/null +++ b/tests/dma/ipe/bench.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +size=65536 + +function pci { + PCILIB_PATH=`pwd`/../../.. + LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci -m kapture $* +} + + +rm -f bench.out + +pci --stop-dma dma0r +pci --start-dma dma0r + +# Clean DMA buffers +#while [ $? -eq 0 ]; do +# pci -r dma0 -s 65536 &> /dev/null +#done + +for i in `seq 1 100`; do + pci -r dma0 --multipacket -s $size -o bench.out + if [ $? -ne 0 ]; then + pci --stop-dma dma0r + exit + fi +done + +pci --stop-dma dma0r + +../../../apps/check_counter bench.out |