summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.bzrignore1
-rw-r--r--CMakeLists.txt3
-rw-r--r--apps/CMakeLists.txt8
-rw-r--r--apps/xilinx.c179
-rw-r--r--cli.c443
-rw-r--r--dma.c44
-rw-r--r--driver/Makefile4
-rw-r--r--driver/ioctl.c1
-rw-r--r--driver/pciDriver.h3
-rw-r--r--driver/sysfs.c11
-rw-r--r--kmem.c16
-rw-r--r--kmem.h6
-rw-r--r--pci.c24
-rw-r--r--pcilib.h1
-rw-r--r--pcilib_types.h3
-rwxr-xr-xtests/new_device.sh3
-rwxr-xr-xtests/xilinx_dma.sh121
17 files changed, 753 insertions, 118 deletions
diff --git a/.bzrignore b/.bzrignore
index 07d71d3..f584400 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -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 */
+}
diff --git a/cli.c b/cli.c
index e273384..cb1d333 100644
--- a/cli.c
+++ b/cli.c
@@ -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);
diff --git a/dma.c b/dma.c
index 19ac5ab..e3bc77c 100644
--- a/dma.c
+++ b/dma.c
@@ -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;
diff --git a/kmem.c b/kmem.c
index b9ad919..d693b60 100644
--- a/kmem.c
+++ b/kmem.c
@@ -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;
diff --git a/kmem.h b/kmem.h
index ef65f64..a11518a 100644
--- a/kmem.h
+++ b/kmem.h
@@ -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);
diff --git a/pci.c b/pci.c
index b1286d5..5164111 100644
--- a/pci.c
+++ b/pci.c
@@ -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;
}
diff --git a/pcilib.h b/pcilib.h
index 0547461..dfe4b6c 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -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