summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cli.c72
-rw-r--r--dma/nwl.c98
-rw-r--r--dma/nwl.h5
-rw-r--r--pci.c38
-rw-r--r--pcilib.h3
5 files changed, 189 insertions, 27 deletions
diff --git a/cli.c b/cli.c
index aac39f5..919d50e 100644
--- a/cli.c
+++ b/cli.c
@@ -55,6 +55,12 @@ typedef enum {
} MODE;
typedef enum {
+ ACCESS_BAR,
+ ACCESS_DMA,
+ ACCESS_FIFO
+} ACCESS_MODE;
+
+typedef enum {
OPT_DEVICE = 'd',
OPT_MODEL = 'm',
OPT_BAR = 'b',
@@ -112,30 +118,30 @@ void Usage(int argc, char *argv[], const char *format, ...) {
"Usage:\n"
" %s <mode> [options] [hex data]\n"
" Modes:\n"
-" -i - Device Info\n"
-" -l - List Data Banks & Registers\n"
-" -p - Performance Evaluation\n"
-" -r <addr|reg> - Read Data/Register\n"
-" -w <addr|reg> - Write Data/Register\n"
-" -g [event] - Grab Event\n"
-" --reset - Reset board\n"
-" --help - Help message\n"
+" -i - Device Info\n"
+" -l - List Data Banks & Registers\n"
+" -p - Performance Evaluation\n"
+" -r <addr|reg|dmaX> - Read Data/Register\n"
+" -w <addr|reg|dmaX> - Write Data/Register\n"
+" -g [event] - Grab Event\n"
+" --reset - Reset board\n"
+" --help - Help message\n"
"\n"
" Addressing:\n"
-" -d <device> - FPGA device (/dev/fpga0)\n"
-" -m <model> - Memory model (autodetected)\n"
-" pci - Plain\n"
-" ipecamera - IPE Camera\n"
-" -b <bank> - Data/Register bank (autodetected)\n"
+" -d <device> - FPGA device (/dev/fpga0)\n"
+" -m <model> - Memory model (autodetected)\n"
+" pci - Plain\n"
+" ipecamera - IPE Camera\n"
+" -b <bank> - Data/Register bank (autodetected)\n"
"\n"
" Options:\n"
-" -s <size> - Number of words (default: 1)\n"
-" -a <bitness> - Bits per word (default: 32)\n"
-" -e <l|b> - Endianess Little/Big (default: host)\n"
-" -o <file> - Output to file (default: stdout)\n"
+" -s <size> - Number of words (default: 1)\n"
+" -a <bitness> - Bits per word (default: 32)\n"
+" -e <l|b> - Endianess Little/Big (default: host)\n"
+" -o <file> - Output to file (default: stdout)\n"
"\n"
" Information:\n"
-" -q - Quiete mode (suppress warnings)\n"
+" -q - Quiete mode (suppress warnings)\n"
"\n"
" Data:\n"
" Data can be specified as sequence of hexdecimal number or\n"
@@ -398,7 +404,7 @@ int Benchmark(pcilib_t *handle, pcilib_bar_t bar) {
#define pci2host16(endianess, value) endianess?
-int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) {
+int ReadData(pcilib_t *handle, ACCESS_MODE mode, pcilib_dma_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess) {
void *buf;
int i, err;
int size = n * abs(access);
@@ -416,7 +422,15 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces
err = posix_memalign( (void**)&buf, 256, size );
if ((err)||(!buf)) Error("Allocation of %i bytes of memory have failed", size);
- pcilib_read(handle, bar, addr, size, buf);
+ if (mode == ACCESS_DMA) {
+ pcilib_dma_t dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma);
+ if (dmaid == PCILIB_DMA_INVALID) Error("Invalid DMA engine (%lu) is specified", dma);
+ pcilib_read_dma(handle, dmaid, size, buf);
+
+ addr = 0;
+ } else {
+ pcilib_read(handle, bar, addr, size, buf);
+ }
if (endianess) pcilib_swap(buf, buf, abs(access), n);
for (i = 0; i < n; i++) {
@@ -443,6 +457,9 @@ int ReadData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acces
free(buf);
}
+
+
+
int ReadRegister(pcilib_t *handle, pcilib_model_t model, const char *bank, const char *reg) {
int i;
int err;
@@ -548,7 +565,7 @@ int ReadRegisterRange(pcilib_t *handle, pcilib_model_t model, const char *bank,
printf("\n\n");
}
-int WriteData(pcilib_t *handle, 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_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, char ** data) {
void *buf, *check;
int res, i, err;
int size = n * abs(access);
@@ -574,7 +591,7 @@ int WriteData(pcilib_t *handle, pcilib_bar_t bar, uintptr_t addr, size_t n, acce
if (memcmp(buf, check, size)) {
printf("Write failed: the data written and read differ, the foolowing is read back:\n");
if (endianess) pcilib_swap(check, check, abs(access), n);
- ReadData(handle, bar, addr, n, access, endianess);
+ ReadData(handle, mode, dma, bar, addr, n, access, endianess);
exit(-1);
}
@@ -687,6 +704,7 @@ int main(int argc, char **argv) {
pcilib_model_t model = PCILIB_MODEL_DETECT;
MODE mode = MODE_INVALID;
+ ACCESS_MODE amode = ACCESS_BAR;
const char *fpga_device = DEFAULT_FPGA_DEVICE;
pcilib_bar_t bar = PCILIB_BAR_DETECT;
const char *addr = NULL;
@@ -695,6 +713,7 @@ int main(int argc, char **argv) {
char **data = NULL;
const char *event = NULL;
+ pcilib_dma_addr_t dma;
uintptr_t start = -1;
size_t size = 1;
access_t access = 4;
@@ -848,7 +867,10 @@ int main(int argc, char **argv) {
}
if (addr) {
- if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) {
+ if (!strncmp(addr, "dma", 3)) {
+ dma = atoi(addr + 3);
+ amode = ACCESS_DMA;
+ } else if ((isxnumber(addr))&&(sscanf(addr, "%lx", &start) == 1)) {
// check if the address in the register range
pcilib_register_range_t *ranges = pcilib_model[model].ranges;
@@ -896,7 +918,7 @@ int main(int argc, char **argv) {
break;
case MODE_READ:
if (addr) {
- ReadData(handle, bar, start, size, access, endianess);
+ ReadData(handle, amode, dma, bar, start, size, access, endianess);
} else {
Error("Address to read is not specified");
}
@@ -906,7 +928,7 @@ int main(int argc, char **argv) {
else ReadRegisterRange(handle, model, bank, start, size);
break;
case MODE_WRITE:
- WriteData(handle, bar, start, size, access, endianess, data);
+ WriteData(handle, amode, dma, bar, start, size, access, endianess, data);
break;
case MODE_WRITE_REGISTER:
if (reg) WriteRegister(handle, model, bank, reg, data);
diff --git a/dma/nwl.c b/dma/nwl.c
index 5a1a719..2c4fc04 100644
--- a/dma/nwl.c
+++ b/dma/nwl.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/time.h>
#include "pci.h"
#include "pcilib.h"
@@ -63,10 +64,45 @@
#define DMA_ENG_NUMBER 0x0000FF00 /**< DMA engine number */
#define DMA_ENG_BD_MAX_BC 0x3F000000 /**< DMA engine max buffer size */
+
/* Shift constants for selected masks */
#define DMA_ENG_NUMBER_SHIFT 8
#define DMA_ENG_BD_MAX_BC_SHIFT 24
+/** @name Bitmasks of REG_DMA_ENG_CTRL_STATUS register.
+ * @{
+ */
+/* Interrupt activity and acknowledgement bits */
+#define DMA_ENG_INT_ENABLE 0x00000001 /**< Enable interrupts */
+#define DMA_ENG_INT_DISABLE 0x00000000 /**< Disable interrupts */
+#define DMA_ENG_INT_ACTIVE_MASK 0x00000002 /**< Interrupt active? */
+#define DMA_ENG_INT_ACK 0x00000002 /**< Interrupt ack */
+#define DMA_ENG_INT_BDCOMP 0x00000004 /**< Int - BD completion */
+#define DMA_ENG_INT_BDCOMP_ACK 0x00000004 /**< Acknowledge */
+#define DMA_ENG_INT_ALERR 0x00000008 /**< Int - BD align error */
+#define DMA_ENG_INT_ALERR_ACK 0x00000008 /**< Acknowledge */
+#define DMA_ENG_INT_FETERR 0x00000010 /**< Int - BD fetch error */
+#define DMA_ENG_INT_FETERR_ACK 0x00000010 /**< Acknowledge */
+#define DMA_ENG_INT_ABORTERR 0x00000020 /**< Int - DMA abort error */
+#define DMA_ENG_INT_ABORTERR_ACK 0x00000020 /**< Acknowledge */
+#define DMA_ENG_INT_CHAINEND 0x00000080 /**< Int - BD chain ended */
+#define DMA_ENG_INT_CHAINEND_ACK 0x00000080 /**< Acknowledge */
+
+/* DMA engine control */
+#define DMA_ENG_ENABLE_MASK 0x00000100 /**< DMA enabled? */
+#define DMA_ENG_ENABLE 0x00000100 /**< Enable DMA */
+#define DMA_ENG_DISABLE 0x00000000 /**< Disable DMA */
+#define DMA_ENG_STATE_MASK 0x00000C00 /**< Current DMA state? */
+#define DMA_ENG_RUNNING 0x00000400 /**< DMA running */
+#define DMA_ENG_IDLE 0x00000000 /**< DMA idle */
+#define DMA_ENG_WAITING 0x00000800 /**< DMA waiting */
+#define DMA_ENG_STATE_WAITED 0x00001000 /**< DMA waited earlier */
+#define DMA_ENG_WAITED_ACK 0x00001000 /**< Acknowledge */
+#define DMA_ENG_USER_RESET 0x00004000 /**< Reset only user logic */
+#define DMA_ENG_RESET 0x00008000 /**< Reset DMA engine + user */
+
+#define DMA_ENG_ALLINT_MASK 0x000000BE /**< To get only int events */
+
#define DMA_ENGINE_PER_SIZE 0x100 /**< Separation between engine regs */
#define DMA_OFFSET 0 /**< Starting register offset */
/**< Size of DMA engine reg space */
@@ -96,6 +132,7 @@ struct nwl_dma_s {
pcilib_register_bank_description_t *dma_bank;
char *base_addr;
+ pcilib_dma_t n_engines;
pcilib_nwl_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1];
};
@@ -105,6 +142,8 @@ struct nwl_dma_s {
static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_t *info, char *base) {
uint32_t val;
+ info->base_addr = base;
+
nwl_read_register(val, ctx, base, REG_DMA_ENG_CAP);
if ((val & DMA_ENG_PRESENT_MASK) == 0) return PCILIB_ERROR_NOTAVAILABLE;
@@ -135,6 +174,54 @@ static int nwl_read_engine_config(nwl_dma_t *ctx, pcilib_nwl_engine_description_
return 0;
}
+static int nwl_stop_engine(nwl_dma_t *ctx, pcilib_dma_t dma) {
+ uint32_t val;
+ struct timeval start, cur;
+
+ pcilib_nwl_engine_description_t *info = ctx->engines + dma;
+ char *base = ctx->engines[dma].base_addr;
+
+ // Disable IRQ
+ nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ val &= ~(DMA_ENG_INT_ENABLE);
+ nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+
+
+ // Reseting
+ val = DMA_ENG_DISABLE|DMA_ENG_USER_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ gettimeofday(&start, NULL);
+ do {
+ nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ gettimeofday(&cur, NULL);
+ } while ((val & (DMA_ENG_STATE_MASK|DMA_ENG_USER_RESET))&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
+
+ if (val & DMA_ENG_RESET) {
+ pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
+ return PCILIB_ERROR_TIMEOUT;
+ }
+
+
+ val = DMA_ENG_RESET; nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ gettimeofday(&start, NULL);
+ do {
+ nwl_read_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ gettimeofday(&cur, NULL);
+ } while ((val & DMA_ENG_RESET)&&(((cur.tv_sec - start.tv_sec)*1000000 + (cur.tv_usec - start.tv_usec)) < PCILIB_REGISTER_TIMEOUT));
+
+ if (val & DMA_ENG_RESET) {
+ pcilib_error("Timeout during reset of DMA engine %i", info->desc.addr);
+ return PCILIB_ERROR_TIMEOUT;
+ }
+
+ // Acknowledge asserted engine interrupts
+ if (val & DMA_ENG_INT_ACTIVE_MASK) {
+ val |= DMA_ENG_ALLINT_MASK;
+ nwl_write_register(val, ctx, base, REG_DMA_ENG_CTRL_STATUS);
+ }
+
+ return 0;
+}
+
pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {
int i;
int err;
@@ -159,20 +246,31 @@ pcilib_dma_context_t *dma_nwl_init(pcilib_t *pcilib) {
for (i = 0, n_engines = 0; i < 2 * PCILIB_MAX_DMA_ENGINES; i++) {
char *addr = ctx->base_addr + DMA_OFFSET + i * DMA_ENGINE_PER_SIZE;
err = nwl_read_engine_config(ctx, ctx->engines + n_engines, addr);
+ if (!err) err = nwl_stop_engine(ctx, n_engines);
if (!err) {
ctx->engines[n_engines].base_addr = addr;
pcilib_set_dma_engine_description(pcilib, n_engines, (pcilib_dma_engine_description_t*)(ctx->engines + n_engines));
++n_engines;
}
+
}
pcilib_set_dma_engine_description(pcilib, n_engines, NULL);
+
+ ctx->n_engines = n_engines;
}
return (pcilib_dma_context_t*)ctx;
}
void dma_nwl_free(pcilib_dma_context_t *vctx) {
+ pcilib_dma_t i;
nwl_dma_t *ctx = (nwl_dma_t*)vctx;
if (ctx) {
+ for (i = 0; i < ctx->n_engines; i++) nwl_stop_engine(vctx, i);
free(ctx);
}
}
+
+int dma_nwl_read(pcilib_dma_context_t *vctx, pcilib_dma_t dma, size_t size, void *buf) {
+ nwl_dma_t *ctx = (nwl_dma_t*)vctx;
+ printf("Reading dma: %i\n", dma);
+}
diff --git a/dma/nwl.h b/dma/nwl.h
index 63fccfb..8a79601 100644
--- a/dma/nwl.h
+++ b/dma/nwl.h
@@ -17,10 +17,13 @@ typedef struct {
pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx);
void dma_nwl_free(pcilib_dma_context_t *vctx);
+int dma_nwl_read(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf);
+
#ifdef _PCILIB_DMA_NWL_C
pcilib_dma_api_description_t nwl_dma_api = {
dma_nwl_init,
- dma_nwl_free
+ dma_nwl_free,
+ dma_nwl_read
};
#else
extern pcilib_dma_api_description_t nwl_dma_api;
diff --git a/pci.c b/pci.c
index ec16476..1cddeac 100644
--- a/pci.c
+++ b/pci.c
@@ -270,6 +270,44 @@ int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, v
pcilib_unmap_bar(ctx, bar, data);
}
+pcilib_dma_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_addr_t dma) {
+ pcilib_dma_t i;
+
+ const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
+ if (!info) {
+ pcilib_error("DMA Engine is not configured in the current model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ for (i = 0; info->engines[i]; i++) {
+ if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break;
+ }
+
+ if (info->engines[i]) return i;
+ return PCILIB_DMA_INVALID;
+}
+
+int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_t dma, size_t size, void *buf) {
+ const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx);
+
+ if (!ctx->model_info->dma_api) {
+ pcilib_error("DMA Engine is not configured in the current model");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (!ctx->model_info->dma_api->read) {
+ pcilib_error("The DMA read is not supported by configured DMA engine");
+ return PCILIB_ERROR_NOTSUPPORTED;
+ }
+
+ if (!info->engines[dma]) {
+ pcilib_error("The DMA engine (%i) is not supported by device", dma);
+ return PCILIB_ERROR_OUTOFRANGE;
+ }
+
+ return ctx->model_info->dma_api->read(ctx->dma_ctx, dma, size, buf);
+}
+
pcilib_register_bank_t pcilib_find_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) {
pcilib_register_bank_t i;
diff --git a/pcilib.h b/pcilib.h
index f0e0746..88f3bfd 100644
--- a/pcilib.h
+++ b/pcilib.h
@@ -66,6 +66,7 @@ typedef enum {
#define PCILIB_BAR_INVALID ((pcilib_bar_t)-1)
#define PCILIB_BAR0 0
#define PCILIB_BAR1 1
+#define PCILIB_DMA_INVALID ((pcilib_dma_t)-1)
#define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1)
#define PCILIB_ADDRESS_INVALID ((uintptr_t)-1)
#define PCILIB_REGISTER_BANK_INVALID ((pcilib_register_bank_t)-1)
@@ -163,7 +164,7 @@ typedef struct {
pcilib_dma_context_t *(*init)(pcilib_t *ctx);
void (*free)(pcilib_dma_context_t *ctx);
-// int (*read)(pcilib_dma_context_t *ctx, pcilib_event_t event_mask, pcilib_callback_t callback, void *user);
+ int (*read)(pcilib_dma_context_t *ctx, pcilib_dma_t dma, size_t size, void *buf);
// int (*write)(pcilib_dma_context_t *ctx);
} pcilib_dma_api_description_t;