diff options
-rw-r--r-- | .bzrignore | 1 | ||||
-rw-r--r-- | CMakeLists.txt | 3 | ||||
-rw-r--r-- | apps/CMakeLists.txt | 8 | ||||
-rw-r--r-- | apps/xilinx.c | 179 | ||||
-rw-r--r-- | cli.c | 443 | ||||
-rw-r--r-- | dma.c | 44 | ||||
-rw-r--r-- | driver/Makefile | 4 | ||||
-rw-r--r-- | driver/ioctl.c | 1 | ||||
-rw-r--r-- | driver/pciDriver.h | 3 | ||||
-rw-r--r-- | driver/sysfs.c | 11 | ||||
-rw-r--r-- | kmem.c | 16 | ||||
-rw-r--r-- | kmem.h | 6 | ||||
-rw-r--r-- | pci.c | 24 | ||||
-rw-r--r-- | pcilib.h | 1 | ||||
-rw-r--r-- | pcilib_types.h | 3 | ||||
-rwxr-xr-x | tests/new_device.sh | 3 | ||||
-rwxr-xr-x | tests/xilinx_dma.sh | 121 |
17 files changed, 753 insertions, 118 deletions
@@ -18,3 +18,4 @@ cmake_install.cmake Makefile *.so.* install_manifest.txt +./xilinx diff --git a/CMakeLists.txt b/CMakeLists.txt index cb3be58..b653b09 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,7 +3,7 @@ project(pcitool) set(PCILIB_VERSION "0.0.1") set(PCILIB_ABI_VERSION "0") -cmake_minimum_required(VERSION 2.8) +cmake_minimum_required(VERSION 2.6) set(DISABLE_PCITOOL FALSE CACHE BOOL "Build only the library") @@ -25,6 +25,7 @@ add_definitions("-fPIC --std=c99 -Wall -O2") add_subdirectory(dma) add_subdirectory(ipecamera) add_subdirectory(pcitool) +add_subdirectory(apps) include_directories( ${FASTWRITER_INCLUDE_DIRS} diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt new file mode 100644 index 0000000..2f882a3 --- /dev/null +++ b/apps/CMakeLists.txt @@ -0,0 +1,8 @@ +include_directories( + ${CMAKE_SOURCE_DIR} +) + +link_directories(${UFODECODE_LIBRARY_DIRS}) + +add_executable(xilinx xilinx.c) +target_link_libraries(xilinx pcilib rt) diff --git a/apps/xilinx.c b/apps/xilinx.c new file mode 100644 index 0000000..1ec31d7 --- /dev/null +++ b/apps/xilinx.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 16 +#define ITERATIONS 16384 +#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 * 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"); + } + + 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, PAGE_SIZE, 4096, USE, 0); + + + WR(0x00, 1) + usleep(1000); + WR(0x00, 0) + WR(0x04, 0) + + WR(0x0C, 0x20) + WR(0x10, (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 * 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 */ +} @@ -16,6 +16,7 @@ #include <alloca.h> #include <arpa/inet.h> #include <sys/types.h> +#include <sys/stat.h> #include <dirent.h> #include <pthread.h> #include <signal.h> @@ -76,7 +77,11 @@ typedef enum { MODE_LIST_DMA, MODE_LIST_DMA_BUFFERS, MODE_READ_DMA_BUFFER, + MODE_ENABLE_IRQ, + MODE_DISABLE_IRQ, + MODE_ACK_IRQ, MODE_WAIT_IRQ, + MODE_ALLOC_KMEM, MODE_LIST_KMEM, MODE_READ_KMEM, MODE_FREE_KMEM @@ -85,7 +90,8 @@ typedef enum { typedef enum { ACCESS_BAR, ACCESS_DMA, - ACCESS_FIFO + ACCESS_FIFO, + ACCESS_CONFIG } ACCESS_MODE; typedef enum { @@ -140,12 +146,20 @@ typedef enum { OPT_READ_DMA_BUFFER, OPT_START_DMA, OPT_STOP_DMA, + OPT_ENABLE_IRQ, + OPT_DISABLE_IRQ, + OPT_ACK_IRQ, OPT_WAIT_IRQ, OPT_ITERATIONS, + OPT_ALLOC_KMEM, OPT_LIST_KMEM, OPT_FREE_KMEM, OPT_READ_KMEM, + OPT_BLOCK_SIZE, + OPT_ALIGNMENT, + OPT_TYPE, OPT_FORCE, + OPT_VERIFY, OPT_WAIT, OPT_MULTIPACKET, OPT_VERBOSE @@ -182,13 +196,21 @@ static struct option long_options[] = { {"list-dma-engines", no_argument, 0, OPT_LIST_DMA }, {"list-dma-buffers", required_argument, 0, OPT_LIST_DMA_BUFFERS }, {"read-dma-buffer", required_argument, 0, OPT_READ_DMA_BUFFER }, + {"enable-irq", optional_argument, 0, OPT_ENABLE_IRQ }, + {"disable-irq", optional_argument, 0, OPT_DISABLE_IRQ }, + {"acknowledge-irq", optional_argument, 0, OPT_ACK_IRQ }, {"wait-irq", optional_argument, 0, OPT_WAIT_IRQ }, - {"list-kernel-memory", no_argument, 0, OPT_LIST_KMEM }, + {"list-kernel-memory", optional_argument, 0, OPT_LIST_KMEM }, {"read-kernel-memory", required_argument, 0, OPT_READ_KMEM }, + {"alloc-kernel-memory", required_argument, 0, OPT_ALLOC_KMEM }, {"free-kernel-memory", required_argument, 0, OPT_FREE_KMEM }, + {"type", required_argument, 0, OPT_TYPE }, + {"block-size", required_argument, 0, OPT_BLOCK_SIZE }, + {"alignment", required_argument, 0, OPT_ALIGNMENT }, {"quiete", no_argument, 0, OPT_QUIETE }, {"verbose", optional_argument, 0, OPT_VERBOSE }, {"force", no_argument, 0, OPT_FORCE }, + {"verify", no_argument, 0, OPT_VERIFY }, {"multipacket", no_argument, 0, OPT_MULTIPACKET }, {"wait", no_argument, 0, OPT_WAIT }, {"help", no_argument, 0, OPT_HELP }, @@ -226,18 +248,24 @@ void Usage(int argc, char *argv[], const char *format, ...) { " --trigger [event] - Trigger Events\n" " -g [event] - Grab Events\n" "\n" +" IRQ Modes:\n" +" --enable-irq [type] - Enable IRQs\n" +" --disable-irq [type] - Disable IRQs\n" +" --acknowledge-irq <source> - Clean IRQ queue\n" +" --wait-irq <source> - Wait for IRQ\n" + " DMA Modes:\n" " --start-dma <num>[r|w] - Start specified DMA engine\n" " --stop-dma [num[r|w]] - Stop specified engine or DMA subsystem\n" " --list-dma-engines - List active DMA engines\n" " --list-dma-buffers <dma> - List buffers for specified DMA engine\n" " --read-dma-buffer <dma:buf> - Read the specified buffer\n" -" --wait-irq <source> - Wait for IRQ\n" "\n" " Kernel Modes:\n" -" --list-kernel-memory - List kernel buffers\n" +" --list-kernel-memory [use] - List kernel buffers\n" " --read-kernel-memory <blk> - Read the specified block of the kernel memory\n" " block is specified as: use:block_number\n" +" --alloc-kernel-memory <use> - Allocate kernel buffers (DANGEROUS)\n" " --free-kernel-memory <use> - Cleans lost kernel space buffers (DANGEROUS)\n" " dma - Remove all buffers allocated by DMA subsystem\n" " #number - Remove all buffers with the specified use id\n" @@ -251,10 +279,11 @@ void Usage(int argc, char *argv[], const char *format, ...) { "\n" " Options:\n" " -s <size> - Number of words (default: 1)\n" -" -a [fifo|dma]<bits> - Access type and bits per word (default: 32)\n" +" -a [fifo|dma|config]<bits> - Access type and bits per word (default: 32)\n" " -e <l|b> - Endianess Little/Big (default: host)\n" " -o <file> - Append output to file (default: stdout)\n" " -t <timeout|unlimited> - Timeout in microseconds\n" +" --check - Verify write operations\n" "\n" " Event Options:\n" " --event <evt> - Specifies event for trigger and grab modes\n" @@ -277,6 +306,15 @@ void Usage(int argc, char *argv[], const char *format, ...) { " --multipacket - Read multiple packets\n" " --wait - Wait until data arrives\n" "\n" +" Kernel Options:\n" +" --type <type> - Type of kernel memory to allocate\n" +" consistent - Consistent memory\n" +" s2c - DMA S2C (write) memory\n" +" c2s - DMA C2S (read) memory\n" +" --page-size <size> - Size of kernel buffer in bytes (default: page)\n" +" -s <size> - Number of buffers to allocate (default: 1)\n" +" --allignment <alignment> - Buffer alignment (default: page)\n" +"\n" " Information:\n" " --verbose [level] - Announce details of ongoing operations\n" " -q - Quiete mode (suppress warnings)\n" @@ -471,7 +509,8 @@ void List(pcilib_t *handle, pcilib_model_description_t *model_info, const char * void Info(pcilib_t *handle, pcilib_model_description_t *model_info) { const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); - printf("Vendor: %x, Device: %x, Interrupt Pin: %i, Interrupt Line: %i\n", board_info->vendor_id, board_info->device_id, board_info->interrupt_pin, board_info->interrupt_line); + printf("Vendor: %x, Device: %x, Bus: %x, Slot: %x, Function: %x\n", board_info->vendor_id, board_info->device_id, board_info->bus, board_info->slot, board_info->func); + printf(" Interrupt - Pin: %i, Line: %i\n", board_info->interrupt_pin, board_info->interrupt_line); List(handle, model_info, (char*)-1, 0); } @@ -491,6 +530,9 @@ int Benchmark(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, size_t irqs; const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); + + if (mode == ACCESS_CONFIG) + Error("No benchmarking of configuration space acess is allowed"); if (mode == ACCESS_DMA) { if (n) { @@ -721,7 +763,12 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_ int numbers_per_block, numbers_per_line; pcilib_dma_engine_t dmaid; pcilib_dma_flags_t dma_flags = 0; - + + int fd; + char stmp[256]; + struct stat st; + const pcilib_board_info_t *board_info; + numbers_per_block = BLOCK_SIZE / access; block_width = numbers_per_block * ((access * 2) + SEPARATOR_WIDTH); @@ -782,6 +829,33 @@ int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_ pcilib_read_fifo(handle, bar, addr, access, n, buf); addr = 0; break; + case ACCESS_CONFIG: + board_info = pcilib_get_board_info(handle); + sprintf(stmp, "/sys/bus/pci/devices/0000:%02x:%02x.%1x/config", board_info->bus, board_info->slot, board_info->func); + fd = open(stmp, O_RDONLY); + + if ((!fd)||(fstat(fd, &st))) Error("Can't open %s", stmp); + + if (st.st_size < addr) + Error("Access beyond the end of PCI configuration space"); + + if (st.st_size < (addr + size)) { + n = (st.st_size - addr) / abs(access); + size = n * abs(access); + if (!n) Error("Access beyond the end of PCI configuration space"); + } + + lseek(fd, addr, SEEK_SET); + ret = read(fd, buf, size); + if (ret == (size_t)-1) Error("Error reading %s", stmp); + + if (ret < size) { + size = ret; + n = ret / abs(access); + } + + close(fd); + break; default: pcilib_read(handle, bar, addr, size, buf); } @@ -949,7 +1023,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_description_t *model_info, return 0; } -int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) { +int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data, int verify) { int read_back = 0; void *buf, *check; int res = 0, i, err; @@ -957,6 +1031,9 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, size_t ret; pcilib_dma_engine_t dmaid; + if (mode == ACCESS_CONFIG) + Error("Writting to PCI configuration space is not supported"); + err = posix_memalign( (void**)&buf, 256, size ); if (!err) err = posix_memalign( (void**)&check, 256, size ); if ((err)||(!buf)||(!check)) Error("Allocation of %i bytes of memory have failed", size); @@ -991,8 +1068,10 @@ int WriteData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_engine_addr_t dma, break; default: pcilib_write(handle, bar, addr, size, buf); - pcilib_read(handle, bar, addr, size, check); - read_back = 1; + if (verify) { + pcilib_read(handle, bar, addr, size, check); + read_back = 1; + } } if ((read_back)&&(memcmp(buf, check, size))) { @@ -1731,7 +1810,7 @@ int StartStopDMA(pcilib_t *handle, pcilib_model_description_t *model_info, pcil typedef struct { - unsigned long use; + pcilib_kmem_use_t use; int referenced; int hw_lock; @@ -1745,7 +1824,23 @@ typedef struct { #define MAX_USES 64 -size_t FindUse(size_t *n_uses, kmem_use_info_t *uses, unsigned long use) { +pcilib_kmem_use_t ParseUse(const char *use) { + unsigned long utmp; + + if (use) { + if ((!isxnumber(use))||(sscanf(use, "%lx", &utmp) != 1)) Error("Invalid use (%s) is specified", use); + + if (strlen(use) < 5) + return PCILIB_KMEM_USE(PCILIB_KMEM_USE_USER,utmp); + else + return utmp; + } + + Error("Kernel memory use is not specified"); + return 0; +} + +size_t FindUse(size_t *n_uses, kmem_use_info_t *uses, pcilib_kmem_use_t use) { size_t i, n = *n_uses; if (uses[n - 1].use == use) return n - 1; @@ -1760,17 +1855,28 @@ size_t FindUse(size_t *n_uses, kmem_use_info_t *uses, unsigned long use) { return (*n_uses)++; } -int ListKMEM(pcilib_t *handle, const char *device) { + +kmem_use_info_t *GetUse(size_t n_uses, kmem_use_info_t *uses, pcilib_kmem_use_t use) { + size_t i; + for (i = 0; i < n_uses; i++) { + if (uses[i].use == use) { + if (uses[i].count) return uses + i; + else return NULL; + } + } + return NULL; +} + + +int ParseKMEM(pcilib_t *handle, const char *device, size_t *uses_number, kmem_use_info_t *uses) { DIR *dir; struct dirent *entry; const char *pos; char sysdir[256]; char fname[256]; char info[256]; - char stmp[256]; - - size_t useid, i, n_uses = 1; // Use 0 is for others - kmem_use_info_t uses[MAX_USES]; + + size_t useid, n_uses = 1; // Use 0 is for others memset(uses, 0, sizeof(uses)); @@ -1819,6 +1925,21 @@ int ListKMEM(pcilib_t *handle, const char *device) { } closedir(dir); + *uses_number = n_uses; + + return 0; +} + +int ListKMEM(pcilib_t *handle, const char *device) { + int err; + char stmp[256]; + + size_t i, useid, n_uses; + kmem_use_info_t uses[MAX_USES]; + + err = ParseKMEM(handle, device, &n_uses, uses); + if (err) Error("Failed to parse kernel memory information provided through sysfs"); + if ((n_uses == 1)&&(uses[0].count == 0)) { printf("No kernel memory is allocated\n"); return 0; @@ -1832,10 +1953,11 @@ int ListKMEM(pcilib_t *handle, const char *device) { i = 0; } else i = useid + 1; - printf("%08lx ", uses[i].use); + printf("%08x ", uses[i].use); if (!i) printf("All Others "); - else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%lu %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); - else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%lu %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_RING) printf("DMA%u %s Ring ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_DMA_PAGES) printf("DMA%u %s Pages ", uses[i].use&0x7F, ((uses[i].use&0x80)?"S2C":"C2S")); + else if ((uses[i].use >> 16) == PCILIB_KMEM_USE_USER) printf("User %04x ", uses[i].use&0xFFFF); else printf (" "); printf(" "); printf("% 6lu", uses[i].count); @@ -1860,13 +1982,60 @@ int ListKMEM(pcilib_t *handle, const char *device) { return 0; } -int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t block, size_t max_size, FILE *o) { +int DetailKMEM(pcilib_t *handle, const char *device, const char *use, size_t block) { + int err; + size_t i, n; + pcilib_kmem_handle_t *kbuf; + pcilib_kmem_use_t useid = ParseUse(use); + + size_t n_uses; + kmem_use_info_t uses[MAX_USES]; + kmem_use_info_t *use_info; + + if (block == (size_t)-1) { + err = ParseKMEM(handle, device, &n_uses, uses); + if (err) Error("Failed to parse kernel memory information provided through sysfs"); + use_info = GetUse(n_uses, uses, useid); + if (!use_info) Error("No kernel buffers is allocated for the specified use (%lx)", useid); + + i = 0; + n = use_info->count; + } else { + i = block; + n = block + 1; + } + + kbuf = pcilib_alloc_kernel_memory(handle, 0, n, 0, 0, useid, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY); + if (!kbuf) { + Error("Allocation of kernel buffer (use %lx, count %lu) is failed\n", useid, n); + return 0; + } + + printf("Buffer Address Hardware Address Bus Address\n"); + printf("--------------------------------------------------------------------------------\n"); + for (; i < n; i++) { + void *data = pcilib_kmem_get_block_ua(handle, kbuf, i); + uintptr_t pa = pcilib_kmem_get_block_pa(handle, kbuf, i); + uintptr_t ba = pcilib_kmem_get_block_ba(handle, kbuf, i); + printf("%6lu %16p %16lx %16lx\n", i, data, pa, ba); + } + printf("\n"); + + pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); + + return 0; +} + + +int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t useid, size_t block, size_t max_size, FILE *o) { int err; void *data; size_t size; pcilib_kmem_handle_t *kbuf; - kbuf = pcilib_alloc_kernel_memory(handle, 0, block + 1, 0, 0, use, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY); + if (block == (size_t)-1) block = 0; + + kbuf = pcilib_alloc_kernel_memory(handle, 0, block + 1, 0, 0, useid, PCILIB_KMEM_FLAG_REUSE|PCILIB_KMEM_FLAG_TRY); if (!kbuf) { Error("The specified kernel buffer is not allocated\n"); return 0; @@ -1896,11 +2065,37 @@ int ReadKMEM(pcilib_t *handle, const char *device, pcilib_kmem_use_t use, size_t return 0; } +int AllocKMEM(pcilib_t *handle, const char *device, const char *use, const char *type, size_t size, size_t block_size, size_t alignment) { + pcilib_kmem_type_t ktype = PCILIB_KMEM_TYPE_PAGE; + pcilib_kmem_flags_t flags = KMEM_FLAG_REUSE; + pcilib_kmem_handle_t *kbuf; + pcilib_kmem_use_t useid = ParseUse(use); + + long page_size = sysconf(_SC_PAGESIZE); + + if (type) { + if (!strcmp(type, "consistent")) ktype = PCILIB_KMEM_TYPE_CONSISTENT; + else if (!strcmp(type, "c2s")) ktype = PCILIB_KMEM_TYPE_DMA_C2S_PAGE; + else if (!strcmp(type, "s2c")) ktype = PCILIB_KMEM_TYPE_DMA_S2C_PAGE; + else Error("Invalid memory type (%s) is specified", type); + } + + if ((block_size)&&(ktype != PCILIB_KMEM_TYPE_CONSISTENT)) + Error("Selected memory type does not allow custom size"); + + kbuf = pcilib_alloc_kernel_memory(handle, ktype, size, (block_size?block_size:page_size), (alignment?alignment:page_size), useid, flags|KMEM_FLAG_PERSISTENT); + if (!kbuf) Error("Allocation of kernel memory has failed"); + + pcilib_free_kernel_memory(handle, kbuf, flags); + + return 0; +} + int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) { int err; int i; - unsigned long useid; + pcilib_kmem_use_t useid; pcilib_kmem_flags_t flags = PCILIB_KMEM_FLAG_HARDWARE|PCILIB_KMEM_FLAG_PERSISTENT|PCILIB_KMEM_FLAG_EXCLUSIVE; if (force) flags |= PCILIB_KMEM_FLAG_FORCE; // this will ignore mmap locks as well. @@ -1920,8 +2115,7 @@ int FreeKMEM(pcilib_t *handle, const char *device, const char *use, int force) { return 0; } - if ((!isxnumber(use))||(sscanf(use, "%lx", &useid) != 1)) Error("Invalid use (%s) is specified", use); - + useid = ParseUse(use); err = pcilib_clean_kernel_memory(handle, useid, flags); if (err) Error("Error cleaning kernel buffers for use (0x%lx)", useid); @@ -1956,10 +2150,10 @@ int ListDMA(pcilib_t *handle, const char *device, pcilib_model_description_t *mo while ((entry = readdir(dir)) != NULL) { FILE *f; unsigned long use = 0; - unsigned long size = 0; - unsigned long refs = 0; +// unsigned long size = 0; +// unsigned long refs = 0; unsigned long mode = 0; - unsigned long hwref = 0; +// unsigned long hwref = 0; if (strncmp(entry->d_name, "kbuf", 4)) continue; if (!isnumber(entry->d_name+4)) continue; @@ -1971,10 +2165,10 @@ int ListDMA(pcilib_t *handle, const char *device, pcilib_model_description_t *mo while(!feof(f)) { fgets(info, 256, f); if (!strncmp(info, "use:", 4)) use = strtoul(info+4, NULL, 16); - if (!strncmp(info, "size:", 5)) size = strtoul(info+5, NULL, 10); - if (!strncmp(info, "refs:", 5)) refs = strtoul(info+5, NULL, 10); +// if (!strncmp(info, "size:", 5)) size = strtoul(info+5, NULL, 10); +// if (!strncmp(info, "refs:", 5)) refs = strtoul(info+5, NULL, 10); if (!strncmp(info, "mode:", 5)) mode = strtoul(info+5, NULL, 16); - if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); +// if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); } fclose(f); @@ -2109,13 +2303,38 @@ int ReadBuffer(pcilib_t *handle, const char *device, pcilib_model_description_t } +int EnableIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_type_t irq_type) { + int err; + + err = pcilib_enable_irq(handle, irq_type, 0); + if (err) { + if ((err != PCILIB_ERROR_NOTSUPPORTED)&&(err != PCILIB_ERROR_NOTAVAILABLE)) + Error("Error enabling IRQs"); + } + + return err; +} + +int DisableIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_type_t irq_type) { + int err; + + err = pcilib_disable_irq(handle, 0); + if (err) { + if ((err != PCILIB_ERROR_NOTSUPPORTED)&&(err != PCILIB_ERROR_NOTAVAILABLE)) + Error("Error disabling IRQs"); + } + + return err; +} + +int AckIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source) { + pcilib_clear_irq(handle, irq_source); + return 0; +} int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source, pcilib_timeout_t timeout) { int err; size_t count; - - err = pcilib_enable_irq(handle, PCILIB_EVENT_IRQ, 0); - if (err) Error("Error enabling IRQs"); err = pcilib_wait_irq(handle, irq_source, timeout, &count); if (err) { @@ -2130,7 +2349,6 @@ int WaitIRQ(pcilib_t *handle, pcilib_model_description_t *model_info, pcilib_irq int main(int argc, char **argv) { int i; long itmp; - unsigned long utmp; size_t ztmp; unsigned char c; @@ -2141,6 +2359,7 @@ int main(int argc, char **argv) { int verbose = 0; int quiete = 0; int force = 0; + int verify = 0; pcilib_model_t model = PCILIB_MODEL_DETECT; pcilib_model_description_t *model_info; @@ -2153,6 +2372,7 @@ int main(int argc, char **argv) { FORMAT format = FORMAT_DEFAULT; PARTITION partition = PARTITION_UNKNOWN; FLAGS flags = 0; + const char *atype = NULL; const char *type = NULL; ACCESS_MODE amode = ACCESS_BAR; const char *fpga_device = DEFAULT_FPGA_DEVICE; @@ -2165,19 +2385,22 @@ int main(int argc, char **argv) { const char *data_type = NULL; const char *dma_channel = NULL; const char *use = NULL; - pcilib_kmem_use_t use_id = 0; - size_t block = 0; + size_t block = (size_t)-1; + pcilib_irq_type_t irq_type = PCILIB_IRQ_TYPE_ALL; pcilib_irq_hw_source_t irq_source = PCILIB_IRQ_SOURCE_DEFAULT; pcilib_dma_direction_t dma_direction = PCILIB_DMA_BIDIRECTIONAL; + pcilib_kmem_use_t useid = 0; pcilib_dma_engine_addr_t dma = PCILIB_DMA_ENGINE_ADDR_INVALID; long addr_shift = 0; uintptr_t start = -1; + size_t block_size = 0; size_t size = 1; access_t access = 4; // int skip = 0; int endianess = 0; size_t timeout = 0; + size_t alignment = 0; const char *output = NULL; FILE *ofile = NULL; size_t iterations = BENCHMARK_ITERATIONS; @@ -2186,8 +2409,8 @@ int main(int argc, char **argv) { int size_set = 0; int timeout_set = 0; - int run_time_set = 0; - +// int run_time_set = 0; + while ((c = getopt_long(argc, argv, "hqilr::w::g::d:m:t:b:a:s:e:o:", long_options, NULL)) != (unsigned char)-1) { extern int optind; switch (c) { @@ -2303,6 +2526,51 @@ int main(int argc, char **argv) { if (optarg) dma_channel = optarg; else if ((optind < argc)&&(argv[optind][0] != '-')) dma_channel = argv[optind++]; break; + case OPT_ENABLE_IRQ: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_ENABLE_IRQ; + if (optarg) num_offset = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++]; + else num_offset = NULL; + + if (num_offset) { + if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) + Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset); + + irq_type = itmp; + } + break; + case OPT_DISABLE_IRQ: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_DISABLE_IRQ; + if (optarg) num_offset = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++]; + else num_offset = NULL; + + if (num_offset) { + if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) + Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset); + + irq_type = itmp; + } + break; + case OPT_ACK_IRQ: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_ACK_IRQ; + if (optarg) num_offset = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) num_offset = argv[optind++]; + else num_offset = NULL; + + if (num_offset) { + if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) + Usage(argc, argv, "Invalid IRQ source is specified (%s)", num_offset); + + irq_source = itmp; + } + break; case OPT_WAIT_IRQ: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -2321,6 +2589,21 @@ int main(int argc, char **argv) { case OPT_LIST_KMEM: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); mode = MODE_LIST_KMEM; + + if (optarg) use = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++]; + else use = NULL; + + if (use) { + num_offset = strchr(use, ':'); + + if (num_offset) { + if (sscanf(num_offset + 1, "%zu", &block) != 1) + Usage(argc, argv, "Invalid block number is specified (%s)", num_offset + 1); + + *(char*)num_offset = 0; + } + } break; case OPT_READ_KMEM: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -2335,13 +2618,15 @@ int main(int argc, char **argv) { *(char*)num_offset = 0; } - if (sscanf(optarg, "%lx", &utmp) != 1) - Usage(argc, argv, "Invalid USE number is specified (%s)", optarg); - - if (!utmp) - Usage(argc, argv, "Can't read buffer with the unspecific use (use number is 0)"); - - use_id = utmp; + use = optarg; + useid = ParseUse(use); + break; + case OPT_ALLOC_KMEM: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + mode = MODE_ALLOC_KMEM; + + if (optarg) use = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++]; break; case OPT_FREE_KMEM: if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); @@ -2363,21 +2648,30 @@ int main(int argc, char **argv) { // if ((sscanf(optarg,"%li", &itmp) != 1)||(itmp < 0)||(itmp >= PCILIB_MAX_BANKS)) Usage(argc, argv, "Invalid data bank (%s) is specified", optarg); // else bar = itmp; break; + case OPT_ALIGNMENT: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &alignment) != 1)) { + Usage(argc, argv, "Invalid alignment is specified (%s)", optarg); + } + break; case OPT_ACCESS: if (!strncasecmp(optarg, "fifo", 4)) { - type = "fifo"; + atype = "fifo"; num_offset = optarg + 4; amode = ACCESS_FIFO; } else if (!strncasecmp(optarg, "dma", 3)) { - type = "dma"; + atype = "dma"; num_offset = optarg + 3; amode = ACCESS_DMA; } else if (!strncasecmp(optarg, "bar", 3)) { - type = "plain"; + atype = "plain"; num_offset = optarg + 3; amode = ACCESS_BAR; + } else if (!strncasecmp(optarg, "config", 6)) { + atype = "config"; + num_offset = optarg + 6; + amode = ACCESS_CONFIG; } else if (!strncasecmp(optarg, "plain", 5)) { - type = "plain"; + atype = "plain"; num_offset = optarg + 5; amode = ACCESS_BAR; } else { @@ -2407,6 +2701,11 @@ int main(int argc, char **argv) { size_set = 1; break; + case OPT_BLOCK_SIZE: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &block_size) != 1)) { + Usage(argc, argv, "Invalid size is specified (%s)", optarg); + } + break; case OPT_ENDIANESS: if ((*optarg == 'b')||(*optarg == 'B')) { if (ntohs(1) == 1) endianess = 0; @@ -2436,6 +2735,9 @@ int main(int argc, char **argv) { case OPT_EVENT: event = optarg; break; + case OPT_TYPE: + type = optarg; + break; case OPT_DATA_TYPE: data_type = optarg; break; @@ -2446,7 +2748,7 @@ int main(int argc, char **argv) { else run_time = 0; } - run_time_set = 1; +// run_time_set = 1; break; case OPT_TRIGGER_TIME: if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &trigger_time) != 1)) @@ -2511,6 +2813,9 @@ int main(int argc, char **argv) { case OPT_FORCE: force = 1; break; + case OPT_VERIFY: + verify = 1; + break; case OPT_MULTIPACKET: flags |= FLAG_MULTIPACKET; break; @@ -2537,7 +2842,6 @@ int main(int argc, char **argv) { switch (mode) { case MODE_WRITE: - if (!addr) Usage(argc, argv, "The address is not specified"); if (((argc - optind) == 1)&&(*argv[optind] == '*')) { int vallen = strlen(argv[optind]); if (vallen > 1) { @@ -2559,11 +2863,11 @@ int main(int argc, char **argv) { } } else if ((argc - optind) == size) data = argv + optind; else Usage(argc, argv, "The %i data values is specified, but %i required", argc - optind, size); - break; case MODE_READ: if (!addr) { if (model == PCILIB_MODEL_PCI) { - Usage(argc, argv, "The address is not specified"); + if ((amode != ACCESS_DMA)&&(amode != ACCESS_CONFIG)) + Usage(argc, argv, "The address is not specified"); } else ++mode; } break; @@ -2601,7 +2905,7 @@ int main(int argc, char **argv) { if (addr) { if ((!strncmp(addr, "dma", 3))&&((addr[3]==0)||isnumber(addr+3))) { - if ((type)&&(amode != ACCESS_DMA)) Usage(argc, argv, "Conflicting access modes, the DMA read is requested, but access type is (%s)", type); + if ((atype)&&(amode != ACCESS_DMA)) Usage(argc, argv, "Conflicting access modes, the DMA read is requested, but access type is (%s)", type); if (bank) { if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting DMA channels are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank); } else { @@ -2609,11 +2913,17 @@ int main(int argc, char **argv) { } dma = atoi(addr + 3); amode = ACCESS_DMA; + addr = NULL; } else if ((!strncmp(addr, "bar", 3))&&((addr[3]==0)||isnumber(addr+3))) { - if ((type)&&(amode != ACCESS_BAR)) Usage(argc, argv, "Conflicting access modes, the plain PCI read is requested, but access type is (%s)", type); + if ((atype)&&(amode != ACCESS_BAR)) Usage(argc, argv, "Conflicting access modes, the plain PCI read is requested, but access type is (%s)", type); if ((addr[3] != 0)&&(strcmp(addr + 3, bank))) Usage(argc, argv, "Conflicting PCI bars are specified in read parameter (%s) and bank parameter (%s)", addr + 3, bank); bar = atoi(addr + 3); amode = ACCESS_BAR; + addr = NULL; + } else if (!strcmp(addr, "config")) { + if ((atype)&&(amode != ACCESS_CONFIG)) Usage(argc, argv, "Conflicting access modes, the read of PCI configurataion space is requested, but access type is (%s)", type); + amode = ACCESS_CONFIG; + addr = NULL; } else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) { // check if the address in the register range pcilib_register_range_t *ranges = model_info->ranges; @@ -2712,6 +3022,8 @@ int main(int argc, char **argv) { case MODE_READ: if (amode == ACCESS_DMA) { ReadData(handle, amode, flags, dma, bar, start, size_set?size:0, access, endianess, timeout_set?timeout:(size_t)-1, ofile); + } else if (amode == ACCESS_CONFIG) { + ReadData(handle, amode, flags, dma, bar, addr?start:0, (addr||size_set)?size:(256/abs(access)), access, endianess, (size_t)-1, ofile); } else if (addr) { ReadData(handle, amode, flags, dma, bar, start, size, access, endianess, (size_t)-1, ofile); } else { @@ -2723,7 +3035,7 @@ int main(int argc, char **argv) { else ReadRegisterRange(handle, model_info, bank, start, addr_shift, size, ofile); break; case MODE_WRITE: - WriteData(handle, amode, dma, bar, start, size, access, endianess, data); + WriteData(handle, amode, dma, bar, start, size, access, endianess, data, verify); break; case MODE_WRITE_REGISTER: if (reg) WriteRegister(handle, model_info, bank, reg, data); @@ -2750,14 +3062,27 @@ int main(int argc, char **argv) { case MODE_STOP_DMA: StartStopDMA(handle, model_info, dma, dma_direction, 0); break; + case MODE_ENABLE_IRQ: + EnableIRQ(handle, model_info, irq_type); + break; + case MODE_DISABLE_IRQ: + DisableIRQ(handle, model_info, irq_type); + break; + case MODE_ACK_IRQ: + AckIRQ(handle, model_info, irq_source); + break; case MODE_WAIT_IRQ: WaitIRQ(handle, model_info, irq_source, timeout); break; case MODE_LIST_KMEM: - ListKMEM(handle, fpga_device); + if (use) DetailKMEM(handle, fpga_device, use, block); + else ListKMEM(handle, fpga_device); break; case MODE_READ_KMEM: - ReadKMEM(handle, fpga_device, use_id, block, 0, ofile); + ReadKMEM(handle, fpga_device, useid, block, 0, ofile); + break; + case MODE_ALLOC_KMEM: + AllocKMEM(handle, fpga_device, use, type, size, block_size, alignment); break; case MODE_FREE_KMEM: FreeKMEM(handle, fpga_device, use, force); @@ -80,6 +80,7 @@ int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); + if (!info) { pcilib_error("DMA is not supported by the device"); return PCILIB_ERROR_NOTSUPPORTED; @@ -99,63 +100,28 @@ int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t f int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) { const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->enable_irq) { - return 0; - } + if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->enable_irq)) return 0; return ctx->model_info.dma_api->enable_irq(ctx->dma_ctx, irq_type, flags); } int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) { const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->disable_irq) { - return 0; - } - + if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->disable_irq)) return 0; + return ctx->model_info.dma_api->disable_irq(ctx->dma_ctx, flags); } int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source) { const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->acknowledge_irq) { - return 0; - } + if ((!info)||(!ctx->model_info.dma_api)||(!ctx->model_info.dma_api->acknowledge_irq)) return 0; return ctx->model_info.dma_api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source); } - - typedef struct { size_t size; void *data; diff --git a/driver/Makefile b/driver/Makefile index 92fa913..13c3310 100644 --- a/driver/Makefile +++ b/driver/Makefile @@ -10,7 +10,7 @@ EXTRA_CFLAGS += -I$(M)/.. default: @KERNEL_GCC_VERSION=`cat /proc/version | head -n1 | cut -d " " -f 7` ;\ - GCC_VERSION=`$(CC) --version | head -n 1 | tr ' ' '\n' | tail -n 1` ;\ + GCC_VERSION=`$(CC) --version | head -n 1 | tr ' ' '\n' | grep -e "[0-9]\+\.[0-9]" | head -n 1` ;\ if [ $$KERNEL_GCC_VERSION != $$GCC_VERSION ]; then \ echo "Kernel is compiled with gcc $$KERNEL_GCC_VERSION, but you are now using $$GCC_VERSION" ;\ GCC_MAJOR=`echo $$KERNEL_GCC_VERSION | cut -d "." -f 1-2` ;\ @@ -20,7 +20,7 @@ default: echo "No compiler of $$GCC_MAJOR series is installed" ;\ exit 1 ;\ fi ;\ - GCC_VERSION=`$$CC --version | head -n 1 | tr ' ' '\n' | tail -n 1` ;\ + GCC_VERSION=`$$CC --version | head -n 1 | tr ' ' '\n' | grep -e "[0-9]\+\.[0-9]" | head -n 1` ;\ if [ $$KERNEL_GCC_VERSION != $$GCC_VERSION ]; then \ echo "The $$GCC_VERSION of $$GCC_MAJOR series is installed" ;\ exit 1 ;\ diff --git a/driver/ioctl.c b/driver/ioctl.c index 43a3cf7..2d4af73 100644 --- a/driver/ioctl.c +++ b/driver/ioctl.c @@ -150,6 +150,7 @@ static int ioctl_pci_info(pcidriver_privdata_t *privdata, unsigned long arg) pci_info.bus = privdata->pdev->bus->number; pci_info.slot = PCI_SLOT(privdata->pdev->devfn); pci_info.devfn = privdata->pdev->devfn; + pci_info.func = PCI_FUNC(privdata->pdev->devfn); if ((ret = pci_read_config_byte(privdata->pdev, PCI_INTERRUPT_PIN, &(pci_info.interrupt_pin))) != 0) return ret; diff --git a/driver/pciDriver.h b/driver/pciDriver.h index 159f6ad..8e9c0bc 100644 --- a/driver/pciDriver.h +++ b/driver/pciDriver.h @@ -61,7 +61,7 @@ /* Identifies the PCI-E Xilinx ML605 */ #define PCIE_XILINX_VENDOR_ID 0x10ee -#define PCIE_ML605_DEVICE_ID 0x04a0 +#define PCIE_ML605_DEVICE_ID 0x6024 /* Identifies the PCI-E IPE Camera */ #define PCIE_IPECAMERA_DEVICE_ID 0x6081 @@ -170,6 +170,7 @@ typedef struct { unsigned short device_id; unsigned short bus; unsigned short slot; + unsigned short func; unsigned short devfn; unsigned char interrupt_pin; unsigned char interrupt_line; diff --git a/driver/sysfs.c b/driver/sysfs.c index 37cf362..8d3fccf 100644 --- a/driver/sysfs.c +++ b/driver/sysfs.c @@ -100,13 +100,16 @@ static SYSFS_GET_FUNCTION(pcidriver_show_kmem_entry) * sanity checks but can directly call simple_strtol() */ int id = simple_strtol(attr->attr.name + strlen("kbuf"), NULL, 10); pcidriver_kmem_entry_t *entry = pcidriver_kmem_find_entry_id(privdata, id); - if (entry) + if (entry) { + unsigned long addr = entry->cpua; + unsigned long dma_addr = entry->dma_handle; + if (entry->size >= 16) { pcidriver_kmem_sync_entry(privdata, entry, PCILIB_KMEM_SYNC_FROMDEVICE); - return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12)); + return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %lx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\ndata: %8x %8x %8x %8x\n", id, addr, dma_addr, dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode, *(u32*)(entry->cpua), *(u32*)(entry->cpua + 4), *(u32*)(entry->cpua + 8), *(u32*)(entry->cpua + 12)); } else - return snprintf(buf, PAGE_SIZE, "buffer: %d\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); - else + return snprintf(buf, PAGE_SIZE, "buffer: %d\naddr: %lx\nhw addr: %lx\nbus addr: %lx\ntype: %lx\nuse: 0x%lx\nitem: %lu\nsize: %lu\nrefs: %lu\nhw ref: %i\nmode: 0x%lx\n", id, addr, dma_addr, dma_addr, entry->type, entry->use, entry->item, entry->size, entry->refs&KMEM_REF_COUNT, (entry->refs&KMEM_REF_HW)?1:0, entry->mode); + } else return snprintf(buf, PAGE_SIZE, "I am in the kmem_entry show function for buffer %d\n", id); #else return 0; @@ -91,7 +91,7 @@ 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_PAGE) { + if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) { kh.size += alignment; } @@ -143,11 +143,11 @@ pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type break; } - if ((kh.align)&&(type != PCILIB_KMEM_TYPE_PAGE)) { + if ((kh.align)&&((kh.type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE)) { if (kh.pa % kh.align) kbuf->buf.blocks[i].alignment_offset = kh.align - kh.pa % kh.align; kbuf->buf.blocks[i].size -= kh.align; } - + addr = mmap( 0, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset, PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 ); if ((!addr)||(addr == MAP_FAILED)) { kbuf->buf.n_blocks = i + 1; @@ -273,6 +273,11 @@ uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k) { return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset; } +uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k) { + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + return kbuf->buf.addr.pa + kbuf->buf.addr.alignment_offset; +} + void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; return kbuf->buf.blocks[block].ua + kbuf->buf.blocks[block].alignment_offset + kbuf->buf.blocks[block].mmap_offset; @@ -283,6 +288,11 @@ uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_ return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset; } +uintptr_t pcilib_kmem_get_block_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + return kbuf->buf.blocks[block].pa + kbuf->buf.blocks[block].alignment_offset; +} + size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block) { pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; return kbuf->buf.blocks[block].size; @@ -2,6 +2,9 @@ #define _PCILIB_KMEM_H #include "pcilib.h" + +typedef struct pcilib_kmem_list_s pcilib_kmem_list_t; + #include "tools.h" typedef enum { @@ -53,7 +56,6 @@ typedef struct { typedef void pcilib_kmem_handle_t; -typedef struct pcilib_kmem_list_s pcilib_kmem_list_t; struct pcilib_kmem_list_s { pcilib_kmem_list_t *next, *prev; @@ -66,8 +68,10 @@ void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_km int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block); void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k); uintptr_t pcilib_kmem_get_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k); +uintptr_t pcilib_kmem_get_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k); void *pcilib_kmem_get_block_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); uintptr_t pcilib_kmem_get_block_pa(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); +uintptr_t pcilib_kmem_get_block_ba(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); size_t pcilib_kmem_get_block_size(pcilib_t *ctx, pcilib_kmem_handle_t *k, size_t block); pcilib_kmem_reuse_state_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k); @@ -96,15 +96,23 @@ pcilib_model_t pcilib_get_model(pcilib_t *ctx) { } static pcilib_bar_t pcilib_detect_bar(pcilib_t *ctx, uintptr_t addr, size_t size) { + int n = 0; pcilib_bar_t i; const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); if (!board_info) return PCILIB_BAR_INVALID; for (i = 0; i < PCILIB_MAX_BANKS; i++) { - if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i; + if (board_info->bar_length[i] > 0) { + if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + size))) return i; + + if (n) n = -1; + else n = i + 1; + } } - + + if (n > 0) return n - 1; + return PCILIB_BAR_INVALID; } @@ -114,24 +122,26 @@ static int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *ad if (*bar == PCILIB_BAR_DETECT) { *bar = pcilib_detect_bar(ctx, *addr, size); - if (*bar < 0) { - pcilib_error("The requested data block at address 0x%x with size 0x%x does not belongs to any available memory bank", *addr, size); + if (*bar == PCILIB_BAR_INVALID) { + pcilib_error("The requested data block at address 0x%x with size %zu does not belongs to any available memory bank", *addr, size); return PCILIB_ERROR_NOTFOUND; } + if (*addr < board_info->bar_start[*bar]) + *addr += board_info->bar_start[*bar]; } else { if ((*addr < board_info->bar_start[*bar])||((board_info->bar_start[*bar] + board_info->bar_length[*bar]) < (((uintptr_t)*addr) + size))) { if ((board_info->bar_length[*bar]) >= (((uintptr_t)*addr) + size)) { *addr += board_info->bar_start[*bar]; } else { - pcilib_error("The requested data block at address 0x%x with size 0x%x does not belong the specified memory bank (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info->bar_start[*bar], board_info->bar_length[*bar]); + pcilib_error("The requested data block at address 0x%x with size %zu does not belong the specified memory bank (Bar %i: starting at 0x%x with size 0x%x)", *addr, size, *bar, board_info->bar_start[*bar], board_info->bar_length[*bar]); return PCILIB_ERROR_NOTFOUND; } } } - + *addr -= board_info->bar_start[*bar]; *addr += board_info->bar_start[*bar] & ctx->page_mask; - + return 0; } @@ -128,6 +128,7 @@ typedef enum { #define PCILIB_EVENT_DATA_TYPE_INVALID ((pcilib_event_data_type_t)-1) #define PCILIB_TIMEOUT_INFINITE ((pcilib_timeout_t)-1) #define PCILIB_TIMEOUT_IMMEDIATE 0 +#define PCILIB_IRQ_TYPE_ALL 0 #define PCILIB_IRQ_SOURCE_DEFAULT 0 typedef struct { diff --git a/pcilib_types.h b/pcilib_types.h index 646b1a1..f4f8f20 100644 --- a/pcilib_types.h +++ b/pcilib_types.h @@ -21,7 +21,8 @@ typedef enum { typedef enum { PCILIB_KMEM_USE_STANDARD = 0, PCILIB_KMEM_USE_DMA_RING = 1, - PCILIB_KMEM_USE_DMA_PAGES = 2 + PCILIB_KMEM_USE_DMA_PAGES = 2, + PCILIB_KMEM_USE_USER = 0x10 } pcilib_kmem_use_t; typedef enum { diff --git a/tests/new_device.sh b/tests/new_device.sh new file mode 100755 index 0000000..3545321 --- /dev/null +++ b/tests/new_device.sh @@ -0,0 +1,3 @@ +#! /bin/bash + +echo "10ee 6028" > /sys/bus/pci/drivers/pciDriver/new_id diff --git a/tests/xilinx_dma.sh b/tests/xilinx_dma.sh new file mode 100755 index 0000000..6aada8b --- /dev/null +++ b/tests/xilinx_dma.sh @@ -0,0 +1,121 @@ +#! /bin/bash + +BAR=0 +USE=1 +ITERATIONS=2 +BUFFERS=16 + +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 32 ]; 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 + +pci --free-kernel-memory $USE +pci --alloc-kernel-memory $USE --type c2s -s $BUFFERS +bus=`pci --list-kernel-memory 00100001 | awk '{ print $4; }' | grep 00` +#ptr=`pci --list-kernel-memory 00100001 | awk '{ print $2; }' | grep 00` + +# TLP size +pci -b $BAR -w 0x0C 0x20 +# TLP count +pci -b $BAR -w 0x10 0x20 +# Data +pci -b $BAR -w 0x14 0x13131313 + +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 +# pci -b $BAR -w 0x04 0x00 + + 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: $((4096 * BUFFERS * ITERATIONS * $speed / $dmaperf / 8)) MB/s" + +#pci -b $BAR -r 0 -s 32 |