From dcd8ad63316eac672492bc18112bbbb52811c3fc Mon Sep 17 00:00:00 2001 From: "Suren A. Chilingaryan" Date: Fri, 24 Apr 2015 05:35:48 +0200 Subject: More structural changes to get ready for stand-alone event engines --- .bzrignore | 1 + CMakeLists.txt | 48 +- apps/CMakeLists.txt | 5 +- bank.c | 201 -- bank.h | 97 - cli.c | 3108 ----------------------------- config.c | 40 - config.h | 30 - dma.c | 362 ---- dma.h | 86 - dma/CMakeLists.txt | 2 +- dma/ipe.h | 4 +- dma/nwl.h | 4 +- error.c | 24 - error.h | 32 - event.c | 437 ----- event.h | 90 - irq.c | 55 - irq.h | 5 - kmem.c | 310 --- kmem.h | 110 -- linux-3.10.h | 81 - model.c | 22 - model.h | 31 - pci.c | 542 ------ pci.h | 77 - pcilib.h | 226 --- pcilib/CMakeLists.txt | 21 + pcilib/bank.c | 204 ++ pcilib/bank.h | 102 + pcilib/config.c | 37 + pcilib/config.h | 17 + pcilib/dma.c | 360 ++++ pcilib/dma.h | 85 + pcilib/error.c | 24 + pcilib/error.h | 32 + pcilib/event.c | 436 +++++ pcilib/event.h | 90 + pcilib/irq.c | 55 + pcilib/irq.h | 5 + pcilib/kmem.c | 310 +++ pcilib/kmem.h | 110 ++ pcilib/linux-3.10.h | 81 + pcilib/model.c | 22 + pcilib/model.h | 29 + pcilib/pci.c | 540 ++++++ pcilib/pci.h | 77 + pcilib/pcilib.h | 226 +++ pcilib/register.c | 290 +++ pcilib/register.h | 51 + pcilib/tools.c | 355 ++++ pcilib/tools.h | 44 + pcitool/CMakeLists.txt | 28 +- pcitool/cli.c | 3110 ++++++++++++++++++++++++++++++ protocols/CMakeLists.txt | 2 +- protocols/default.h | 2 +- register.c | 290 --- register.h | 51 - tests/grab.sh | 4 +- tests/ipedma/ipecamera-frame.sh | 2 +- tests/ipedma/ipecamera-test.sh | 2 +- tests/ipedma/test.sh | 2 +- tests/nwldma/bench.sh | 4 +- tests/nwldma/cleanup.sh | 4 +- tests/test-iommu.sh | 5 + tests/xilinxdma/xilinx_dma.sh | 4 +- tests/xilinxdma/xilinx_dma_static_mem.sh | 2 +- tools.c | 355 ---- tools.h | 44 - 69 files changed, 6769 insertions(+), 6775 deletions(-) delete mode 100644 bank.c delete mode 100644 bank.h delete mode 100644 cli.c delete mode 100644 config.c delete mode 100644 config.h delete mode 100644 dma.c delete mode 100644 dma.h delete mode 100644 error.c delete mode 100644 error.h delete mode 100644 event.c delete mode 100644 event.h delete mode 100644 irq.c delete mode 100644 irq.h delete mode 100644 kmem.c delete mode 100644 kmem.h delete mode 100644 linux-3.10.h delete mode 100644 model.c delete mode 100644 model.h delete mode 100644 pci.c delete mode 100644 pci.h delete mode 100644 pcilib.h create mode 100644 pcilib/CMakeLists.txt create mode 100644 pcilib/bank.c create mode 100644 pcilib/bank.h create mode 100644 pcilib/config.c create mode 100644 pcilib/config.h create mode 100644 pcilib/dma.c create mode 100644 pcilib/dma.h create mode 100644 pcilib/error.c create mode 100644 pcilib/error.h create mode 100644 pcilib/event.c create mode 100644 pcilib/event.h create mode 100644 pcilib/irq.c create mode 100644 pcilib/irq.h create mode 100644 pcilib/kmem.c create mode 100644 pcilib/kmem.h create mode 100644 pcilib/linux-3.10.h create mode 100644 pcilib/model.c create mode 100644 pcilib/model.h create mode 100644 pcilib/pci.c create mode 100644 pcilib/pci.h create mode 100644 pcilib/pcilib.h create mode 100644 pcilib/register.c create mode 100644 pcilib/register.h create mode 100644 pcilib/tools.c create mode 100644 pcilib/tools.h create mode 100644 pcitool/cli.c delete mode 100644 register.c delete mode 100644 register.h delete mode 100644 tools.c delete mode 100644 tools.h diff --git a/.bzrignore b/.bzrignore index 6fe7019..a4a8059 100644 --- a/.bzrignore +++ b/.bzrignore @@ -25,3 +25,4 @@ apps/heb_strip_bad_values *.out apps/check_counter apps/lorenzo_ipedma_test +pci diff --git a/CMakeLists.txt b/CMakeLists.txt index 6eb4c26..faed5aa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,66 +16,20 @@ if (NOT DISABLE_PCITOOL) pkg_check_modules(FASTWRITER fastwriter REQUIRED) endif (NOT DISABLE_PCITOOL) -set(HEADERS pcilib.h pci.h config.h model.h bank.h register.h kmem.h irq.h dma.h event.h tools.h error.h) add_definitions("-fPIC --std=c99 -Wall -O2 -gdwarf-2 -g3") #add_definitions("-fPIC --std=c99 -Wall -O2") add_subdirectory(dma) add_subdirectory(protocols) +add_subdirectory(pcilib) add_subdirectory(pcitool) add_subdirectory(apps) -include_directories( - . - ${FASTWRITER_INCLUDE_DIRS} -) - -link_directories( - ${FASTWRITER_LIBRARY_DIRS} - ${UFODECODE_LIBRARY_DIRS} -) - -add_library(pcilib SHARED pci.c config.c model.c bank.c register.c kmem.c irq.c dma.c event.c tools.c error.c) -target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ) -add_dependencies(pcilib dma protocols pcitool) - set_target_properties(pcilib PROPERTIES VERSION ${PCILIB_VERSION} SOVERSION ${PCILIB_ABI_VERSION} ) -if (NOT DISABLE_PCITOOL) - add_executable(pci cli.c) - add_dependencies(pci pcitool) - target_link_libraries(pci pcilib pcitool ${FASTWRITER_LIBRARIES}) - set_target_properties(pci PROPERTIES - LINK_FLAGS ${CMAKE_THREAD_LIBS_INIT} - ) -endif (NOT DISABLE_PCITOOL) - -#set_target_properties(pci PROPERTIES -# LINK_FLAGS "-Wl,pcitool/libpcitool.a" -#) -if(NOT DEFINED BIN_INSTALL_DIR) - set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") -endif(NOT DEFINED BIN_INSTALL_DIR) -install(TARGETS pcilib - LIBRARY DESTINATION lib${LIB_SUFFIX} -) - -if (NOT DISABLE_PCITOOL) - install(TARGETS pci - DESTINATION ${BIN_INSTALL_DIR} - ) -endif (NOT DISABLE_PCITOOL) - -install(FILES pcilib.h - DESTINATION include -) - -install(FILES bank.h register.h dma.h event.h model.h error.h tools.h - DESTINATION include/pcilib -) diff --git a/apps/CMakeLists.txt b/apps/CMakeLists.txt index de652b5..32aac62 100644 --- a/apps/CMakeLists.txt +++ b/apps/CMakeLists.txt @@ -1,8 +1,11 @@ include_directories( ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pcilib ) -link_directories(${UFODECODE_LIBRARY_DIRS}) +link_directories( + ${CMAKE_SOURCE_DIR}/pcilib +) add_executable(xilinx xilinx.c) target_link_libraries(xilinx pcilib rt) diff --git a/bank.c b/bank.c deleted file mode 100644 index c601c57..0000000 --- a/bank.c +++ /dev/null @@ -1,201 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" - -#include "tools.h" -#include "error.h" - -int pcilib_init_register_banks(pcilib_t *ctx) { - int err; - - err = pcilib_map_register_space(ctx); - if (err) return err; - - for (; ctx->num_banks_init < ctx->num_banks; ctx->num_banks_init++) { - pcilib_register_bank_context_t *bank_ctx; - pcilib_register_protocol_t protocol; - const pcilib_register_protocol_api_description_t *bapi; - - protocol = pcilib_find_register_protocol_by_addr(ctx, ctx->banks[ctx->num_banks_init].protocol); - if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) { - const char *name = ctx->banks[ctx->num_banks_init].name; - if (!name) name = "unnamed"; - pcilib_error("Invalid register protocol address (%u) is specified for bank %i (%s)", ctx->banks[ctx->num_banks_init].protocol, ctx->banks[ctx->num_banks_init].addr, name); - return PCILIB_ERROR_INVALID_BANK; - } - - bapi = ctx->protocols[protocol].api; - - if (bapi->init) - bank_ctx = bapi->init(ctx, ctx->num_banks_init, ctx->protocols[protocol].model, ctx->protocols[protocol].args); - else - bank_ctx = (pcilib_register_bank_context_t*)malloc(sizeof(pcilib_register_bank_context_t)); - - if (!bank_ctx) - return PCILIB_ERROR_FAILED; - - bank_ctx->bank = ctx->banks + ctx->num_banks_init; - bank_ctx->api = bapi; - ctx->bank_ctx[ctx->num_banks_init] = bank_ctx; - } - - return 0; -} - -void pcilib_free_register_banks(pcilib_t *ctx) { - size_t i; - - for (i = 0; i < ctx->num_banks_init; i++) { - const pcilib_register_protocol_api_description_t *bapi = ctx->bank_ctx[i]->api; - - if (ctx->bank_ctx[i]) { - if (bapi->free) - bapi->free(ctx->bank_ctx[i]); - else - free(ctx->bank_ctx[i]); - - ctx->bank_ctx[i] = NULL; - } - } - - ctx->num_banks_init = 0; -} - - -int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks) { - // DS: What we are doing if bank exists? - - if (!n) { - for (n = 0; banks[n].access; n++); - } - - if ((ctx->num_banks + n + 1) > PCILIB_MAX_REGISTER_BANKS) - return PCILIB_ERROR_TOOBIG; - - memset(ctx->banks + ctx->num_banks + n, 0, sizeof(pcilib_register_bank_description_t)); - memcpy(ctx->banks + ctx->num_banks, banks, n * sizeof(pcilib_register_bank_description_t)); - ctx->num_banks += n; - - // If banks are already initialized, we need to re-run the initialization code - // DS: Locking is currently missing - if (ctx->reg_bar_mapped) { - ctx->reg_bar_mapped = 0; - return pcilib_init_register_banks(ctx); - } - - return 0; -} - -pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) { - pcilib_register_bank_t i; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_bank_description_t *banks = model_info->banks; - - for (i = 0; banks[i].access; i++) - if (banks[i].addr == bank) return i; - - return PCILIB_REGISTER_BANK_INVALID; -} - -pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname) { - pcilib_register_bank_t i; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_bank_description_t *banks = model_info->banks; - - for (i = 0; banks[i].access; i++) - if (!strcasecmp(banks[i].name, bankname)) return i; - - return PCILIB_REGISTER_BANK_INVALID; -} - -pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank) { - pcilib_register_bank_t res; - unsigned long addr; - - if (!bank) { - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_bank_description_t *banks = model_info->banks; - if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0; - return PCILIB_REGISTER_BANK_INVALID; - } - - if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) { - res = pcilib_find_register_bank_by_addr(ctx, addr); - if (res != PCILIB_REGISTER_BANK_INVALID) return res; - } - - return pcilib_find_register_bank_by_name(ctx, bank); -} - - // DS: FIXME create hash during map_register space -pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) { - pcilib_register_t i; - pcilib_register_bank_t bank_id; - pcilib_register_bank_addr_t bank_addr = 0; - - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_description_t *registers = model_info->registers; - - if (bank) { - bank_id = pcilib_find_register_bank(ctx, bank); - if (bank_id == PCILIB_REGISTER_BANK_INVALID) { - pcilib_error("Invalid bank (%s) is specified", bank); - return PCILIB_REGISTER_INVALID; - } - - bank_addr = model_info->banks[bank_id].addr; - } - - for (i = 0; registers[i].bits; i++) { - if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i; - } - - return PCILIB_REGISTER_INVALID; -}; - - -pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx, pcilib_register_protocol_addr_t protocol) { - pcilib_register_protocol_t i; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_protocol_description_t *protocols = model_info->protocols; - - for (i = 0; protocols[i].api; i++) - if (protocols[i].addr == protocol) return i; - - return PCILIB_REGISTER_PROTOCOL_INVALID; -} - -pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name) { - pcilib_register_protocol_t i; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_protocol_description_t *protocols = model_info->protocols; - - for (i = 0; protocols[i].api; i++) - if (!strcasecmp(protocols[i].name, name)) return i; - - return PCILIB_REGISTER_PROTOCOL_INVALID; -} - -pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *protocol) { - pcilib_register_bank_t res; - unsigned long addr; - - if (pcilib_isxnumber(protocol)&&(sscanf(protocol,"%lx", &addr) == 1)) { - res = pcilib_find_register_protocol_by_addr(ctx, addr); - if (res != PCILIB_REGISTER_BANK_INVALID) return res; - } - - return pcilib_find_register_protocol_by_name(ctx, protocol); -} diff --git a/bank.h b/bank.h deleted file mode 100644 index 2a0b0b3..0000000 --- a/bank.h +++ /dev/null @@ -1,97 +0,0 @@ -#ifndef _PCILIB_BANK_H -#define _PCILIB_BANK_H - -#include - -#define PCILIB_REGISTER_BANK_INVALID ((pcilib_register_bank_t)-1) -#define PCILIB_REGISTER_BANK0 0 /**< First BANK to be used in the event engine */ -#define PCILIB_REGISTER_BANK1 1 -#define PCILIB_REGISTER_BANK2 2 -#define PCILIB_REGISTER_BANK3 3 -#define PCILIB_REGISTER_BANK_DMA 64 /**< First BANK address to be used by DMA engines */ -#define PCILIB_REGISTER_BANK_DYNAMIC 128 /**< First BANK address to map dynamic XML configuration */ -#define PCILIB_REGISTER_PROTOCOL_INVALID ((pcilib_register_protocol_t)-1) -#define PCILIB_REGISTER_PROTOCOL0 0 /**< First PROTOCOL address to be used in the event engine */ -#define PCILIB_REGISTER_PROTOCOL_DEFAULT 64 /**< Default memmap based protocol */ -#define PCILIB_REGISTER_PROTOCOL_DMA 96 /**< First PROTOCOL address to be used by DMA engines */ -#define PCILIB_REGISTER_PROTOCOL_DYNAMIC 128 /**< First PROTOCOL address to be used by plugins */ - -#define PCILIB_REGISTER_NO_BITS 0 -#define PCILIB_REGISTER_ALL_BITS ((pcilib_register_value_t)-1) - -typedef uint8_t pcilib_register_bank_t; /**< Type holding the bank position within the field listing register banks in the model */ -typedef uint8_t pcilib_register_bank_addr_t; /**< Type holding the bank address number */ -typedef uint8_t pcilib_register_protocol_t; /**< Type holding the protocol position within the field listing register protocols in the model */ -typedef uint8_t pcilib_register_protocol_addr_t; /**< Type holding the protocol address */ - - -typedef struct pcilib_register_bank_context_s pcilib_register_bank_context_t; - -typedef struct { - pcilib_register_bank_context_t *(*init)(pcilib_t *ctx, pcilib_register_bank_t bank, const char *model, const void *args); - void (*free)(pcilib_register_bank_context_t *ctx); - int (*read)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value); - int (*write)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t value); -} pcilib_register_protocol_api_description_t; - -typedef struct { - pcilib_register_protocol_addr_t addr; - const pcilib_register_protocol_api_description_t *api; - const char *model; - const void *args; - const char *name; - const char *description; -} pcilib_register_protocol_description_t; - -typedef struct { - pcilib_register_bank_addr_t addr; - - pcilib_bar_t bar; // optional - size_t size; - - pcilib_register_protocol_addr_t protocol; - - uintptr_t read_addr; // or offset if bar specified - uintptr_t write_addr; // or offset if bar specified - pcilib_endianess_t raw_endianess; - - uint8_t access; - pcilib_endianess_t endianess; - - const char *format; - const char *name; - const char *description; -} pcilib_register_bank_description_t; - -/** - * Default mappings - */ -typedef struct { - uintptr_t start; - uintptr_t end; - pcilib_register_bank_addr_t bank; - long addr_shift; -} pcilib_register_range_t; - - - -struct pcilib_register_bank_context_s { - const pcilib_register_bank_description_t *bank; - const pcilib_register_protocol_api_description_t *api; -}; - - - // we don't copy strings, they should be statically allocated -int pcilib_init_register_banks(pcilib_t *ctx); -void pcilib_free_register_banks(pcilib_t *ctx); -int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks); - -pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank); -pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname); -pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank); - -pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx, pcilib_register_protocol_addr_t protocol); -pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name); -pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *name); - -#endif /* _PCILIB_BANK_H */ diff --git a/cli.c b/cli.c deleted file mode 100644 index 616e9ad..0000000 --- a/cli.c +++ /dev/null @@ -1,3108 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#define _BSD_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include "pcitool/sysinfo.h" -#include "pcitool/formaters.h" - -#include "pci.h" -#include "tools.h" -#include "kmem.h" -#include "error.h" -#include "model.h" - -/* defines */ -#define MAX_KBUF 14 -//#define BIGBUFSIZE (512*1024*1024) -#define BIGBUFSIZE (1024*1024) - - -#define DEFAULT_FPGA_DEVICE "/dev/fpga0" - -#define LINE_WIDTH 80 -#define SEPARATOR_WIDTH 2 -#define BLOCK_SEPARATOR_WIDTH 2 -#define BLOCK_SIZE 8 -#define BENCHMARK_ITERATIONS 128 -#define STATUS_MESSAGE_INTERVAL 5 /* seconds */ - - -#define isnumber pcilib_isnumber -#define isxnumber pcilib_isxnumber -#define isnumber_n pcilib_isnumber_n -#define isxnumber_n pcilib_isxnumber_n - -typedef uint8_t access_t; - -typedef enum { - GRAB_MODE_GRAB = 1, - GRAB_MODE_TRIGGER = 2 -} GRAB_MODE; - -typedef enum { - MODE_INVALID, - MODE_INFO, - MODE_LIST, - MODE_BENCHMARK, - MODE_READ, - MODE_READ_REGISTER, - MODE_WRITE, - MODE_WRITE_REGISTER, - MODE_RESET, - MODE_GRAB, - MODE_START_DMA, - MODE_STOP_DMA, - 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 -} MODE; - -typedef enum { - ACCESS_BAR, - ACCESS_DMA, - ACCESS_FIFO, - ACCESS_CONFIG -} ACCESS_MODE; - -typedef enum { - FLAG_MULTIPACKET = 1, - FLAG_WAIT = 2 -} FLAGS; - - -typedef enum { - FORMAT_DEFAULT = 0, - FORMAT_RAW, - FORMAT_HEADER, - FORMAT_RINGFS -} FORMAT; - -typedef enum { - PARTITION_UNKNOWN, - PARTITION_RAW, - PARTITION_EXT4, - PARTITION_NULL -} PARTITION; - -typedef enum { - OPT_DEVICE = 'd', - OPT_MODEL = 'm', - OPT_BAR = 'b', - OPT_ACCESS = 'a', - OPT_ENDIANESS = 'e', - OPT_SIZE = 's', - OPT_OUTPUT = 'o', - OPT_TIMEOUT = 't', - OPT_INFO = 'i', - OPT_LIST = 'l', - OPT_READ = 'r', - OPT_WRITE = 'w', - OPT_GRAB = 'g', - OPT_QUIETE = 'q', - OPT_HELP = 'h', - OPT_RESET = 128, - OPT_BENCHMARK, - OPT_TRIGGER, - OPT_DATA_TYPE, - OPT_EVENT, - OPT_TRIGGER_RATE, - OPT_TRIGGER_TIME, - OPT_RUN_TIME, - OPT_FORMAT, - OPT_BUFFER, - OPT_THREADS, - OPT_LIST_DMA, - OPT_LIST_DMA_BUFFERS, - 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 -} OPTIONS; - -static struct option long_options[] = { - {"device", required_argument, 0, OPT_DEVICE }, - {"model", required_argument, 0, OPT_MODEL }, - {"bar", required_argument, 0, OPT_BAR }, - {"access", required_argument, 0, OPT_ACCESS }, - {"endianess", required_argument, 0, OPT_ENDIANESS }, - {"size", required_argument, 0, OPT_SIZE }, - {"output", required_argument, 0, OPT_OUTPUT }, - {"timeout", required_argument, 0, OPT_TIMEOUT }, - {"iterations", required_argument, 0, OPT_ITERATIONS }, - {"info", no_argument, 0, OPT_INFO }, - {"list", no_argument, 0, OPT_LIST }, - {"reset", no_argument, 0, OPT_RESET }, - {"benchmark", optional_argument, 0, OPT_BENCHMARK }, - {"read", optional_argument, 0, OPT_READ }, - {"write", optional_argument, 0, OPT_WRITE }, - {"grab", optional_argument, 0, OPT_GRAB }, - {"trigger", optional_argument, 0, OPT_TRIGGER }, - {"data", required_argument, 0, OPT_DATA_TYPE }, - {"event", required_argument, 0, OPT_EVENT }, - {"run-time", required_argument, 0, OPT_RUN_TIME }, - {"trigger-rate", required_argument, 0, OPT_TRIGGER_RATE }, - {"trigger-time", required_argument, 0, OPT_TRIGGER_TIME }, - {"format", required_argument, 0, OPT_FORMAT }, - {"buffer", optional_argument, 0, OPT_BUFFER }, - {"threads", optional_argument, 0, OPT_THREADS }, - {"start-dma", required_argument, 0, OPT_START_DMA }, - {"stop-dma", optional_argument, 0, OPT_STOP_DMA }, - {"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", 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 }, - { 0, 0, 0, 0 } -}; - - -void Usage(int argc, char *argv[], const char *format, ...) { - if (format) { - va_list ap; - - va_start(ap, format); - printf("Error %i: ", errno); - vprintf(format, ap); - printf("\n"); - va_end(ap); - - printf("\n"); - } - - - printf( -"Usage:\n" -" %s [options] [hex data]\n" -" Modes:\n" -" -i - Device Info\n" -" -l[l] - List (detailed) Data Banks & Registers\n" -" -r - Read Data/Register\n" -" -w - Write Data/Register\n" -" --benchmark - Performance Evaluation\n" -" --reset - Reset board\n" -" --help - Help message\n" -"\n" -" Event Modes:\n" -" --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 - Clean IRQ queue\n" -" --wait-irq - Wait for IRQ\n" - -" DMA Modes:\n" -" --start-dma [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 - List buffers for specified DMA engine\n" -" --read-dma-buffer - Read the specified buffer\n" -"\n" -" Kernel Modes:\n" -" --list-kernel-memory [use] - List kernel buffers\n" -" --read-kernel-memory - Read the specified block of the kernel memory\n" -" block is specified as: use:block_number\n" -" --alloc-kernel-memory - Allocate kernel buffers (DANGEROUS)\n" -" --free-kernel-memory - 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" -"\n" -" Addressing:\n" -" -d - FPGA device (/dev/fpga0)\n" -" -m - Memory model (autodetected)\n" -" pci - Plain\n" -" ipecamera - IPE Camera\n" -" -b - PCI bar, Register bank, or DMA channel\n" -"\n" -" Options:\n" -" -s - Number of words (default: 1)\n" -" -a [fifo|dma|config] - Access type and bits per word (default: 32)\n" -" -e - Endianess Little/Big (default: host)\n" -" -o - Append output to file (default: stdout)\n" -" -t - Timeout in microseconds\n" -" --check - Verify write operations\n" -"\n" -" Event Options:\n" -" --event - Specifies event for trigger and grab modes\n" -" --data - Data type to request for the events\n" -" --run-time - Limit time to grab/trigger events\n" -" -t - Timeout to stop if no events triggered\n" -" --trigger-rate - Generate tps triggers per second\n" -" --trigger-time - Specifies delay between triggers (us)\n" -" -s - Number of events to grab and trigger\n" -" --format [type] - Specifies how event data should be stored\n" -" raw - Just write all events sequentially\n" -" add_header - Prefix events with 512 bit header:\n" -" event(64), data(64), nope(64), size(64)\n" -" seqnum(64), offset(64), timestamp(128)\n" -//" ringfs - Write to RingFS\n" -" --buffer [size] - Request data buffering, size in MB\n" -" --threads [num] - Allow multithreaded processing\n" -"\n" -" DMA Options:\n" -" --multipacket - Read multiple packets\n" -" --wait - Wait until data arrives\n" -"\n" -" Kernel Options:\n" -" --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 of kernel buffer in bytes (default: page)\n" -" -s - Number of buffers to allocate (default: 1)\n" -" --allignment - Buffer alignment (default: page)\n" -"\n" -" Information:\n" -" --verbose [level] - Announce details of ongoing operations\n" -" -q - Quiete mode (suppress warnings)\n" -"\n" -" Data:\n" -" Data can be specified as sequence of hexdecimal number or\n" -" a single value prefixed with '*'. In this case it will be\n" -" replicated the specified amount of times\n" -"\n\n", -argv[0]); - - exit(0); -} - -static int StopFlag = 0; - -static void signal_exit_handler(int signo) { - if (++StopFlag > 2) - exit(-1); -} - - -void Error(const char *format, ...) { - va_list ap; - - va_start(ap, format); - printf("Error %i: ", errno); - vprintf(format, ap); - if (errno) printf("\n errno: %s", strerror(errno)); - printf("\n\n"); - va_end(ap); - - exit(-1); -} - -void Silence(const char *format, ...) { -} - -void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, int details) { - int i,j; - const pcilib_register_bank_description_t *banks; - const pcilib_register_description_t *registers; - const pcilib_event_description_t *events; - const pcilib_event_data_type_description_t *types; - - const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); - const pcilib_dma_description_t *dma_info = pcilib_get_dma_info(handle); - - for (i = 0; i < PCILIB_MAX_BARS; i++) { - if (board_info->bar_length[i] > 0) { - printf(" BAR %d - ", i); - - switch ( board_info->bar_flags[i]&IORESOURCE_TYPE_BITS) { - case IORESOURCE_IO: printf(" IO"); break; - case IORESOURCE_MEM: printf("MEM"); break; - case IORESOURCE_IRQ: printf("IRQ"); break; - case IORESOURCE_DMA: printf("DMA"); break; - } - - if (board_info->bar_flags[i]&IORESOURCE_MEM_64) printf("64"); - else printf("32"); - - printf(", Start: 0x%08lx, Length: 0x%8lx, Flags: 0x%08lx\n", board_info->bar_start[i], board_info->bar_length[i], board_info->bar_flags[i] ); - } - } - printf("\n"); - - if ((dma_info)&&(dma_info->engines)) { - printf("DMA Engines: \n"); - for (i = 0; dma_info->engines[i].addr_bits; i++) { - const pcilib_dma_engine_description_t *engine = &dma_info->engines[i]; - printf(" DMA %2d ", engine->addr); - switch (engine->direction) { - case PCILIB_DMA_FROM_DEVICE: - printf("C2S"); - break; - case PCILIB_DMA_TO_DEVICE: - printf("S2C"); - break; - case PCILIB_DMA_BIDIRECTIONAL: - printf("BI "); - break; - } - printf(" - Type: "); - switch (engine->type) { - case PCILIB_DMA_TYPE_BLOCK: - printf("Block"); - break; - case PCILIB_DMA_TYPE_PACKET: - printf("Packet"); - break; - default: - printf("Unknown"); - } - - printf(", Address Width: %02lu bits\n", engine->addr_bits); - } - printf("\n"); - } - - if ((bank)&&(bank != (char*)-1)) banks = NULL; - else banks = model_info->banks; - - if (banks) { - printf("Banks: \n"); - for (i = 0; banks[i].access; i++) { - printf(" 0x%02x %s", banks[i].addr, banks[i].name); - if ((banks[i].description)&&(banks[i].description[0])) { - printf(": %s", banks[i].description); - } - printf("\n"); - } - printf("\n"); - } - - if (bank == (char*)-1) registers = NULL; - else registers = model_info->registers; - - if (registers) { - pcilib_register_bank_addr_t bank_addr = 0; - if (bank) { - pcilib_register_bank_t bank_id = pcilib_find_register_bank(handle, bank); - const pcilib_register_bank_description_t *b = model_info->banks + bank_id; - - bank_addr = b->addr; - if (b->description) printf("%s:\n", b->description); - else if (b->name) printf("Registers of bank %s:\n", b->name); - else printf("Registers of bank 0x%x:\n", b->addr); - } else { - printf("Registers: \n"); - } - for (i = 0; registers[i].bits; i++) { - const char *mode; - - if ((bank)&&(registers[i].bank != bank_addr)) continue; - if (registers[i].type == PCILIB_REGISTER_BITS) { - if (!details) continue; - - if (registers[i].bits > 1) { - printf(" [%2u:%2u] - %s\n", registers[i].offset, registers[i].offset + registers[i].bits, registers[i].name); - } else { - printf(" [ %2u] - %s\n", registers[i].offset, registers[i].name); - } - - continue; - } - - if (registers[i].mode == PCILIB_REGISTER_RW) mode = "RW"; - else if (registers[i].mode == PCILIB_REGISTER_R) mode = "R "; - else if (registers[i].mode == PCILIB_REGISTER_W) mode = " W"; - else mode = " "; - - printf(" 0x%02x (%2i %s) %s", registers[i].addr, registers[i].bits, mode, registers[i].name); - if ((details > 0)&&(registers[i].description)&&(registers[i].description[0])) { - printf(": %s", registers[i].description); - } - printf("\n"); - - } - printf("\n"); - } - - if (bank == (char*)-1) events = NULL; - else { - events = model_info->events; - types = model_info->data_types; - } - - if (events) { - printf("Events: \n"); - for (i = 0; events[i].name; i++) { - printf(" %s", events[i].name); - if ((events[i].description)&&(events[i].description[0])) { - printf(": %s", events[i].description); - } - - if (types) { - for (j = 0; types[j].name; j++) { - if (types[j].evid & events[i].evid) { - printf("\n %s", types[j].name); - if ((types[j].description)&&(types[j].description[0])) { - printf(": %s", types[j].description); - } - } - } - } - } - printf("\n"); - } -} - -void Info(pcilib_t *handle, const pcilib_model_description_t *model_info) { - const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); - - 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); -} - - -#define BENCH_MAX_DMA_SIZE 4 * 1024 * 1024 -#define BENCH_MAX_FIFO_SIZE 1024 * 1024 - -int Benchmark(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, size_t iterations) { - int err; - int i, j, errors; - void *data, *buf, *check; - void *fifo = NULL; - struct timeval start, end; - unsigned long time; - size_t size, min_size, max_size; - double mbs_in, mbs_out, mbs; - 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) { - min_size = n * access; - max_size = n * access; - } else { - min_size = 1024; - max_size = BENCH_MAX_DMA_SIZE; - } - - for (size = min_size; size <= max_size; size *= 4) { - mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_FROM_DEVICE); - mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_TO_DEVICE); - mbs = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_BIDIRECTIONAL); - err = pcilib_wait_irq(handle, 0, 0, &irqs); - if (err) irqs = 0; - - printf("%8zu KB - ", size / 1024); - - printf("RW: "); - if (mbs < 0) printf("failed ... "); - else printf("%8.2lf MB/s", mbs); - - printf(", R: "); - if (mbs_in < 0) printf("failed ... "); - else printf("%8.2lf MB/s", mbs_in); - - printf(", W: "); - if (mbs_out < 0) printf("failed ... "); - else printf("%8.2lf MB/s", mbs_out); - - if (irqs) { - printf(", IRQs: %lu", irqs); - } - - printf("\n"); - } - - return 0; - } - - if (bar == PCILIB_BAR_INVALID) { - unsigned long maxlength = 0; - - - for (i = 0; i < PCILIB_MAX_REGISTER_BANKS; i++) { - if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + access))) { - bar = i; - break; - } - - if (board_info->bar_length[i] > maxlength) { - maxlength = board_info->bar_length[i]; - bar = i; - } - } - - if (bar < 0) Error("Data banks are not available"); - } - - if (n) { - if ((mode == ACCESS_BAR)&&(n * access > board_info->bar_length[bar])) Error("The specified size (%i) exceeds the size of bar (%i)", n * access, board_info->bar_length[bar]); - - min_size = n * access; - max_size = n * access; - } else { - min_size = access; - if (mode == ACCESS_BAR) max_size = board_info->bar_length[bar]; - else max_size = BENCH_MAX_FIFO_SIZE; - } - - err = posix_memalign( (void**)&buf, 256, max_size ); - if (!err) err = posix_memalign( (void**)&check, 256, max_size ); - if ((err)||(!buf)||(!check)) Error("Allocation of %i bytes of memory have failed", max_size); - - data = pcilib_map_bar(handle, bar); - if (!data) Error("Can't map bar %i", bar); - - if (mode == ACCESS_FIFO) { - fifo = data + (addr - board_info->bar_start[bar]) + (board_info->bar_start[bar] & pcilib_get_page_mask()); -// pcilib_resolve_register_address(handle, bar, addr); - if (!fifo) Error("Can't resolve address (%lx) in bar (%u)", addr, bar); - } - - if (mode == ACCESS_FIFO) - printf("Transfer time (Bank: %i, Fifo: %lx):\n", bar, addr); - else - printf("Transfer time (Bank: %i):\n", bar); - - for (size = min_size ; size < max_size; size *= 8) { - gettimeofday(&start,NULL); - if (mode == ACCESS_BAR) { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_memcpy(buf, data, size); - } - } else { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - for (j = 0; j < (size/access); j++) { - pcilib_memcpy(buf + j * access, fifo, access); - } - } - } - gettimeofday(&end,NULL); - - time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); - - fflush(0); - - gettimeofday(&start,NULL); - if (mode == ACCESS_BAR) { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_memcpy(data, buf, size); - } - } else { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - for (j = 0; j < (size/access); j++) { - pcilib_memcpy(fifo, buf + j * access, access); - } - } - } - gettimeofday(&end,NULL); - - time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); - } - - pcilib_unmap_bar(handle, bar, data); - - printf("\n\nOpen-Transfer-Close time: \n"); - - for (size = 4 ; size < max_size; size *= 8) { - gettimeofday(&start,NULL); - if (mode == ACCESS_BAR) { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_read(handle, bar, 0, size, buf); - } - } else { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_read_fifo(handle, bar, addr, access, size / access, buf); - } - } - gettimeofday(&end,NULL); - - time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); - - fflush(0); - - gettimeofday(&start,NULL); - if (mode == ACCESS_BAR) { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_write(handle, bar, 0, size, buf); - } - } else { - for (i = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_write_fifo(handle, bar, addr, access, size / access, buf); - } - } - - gettimeofday(&end,NULL); - - time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); - - if (mode == ACCESS_BAR) { - gettimeofday(&start,NULL); - for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) { - pcilib_write(handle, bar, 0, size, buf); - pcilib_read(handle, bar, 0, size, check); - if (memcmp(buf, check, size)) ++errors; - } - gettimeofday(&end,NULL); - - time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); - printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); - if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS); - } - printf("\n"); - } - - printf("\n\n"); - - free(check); - free(buf); - - return 0; -} - -#define pci2host16(endianess, value) endianess? - -/* -typedef struct { - size_t size; - void *data; - size_t pos; - - int multi_mode; -} DMACallbackContext; - -static int DMACallback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { - DMACallbackContext *ctx = (DMACallbackContext*)arg; - - if ((ctx->pos + bufsize > ctx->size)||(!ctx->data)) { - ctx->size *= 2; - ctx->data = realloc(ctx->data, ctx->size); - if (!ctx->data) { - Error("Allocation of %i bytes of memory have failed", ctx->size); - return 0; - } - } - - memcpy(ctx->data + ctx->pos, buf, bufsize); - ctx->pos += bufsize; - - if (flags & PCILIB_DMA_FLAG_EOP) return 0; - return 1; -} -*/ - - -int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, size_t timeout, FILE *o) { - void *buf; - int i, err; - size_t ret, bytes; - size_t size = n * abs(access); - int block_width, blocks_per_line; - 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); - blocks_per_line = (LINE_WIDTH - 10) / (block_width + BLOCK_SEPARATOR_WIDTH); - if ((blocks_per_line > 1)&&(blocks_per_line % 2)) --blocks_per_line; - numbers_per_line = blocks_per_line * numbers_per_block; - - if (size) { - buf = malloc(size); - if (!buf) Error("Allocation of %zu bytes of memory has failed", size); - } else { - buf = NULL; - } - - switch (mode) { - case ACCESS_DMA: - if (timeout == (size_t)-1) timeout = PCILIB_DMA_TIMEOUT; - - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); - - if (flags&FLAG_MULTIPACKET) dma_flags |= PCILIB_DMA_FLAG_MULTIPACKET; - if (flags&FLAG_WAIT) dma_flags |= PCILIB_DMA_FLAG_WAIT; - - if (size) { - err = pcilib_read_dma_custom(handle, dmaid, addr, size, dma_flags, timeout, buf, &bytes); - if (err) Error("Error (%i) is reported by DMA engine", err); - } else { - dma_flags |= PCILIB_DMA_FLAG_IGNORE_ERRORS; - - size = 2048; bytes = 0; - do { - size *= 2; - buf = realloc(buf, size); - if (!buf) Error("Allocation of %zu bytes of memory has failed", size); - err = pcilib_read_dma_custom(handle, dmaid, addr, size - bytes, dma_flags, timeout, buf + bytes, &ret); - bytes += ret; - - if ((!err)&&(flags&FLAG_MULTIPACKET)) { - err = PCILIB_ERROR_TOOBIG; - if ((flags&FLAG_WAIT)==0) timeout = 0; - } - } while (err == PCILIB_ERROR_TOOBIG); - } - - if ((err)&&(err != PCILIB_ERROR_TIMEOUT)) { - Error("Error (%i) during DMA read", err); - } - if (bytes <= 0) { - pcilib_warning("No data is returned by DMA engine"); - return 0; - } - size = bytes; - n = bytes / abs(access); - addr = 0; - break; - case ACCESS_FIFO: - 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); - } - - if (endianess) pcilib_swap(buf, buf, abs(access), n); - - if (o) { - printf("Writting output (%zu bytes) to file (append to the end)...\n", n * abs(access)); - fwrite(buf, abs(access), n, o); - } else { - for (i = 0; i < n; i++) { - if (i) { - if (i%numbers_per_line == 0) printf("\n"); - else { - printf("%*s", SEPARATOR_WIDTH, ""); - if (i%numbers_per_block == 0) printf("%*s", BLOCK_SEPARATOR_WIDTH, ""); - } - } - - if (i%numbers_per_line == 0) printf("%8lx: ", addr + i * abs(access)); - - switch (access) { - case 1: printf("%0*hhx", access * 2, ((uint8_t*)buf)[i]); break; - case 2: printf("%0*hx", access * 2, ((uint16_t*)buf)[i]); break; - case 4: printf("%0*x", access * 2, ((uint32_t*)buf)[i]); break; - case 8: printf("%0*lx", access * 2, ((uint64_t*)buf)[i]); break; - } - } - printf("\n\n"); - } - - - free(buf); - return 0; -} - - - - -int ReadRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg) { - int i; - int err; - const char *format; - - pcilib_register_bank_t bank_id; - pcilib_register_bank_addr_t bank_addr = 0; - - pcilib_register_value_t value; - - if (reg) { - pcilib_register_t regid = pcilib_find_register(handle, bank, reg); - bank_id = pcilib_find_register_bank_by_addr(handle, model_info->registers[regid].bank); - format = model_info->banks[bank_id].format; - if (!format) format = "%lu"; - - err = pcilib_read_register_by_id(handle, regid, &value); - // err = pcilib_read_register(handle, bank, reg, &value); - if (err) printf("Error reading register %s\n", reg); - else { - printf("%s = ", reg); - printf(format, value); - printf("\n"); - } - } else { - // Adding DMA registers - pcilib_get_dma_info(handle); - - if (model_info->registers) { - if (bank) { - bank_id = pcilib_find_register_bank(handle, bank); - bank_addr = model_info->banks[bank_id].addr; - } - - printf("Registers:\n"); - for (i = 0; model_info->registers[i].bits; i++) { - if ((model_info->registers[i].mode & PCILIB_REGISTER_R)&&((!bank)||(model_info->registers[i].bank == bank_addr))&&(model_info->registers[i].type != PCILIB_REGISTER_BITS)) { - bank_id = pcilib_find_register_bank_by_addr(handle, model_info->registers[i].bank); - format = model_info->banks[bank_id].format; - if (!format) format = "%lu"; - - err = pcilib_read_register_by_id(handle, i, &value); - if (err) printf(" %s = error reading value", model_info->registers[i].name); - else { - printf(" %s = ", model_info->registers[i].name); - printf(format, value); - } - - printf(" ["); - printf(format, model_info->registers[i].defvalue); - printf("]"); - printf("\n"); - } - } - } else { - printf("No registers"); - } - printf("\n"); - } - - return 0; -} - -#define WRITE_REGVAL(buf, n, access, o) {\ - uint##access##_t tbuf[n]; \ - for (i = 0; i < n; i++) { \ - tbuf[i] = (uint##access##_t)buf[i]; \ - } \ - fwrite(tbuf, access/8, n, o); \ -} - -int ReadRegisterRange(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, uintptr_t addr, long addr_shift, size_t n, FILE *o) { - int err; - int i; - - const pcilib_register_bank_description_t *banks = model_info->banks; - pcilib_register_bank_t bank_id = pcilib_find_register_bank(handle, bank); - - if (bank_id == PCILIB_REGISTER_BANK_INVALID) { - if (bank) Error("Invalid register bank is specified (%s)", bank); - else Error("Register bank should be specified"); - } - - int access = banks[bank_id].access / 8; -// int size = n * abs(access); - int block_width, blocks_per_line; - int numbers_per_block, numbers_per_line; - - numbers_per_block = BLOCK_SIZE / access; - - block_width = numbers_per_block * ((access * 2) + SEPARATOR_WIDTH); - blocks_per_line = (LINE_WIDTH - 6) / (block_width + BLOCK_SEPARATOR_WIDTH); - if ((blocks_per_line > 1)&&(blocks_per_line % 2)) --blocks_per_line; - numbers_per_line = blocks_per_line * numbers_per_block; - - - pcilib_register_value_t buf[n]; - err = pcilib_read_register_space(handle, bank, addr, n, buf); - if (err) Error("Error reading register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); - - - if (o) { - printf("Writting output (%zu bytes) to file (append to the end)...\n", n * abs(access)); - switch (access) { - case 1: WRITE_REGVAL(buf, n, 8, o) break; - case 2: WRITE_REGVAL(buf, n, 16, o) break; - case 4: WRITE_REGVAL(buf, n, 32, o) break; - case 8: WRITE_REGVAL(buf, n, 64, o) break; - } - } else { - for (i = 0; i < n; i++) { - if (i) { - if (i%numbers_per_line == 0) printf("\n"); - else { - printf("%*s", SEPARATOR_WIDTH, ""); - if (i%numbers_per_block == 0) printf("%*s", BLOCK_SEPARATOR_WIDTH, ""); - } - } - - if (i%numbers_per_line == 0) printf("%4lx: ", addr + 4 * i - addr_shift); - printf("%0*lx", access * 2, (unsigned long)buf[i]); - } - printf("\n\n"); - } - - 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 verify) { - int read_back = 0; - void *buf, *check; - int res = 0, i, err; - int size = n * abs(access); - 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); - - for (i = 0; i < n; i++) { - switch (access) { - case 1: res = sscanf(data[i], "%hhx", ((uint8_t*)buf)+i); break; - case 2: res = sscanf(data[i], "%hx", ((uint16_t*)buf)+i); break; - case 4: res = sscanf(data[i], "%x", ((uint32_t*)buf)+i); break; - case 8: res = sscanf(data[i], "%lx", ((uint64_t*)buf)+i); break; - default: Error("Unexpected data size (%lu)", access); - } - if ((res != 1)||(!isxnumber(data[i]))) Error("Can't parse data value at poition %i, (%s) is not valid hex number", i, data[i]); - } - - if (endianess) pcilib_swap(buf, buf, abs(access), n); - - switch (mode) { - case ACCESS_DMA: - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); - err = pcilib_write_dma(handle, dmaid, addr, size, buf, &ret); - if ((err)||(ret != size)) { - if (err == PCILIB_ERROR_TIMEOUT) Error("Timeout writting the data to DMA"); - else if (err) Error("DMA engine returned a error while writing the data"); - else if (!ret) Error("No data is written by DMA engine"); - else Error("Only %lu bytes of %lu is written by DMA engine", ret, size); - } - break; - case ACCESS_FIFO: - pcilib_write_fifo(handle, bar, addr, access, n, buf); - break; - default: - pcilib_write(handle, bar, addr, size, buf); - if (verify) { - pcilib_read(handle, bar, addr, size, check); - read_back = 1; - } - } - - if ((read_back)&&(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, mode, 0, dma, bar, addr, n, access, endianess, (size_t)-1, NULL); - exit(-1); - } - - free(check); - free(buf); - - return 0; -} - -int WriteRegisterRange(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, uintptr_t addr, long addr_shift, size_t n, char ** data) { - pcilib_register_value_t *buf, *check; - int res, i, err; - unsigned long value; - int size = n * sizeof(pcilib_register_value_t); - - 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); - - for (i = 0; i < n; i++) { - res = sscanf(data[i], "%lx", &value); - if ((res != 1)||(!isxnumber(data[i]))) Error("Can't parse data value at poition %i, (%s) is not valid hex number", i, data[i]); - buf[i] = value; - } - - err = pcilib_write_register_space(handle, bank, addr, n, buf); - if (err) Error("Error writting register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); - - err = pcilib_read_register_space(handle, bank, addr, n, check); - if (err) Error("Error reading register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); - - if (memcmp(buf, check, size)) { - printf("Write failed: the data written and read differ, the foolowing is read back:\n"); - ReadRegisterRange(handle, model_info, bank, addr, addr_shift, n, NULL); - exit(-1); - } - - free(check); - free(buf); - - return 0; - -} - -int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, char ** data) { - int err; - - unsigned long val; - pcilib_register_value_t value; - - const char *format = NULL; - - pcilib_register_t regid = pcilib_find_register(handle, bank, reg); - if (regid == PCILIB_REGISTER_INVALID) Error("Can't find register (%s) from bank (%s)", reg, bank?bank:"autodetected"); - -/* - pcilib_register_bank_t bank_id; - pcilib_register_bank_addr_t bank_addr; - - bank_id = pcilib_find_bank_by_addr(handle, model_info->registers[regid].bank); - if (bank_id == PCILIB_REGISTER_BANK_INVALID) Error("Can't find bank of the register (%s)", reg); - format = model_info->banks[bank_id].format; - if (!format) format = "%lu"; -*/ - - if (isnumber(*data)) { - if (sscanf(*data, "%li", &val) != 1) { - Error("Can't parse data value (%s) is not valid decimal number", *data); - } - - format = "%li"; - } else if (isxnumber(*data)) { - if (sscanf(*data, "%lx", &val) != 1) { - Error("Can't parse data value (%s) is not valid decimal number", *data); - } - - format = "0x%lx"; - } else { - Error("Can't parse data value (%s) is not valid decimal number", *data); - } - - value = val; - - err = pcilib_write_register(handle, bank, reg, value); - if (err) Error("Error writting register %s\n", reg); - - if ((model_info->registers[regid].mode&PCILIB_REGISTER_RW) == PCILIB_REGISTER_RW) { - err = pcilib_read_register(handle, bank, reg, &value); - if (err) Error("Error reading back register %s for verification\n", reg); - - if (val != value) { - Error("Failed to write register %s: %lu is written and %lu is read back", reg, val, value); - } else { - printf("%s = ", reg); - printf(format, value); - printf("\n"); - } - } else { - printf("%s is written\n ", reg); - } - - return 0; -} - -typedef struct { - pcilib_t *handle; - pcilib_event_t event; - pcilib_event_data_type_t data; - - fastwriter_t *writer; - - int verbose; - pcilib_timeout_t timeout; - size_t run_time; - size_t trigger_time; - size_t max_triggers; - pcilib_event_flags_t flags; - FORMAT format; - - volatile int event_pending; /**< Used to detect that we have read previously triggered event */ - volatile int trigger_thread_started; /**< Indicates that trigger thread is ready and we can't procced to start event recording */ - volatile int started; /**< Indicates that recording is started */ - - volatile int run_flag; - volatile int writing_flag; - - struct timeval first_frame; - struct timeval last_frame; - size_t last_num; - - size_t trigger_failed; - size_t trigger_count; - size_t event_count; - size_t incomplete_count; - size_t broken_count; - size_t missing_count; - size_t storage_count; - - struct timeval start_time; - struct timeval stop_time; -} GRABContext; - -int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) { - int err = 0; - void *data; - size_t size; - - GRABContext *ctx = (GRABContext*)user; - pcilib_t *handle = ctx->handle; - - gettimeofday(&ctx->last_frame, NULL); - - if (!ctx->event_count) { - memcpy(&ctx->first_frame, &ctx->last_frame, sizeof(struct timeval)); - } - - ctx->event_pending = 0; - ctx->event_count++; - - ctx->missing_count += (info->seqnum - ctx->last_num) - 1; - ctx->last_num = info->seqnum; - - if (info->flags&PCILIB_EVENT_INFO_FLAG_BROKEN) { - ctx->incomplete_count++; - return PCILIB_STREAMING_CONTINUE; - } - - switch (ctx->format) { - case FORMAT_DEFAULT: - data = pcilib_get_data(handle, event_id, PCILIB_EVENT_DATA, &size); - break; - default: - data = pcilib_get_data(handle, event_id, PCILIB_EVENT_RAW_DATA, &size); - } - - if (!data) { - ctx->broken_count++; - return PCILIB_STREAMING_CONTINUE; - } - - if (ctx->format == FORMAT_HEADER) { - uint64_t header[8]; - header[0] = info->type; - header[1] = ctx->data; - header[2] = 0; - header[3] = size; - header[4] = info->seqnum; - header[5] = info->offset; - memcpy(header + 6, &info->timestamp, 16); - - err = fastwriter_push(ctx->writer, 64, header); - } - - if (!err) - err = fastwriter_push(ctx->writer, size, data); - - if (err) { - fastwriter_cancel(ctx->writer); - - if (err != EWOULDBLOCK) - Error("Storage error %i", err); - - ctx->storage_count++; - pcilib_return_data(handle, event_id, ctx->data, data); - return PCILIB_STREAMING_CONTINUE; - } - - err = pcilib_return_data(handle, event_id, ctx->data, data); - if (err) { - ctx->missing_count++; - fastwriter_cancel(ctx->writer); - return PCILIB_STREAMING_CONTINUE; - } - - err = fastwriter_commit(ctx->writer); - if (err) Error("Error commiting data to storage, Error: %i", err); - - return PCILIB_STREAMING_CONTINUE; -} - -int raw_data(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user) { - int err; - - GRABContext *ctx = (GRABContext*)user; -// pcilib_t *handle = ctx->handle; - - - if ((info)&&(info->seqnum != ctx->last_num)) { - gettimeofday(&ctx->last_frame, NULL); - if (!ctx->event_count) { - memcpy(&ctx->first_frame, &ctx->last_frame, sizeof(struct timeval)); - } - - ctx->event_count++; - ctx->missing_count += (info->seqnum - ctx->last_num) - 1; - ctx->last_num = info->seqnum; - } - - err = fastwriter_push_data(ctx->writer, size, data); - if (err) { - if (err == EWOULDBLOCK) Error("Storage is not able to handle the data stream, buffer overrun"); - Error("Storage error %i", err); - } - - return PCILIB_STREAMING_CONTINUE; -} - - -void *Trigger(void *user) { - int err; - struct timeval start; - - GRABContext *ctx = (GRABContext*)user; - size_t trigger_time = ctx->trigger_time; - size_t max_triggers = ctx->max_triggers; - - ctx->trigger_thread_started = 1; - ctx->event_pending = 1; - - while (!ctx->started) ; - - gettimeofday(&start, NULL); - do { - err = pcilib_trigger(ctx->handle, ctx->event, 0, NULL); - if (err) ctx->trigger_failed++; - if ((++ctx->trigger_count == max_triggers)&&(max_triggers)) break; - - if (trigger_time) { - pcilib_add_timeout(&start, trigger_time); - if ((ctx->stop_time.tv_sec)&&(pcilib_timecmp(&start, &ctx->stop_time)>0)) break; - pcilib_sleep_until_deadline(&start); - } else { - while ((ctx->event_pending)&&(ctx->run_flag)) usleep(10); - ctx->event_pending = 1; - } - } while (ctx->run_flag); - - ctx->trigger_thread_started = 0; - - return NULL; -} - -void GrabStats(GRABContext *ctx, struct timeval *end_time) { - int verbose; - pcilib_timeout_t duration, fps_duration; - struct timeval cur; - double fps = 0, good_fps = 0; - size_t total, good, pending = 0; - - verbose = ctx->verbose; - - if (end_time) { - if (verbose++) { - printf("-------------------------------------------------------------------------------\n"); - } - } else { - gettimeofday(&cur, NULL); - end_time = &cur; - } - -// if ((ctx->event_count + ctx->missing_count) == 0) -// return; - - duration = pcilib_timediff(&ctx->start_time, end_time); - fps_duration = pcilib_timediff(&ctx->first_frame, &ctx->last_frame); - - if (ctx->trigger_count) { - total = ctx->trigger_count; - pending = ctx->trigger_count - ctx->event_count - ctx->missing_count - ctx->trigger_failed; - } else { - total = ctx->event_count + ctx->missing_count; - } - - good = ctx->event_count - ctx->broken_count - ctx->incomplete_count - ctx->storage_count; - - if (ctx->event_count > 1) { - fps = (ctx->event_count - 1) / (1.*fps_duration/1000000); - } - - if (good > 1) { - good_fps = (good - 1) / (1.*fps_duration/1000000); - } - - printf("Run: "); - PrintTime(duration); - - if (ctx->trigger_count) { - printf(", Triggers: "); - PrintNumber(ctx->trigger_count); - } - - printf(", Captured: "); - PrintNumber(ctx->event_count); - printf(" FPS %5.0lf", fps); - - if ((ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) == 0) { - printf(", Stored: "); - PrintNumber(good); - printf(" FPS %5.0lf", good_fps); - } - - printf("\n"); - - if (verbose > 2) { - if (ctx->trigger_count) { - printf("Trig: "); - PrintNumber(ctx->trigger_count); - printf(" Issued: "); - PrintNumber(ctx->trigger_count - ctx->trigger_failed); - printf(" ("); - PrintPercent(ctx->trigger_count - ctx->trigger_failed, ctx->trigger_count); - printf("%%) Failed: "); - PrintNumber(ctx->trigger_failed); - printf( " ("); - PrintPercent(ctx->trigger_failed, ctx->trigger_count); - printf( "%%); Pending: "); - PrintNumber(pending); - printf( " ("); - PrintPercent(pending, ctx->trigger_count); - printf( "%%)\n"); - } - - if (ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { - printf("Captured: "); - PrintNumber(good); - } else { - printf("Good: "); - PrintNumber(good); - printf(", Dropped: "); - PrintNumber(ctx->storage_count); - printf(", Bad: "); - PrintNumber(ctx->incomplete_count); - printf(", Empty: "); - PrintNumber(ctx->broken_count); - } - printf(", Lost: "); - PrintNumber(ctx->missing_count); - printf("\n"); - } - - if (verbose > 1) { - if (ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { - printf("Captured: "); - PrintPercent(good, total); - } else { - printf("Good: "); - PrintPercent(good, total); - printf("%% Dropped: "); - PrintPercent(ctx->storage_count, total); - printf("%% Bad: "); - PrintPercent(ctx->incomplete_count, total); - printf("%% Empty: "); - PrintPercent(ctx->broken_count, total); - } - - printf("%% Lost: "); - PrintPercent(ctx->missing_count, total); - printf("%%"); - printf("\n"); - } -} - -void StorageStats(GRABContext *ctx) { - int err; - fastwriter_stats_t st; - - pcilib_timeout_t duration; - struct timeval cur; - - gettimeofday(&cur, NULL); - duration = pcilib_timediff(&ctx->start_time, &cur); - - - err = fastwriter_get_stats(ctx->writer, &st); - if (err) return; - - printf("Wrote "); - PrintSize(st.written); - printf(" of "); - PrintSize(st.commited); - printf(" at "); - PrintSize(1000000.*st.written / duration); - printf("/s, %6.2lf%% ", 100.*st.buffer_used / st.buffer_size); - printf(" of "); - PrintSize(st.buffer_size); - printf(" buffer (%6.2lf%% max)\n", 100.*st.buffer_max / st.buffer_size); -} - -void *Monitor(void *user) { - struct timeval deadline; - struct timeval nextinfo; - - GRABContext *ctx = (GRABContext*)user; - int verbose = ctx->verbose; - pcilib_timeout_t timeout = ctx->timeout; - - - if (timeout == PCILIB_TIMEOUT_INFINITE) timeout = 0; - -// while (!ctx->started); - - if (timeout) { - memcpy(&deadline, (struct timeval*)&ctx->last_frame, sizeof(struct timeval)); - pcilib_add_timeout(&deadline, timeout); - } - - if (verbose > 0) { - pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); - } - - while (ctx->run_flag) { - if (StopFlag) { - pcilib_stop(ctx->handle, PCILIB_EVENT_FLAG_STOP_ONLY); - break; - } - - if (timeout) { - if (pcilib_calc_time_to_deadline(&deadline) == 0) { - memcpy(&deadline, (struct timeval*)&ctx->last_frame, sizeof(struct timeval)); - pcilib_add_timeout(&deadline, timeout); - - if (pcilib_calc_time_to_deadline(&deadline) == 0) { - pcilib_stop(ctx->handle, PCILIB_EVENT_FLAG_STOP_ONLY); - break; - } - } - } - - if (verbose > 0) { - if (pcilib_calc_time_to_deadline(&nextinfo) == 0) { - GrabStats(ctx, NULL); - StorageStats(ctx); - pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); - } - } - - usleep(100000); - } - - pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); - while (ctx->writing_flag) { - if (pcilib_calc_time_to_deadline(&nextinfo) == 0) { - if (verbose >= 0) StorageStats(ctx); - pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); - } - - usleep(100000); - } - - return NULL; -} - -int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *evname, const char *data_type, size_t num, size_t run_time, size_t trigger_time, pcilib_timeout_t timeout, PARTITION partition, FORMAT format, size_t buffer_size, size_t threads, int verbose, const char *output) { - int err; - GRABContext ctx; -// void *data = NULL; -// size_t size, written; - - pcilib_event_t event; - pcilib_event_t listen_events; - pcilib_event_data_type_t data; - - pthread_t monitor_thread; - pthread_t trigger_thread; - pthread_attr_t attr; - struct sched_param sched; - - struct timeval end_time; - pcilib_event_flags_t flags; - - if (evname) { - event = pcilib_find_event(handle, evname); - if (event == PCILIB_EVENT_INVALID) - Error("Can't find event (%s)", evname); - - listen_events = event; - } else { - listen_events = PCILIB_EVENTS_ALL; - event = PCILIB_EVENT0; - } - - if (data_type) { - data = pcilib_find_event_data_type(handle, event, data_type); - if (data == PCILIB_EVENT_DATA_TYPE_INVALID) - Error("Can't find data type (%s)", data_type); - } else { - data = PCILIB_EVENT_DATA; - } - - memset(&ctx, 0, sizeof(GRABContext)); - - ctx.handle = handle; - ctx.event = event; - ctx.data = data; - ctx.run_time = run_time; - ctx.timeout = timeout; - ctx.format = format; - - if (grab_mode&GRAB_MODE_GRAB) ctx.verbose = verbose; - else ctx.verbose = 0; - - if (grab_mode&GRAB_MODE_GRAB) { - ctx.writer = fastwriter_init(output, 0); - if (!ctx.writer) - Error("Can't initialize fastwritter library"); - - fastwriter_set_buffer_size(ctx.writer, buffer_size); - - err = fastwriter_open(ctx.writer, output, 0); - if (err) - Error("Error opening file (%s), Error: %i\n", output, err); - - ctx.writing_flag = 1; - } - - ctx.run_flag = 1; - - flags = PCILIB_EVENT_FLAGS_DEFAULT; - - if (data == PCILIB_EVENT_RAW_DATA) { - if (format == FORMAT_RAW) { - flags |= PCILIB_EVENT_FLAG_RAW_DATA_ONLY; - } - } else { - flags |= PCILIB_EVENT_FLAG_PREPROCESS; - } - - ctx.flags = flags; - -// printf("Limits: %lu %lu %lu\n", num, run_time, timeout); - pcilib_configure_autostop(handle, num, run_time); - - if (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { - pcilib_configure_rawdata_callback(handle, &raw_data, &ctx); - } - - if (flags&PCILIB_EVENT_FLAG_PREPROCESS) { - pcilib_configure_preprocessing_threads(handle, threads); - } - - if (grab_mode&GRAB_MODE_TRIGGER) { - if (trigger_time) { - if ((timeout)&&(trigger_time * 2 > timeout)) { - timeout = 2 * trigger_time; - ctx.timeout = timeout; - } - } else { - // Otherwise, we will trigger next event after previous one is read - if (((grab_mode&GRAB_MODE_GRAB) == 0)||(flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)) trigger_time = PCILIB_TRIGGER_TIMEOUT; - } - - ctx.max_triggers = num; - ctx.trigger_count = 0; - ctx.trigger_time = trigger_time; - - // We don't really care if RT priority is imposible - pthread_attr_init(&attr); - if (!pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { - sched.sched_priority = sched_get_priority_min(SCHED_FIFO); - pthread_attr_setschedparam(&attr, &sched); - } - - // Start triggering thread and wait until it is schedulled - if (pthread_create(&trigger_thread, &attr, Trigger, (void*)&ctx)) - Error("Error spawning trigger thread"); - - while (!ctx.trigger_thread_started) usleep(10); - } - - gettimeofday(&ctx.start_time, NULL); - - if (grab_mode&GRAB_MODE_GRAB) { - err = pcilib_start(handle, listen_events, flags); - if (err) Error("Failed to start event engine, error %i", err); - } - - ctx.started = 1; - - if (run_time) { - ctx.stop_time.tv_usec = ctx.start_time.tv_usec + run_time%1000000; - if (ctx.stop_time.tv_usec > 999999) { - ctx.stop_time.tv_usec -= 1000000; - __sync_synchronize(); - ctx.stop_time.tv_sec = ctx.start_time.tv_sec + 1 + run_time / 1000000; - } else { - __sync_synchronize(); - ctx.stop_time.tv_sec = ctx.start_time.tv_sec + run_time / 1000000; - } - } - - memcpy(&ctx.last_frame, &ctx.start_time, sizeof(struct timeval)); - if (pthread_create(&monitor_thread, NULL, Monitor, (void*)&ctx)) - Error("Error spawning monitoring thread"); - - if (grab_mode&GRAB_MODE_GRAB) { - err = pcilib_stream(handle, &GrabCallback, &ctx); - if (err) Error("Error streaming events, error %i", err); - } - - ctx.run_flag = 0; - - if (grab_mode&GRAB_MODE_TRIGGER) { - while (ctx.trigger_thread_started) usleep(10); - } - - if (grab_mode&GRAB_MODE_GRAB) { - pcilib_stop(handle, PCILIB_EVENT_FLAGS_DEFAULT); - } - - gettimeofday(&end_time, NULL); - - if (grab_mode&GRAB_MODE_TRIGGER) { - pthread_join(trigger_thread, NULL); - } - - - if (grab_mode&GRAB_MODE_GRAB) { - if (verbose >= 0) - printf("Grabbing is finished, flushing results....\n"); - - err = fastwriter_close(ctx.writer); - if (err) Error("Storage problems, error %i", err); - } - - ctx.writing_flag = 0; - - pthread_join(monitor_thread, NULL); - - if ((grab_mode&GRAB_MODE_GRAB)&&(verbose>=0)) { - GrabStats(&ctx, &end_time); - StorageStats(&ctx); - } - - fastwriter_destroy(ctx.writer); - - return 0; -} - -int StartStopDMA(pcilib_t *handle, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, int start) { - int err; - pcilib_dma_engine_t dmaid; - - if (dma == PCILIB_DMA_ENGINE_ADDR_INVALID) { - const pcilib_dma_description_t *dma_info = pcilib_get_dma_info(handle); - - if (start) Error("DMA engine should be specified"); - - for (dmaid = 0; dma_info->engines[dmaid].addr_bits; dmaid++) { - err = pcilib_start_dma(handle, dmaid, 0); - if (err) Error("Error starting DMA Engine (%s %i)", ((dma_info->engines[dmaid].direction == PCILIB_DMA_FROM_DEVICE)?"C2S":"S2C"), dma_info->engines[dmaid].addr); - err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); - if (err) Error("Error stopping DMA Engine (%s %i)", ((dma_info->engines[dmaid].direction == PCILIB_DMA_FROM_DEVICE)?"C2S":"S2C"), dma_info->engines[dmaid].addr); - } - - return 0; - } - - if (dma_direction&PCILIB_DMA_FROM_DEVICE) { - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (C2S %lu) is specified", dma); - - if (start) { - err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); - if (err) Error("Error starting DMA engine (C2S %lu)", dma); - } else { - err = pcilib_start_dma(handle, dmaid, 0); - if (err) Error("Error starting DMA engine (C2S %lu)", dma); - err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); - if (err) Error("Error stopping DMA engine (C2S %lu)", dma); - } - } - - if (dma_direction&PCILIB_DMA_TO_DEVICE) { - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (S2C %lu) is specified", dma); - - if (start) { - err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); - if (err) Error("Error starting DMA engine (S2C %lu)", dma); - } else { - err = pcilib_start_dma(handle, dmaid, 0); - if (err) Error("Error starting DMA engine (S2C %lu)", dma); - err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); - if (err) Error("Error stopping DMA engine (S2C %lu)", dma); - } - } - - return 0; -} - - -typedef struct { - pcilib_kmem_use_t use; - - int referenced; - int hw_lock; - int reusable; - int persistent; - int open; - - size_t count; - size_t size; -} kmem_use_info_t; - -#define MAX_USES 64 - -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; - - for (i = 1; i < (n - 1); i++) { - if (uses[i].use == use) return i; - } - - if (n == MAX_USES) return 0; - - memset(&uses[n], 0, sizeof(pcilib_kmem_use_t)); - uses[n].use = use; - return (*n_uses)++; -} - - -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]; - - size_t useid, n_uses = 1; // Use 0 is for others - - memset(uses, 0, sizeof(kmem_use_info_t)); - - pos = strrchr(device, '/'); - if (pos) ++pos; - else pos = device; - - snprintf(sysdir, 255, "/sys/class/fpga/%s", pos); - - dir = opendir(sysdir); - if (!dir) Error("Can't open directory (%s)", sysdir); - - while ((entry = readdir(dir)) != NULL) { - FILE *f; - unsigned long use = 0; - unsigned long size = 0; - unsigned long refs = 0; - unsigned long mode = 0; - unsigned long hwref = 0; - - if (strncmp(entry->d_name, "kbuf", 4)) continue; - if (!isnumber(entry->d_name+4)) continue; - - snprintf(fname, 255, "%s/%s", sysdir, entry->d_name); - f = fopen(fname, "r"); - if (!f) Error("Can't access file (%s)", fname); - - while(!feof(f)) { - if (!fgets(info, 256, f)) - break; - - 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, "mode:", 5)) mode = strtoul(info+5, NULL, 16); - if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); - - } - fclose(f); - - useid = FindUse(&n_uses, uses, use); - uses[useid].count++; - uses[useid].size += size; - if (refs) uses[useid].referenced = 1; - if (hwref) uses[useid].hw_lock = 1; - if (mode&KMEM_MODE_REUSABLE) uses[useid].reusable = 1; - if (mode&KMEM_MODE_PERSISTENT) uses[useid].persistent = 1; - if (mode&KMEM_MODE_COUNT) uses[useid].open = 1; - } - 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; - } - - printf("Use Type Count Total Size REF Mode \n"); - printf("--------------------------------------------------------------------------------\n"); - for (useid = 0; useid < n_uses; useid++) { - if (useid + 1 == n_uses) { - if (!uses[0].count) continue; - i = 0; - } else i = useid + 1; - - printf("%08x ", uses[i].use); - if (!i) printf("All Others "); - 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("%6zu", uses[i].count); - printf(" "); - printf("%10s", GetPrintSize(stmp, uses[i].size)); - printf(" "); - if (uses[i].referenced&&uses[i].hw_lock) printf("HW+SW"); - else if (uses[i].referenced) printf(" SW"); - else if (uses[i].hw_lock) printf("HW "); - else printf(" - "); - printf(" "); - if (uses[i].persistent) printf("Persistent"); - else if (uses[i].open) printf("Open "); - else if (uses[i].reusable) printf("Reusable "); - else printf("Closed "); - printf("\n"); - } - printf("--------------------------------------------------------------------------------\n"); - printf("REF - Software/Hardware Reference, MODE - Reusable/Persistent/Open\n"); - - - return 0; -} - -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; - - 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; - } - - err = pcilib_kmem_sync_block(handle, kbuf, PCILIB_KMEM_SYNC_FROMDEVICE, block); - if (err) { - pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); - Error("The synchronization of kernel buffer has failed\n"); - return 0; - } - - data = pcilib_kmem_get_block_ua(handle, kbuf, block); - if (data) { - size = pcilib_kmem_get_block_size(handle, kbuf, block); - if ((max_size)&&(size > max_size)) size = max_size; - - fwrite(data, 1, size, o?o:stdout); - } else { - pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); - Error("The specified block is not existing\n"); - return 0; - } - - pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); - - 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; - - 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. - - if (!strcasecmp(use, "dma")) { - for (i = 0; i < PCILIB_MAX_DMA_ENGINES; i++) { - err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, i), flags); - if (err) Error("Error cleaning DMA%i C2S Ring buffer", i); - err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x80|i), flags); - if (err) Error("Error cleaning DMA%i S2C Ring buffer", i); - err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, i), flags); - if (err) Error("Error cleaning DMA%i C2S Page buffers", i); - err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x80|i), flags); - if (err) Error("Error cleaning DMA%i S2C Page buffers", i); - } - - return 0; - } - - useid = ParseUse(use); - err = pcilib_clean_kernel_memory(handle, useid, flags); - if (err) Error("Error cleaning kernel buffers for use (0x%lx)", useid); - - return 0; -} - -int ListDMA(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info) { - int err; - - DIR *dir; - struct dirent *entry; - const char *pos; - char sysdir[256]; - char fname[256]; - char info[256]; - char stmp[256]; - - pcilib_dma_engine_t dmaid; - pcilib_dma_engine_status_t status; - - pos = strrchr(device, '/'); - if (pos) ++pos; - else pos = device; - - snprintf(sysdir, 255, "/sys/class/fpga/%s", pos); - - dir = opendir(sysdir); - if (!dir) Error("Can't open directory (%s)", sysdir); - - printf("DMA Engine Status Total Size Buffer Ring (1st used - 1st free)\n"); - printf("--------------------------------------------------------------------------------\n"); - while ((entry = readdir(dir)) != NULL) { - FILE *f; - unsigned long use = 0; -// unsigned long size = 0; -// unsigned long refs = 0; - unsigned long mode = 0; -// unsigned long hwref = 0; - - if (strncmp(entry->d_name, "kbuf", 4)) continue; - if (!isnumber(entry->d_name+4)) continue; - - snprintf(fname, 255, "%s/%s", sysdir, entry->d_name); - f = fopen(fname, "r"); - if (!f) Error("Can't access file (%s)", fname); - - while(!feof(f)) { - if (!fgets(info, 256, f)) - break; - - 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, "mode:", 5)) mode = strtoul(info+5, NULL, 16); -// if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); - } - fclose(f); - - if ((mode&(KMEM_MODE_REUSABLE|KMEM_MODE_PERSISTENT|KMEM_MODE_COUNT)) == 0) continue; // closed - if ((use >> 16) != PCILIB_KMEM_USE_DMA_RING) continue; - - if (use&0x80) { - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, use&0x7F); - } else { - dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, use&0x7F); - } - - if (dmaid == PCILIB_DMA_ENGINE_INVALID) continue; - - - printf("DMA%lu %s ", use&0x7F, (use&0x80)?"S2C":"C2S"); - err = pcilib_start_dma(handle, dmaid, 0); - if (err) { - printf("-- Wrong state, start is failed\n"); - continue; - } - - err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); - if (err) { - printf("-- Wrong state, failed to obtain status\n"); - pcilib_stop_dma(handle, dmaid, 0); - continue; - } - - pcilib_stop_dma(handle, dmaid, 0); - - if (status.started) printf("S"); - else printf(" "); - - if (status.ring_head == status.ring_tail) printf(" "); - else printf("D"); - - printf(" "); - printf("%10s", GetPrintSize(stmp, status.ring_size * status.buffer_size)); - - printf(" "); - printf("%zu - %zu (of %zu)", status.ring_tail, status.ring_head, status.ring_size); - - printf("\n"); - - } - closedir(dir); - - printf("--------------------------------------------------------------------------------\n"); - printf("S - Started, D - Data in buffers\n"); - - return 0; -} - -int ListBuffers(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction) { - int err; - size_t i; - pcilib_dma_engine_t dmaid; - pcilib_dma_engine_status_t status; - pcilib_dma_buffer_status_t *buffer; - char stmp[256]; - - dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); - - err = pcilib_start_dma(handle, dmaid, 0); - if (err) Error("Error starting the specified DMA engine"); - - err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); - if (err) Error("Failed to obtain status of the specified DMA engine"); - - buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t)); - if (!buffer) Error("Failed to allocate memory for status buffer"); - - err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer); - if (err) Error("Failed to obtain extended status of the specified DMA engine"); - - - printf("Buffer Status Total Size \n"); - printf("--------------------------------------------------------------------------------\n"); - - for (i = 0; i < status.ring_size; i++) { - printf("%8zu ", i); - printf("%c%c %c%c ", buffer[i].used?'U':' ', buffer[i].error?'E':' ', buffer[i].first?'F':' ', buffer[i].last?'L':' '); - printf("%10s", GetPrintSize(stmp, buffer[i].size)); - printf("\n"); - } - - printf("--------------------------------------------------------------------------------\n"); - printf("U - Used, E - Error, F - First block, L - Last Block\n"); - - free(buffer); - - pcilib_stop_dma(handle, dmaid, 0); - - return 0; -} - -int ReadBuffer(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, size_t block, FILE *o) { - int err; - pcilib_dma_engine_t dmaid; - pcilib_dma_engine_status_t status; - pcilib_dma_buffer_status_t *buffer; - size_t size; - - dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); - if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); - - err = pcilib_start_dma(handle, dmaid, 0); - if (err) Error("Error starting the specified DMA engine"); - - err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); - if (err) Error("Failed to obtain status of the specified DMA engine"); - - buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t)); - if (!buffer) Error("Failed to allocate memory for status buffer"); - - err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer); - if (err) Error("Failed to obtain extended status of the specified DMA engine"); - - if (block == (size_t)-1) { - // get current - } - - size = buffer[block].size; - - free(buffer); - - pcilib_stop_dma(handle, dmaid, 0); - - return ReadKMEM(handle, device, ((dma&0x7F)|((dma_direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00))|(PCILIB_KMEM_USE_DMA_PAGES<<16), block, size, o); -} - - -int EnableIRQ(pcilib_t *handle, const 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, const 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, const 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, const pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source, pcilib_timeout_t timeout) { - int err; - size_t count; - - err = pcilib_wait_irq(handle, irq_source, timeout, &count); - if (err) { - if (err == PCILIB_ERROR_TIMEOUT) Error("Timeout waiting for IRQ"); - else Error("Error waiting for IRQ"); - } - - return 0; -} - - -int main(int argc, char **argv) { - int i; - long itmp; - size_t ztmp; - unsigned char c; - - const char *stmp; - const char *num_offset; - - int details = 0; - int verbose = 0; - int quiete = 0; - int force = 0; - int verify = 0; - - const char *model = NULL; - const pcilib_model_description_t *model_info; - MODE mode = MODE_INVALID; - GRAB_MODE grab_mode = 0; - size_t trigger_time = 0; - size_t run_time = 0; - size_t buffer = 0; - size_t threads = 1; - 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; - pcilib_bar_t bar = PCILIB_BAR_DETECT; - const char *addr = NULL; - const char *reg = NULL; - const char *bank = NULL; - char **data = NULL; - const char *event = NULL; - const char *data_type = NULL; - const char *dma_channel = NULL; - const char *use = NULL; - 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; - - pcilib_t *handle; - - int size_set = 0; - int timeout_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) { - case OPT_HELP: - Usage(argc, argv, NULL); - break; - case OPT_INFO: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_INFO; - break; - case OPT_LIST: - if (mode == MODE_LIST) details++; - else if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_LIST; - break; - case OPT_RESET: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_RESET; - break; - case OPT_BENCHMARK: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_BENCHMARK; - - if (optarg) addr = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; - break; - case OPT_READ: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_READ; - if (optarg) addr = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; - break; - case OPT_WRITE: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_WRITE; - if (optarg) addr = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; - break; - case OPT_GRAB: - if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_GRAB))) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_GRAB; - grab_mode |= GRAB_MODE_GRAB; - - stmp = NULL; - if (optarg) stmp = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++]; - - if (stmp) { - if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event"); - event = stmp; - } - break; - case OPT_TRIGGER: - if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_TRIGGER))) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_GRAB; - grab_mode |= GRAB_MODE_TRIGGER; - - stmp = NULL; - if (optarg) stmp = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++]; - - if (stmp) { - if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event"); - event = stmp; - } - break; - case OPT_LIST_DMA: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_LIST_DMA; - break; - case OPT_LIST_DMA_BUFFERS: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_LIST_DMA_BUFFERS; - dma_channel = optarg; - break; - case OPT_READ_DMA_BUFFER: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_READ_DMA_BUFFER; - - num_offset = strchr(optarg, ':'); - - if (num_offset) { - if (sscanf(num_offset + 1, "%zu", &block) != 1) - Usage(argc, argv, "Invalid buffer is specified (%s)", num_offset + 1); - - *(char*)num_offset = 0; - } else block = (size_t)-1; - - dma_channel = optarg; - break; - case OPT_START_DMA: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_START_DMA; - if (optarg) dma_channel = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) dma_channel = argv[optind++]; - break; - case OPT_STOP_DMA: - if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); - - mode = MODE_STOP_DMA; - 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"); - - mode = MODE_WAIT_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_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"); - mode = MODE_READ_KMEM; - - num_offset = strchr(optarg, ':'); - - 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; - } - - 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"); - mode = MODE_FREE_KMEM; - - if (optarg) use = optarg; - else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++]; - break; - case OPT_DEVICE: - fpga_device = optarg; - break; - case OPT_MODEL: - model = optarg; -/* if (!strcasecmp(optarg, "pci")) model = PCILIB_MODEL_PCI; - else if (!strcasecmp(optarg, "ipecamera")) model = PCILIB_MODEL_IPECAMERA; - else if (!strcasecmp(optarg, "kapture")) model = PCILIB_MODEL_KAPTURE; - else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);*/ - break; - case OPT_BAR: - bank = optarg; -// 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)) { - atype = "fifo"; - num_offset = optarg + 4; - amode = ACCESS_FIFO; - } else if (!strncasecmp(optarg, "dma", 3)) { - atype = "dma"; - num_offset = optarg + 3; - amode = ACCESS_DMA; - } else if (!strncasecmp(optarg, "bar", 3)) { - 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)) { - atype = "plain"; - num_offset = optarg + 5; - amode = ACCESS_BAR; - } else { - num_offset = optarg; - } - - if (*num_offset) { - if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) - Usage(argc, argv, "Invalid access type (%s) is specified", optarg); - - switch (itmp) { - case 8: access = 1; break; - case 16: access = 2; break; - case 32: access = 4; break; - case 64: access = 8; break; - default: Usage(argc, argv, "Invalid data width (%s) is specified", num_offset); - } - } - break; - case OPT_SIZE: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1)) { - if (strcasecmp(optarg, "unlimited")) - Usage(argc, argv, "Invalid size is specified (%s)", optarg); - else - size = 0;//(size_t)-1; - } - - 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; - else endianess = 1; - } else if ((*optarg == 'l')||(*optarg == 'L')) { - if (ntohs(1) == 1) endianess = 1; - else endianess = 0; - } else Usage(argc, argv, "Invalid endianess is specified (%s)", optarg); - - break; - case OPT_TIMEOUT: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1)) { - if (strcasecmp(optarg, "unlimited")) - Usage(argc, argv, "Invalid timeout is specified (%s)", optarg); - else - timeout = PCILIB_TIMEOUT_INFINITE; - } - timeout_set = 1; - break; - case OPT_OUTPUT: - output = optarg; - break; - case OPT_ITERATIONS: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &iterations) != 1)) - Usage(argc, argv, "Invalid number of iterations is specified (%s)", optarg); - break; - case OPT_EVENT: - event = optarg; - break; - case OPT_TYPE: - type = optarg; - break; - case OPT_DATA_TYPE: - data_type = optarg; - break; - case OPT_RUN_TIME: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1)) { - if (strcasecmp(optarg, "unlimited")) - Usage(argc, argv, "Invalid run-time is specified (%s)", optarg); - else - run_time = 0; - } -// run_time_set = 1; - break; - case OPT_TRIGGER_TIME: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &trigger_time) != 1)) - Usage(argc, argv, "Invalid trigger-time is specified (%s)", optarg); - break; - case OPT_TRIGGER_RATE: - if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &ztmp) != 1)) - Usage(argc, argv, "Invalid trigger-rate is specified (%s)", optarg); - - trigger_time = (1000000 / ztmp) + ((1000000 % ztmp)?1:0); - break; - case OPT_BUFFER: - 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, "%zu", &buffer) != 1)) - Usage(argc, argv, "Invalid buffer size is specified (%s)", num_offset); - buffer *= 1024 * 1024; - } else { - buffer = get_free_memory(); - if (buffer < 256) Error("Not enough free memory (%lz MB) for buffering", buffer / 1024 / 1024); - - buffer -= 128 + buffer/16; - } - break; - case OPT_THREADS: - 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, "%zu", &threads) != 1)) - Usage(argc, argv, "Invalid threads number is specified (%s)", num_offset); - } else { - threads = 0; - } - break; - case OPT_FORMAT: - if (!strcasecmp(optarg, "raw")) format = FORMAT_RAW; - else if (!strcasecmp(optarg, "add_header")) format = FORMAT_HEADER; -// else if (!strcasecmp(optarg, "ringfs")) format = FORMAT_RINGFS; - else if (strcasecmp(optarg, "default")) Error("Invalid format (%s) is specified", optarg); - break; - case OPT_QUIETE: - quiete = 1; - verbose = -1; - break; - case OPT_VERBOSE: - 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, "%i", &verbose) != 1)) - Usage(argc, argv, "Invalid verbosity level is specified (%s)", num_offset); - } else { - verbose = 1; - } - break; - case OPT_FORCE: - force = 1; - break; - case OPT_VERIFY: - verify = 1; - break; - case OPT_MULTIPACKET: - flags |= FLAG_MULTIPACKET; - break; - case OPT_WAIT: - flags |= FLAG_WAIT; - break; - default: - Usage(argc, argv, "Unknown option (%s) with argument (%s)", optarg?argv[optind-2]:argv[optind-1], optarg?optarg:"(null)"); - } - } - - if (mode == MODE_INVALID) { - if (argc > 1) Usage(argc, argv, "Operation is not specified"); - else Usage(argc, argv, NULL); - } - - pcilib_set_error_handler(&Error, quiete?Silence:NULL); - - handle = pcilib_open(fpga_device, model); - if (handle < 0) Error("Failed to open FPGA device: %s", fpga_device); - - model_info = pcilib_get_model_description(handle); - - switch (mode) { - case MODE_WRITE: - if (((argc - optind) == 1)&&(*argv[optind] == '*')) { - int vallen = strlen(argv[optind]); - if (vallen > 1) { - data = (char**)malloc(size * (vallen + sizeof(char*))); - if (!data) Error("Error allocating memory for data array"); - - for (i = 0; i < size; i++) { - data[i] = ((char*)data) + size * sizeof(char*) + i * vallen; - strcpy(data[i], argv[optind] + 1); - } - } else { - data = (char**)malloc(size * (9 + sizeof(char*))); - if (!data) Error("Error allocating memory for data array"); - - for (i = 0; i < size; i++) { - data[i] = ((char*)data) + size * sizeof(char*) + i * 9; - sprintf(data[i], "%x", i); - } - } - } else if ((argc - optind) == size) data = argv + optind; - else Usage(argc, argv, "The %i data values is specified, but %i required", argc - optind, size); - case MODE_READ: - if (!addr) { - if (((!model_info->dma)||(!model_info->dma->api))&&(!model_info->api)) { -// if (model == PCILIB_MODEL_PCI) { - if ((amode != ACCESS_DMA)&&(amode != ACCESS_CONFIG)) - Usage(argc, argv, "The address is not specified"); - } else ++mode; - } - break; - case MODE_START_DMA: - case MODE_STOP_DMA: - case MODE_LIST_DMA_BUFFERS: - case MODE_READ_DMA_BUFFER: - if ((dma_channel)&&(*dma_channel)) { - itmp = strlen(dma_channel) - 1; - if (dma_channel[itmp] == 'r') dma_direction = PCILIB_DMA_FROM_DEVICE; - else if (dma_channel[itmp] == 'w') dma_direction = PCILIB_DMA_TO_DEVICE; - - if (dma_direction != PCILIB_DMA_BIDIRECTIONAL) itmp--; - - if (strncmp(dma_channel, "dma", 3)) num_offset = dma_channel; - else { - num_offset = dma_channel + 3; - itmp -= 3; - } - - if (bank) { - if (strncmp(num_offset, bank, itmp)) Usage(argc, argv, "Conflicting DMA channels are specified in mode parameter (%s) and bank parameter (%s)", dma_channel, bank); - } - - if (!isnumber_n(num_offset, itmp)) - Usage(argc, argv, "Invalid DMA channel (%s) is specified", dma_channel); - - dma = atoi(num_offset); - } - break; - default: - if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied"); - } - - - if (addr) { - if ((!strncmp(addr, "dma", 3))&&((addr[3]==0)||isnumber(addr+3))) { - 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 { - if (addr[3] == 0) Usage(argc, argv, "The DMA channel is not specified"); - } - dma = atoi(addr + 3); - amode = ACCESS_DMA; - addr = NULL; - } else if ((!strncmp(addr, "bar", 3))&&((addr[3]==0)||isnumber(addr+3))) { - 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 - const pcilib_register_range_t *ranges = model_info->ranges; - - if (ranges) { - for (i = 0; ranges[i].start != ranges[i].end; i++) - if ((start >= ranges[i].start)&&(start <= ranges[i].end)) break; - - // register access in plain mode - if (ranges[i].start != ranges[i].end) { - pcilib_register_bank_t regbank = pcilib_find_register_bank_by_addr(handle, ranges[i].bank); - if (regbank == PCILIB_REGISTER_BANK_INVALID) Error("Configuration error: register bank specified in the address range is not found"); - - bank = model_info->banks[regbank].name; - start += ranges[i].addr_shift; - addr_shift = ranges[i].addr_shift; - ++mode; - } - } - } else { - if (pcilib_find_register(handle, bank, addr) == PCILIB_REGISTER_INVALID) { - Usage(argc, argv, "Invalid address (%s) is specified", addr); - } else { - reg = addr; - ++mode; - } - } - } - - if (mode == MODE_GRAB) { - if (output) { - char fsname[128]; - if (!get_file_fs(output, 127, fsname)) { - if (!strcmp(fsname, "ext4")) partition = PARTITION_EXT4; - else if (!strcmp(fsname, "raw")) partition = PARTITION_RAW; - } - } else { - output = "/dev/null"; - partition = PARTITION_NULL; - } - - if (!timeout_set) { - if (run_time) timeout = PCILIB_TIMEOUT_INFINITE; - else timeout = PCILIB_EVENT_TIMEOUT; - } - - if (!size_set) { - if (run_time) size = 0; - } - } - - if (mode != MODE_GRAB) { - if (size == (size_t)-1) - Usage(argc, argv, "Unlimited size is not supported in selected operation mode"); - } - - - if ((bank)&&(amode == ACCESS_DMA)) { - if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0)) - Usage(argc, argv, "Invalid DMA channel (%s) is specified", bank); - else dma = itmp; - } else if (bank) { - switch (mode) { - case MODE_BENCHMARK: - case MODE_READ: - case MODE_WRITE: - if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0)||(itmp >= PCILIB_MAX_REGISTER_BANKS)) - Usage(argc, argv, "Invalid data bank (%s) is specified", bank); - else bar = itmp; - break; - default: - if (pcilib_find_register_bank(handle, bank) == PCILIB_REGISTER_BANK_INVALID) - Usage(argc, argv, "Invalid data bank (%s) is specified", bank); - } - } - - signal(SIGINT, signal_exit_handler); - - if ((mode != MODE_GRAB)&&(output)) { - ofile = fopen(output, "a+"); - if (!ofile) { - Error("Failed to open file \"%s\"", output); - } - } - - switch (mode) { - case MODE_INFO: - Info(handle, model_info); - break; - case MODE_LIST: - List(handle, model_info, bank, details); - break; - case MODE_BENCHMARK: - Benchmark(handle, amode, dma, bar, start, size_set?size:0, access, iterations); - break; - 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 { - Error("Address to read is not specified"); - } - break; - case MODE_READ_REGISTER: - if ((reg)||(!addr)) ReadRegister(handle, model_info, bank, reg); - 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, verify); - break; - case MODE_WRITE_REGISTER: - if (reg) WriteRegister(handle, model_info, bank, reg, data); - else WriteRegisterRange(handle, model_info, bank, start, addr_shift, size, data); - break; - case MODE_RESET: - pcilib_reset(handle); - break; - case MODE_GRAB: - TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, timeout, partition, format, buffer, threads, verbose, output); - break; - case MODE_LIST_DMA: - ListDMA(handle, fpga_device, model_info); - break; - case MODE_LIST_DMA_BUFFERS: - ListBuffers(handle, fpga_device, model_info, dma, dma_direction); - break; - case MODE_READ_DMA_BUFFER: - ReadBuffer(handle, fpga_device, model_info, dma, dma_direction, block, ofile); - break; - case MODE_START_DMA: - StartStopDMA(handle, model_info, dma, dma_direction, 1); - break; - 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: - if (use) DetailKMEM(handle, fpga_device, use, block); - else ListKMEM(handle, fpga_device); - break; - case MODE_READ_KMEM: - 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); - break; - case MODE_INVALID: - break; - } - - if (ofile) fclose(ofile); - - pcilib_close(handle); - - if (data != argv + optind) free(data); -} diff --git a/config.c b/config.c deleted file mode 100644 index 642c505..0000000 --- a/config.c +++ /dev/null @@ -1,40 +0,0 @@ -#define _PCILIB_CONFIG_C - -#include - -#include "model.h" -#include "error.h" -#include "config.h" - -#include "protocols/default.h" - - -void (*pcilib_error)(const char *msg, ...) = pcilib_print_error; -void (*pcilib_warning)(const char *msg, ...) = pcilib_print_error; - - -const pcilib_register_protocol_description_t pcilib_protocols[] = { - { PCILIB_REGISTER_PROTOCOL_DEFAULT, &pcilib_default_protocol_api, NULL, NULL, "default", "" }, - { 0 } -}; - -//static const pcilib_register_protocol_description_t *pcilib_protocol_default = NULL;//{0};//&pcilib_protocols[0]; - -#include "dma/nwl.h" -#include "dma/ipe.h" - - -/* -pcilib_register_protocol_alias_t pcilib_protocols[] = { - { "default", { &pcilib_default_protocol_api, PCILIB_REGISTER_PROTOCOL_MODIFICATION_DEFAULT, NULL } }, - { NULL, {0} } -}; -*/ - - -const pcilib_dma_description_t pcilib_dma[] = { - { &ipe_dma_api, ipe_dma_banks, ipe_dma_registers, ipe_dma_engines, NULL, NULL, "ipedma", "DMA engine developed by M. Caselle" }, - { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, NULL, NULL, "nwldma", "North West Logic DMA Engine" }, - { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, "ipecamera", NULL, "nwldma-ipe", "North West Logic DMA Engine" }, - { 0 } -}; diff --git a/config.h b/config.h deleted file mode 100644 index 3ba92ee..0000000 --- a/config.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef _PCILIB_CONFIG_H -#define _PCILIB_CONFIG_H - - -#include "register.h" -#include "dma.h" - -/* -typedef struct { - const char *alias; - pcilib_register_protocol_description_t *protocol; -} pcilib_register_protocol_alias_t; - - -typedef struct { - const char *alias; - pcilib_dma_description_t dma; -} pcilib_dma_alias_t; - -extern pcilib_register_protocol_alias_t pcilib_protocols[]; -extern pcilib_dma_alias_t pcilib_dma[]; -*/ - -extern const pcilib_register_protocol_description_t pcilib_protocols[]; -extern const pcilib_dma_description_t pcilib_dma[]; - - -//extern const pcilib_register_protocol_description_t *pcilib_protocol_default; - -#endif /* _PCILIB_CONFIG_H */ diff --git a/dma.c b/dma.c deleted file mode 100644 index ba99ba1..0000000 --- a/dma.c +++ /dev/null @@ -1,362 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "error.h" -#include "pcilib.h" -#include "pci.h" -#include "dma.h" - -const pcilib_dma_description_t *pcilib_get_dma_info(pcilib_t *ctx) { - int err; - - err = pcilib_init_dma(ctx); - if (err) { - pcilib_error("Error (%i) while initializing DMA", err); - return NULL; - } - - if (!ctx->dma_ctx) return NULL; - - return ctx->model_info.dma; -} - - -pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) { - pcilib_dma_engine_t i; - - const pcilib_dma_description_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].addr_bits; i++) { - if ((info->engines[i].addr == dma)&&((info->engines[i].direction&direction)==direction)) break; - } - - if (info->engines[i].addr_bits) return i; - return PCILIB_DMA_ENGINE_INVALID; -} - - -pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_description_t *desc) { - pcilib_dma_engine_t engine = ctx->num_engines++; - memcpy (&ctx->engines[engine], desc, sizeof(pcilib_dma_engine_description_t)); - return engine; -} - - -int pcilib_init_dma(pcilib_t *ctx) { - int err; - pcilib_dma_context_t *dma_ctx = NULL; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - if (ctx->dma_ctx) - return 0; - - - if ((ctx->event_ctx)&&(model_info->api)&&(model_info->api->init_dma)) { - err = pcilib_init_register_banks(ctx); - if (err) { - pcilib_error("Error (%i) while initializing register banks", err); - return err; - } - - dma_ctx = model_info->api->init_dma(ctx->event_ctx); - } else if ((model_info->dma)&&(model_info->dma->api)&&(model_info->dma->api->init)) { - const pcilib_dma_description_t *dma = model_info->dma; - - err = pcilib_init_register_banks(ctx); - if (err) { - pcilib_error("Error (%i) while initializing register banks", err); - return err; - } - - dma_ctx = dma->api->init(ctx, (dma->model?dma->model:ctx->model), dma->args); - } - - if (dma_ctx) { - dma_ctx->pcilib = ctx; - // DS: parameters? - ctx->dma_ctx = dma_ctx; - } - - return 0; -} - -int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { - const pcilib_dma_description_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->start_dma) { - return 0; - } - - return ctx->model_info.dma->api->start_dma(ctx->dma_ctx, dma, flags); -} - -int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { - const pcilib_dma_description_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->stop_dma) { - return 0; - } - - return ctx->model_info.dma->api->stop_dma(ctx->dma_ctx, dma, flags); -} - -int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) { - const pcilib_dma_description_t *info = pcilib_get_dma_info(ctx); - - 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_description_t *info = pcilib_get_dma_info(ctx); - - 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_description_t *info = pcilib_get_dma_info(ctx); - - 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; - size_t pos; - - pcilib_dma_flags_t flags; -} pcilib_dma_read_callback_context_t; - -static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { - pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg; - - if (ctx->pos + bufsize > ctx->size) { - if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0) - pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); - return -PCILIB_ERROR_TOOBIG; - } - - memcpy(ctx->data + ctx->pos, buf, bufsize); - ctx->pos += bufsize; - - if (flags & PCILIB_DMA_FLAG_EOP) { - if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) { - if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT; - else return PCILIB_STREAMING_CONTINUE; - } - return PCILIB_STREAMING_STOP; - } - - return PCILIB_STREAMING_REQ_FRAGMENT; -} - -static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { - struct timeval *tv = (struct timeval*)arg; - struct timeval cur; - - if (tv) { - gettimeofday(&cur, NULL); - if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP; - } - - return PCILIB_STREAMING_REQ_PACKET; -} - -int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) { - const pcilib_dma_description_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->stream) { - pcilib_error("The DMA read is not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - // DS: We should check we are not going outside of allocated engine space - if (!info->engines[dma].addr_bits) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if ((info->engines[dma].direction&PCILIB_DMA_FROM_DEVICE) == 0) { - pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma); - return PCILIB_ERROR_NOTSUPPORTED; - } - - return ctx->model_info.dma->api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr); -} - -int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) { - int err; - - pcilib_dma_read_callback_context_t opts = { - size, buf, 0, flags - }; - - err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts); - if (read_bytes) *read_bytes = opts.pos; - return err; -} - -int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) { - int err; - - pcilib_dma_read_callback_context_t opts = { - size, buf, 0, 0 - }; - - err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts); - if (read_bytes) *read_bytes = opts.pos; - return err; -} - - -int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) { - int err; - struct timeval tv, cur; - - gettimeofday(&tv, NULL); - tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT; - tv.tv_sec += tv.tv_usec / 1000000; - tv.tv_usec += tv.tv_usec % 1000000; - - do { - // IMMEDIATE timeout is not working properly, so default is set - err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv); - gettimeofday(&cur, NULL); - } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec)))); - - if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT; - - return 0; -} - - -int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) { - const pcilib_dma_description_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->push) { - pcilib_error("The DMA write is not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - // DS: We should check we don't exceed allocated engine range - if (!info->engines[dma].addr_bits) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if ((info->engines[dma].direction&PCILIB_DMA_TO_DEVICE) == 0) { - pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma); - return PCILIB_ERROR_NOTSUPPORTED; - } - - return ctx->model_info.dma->api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written); -} - - -int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) { - return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes); -} - -double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) { - const pcilib_dma_description_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return 0; - } - - if (!ctx->model_info.dma->api) { - pcilib_error("DMA Engine is not configured in the current model"); - return -1; - } - - if (!ctx->model_info.dma->api->benchmark) { - pcilib_error("The DMA benchmark is not supported by configured DMA engine"); - return -1; - } - - return ctx->model_info.dma->api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction); -} - -int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) { - const pcilib_dma_description_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return 0; - } - - if (!ctx->model_info.dma->api) { - pcilib_error("DMA Engine is not configured in the current model"); - return -1; - } - - if (!ctx->model_info.dma->api->status) { - memset(status, 0, sizeof(pcilib_dma_engine_status_t)); - return -1; - } - - // DS: We should check we don't exceed allocated engine range - if (!info->engines[dma].addr_bits) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - return -1; - } - - return ctx->model_info.dma->api->status(ctx->dma_ctx, dma, status, n_buffers, buffers); -} diff --git a/dma.h b/dma.h deleted file mode 100644 index 2ed850d..0000000 --- a/dma.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef _PCILIB_DMA_H -#define _PCILIB_DMA_H - -#define PCILIB_DMA_BUFFER_INVALID ((size_t)-1) - - -typedef struct { - int started; - size_t ring_size, buffer_size; - size_t ring_head, ring_tail; -} pcilib_dma_engine_status_t; - -typedef enum { - PCILIB_DMA_TYPE_BLOCK, - PCILIB_DMA_TYPE_PACKET, - PCILIB_DMA_TYPE_UNKNOWN -} pcilib_dma_engine_type_t; - -typedef struct { - pcilib_dma_engine_addr_t addr; - pcilib_dma_engine_type_t type; - pcilib_dma_direction_t direction; - size_t addr_bits; - - const char *name; - const char *description; -} pcilib_dma_engine_description_t; - -typedef struct { - int used; - int error; - int first; - int last; - size_t size; -} pcilib_dma_buffer_status_t; - -/* -typedef struct { - int ignore_eop; -} pcilib_dma_parameters_t; -*/ - -typedef struct { -// pcilib_dma_parameters_t params; - pcilib_t *pcilib; -} pcilib_dma_context_t; - -typedef struct { - pcilib_dma_context_t *(*init)(pcilib_t *ctx, const char *model, const void *arg); - void (*free)(pcilib_dma_context_t *ctx); - - int (*status)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); - - int (*enable_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags); - int (*disable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags); - int (*acknowledge_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); - - int (*start_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); - int (*stop_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); - - int (*push)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written); - int (*stream)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); - - double (*benchmark)(pcilib_dma_context_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); -} pcilib_dma_api_description_t; - - -typedef struct { - const pcilib_dma_api_description_t *api; - const pcilib_register_bank_description_t *banks; - const pcilib_register_description_t *registers; - const pcilib_dma_engine_description_t *engines; - const char *model; - const void *args; - const char *name; - const char *description; -} pcilib_dma_description_t; - - -const pcilib_dma_description_t *pcilib_get_dma_info(pcilib_t *ctx); -pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_description_t *desc); -int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); -int pcilib_init_dma(pcilib_t *ctx); - - -#endif /* _PCILIB_DMA_H */ diff --git a/dma/CMakeLists.txt b/dma/CMakeLists.txt index 9bbfacd..8a3a8e1 100644 --- a/dma/CMakeLists.txt +++ b/dma/CMakeLists.txt @@ -1,8 +1,8 @@ include_directories( ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pcilib ) - set(HEADERS ${HEADERS} nwl.h nwl_private.h nwl_engine.h nwl_irq.h nwl_loopback.h ipe.h ipe_private.h) add_library(dma STATIC nwl.c nwl_engine.c nwl_irq.c nwl_loopback.c ipe.c) diff --git a/dma/ipe.h b/dma/ipe.h index 208911a..c647954 100644 --- a/dma/ipe.h +++ b/dma/ipe.h @@ -2,7 +2,7 @@ #define _PCILIB_DMA_IPE_H #include -#include "../pcilib.h" +#include "pcilib.h" //#define PCILIB_NWL_MODIFICATION_IPECAMERA 0x100 @@ -38,7 +38,7 @@ static const pcilib_dma_engine_description_t ipe_dma_engines[] = { }; static const pcilib_register_bank_description_t ipe_dma_banks[] = { - { PCILIB_REGISTER_BANK_DMA, PCILIB_BAR0, 0xA000, PCILIB_REGISTER_PROTOCOL_DEFAULT, 0, 0, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, + { PCILIB_REGISTER_BANK_DMA, PCILIB_REGISTER_PROTOCOL_DEFAULT, PCILIB_BAR0, 0, 0, 32, 0x0200, PCILIB_LITTLE_ENDIAN, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } }; diff --git a/dma/nwl.h b/dma/nwl.h index d4742fd..3d6e988 100644 --- a/dma/nwl.h +++ b/dma/nwl.h @@ -2,7 +2,7 @@ #define _PCILIB_DMA_NWL_H #include -#include "../pcilib.h" +#include "pcilib.h" pcilib_dma_context_t *dma_nwl_init(pcilib_t *ctx, const char *model, const void *arg); void dma_nwl_free(pcilib_dma_context_t *vctx); @@ -36,7 +36,7 @@ static const pcilib_dma_api_description_t nwl_dma_api = { }; static pcilib_register_bank_description_t nwl_dma_banks[] = { - { PCILIB_REGISTER_BANK_DMA, PCILIB_BAR0, 0xA000, PCILIB_REGISTER_PROTOCOL_DEFAULT , 0, 0, PCILIB_LITTLE_ENDIAN, 32, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, + { PCILIB_REGISTER_BANK_DMA, PCILIB_REGISTER_PROTOCOL_DEFAULT, PCILIB_BAR0, 0, 0, 32, 0xA000, PCILIB_LITTLE_ENDIAN, PCILIB_LITTLE_ENDIAN, "0x%lx", "dma", "DMA Registers"}, { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL } }; diff --git a/error.c b/error.c deleted file mode 100644 index f242209..0000000 --- a/error.c +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include - -#include "config.h" -#include "error.h" - -void pcilib_print_error(const char *msg, ...) { - va_list va; - - va_start(va, msg); - vprintf(msg, va); - va_end(va); - printf("\n"); -} - - -int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)) { - if (err) pcilib_error = err; - else pcilib_error = pcilib_print_error; - if (warn) pcilib_warning = warn; - else pcilib_warning = pcilib_print_error; - - return 0; -} diff --git a/error.h b/error.h deleted file mode 100644 index d923d3f..0000000 --- a/error.h +++ /dev/null @@ -1,32 +0,0 @@ -#ifndef _PCILIB_ERROR_H -#define _PCILIB_ERROR_H - -#include - -enum { - PCILIB_ERROR_SUCCESS = 0, - PCILIB_ERROR_MEMORY = ENOMEM, - PCILIB_ERROR_INVALID_REQUEST = EBADR, - PCILIB_ERROR_INVALID_ADDRESS = EFAULT, - PCILIB_ERROR_INVALID_BANK = ENOENT, - PCILIB_ERROR_INVALID_DATA = EILSEQ, - PCILIB_ERROR_INVALID_STATE = EBADFD, - PCILIB_ERROR_INVALID_ARGUMENT = EINVAL, - PCILIB_ERROR_TIMEOUT = ETIME, - PCILIB_ERROR_FAILED = EBADE, - PCILIB_ERROR_VERIFY = EREMOTEIO, - PCILIB_ERROR_NOTSUPPORTED = ENOTSUP, - PCILIB_ERROR_NOTFOUND = ESRCH, - PCILIB_ERROR_OUTOFRANGE = ERANGE, - PCILIB_ERROR_NOTAVAILABLE = ENAVAIL, - PCILIB_ERROR_NOTINITIALIZED = EBADFD, - PCILIB_ERROR_TOOBIG = EFBIG, - PCILIB_ERROR_OVERWRITTEN = ESTALE, - PCILIB_ERROR_BUSY = EBUSY -} pcilib_errot_t; - -void pcilib_print_error(const char *msg, ...); -extern void (*pcilib_error)(const char *msg, ...); -extern void (*pcilib_warning)(const char *msg, ...); - -#endif /* _PCILIB_ERROR_H */ diff --git a/event.c b/event.c deleted file mode 100644 index fc07fd0..0000000 --- a/event.c +++ /dev/null @@ -1,437 +0,0 @@ -#define _POSIX_C_SOURCE 199309L -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" - -#include "tools.h" -#include "error.h" - -#ifndef __timespec_defined -struct timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif /* __timespec_defined */ - - -pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) { - int i; - - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_description_t *events = model_info->events; - - for (i = 0; events[i].name; i++) { - if (!strcasecmp(events[i].name, event)) return events[i].evid; - } - - return (pcilib_event_t)-1; -} - -pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type) { - int i; - - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_data_type_description_t *data_types = model_info->data_types; - - for (i = 0; data_types[i].name; i++) { - if ((data_types[i].evid&event)&&(!strcasecmp(data_types[i].name, data_type))) return data_types[i].data_type; - } - - return (pcilib_event_data_type_t)-1; -} - -int pcilib_init_event_engine(pcilib_t *ctx) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - -// api = pcilib_model[model].api; - if ((api)&&(api->init)) { - ctx->event_ctx = api->init(ctx); - if (ctx->event_ctx) { - ctx->event_ctx->pcilib = ctx; - } - } - - return 0; -} - -int pcilib_reset(pcilib_t *ctx) { - const pcilib_event_api_description_t *api; - - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->reset) - return api->reset(ctx->event_ctx); - - return 0; -} - -int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - ctx->event_ctx->params.rawdata.callback = callback; - ctx->event_ctx->params.rawdata.user = user; - - return 0; -} - -int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - ctx->event_ctx->params.autostop.max_events = max_events; - ctx->event_ctx->params.autostop.duration = duration; - - return 0; -} - -int pcilib_configure_autotrigger(pcilib_t *ctx, pcilib_timeout_t interval, pcilib_event_t event, size_t trigger_size, void *trigger_data) { - /* To support hardware without autotriggering, we need to provide in event.c a code - to generate multiple triggers in a thread (available in cli). The function should - be re-enabled afterwards: just set parameters and let implementation decide if it - can make triggering in hardware or will use our emulation */ - - return PCILIB_ERROR_NOTSUPPORTED; -} - -int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - ctx->event_ctx->params.parallel.max_threads = max_threads; - - return 0; -} - -int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->start) - return api->start(ctx->event_ctx, event_mask, flags); - - return 0; -} - -int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->stop) - return api->stop(ctx->event_ctx, flags); - - return 0; -} - -int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->stream) - return api->stream(ctx->event_ctx, callback, user); - - if (api->next_event) { - pcilib_error("Streaming using next_event API is not implemented yet"); - } - - pcilib_error("Event enumeration is not suppored by API"); - return PCILIB_ERROR_NOTSUPPORTED; -} -/* -typedef struct { - pcilib_event_id_t event_id; - pcilib_event_info_t *info; -} pcilib_return_event_callback_context_t; - -static int pcilib_return_event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) { - pcilib_return_event_callback_context_t *ctx = (pcilib_return_event_callback_context_t*)user; - ctx->event_id = event_id; - ctx->info = info; -} -*/ - -int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) { - const pcilib_event_api_description_t *api; -// pcilib_return_event_callback_context_t user; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->next_event) - return api->next_event(ctx->event_ctx, timeout, evid, info_size, info); - -/* - if (api->stream) { - err = api->stream(ctx->event_ctx, 1, timeout, pcilib_return_event_callback, &user); - if (err) return err; - - if (evid) *evid = user->event_id; - if (info) *info = user->info; - - return 0; - } -*/ - - pcilib_error("Event enumeration is not suppored by API"); - return PCILIB_ERROR_NOTSUPPORTED; -} - -int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { - const pcilib_event_api_description_t *api; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->trigger) - return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data); - - pcilib_error("Self triggering is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; -} - - -void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) { - int err; - void *res = NULL; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *api = model_info->api; - if (!api) { - if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; - pcilib_error("Event API is not supported by the selected model"); - return NULL; - } - - if (api->get_data) { - err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size, &res); - if (err) { - if (size) *size = (size_t)err; - return NULL; - } - return res; - } - - if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; - return NULL; -} - -int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t size, void *buf, size_t *retsize) { - int err; - void *res = buf; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->get_data) { - err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, &size, &res); - if (err) return err; - - if (buf != res) memcpy(buf, res, size); - - if (retsize) *retsize = size; - return 0; - } - - return PCILIB_ERROR_NOTSUPPORTED; -} - - -void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) { - int err; - void *res = NULL; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; - return NULL; - } - - if (api->get_data) { - err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, &res); - if (err) { - if (size) *size = (size_t)err; - return NULL; - } - return res; - } - - if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; - return NULL; -} - -int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *ret_size) { - int err; - void *res = buf; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->get_data) { - err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, &size, &res); - if (err) return err; - - if (buf != res) memcpy(buf, res, size); - - if (ret_size) *ret_size = size; - return 0; - } - - return PCILIB_ERROR_NOTSUPPORTED; -} - -int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *api = model_info->api; - if (!api) { - pcilib_error("Event API is not supported by the selected model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (api->return_data) - return api->return_data(ctx->event_ctx, event_id, data_type, data); - - return 0; -} - - -typedef struct { - pcilib_t *ctx; - - size_t *size; - void **data; -} pcilib_grab_callback_user_data_t; - - -static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) { - int err; - void *data; - size_t size; - int allocated = 0; - - pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser; - - data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size); - if (!data) { - pcilib_error("Error getting event data"); - return -(int)size; - } - - if (*(user->data)) { - if ((user->size)&&(*(user->size) < size)) { - pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size); - return -PCILIB_ERROR_MEMORY; - } - - *(user->size) = size; - } else { - *(user->data) = malloc(size); - if (!*(user->data)) { - pcilib_error("Memory allocation (%i bytes) for event data is failed"); - return -PCILIB_ERROR_MEMORY; - } - if (*(user->size)) *(user->size) = size; - allocated = 1; - } - - memcpy(*(user->data), data, size); - - err = pcilib_return_data(user->ctx, event_id, PCILIB_EVENT_DATA, data); - if (err) { - if (allocated) { - free(*(user->data)); - *(user->data) = NULL; - } - pcilib_error("The event data had been overwritten before it was returned, data corruption may occur"); - return -err; - } - - return PCILIB_STREAMING_CONTINUE; -} - -int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout) { - int err; - pcilib_event_id_t eid; - - pcilib_grab_callback_user_data_t user = {ctx, size, data}; - - err = pcilib_start(ctx, event_mask, PCILIB_EVENT_FLAGS_DEFAULT); - if (!err) err = pcilib_trigger(ctx, event_mask, 0, NULL); - if (!err) { - err = pcilib_get_next_event(ctx, timeout, &eid, 0, NULL); - if (!err) pcilib_grab_callback(event_mask, eid, &user); - } - pcilib_stop(ctx, PCILIB_EVENT_FLAGS_DEFAULT); - return err; -} diff --git a/event.h b/event.h deleted file mode 100644 index a71d761..0000000 --- a/event.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef _PCILIB_EVENT_H -#define _PCILIB_EVENT_H - -#include "pcilib.h" - -typedef struct { - size_t max_events; - pcilib_timeout_t duration; -} pcilib_autostop_parameters_t; - -typedef struct { - pcilib_event_rawdata_callback_t callback; - void *user; -} pcilib_rawdata_parameters_t; - -typedef struct { - size_t max_threads; -} pcilib_parallel_parameters_t; - -typedef struct { - pcilib_autostop_parameters_t autostop; - pcilib_rawdata_parameters_t rawdata; - pcilib_parallel_parameters_t parallel; -} pcilib_event_parameters_t; - -struct pcilib_event_context_s { - pcilib_event_parameters_t params; - pcilib_t *pcilib; -}; - -typedef struct { - pcilib_event_t evid; - const char *name; - const char *description; -} pcilib_event_description_t; - -typedef struct { - pcilib_event_data_type_t data_type; - pcilib_event_t evid; - const char *name; - const char *description; -} pcilib_event_data_type_description_t; - -typedef enum { - PCILIB_STREAMING_STOP = 0, /**< stop streaming */ - PCILIB_STREAMING_CONTINUE = 1, /**< wait the default DMA timeout for a new data */ - PCILIB_STREAMING_WAIT = 2, /**< wait the specified timeout for a new data */ - PCILIB_STREAMING_CHECK = 3, /**< do not wait for the data, bail out imideatly if no data ready */ - PCILIB_STREAMING_FAIL = 4, /**< fail if data is not available on timeout */ - PCILIB_STREAMING_REQ_FRAGMENT = 5, /**< only fragment of a packet is read, wait for next fragment and fail if no data during DMA timeout */ - PCILIB_STREAMING_REQ_PACKET = 6, /**< wait for next packet and fail if no data during the specified timeout */ - PCILIB_STREAMING_TIMEOUT_MASK = 3 /**< mask specifying all timeout modes */ -} pcilib_streaming_action_t; - -/* - * get_data: This call is used by get_data and copy_data functions of public - * interface. When copy_data is the caller, the data parameter will be passed. - * Therefore, depending on data the parameter, the function should behave - * diferently. If get get_data function is used (buf == NULL), the caller is - * expected to call return_data afterwards. Otherwise, if buf != NULL and - * copy_data is used, the return call will not be executed. - * Still, the get_data function is not obliged to return the data in the - * passed buf, but a reference to the staticaly allocated memory may be - * returned instead. The copy can be managed by the envelope function. - */ - -typedef struct { - pcilib_context_t *(*init)(pcilib_t *ctx); - void (*free)(pcilib_context_t *ctx); - - pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx); - - int (*reset)(pcilib_context_t *ctx); - - int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); - int (*stop)(pcilib_context_t *ctx, pcilib_event_flags_t flags); - int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); - - int (*stream)(pcilib_context_t *ctx, pcilib_event_callback_t callback, void *user); - int (*next_event)(pcilib_context_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); - - int (*get_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **data); - int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); -} pcilib_event_api_description_t; - - -int pcilib_init_event_engine(pcilib_t *ctx); - - -#endif /* _PCILIB_EVENT_H */ diff --git a/irq.c b/irq.c deleted file mode 100644 index 3d387bb..0000000 --- a/irq.c +++ /dev/null @@ -1,55 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" - -#include "tools.h" -#include "error.h" - -int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count) { - int err; - - interrupt_wait_t arg = { 0 }; - - arg.source = source; - arg.timeout = timeout; - - if (count) arg.count = 1; - - err = ioctl(ctx->handle, PCIDRIVER_IOC_WAITI, &arg); - if (err) { - pcilib_error("PCIDRIVER_IOC_WAITI ioctl have failed"); - return PCILIB_ERROR_FAILED; - } - - if (!arg.count) return PCILIB_ERROR_TIMEOUT; - - if (count) *count = arg.count; - - return 0; -} - -int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source) { - int err; - - err = ioctl(ctx->handle, PCIDRIVER_IOC_CLEAR_IOQ, source); - if (err) { - pcilib_error("PCIDRIVER_IOC_CLEAR_IOQ ioctl have failed"); - return PCILIB_ERROR_FAILED; - } - - return 0; -} - - diff --git a/irq.h b/irq.h deleted file mode 100644 index 441e0e5..0000000 --- a/irq.h +++ /dev/null @@ -1,5 +0,0 @@ -#ifndef _PCILIB_IRQ_H -#define _PCILIB_IRQ_H - - -#endif /* _PCILIB_IRQ_H */ diff --git a/kmem.c b/kmem.c deleted file mode 100644 index 8560eae..0000000 --- a/kmem.c +++ /dev/null @@ -1,310 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcilib.h" -#include "pci.h" -#include "kmem.h" -#include "error.h" - -int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { - kmem_handle_t kh = {0}; - kh.use = use; - kh.flags = flags|PCILIB_KMEM_FLAG_MASS; - - return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); -} - - -static int pcilib_free_kernel_buffer(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, size_t i, pcilib_kmem_flags_t flags) { - kmem_handle_t kh = {0}; - - if (kbuf->buf.blocks[i].ua) munmap(kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); - kh.handle_id = kbuf->buf.blocks[i].handle_id; - kh.pa = kbuf->buf.blocks[i].pa; - kh.flags = flags; - - return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); -} - -static void pcilib_cancel_kernel_memory(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, pcilib_kmem_flags_t flags, int last_flags) { - int ret; - - if (!kbuf->buf.n_blocks) return; - - // consistency error during processing of last block, special treatment could be needed - if (last_flags) { - pcilib_kmem_flags_t failed_flags = flags; - - if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) flags&=~PCILIB_KMEM_FLAG_PERSISTENT; - if (last_flags&KMEM_FLAG_REUSED_HW) flags&=~PCILIB_KMEM_FLAG_HARDWARE; - - if (failed_flags != flags) { - ret = pcilib_free_kernel_buffer(ctx, kbuf, --kbuf->buf.n_blocks, failed_flags); - if (ret) pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); - } - } - - pcilib_free_kernel_memory(ctx, kbuf, flags); -} - -pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { - int err = 0; - const char *error = NULL; - - int ret; - int i; - void *addr; - - pcilib_tristate_t reused = PCILIB_TRISTATE_NO; - int persistent = -1; - int hardware = -1; - - kmem_handle_t kh = {0}; - - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)malloc(sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); - if (!kbuf) { - pcilib_error("Memory allocation has failed"); - return NULL; - } - - memset(kbuf, 0, sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); - - ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM ); - if (ret) { - pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed"); - return NULL; - } - - kh.type = type; - kh.size = size; - kh.align = alignment; - kh.use = use; - - if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { - kh.align = 0; - } else if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) { - kh.size += alignment; - } - - for ( i = 0; i < nmemb; i++) { - kh.item = i; - kh.flags = flags; - - if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { - kh.pa = alignment + i * size; - } - - ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh); - if (ret) { - kbuf->buf.n_blocks = i; - error = "PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed"; - break; - } - - kbuf->buf.blocks[i].handle_id = kh.handle_id; - kbuf->buf.blocks[i].pa = kh.pa; - kbuf->buf.blocks[i].size = kh.size; - - if (!i) reused = (kh.flags&KMEM_FLAG_REUSED)?PCILIB_TRISTATE_YES:PCILIB_TRISTATE_NO; - - if (kh.flags&KMEM_FLAG_REUSED) { - if (!i) reused = PCILIB_TRISTATE_YES; - else if (!reused) reused = PCILIB_TRISTATE_PARTIAL; - - if (persistent) { - if (persistent < 0) { - /*if (((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE; - else*/ persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0; - } else if ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT) == 0) err = PCILIB_ERROR_INVALID_STATE; - } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE; - - if (hardware) { - if (hardware < 0) { - /*if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE; - else*/ hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0; - } else if ((kh.flags&KMEM_FLAG_REUSED_HW) == 0) err = PCILIB_ERROR_INVALID_STATE; - } else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE; - - } else { - if (!i) reused = PCILIB_TRISTATE_NO; - else if (reused) reused = PCILIB_TRISTATE_PARTIAL; - - if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) err = PCILIB_ERROR_INVALID_STATE; - if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) err = PCILIB_ERROR_INVALID_STATE; - } - - if (err) { - kbuf->buf.n_blocks = i + 1; - break; - } - - 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; - error = "Failed to mmap allocated kernel memory"; - break; - } - - kbuf->buf.blocks[i].ua = addr; -// if (use == PCILIB_KMEM_USE_DMA_PAGES) { -// memset(addr, 10, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); -// } - - kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask; - } - - //This is possible in the case of error (nothing is allocated yet) or if buffers are not reused - if (persistent < 0) persistent = 0; - if (hardware < 0) hardware = 0; - - if (err||error) { - pcilib_kmem_flags_t free_flags = 0; - - // for the sake of simplicity always clean partialy reused buffers - if ((persistent == PCILIB_TRISTATE_PARTIAL)||((persistent <= 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT))) { - free_flags |= PCILIB_KMEM_FLAG_PERSISTENT; - } - - if ((hardware <= 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE)) { - free_flags |= PCILIB_KMEM_FLAG_HARDWARE; - } - - // do not clean if we have reused peresistent buffers - // we don't care about -1, because it will be the value only if no buffers actually allocated - if ((!persistent)||(reused != PCILIB_TRISTATE_YES)) { - pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, err?kh.flags:0); - } - - if (!error) error = "Reused buffers are inconsistent"; - pcilib_error(error); - - return NULL; - } - - if (nmemb == 1) { - memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t)); - } - - kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0); - kbuf->buf.n_blocks = nmemb; - - kbuf->prev = NULL; - kbuf->next = ctx->kmem_list; - if (ctx->kmem_list) ctx->kmem_list->prev = kbuf; - ctx->kmem_list = kbuf; - - return (pcilib_kmem_handle_t*)kbuf; -} - -void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags) { - int ret, err = 0; - int i; - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; - - // if linked in to the list - if (kbuf->next) kbuf->next->prev = kbuf->prev; - if (kbuf->prev) kbuf->prev->next = kbuf->next; - else if (ctx->kmem_list == kbuf) ctx->kmem_list = kbuf->next; - - for (i = 0; i < kbuf->buf.n_blocks; i++) { - ret = pcilib_free_kernel_buffer(ctx, kbuf, i, flags); - if ((ret)&&(!err)) err = ret; - } - - free(kbuf); - - if (err) { - pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); - } -} - -/* -int pcilib_kmem_sync(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir) { - int i; - int ret; - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; - - for (i = 0; i < kbuf->buf.n_blocks; i++) { - ret = pcilib_kmem_sync_block(ctx, k, dir, i); - if (ret) { - pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed"); - return PCILIB_ERROR_FAILED; - } - } - - return 0; -} -*/ - -int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block) { - int ret; - kmem_sync_t ks; - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; - - ks.dir = dir; - ks.handle.handle_id = kbuf->buf.blocks[block].handle_id; - ks.handle.pa = kbuf->buf.blocks[block].pa; - ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks); - if (ret) { - pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed"); - return PCILIB_ERROR_FAILED; - } - - return 0; -} - -void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) { - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; - return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset; -} - -uintptr_t pcilib_kmem_get_pa(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; -} - -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; -} - -uintptr_t pcilib_kmem_get_block_pa(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; -} - -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; -} - -pcilib_kmem_reuse_state_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k) { - pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; - return kbuf->buf.reused; -} diff --git a/kmem.h b/kmem.h deleted file mode 100644 index 8302b6a..0000000 --- a/kmem.h +++ /dev/null @@ -1,110 +0,0 @@ -#ifndef _PCILIB_KMEM_H -#define _PCILIB_KMEM_H - -typedef struct pcilib_s pcilib_t; -typedef struct pcilib_kmem_list_s pcilib_kmem_list_t; - -typedef enum { - PCILIB_TRISTATE_NO = 0, - PCILIB_TRISTATE_PARTIAL = 1, - PCILIB_TRISTATE_YES = 2 -} pcilib_tristate_t; - -#define PCILIB_KMEM_TYPE_MASK 0xFFFF0000 -#define PCILIB_KMEM_USE(type, subtype) (((type) << 16)|(subtype)) - -typedef enum { - PCILIB_KMEM_TYPE_CONSISTENT = 0x00000, - PCILIB_KMEM_TYPE_PAGE = 0x10000, - PCILIB_KMEM_TYPE_DMA_S2C_PAGE = 0x10001, - PCILIB_KMEM_TYPE_DMA_C2S_PAGE = 0x10002, - PCILIB_KMEM_TYPE_REGION = 0x20000, - PCILIB_KMEM_TYPE_REGION_S2C = 0x20001, - PCILIB_KMEM_TYPE_REGION_C2S = 0x20002 -} pcilib_kmem_type_t; - -typedef enum { - PCILIB_KMEM_USE_STANDARD = 0, - PCILIB_KMEM_USE_DMA_RING = 1, - PCILIB_KMEM_USE_DMA_PAGES = 2, - PCILIB_KMEM_USE_USER = 0x10 -} pcilib_kmem_use_t; - -typedef enum { - PCILIB_KMEM_SYNC_BIDIRECTIONAL = 0, - PCILIB_KMEM_SYNC_TODEVICE = 1, - PCILIB_KMEM_SYNC_FROMDEVICE = 2 -} pcilib_kmem_sync_direction_t; - -typedef enum { - PCILIB_KMEM_FLAG_REUSE = 1, /**< Try to reuse existing buffer with the same use & item */ - PCILIB_KMEM_FLAG_EXCLUSIVE = 2, /**< Allow only a single application accessing a specified use & item */ - PCILIB_KMEM_FLAG_PERSISTENT = 4, /**< Sets persistent mode */ - PCILIB_KMEM_FLAG_HARDWARE = 8, /**< The buffer may be accessed by hardware, the hardware access will not occur any more if passed to _free function */ - PCILIB_KMEM_FLAG_FORCE = 16, /**< Force memory cleanup even if references are present */ - PCILIB_KMEM_FLAG_MASS = 32, /**< Apply to all buffers of selected use */ - PCILIB_KMEM_FLAG_TRY = 64 /**< Do not allocate buffers, try to reuse and fail if not possible */ -} pcilib_kmem_flags_t; - - -typedef enum { - PCILIB_KMEM_REUSE_ALLOCATED = PCILIB_TRISTATE_NO, - PCILIB_KMEM_REUSE_REUSED = PCILIB_TRISTATE_YES, - PCILIB_KMEM_REUSE_PARTIAL = PCILIB_TRISTATE_PARTIAL, - PCILIB_KMEM_REUSE_PERSISTENT = 0x100, - PCILIB_KMEM_REUSE_HARDWARE = 0x200 -} pcilib_kmem_reuse_state_t; - - -typedef struct { - int handle_id; - pcilib_kmem_reuse_state_t reused; - - uintptr_t pa; -// uintptr_t va; - void *ua; - size_t size; - - size_t alignment_offset; - size_t mmap_offset; -} pcilib_kmem_addr_t; - -/** - * single allocation - we set only addr, n_blocks = 0 - * multiple allocation - addr is not set, blocks are set, n_blocks > 0 - * sgmap allocation - addr contains ua, but pa's are set in blocks, n_blocks > 0 - */ -typedef struct { - pcilib_kmem_addr_t addr; - - pcilib_kmem_reuse_state_t reused; - - size_t n_blocks; - pcilib_kmem_addr_t blocks[]; -} pcilib_kmem_buffer_t; - -typedef void pcilib_kmem_handle_t; - - -struct pcilib_kmem_list_s { - pcilib_kmem_list_t *next, *prev; - - pcilib_kmem_buffer_t buf; // variable size, should be last item in struct -}; - -pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags); -void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags); -//int pcilib_kmem_sync(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir); -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); - -int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags); - -#endif /* _PCILIB_KMEM_H */ diff --git a/linux-3.10.h b/linux-3.10.h deleted file mode 100644 index 161d2aa..0000000 --- a/linux-3.10.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Extract from kernel headers - * iomap.h - */ - -/* - * IO resources have these defined flags. - */ -#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ - -#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */ -#define IORESOURCE_IO 0x00000100 -#define IORESOURCE_MEM 0x00000200 -#define IORESOURCE_IRQ 0x00000400 -#define IORESOURCE_DMA 0x00000800 - -#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ -#define IORESOURCE_READONLY 0x00002000 -#define IORESOURCE_CACHEABLE 0x00004000 -#define IORESOURCE_RANGELENGTH 0x00008000 -#define IORESOURCE_SHADOWABLE 0x00010000 - -#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ -#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ - -#define IORESOURCE_MEM_64 0x00100000 - -#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ -#define IORESOURCE_DISABLED 0x10000000 -#define IORESOURCE_UNSET 0x20000000 -#define IORESOURCE_AUTO 0x40000000 -#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ - -/* PnP IRQ specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IRQ_HIGHEDGE (1<<0) -#define IORESOURCE_IRQ_LOWEDGE (1<<1) -#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) -#define IORESOURCE_IRQ_LOWLEVEL (1<<3) -#define IORESOURCE_IRQ_SHAREABLE (1<<4) -#define IORESOURCE_IRQ_OPTIONAL (1<<5) - -/* PnP DMA specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_DMA_TYPE_MASK (3<<0) -#define IORESOURCE_DMA_8BIT (0<<0) -#define IORESOURCE_DMA_8AND16BIT (1<<0) -#define IORESOURCE_DMA_16BIT (2<<0) - -#define IORESOURCE_DMA_MASTER (1<<2) -#define IORESOURCE_DMA_BYTE (1<<3) -#define IORESOURCE_DMA_WORD (1<<4) - -#define IORESOURCE_DMA_SPEED_MASK (3<<6) -#define IORESOURCE_DMA_COMPATIBLE (0<<6) -#define IORESOURCE_DMA_TYPEA (1<<6) -#define IORESOURCE_DMA_TYPEB (2<<6) -#define IORESOURCE_DMA_TYPEF (3<<6) - -/* PnP memory I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ -#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ -#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ -#define IORESOURCE_MEM_TYPE_MASK (3<<3) -#define IORESOURCE_MEM_8BIT (0<<3) -#define IORESOURCE_MEM_16BIT (1<<3) -#define IORESOURCE_MEM_8AND16BIT (2<<3) -#define IORESOURCE_MEM_32BIT (3<<3) -#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ -#define IORESOURCE_MEM_EXPANSIONROM (1<<6) - -/* PnP I/O specific bits (IORESOURCE_BITS) */ -#define IORESOURCE_IO_16BIT_ADDR (1<<0) -#define IORESOURCE_IO_FIXED (1<<1) - -/* PCI ROM control bits (IORESOURCE_BITS) */ -#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ -#define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */ -#define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */ -#define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */ - -/* PCI control bits. Shares IORESOURCE_BITS with above PCI ROM. */ -#define IORESOURCE_PCI_FIXED (1<<4) /* Do not move resource */ diff --git a/model.c b/model.c deleted file mode 100644 index 65f96aa..0000000 --- a/model.c +++ /dev/null @@ -1,22 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcilib.h" -#include "pci.h" -#include "tools.h" -#include "error.h" - - -const pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx) { - return &ctx->model_info; -} diff --git a/model.h b/model.h deleted file mode 100644 index 2d8d6b7..0000000 --- a/model.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _PCILIB_MODEL_H -#define _PCILIB_MODEL_H - -#include -#include -#include -#include - -typedef struct { - uint8_t access; - pcilib_endianess_t endianess; - - const pcilib_register_description_t *registers; - const pcilib_register_bank_description_t *banks; - const pcilib_register_protocol_description_t *protocols; - const pcilib_register_range_t *ranges; - - const pcilib_event_description_t *events; - const pcilib_event_data_type_description_t *data_types; - - const pcilib_dma_description_t *dma; - const pcilib_event_api_description_t *api; - - const char *name; - const char *description; -} pcilib_model_description_t; - - -const pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx); - -#endif /* _PCILIB_MODEL_H */ diff --git a/pci.c b/pci.c deleted file mode 100644 index 61571fc..0000000 --- a/pci.c +++ /dev/null @@ -1,542 +0,0 @@ -//#define PCILIB_FILE_IO -#define _BSD_SOURCE -#define _POSIX_C_SOURCE 200809L - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pcilib.h" -#include "pci.h" -#include "tools.h" -#include "error.h" -#include "model.h" - -static int pcilib_detect_model(pcilib_t *ctx, const char *model) { - int i, j; - - // Registers & Banks must be copied! - - if (model) { - // Check for DMA models - for (i = 0; pcilib_dma[i].name; i++) { - if (!strcasecmp(model, pcilib_dma[i].name)) - break; - } - - if (pcilib_dma[i].api) { - memcpy(&ctx->dma, &pcilib_dma[i], sizeof(pcilib_dma_description_t)); - ctx->model_info.dma = &ctx->dma; - - if (pcilib_dma[i].banks) - pcilib_add_register_banks(ctx, 0, pcilib_dma[i].banks); - - if (pcilib_dma[i].registers) - pcilib_add_registers(ctx, 0, pcilib_dma[i].registers); - - if (pcilib_dma[i].engines) { - for (j = 0; pcilib_dma[i].engines[j].addr_bits; j++) - memcpy(ctx->engines, pcilib_dma[i].engines, j * sizeof(pcilib_dma_engine_description_t)); - ctx->num_engines = j; - } else - ctx->dma.engines = ctx->engines; - - return 0; - } - - // Check for XML models (DMA + XML registers) - - // Check for specified model - - // Iterate other all other models - } - - // Check for all installed models - // memcpy(&ctx->model_info, model, sizeof(pcilib_model_description_t)); - // how we reconcile the banks from event model and dma description? The banks specified in the DMA description should override corresponding banks of events... - - - if (model) - return PCILIB_ERROR_NOTFOUND; - - // Otherwise, simple pci access (all model members are set to NULL) - - return 0; -} - - - -pcilib_t *pcilib_open(const char *device, const char *model) { - int err; - size_t i; - pcilib_t *ctx = malloc(sizeof(pcilib_t)); - - if (ctx) { - memset(ctx, 0, sizeof(pcilib_t)); - - ctx->handle = open(device, O_RDWR); - if (ctx->handle < 0) { - pcilib_error("Error opening device (%s)", device); - free(ctx); - return NULL; - } - - ctx->page_mask = (uintptr_t)-1; - ctx->model = model?strdup(model):NULL; - - ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE; - ctx->registers = (pcilib_register_description_t *)malloc(PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_description_t)); -/* ctx->banks = (pcilib_register_bank_context_t *)malloc(PCILIB_MAX_BANKS * sizeof(pcilib_register_bank_context_t)); - ctx->ranges = (pcilib_register_range_t *)malloc(PCILIB_MAX_RANGES * sizeof(pcilib_register_range_t)); - ctx->protocols - ctx->engines*/ - - if ((!ctx->registers)/*||(!ctx->banks)||(!ctx->ranges)*/) { - pcilib_error("Error allocating memory for register model"); - pcilib_close(ctx); - free(ctx); - return NULL; - } - - memset(ctx->registers, 0, sizeof(pcilib_register_description_t)); - memset(ctx->banks, 0, sizeof(pcilib_register_bank_description_t)); - memset(ctx->ranges, 0, sizeof(pcilib_register_range_t)); - - for (i = 0; pcilib_protocols[i].api; i++); - memcpy(ctx->protocols, pcilib_protocols, i * sizeof(pcilib_register_protocol_description_t)); - - ctx->model_info.registers = ctx->registers; - ctx->model_info.banks = ctx->banks; - ctx->model_info.protocols = ctx->protocols; - ctx->model_info.ranges = ctx->ranges; - - err = pcilib_detect_model(ctx, model); - if (err) { - const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (board_info) - pcilib_error("Error (%i) configuring model %s (%x:%x)", err, (model?model:""), board_info->vendor_id, board_info->device_id); - else - pcilib_error("Error (%i) configuring model %s", err, (model?model:"")); - pcilib_close(ctx); - free(ctx); - return NULL; - } - - err = pcilib_init_register_banks(ctx); - if (err) { - pcilib_error("Error (%i) initializing regiser banks\n", err); - pcilib_close(ctx); - free(ctx); - return NULL; - } - - err = pcilib_init_event_engine(ctx); - if (err) { - pcilib_error("Error (%i) initializing event engine\n", err); - pcilib_close(ctx); - free(ctx); - return NULL; - } - } - - return ctx; -} - - -const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { - int ret; - - if (ctx->page_mask == (uintptr_t)-1) { - ret = ioctl( ctx->handle, PCIDRIVER_IOC_PCI_INFO, &ctx->board_info ); - if (ret) { - pcilib_error("PCIDRIVER_IOC_PCI_INFO ioctl have failed"); - return NULL; - } - - ctx->page_mask = pcilib_get_page_mask(); - } - - return &ctx->board_info; -} - - -pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) { - return ctx->event_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_BARS; 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; -} - -int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) { - const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (!board_info) return PCILIB_ERROR_NOTFOUND; - - if (*bar == PCILIB_BAR_DETECT) { - *bar = pcilib_detect_bar(ctx, *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 %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; -} - -void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) { - void *res; - int ret; - - const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (!board_info) return NULL; - - if (ctx->bar_space[bar]) return ctx->bar_space[bar]; - - ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI ); - if (ret) { - pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar); - return NULL; - } - - ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar ); - if (ret) { - pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar); - return NULL; - } - -#ifdef PCILIB_FILE_IO - file_io_handle = open("/root/data", O_RDWR); - res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 ); -#else - res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 ); -#endif - if ((!res)||(res == MAP_FAILED)) { - pcilib_error("Failed to mmap data bank %i", bar); - return NULL; - } - - - return res; -} - -void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) { - const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (!board_info) return; - - if (ctx->bar_space[bar]) return; - - munmap(data, board_info->bar_length[bar]); -#ifdef PCILIB_FILE_IO - close(ctx->file_io_handle); -#endif -} - -int pcilib_map_register_space(pcilib_t *ctx) { - int err; - pcilib_register_bank_t i; - - if (!ctx->reg_bar_mapped) { - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_register_bank_description_t *banks = model_info->banks; - - for (i = 0; ((banks)&&(banks[i].access)); i++) { -// uint32_t buf[2]; - void *reg_space; - pcilib_bar_t bar = banks[i].bar; - - if (bar == PCILIB_BAR_DETECT) { - uintptr_t addr = banks[0].read_addr; - - err = pcilib_detect_address(ctx, &bar, &addr, 1); - if (err) return err; - - if (!ctx->bar_space[bar]) { - reg_space = pcilib_map_bar(ctx, bar); -// pcilib_memcpy(&buf, reg_space, 8); - - if (reg_space) { - ctx->bar_space[bar] = reg_space; - } else { - return PCILIB_ERROR_FAILED; - } - } - } else if (!ctx->bar_space[bar]) { - reg_space = pcilib_map_bar(ctx, bar); - if (reg_space) { - ctx->bar_space[bar] = reg_space; - } else { - return PCILIB_ERROR_FAILED; - } -// pcilib_memcpy(&buf, reg_space, 8); - - } - - if (!i) ctx->reg_bar = bar; - } - - - ctx->reg_bar_mapped = 1; - } - - return 0; -} - -int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) { - int err; - pcilib_bar_t i; - - if (!ctx->data_bar_mapped) { - const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); - if (!board_info) return PCILIB_ERROR_FAILED; - - err = pcilib_map_register_space(ctx); - if (err) { - pcilib_error("Error mapping register space"); - return err; - } - - int data_bar = -1; - - for (i = 0; i < PCILIB_MAX_BARS; i++) { - if ((ctx->bar_space[i])||(!board_info->bar_length[i])) continue; - - if (addr) { - if (board_info->bar_start[i] == addr) { - data_bar = i; - break; - } - } else { - if (data_bar >= 0) { - data_bar = -1; - break; - } - - data_bar = i; - } - } - - - if (data_bar < 0) { - if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr); - else pcilib_error("Unable to find the data space"); - return PCILIB_ERROR_NOTFOUND; - } - - ctx->data_bar = data_bar; - - if (!ctx->bar_space[data_bar]) { - char *data_space = pcilib_map_bar(ctx, data_bar); - if (data_space) ctx->bar_space[data_bar] = data_space; - else { - pcilib_error("Unable to map the data space"); - return PCILIB_ERROR_FAILED; - } - } - - ctx->data_bar_mapped = 0; - } - - return 0; -} - -char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr) { - if (bar == PCILIB_BAR_DETECT) { - // First checking the default register bar - size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar]; - if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) { - if (!ctx->bar_space[ctx->reg_bar]) { - pcilib_error("The register bar is not mapped"); - return NULL; - } - - return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask); - } - - // Otherwise trying to detect - bar = pcilib_detect_bar(ctx, addr, 1); - if (bar != PCILIB_BAR_INVALID) { - size_t offset = addr - ctx->board_info.bar_start[bar]; - if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) { - if (!ctx->bar_space[bar]) { - pcilib_error("The requested bar (%i) is not mapped", bar); - return NULL; - } - return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask); - } - } - } else { - if (!ctx->bar_space[bar]) { - pcilib_error("The requested bar (%i) is not mapped", bar); - return NULL; - } - - if (addr < ctx->board_info.bar_length[bar]) { - return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask); - } - - if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) { - return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask); - } - } - - return NULL; -} - -char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) { - int err; - - err = pcilib_map_data_space(ctx, addr); - if (err) { - pcilib_error("Failed to map the specified address space (%lx)", addr); - return NULL; - } - - if (size) *size = ctx->board_info.bar_length[ctx->data_bar]; - - return ctx->bar_space[ctx->data_bar] + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask); -} - - -void pcilib_close(pcilib_t *ctx) { - pcilib_bar_t i; - - if (ctx) { - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - const pcilib_event_api_description_t *eapi = model_info->api; - const pcilib_dma_api_description_t *dapi = NULL; - - if (model_info->dma) dapi = model_info->dma->api; - - if ((eapi)&&(eapi->free)) eapi->free(ctx->event_ctx); - if ((dapi)&&(dapi->free)) dapi->free(ctx->dma_ctx); - - pcilib_free_register_banks(ctx); - - if (ctx->kmem_list) { - pcilib_warning("Not all kernel buffers are properly cleaned"); - - while (ctx->kmem_list) { - pcilib_free_kernel_memory(ctx, ctx->kmem_list, 0); - } - } - - for (i = 0; i < PCILIB_MAX_BARS; i++) { - if (ctx->bar_space[i]) { - char *ptr = ctx->bar_space[i]; - ctx->bar_space[i] = NULL; - pcilib_unmap_bar(ctx, i, ptr); - } - } - - if (ctx->registers) - free(ctx->registers); - - if (ctx->model) - free(ctx->model); - - if (ctx->handle >= 0) - close(ctx->handle); - - free(ctx); - } -} - -int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { - void *data; - - pcilib_detect_address(ctx, &bar, &addr, size); - data = pcilib_map_bar(ctx, bar); - - pcilib_memcpy(buf, data + addr, size); - - pcilib_unmap_bar(ctx, bar, data); - - return 0; -} - -int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { - void *data; - - pcilib_detect_address(ctx, &bar, &addr, size); - data = pcilib_map_bar(ctx, bar); - - pcilib_memcpy(data + addr, buf, size); - - pcilib_unmap_bar(ctx, bar, data); - - return 0; -} - - -int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { - int i; - void *data; - - pcilib_detect_address(ctx, &bar, &addr, fifo_size); - data = pcilib_map_bar(ctx, bar); - - for (i = 0; i < n; i++) { - pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size); - } - - pcilib_unmap_bar(ctx, bar, data); - - return 0; -} - -int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { - int i; - void *data; - - pcilib_detect_address(ctx, &bar, &addr, fifo_size); - data = pcilib_map_bar(ctx, bar); - - for (i = 0; i < n; i++) { - pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size); - } - - pcilib_unmap_bar(ctx, bar, data); - - return 0; -} diff --git a/pci.h b/pci.h deleted file mode 100644 index fe2ff8a..0000000 --- a/pci.h +++ /dev/null @@ -1,77 +0,0 @@ -#ifndef _PCITOOL_PCI_H -#define _PCITOOL_PCI_H - -#define PCILIB_DEFAULT_CPU_COUNT 2 -#define PCILIB_EVENT_TIMEOUT 1000000 /**< us */ -#define PCILIB_TRIGGER_TIMEOUT 100000 /**< us */ -#define PCILIB_DMA_TIMEOUT 10000 /**< us */ -#define PCILIB_DMA_SKIP_TIMEOUT 1000000 /**< us */ -#define PCILIB_REGISTER_TIMEOUT 10000 /**< us */ -#define PCILIB_MAX_BARS 6 /**< this is defined by PCI specification */ -#define PCILIB_DEFAULT_REGISTER_SPACE 1024 /**< number of registers to allocate on init */ -#define PCILIB_MAX_REGISTER_BANKS 32 /**< maximum number of register banks to allocate space for */ -#define PCILIB_MAX_REGISTER_RANGES 32 /**< maximum number of register ranges to allocate space for */ -#define PCILIB_MAX_REGISTER_PROTOCOLS 32 /**< maximum number of register protocols to support */ -#define PCILIB_MAX_DMA_ENGINES 32 /**< maximum number of supported DMA engines */ - -#include "linux-3.10.h" -#include "driver/pciDriver.h" - -#include "pcilib.h" -#include "register.h" -#include "kmem.h" -#include "irq.h" -#include "dma.h" -#include "event.h" -#include "model.h" -#include "config.h" - -struct pcilib_s { - int handle; /**< file handle of device */ - - uintptr_t page_mask; /**< Selects bits which define offset within the page */ - pcilib_board_info_t board_info; /**< The mandatory information about board as defined by PCI specification */ - char *bar_space[PCILIB_MAX_BARS]; /**< Pointers to the mapped BARs in virtual address space */ - - int reg_bar_mapped; /**< Indicates that all BARs used to access registers are mapped */ - pcilib_bar_t reg_bar; /**< Default BAR to look for registers, other BARs will be looked as well */ - int data_bar_mapped; /**< Indicates that a BAR for large PIO is mapped */ - pcilib_bar_t data_bar; /**< BAR for large PIO operations */ - - pcilib_kmem_list_t *kmem_list; /**< List of currently allocated kernel memory */ - - char *model; /**< Requested model */ - pcilib_model_description_t model_info; /**< Current model description combined from the information returned by the event plugin and all dynamic sources (XML, DMA registers, etc.). Contains only pointers, no deep copy of information returned by event plugin */ - - size_t num_banks_init; /**< Number of initialized banks */ - size_t num_reg, alloc_reg; /**< Number of registered and allocated registers */ - size_t num_banks, num_ranges; /**< Number of registered banks and register ranges */ - size_t num_engines; /**> Number of configured DMA engines */ - pcilib_register_description_t *registers; /**< List of currently defined registers (from all sources) */ - pcilib_register_bank_description_t banks[PCILIB_MAX_REGISTER_BANKS + 1]; /**< List of currently defined register banks (from all sources) */ - pcilib_register_range_t ranges[PCILIB_MAX_REGISTER_RANGES + 1]; /**< List of currently defined register ranges (from all sources) */ - pcilib_register_protocol_description_t protocols[PCILIB_MAX_REGISTER_PROTOCOLS + 1];/**< List of currently defined register protocols (from all sources) */ - pcilib_dma_description_t dma; /**< Configuration of used DMA implementation */ - pcilib_dma_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; /**< List of engines defined by the DMA implementation */ - -// pcilib_register_context_t *register_ctx; /**< Contexts for registers */ - pcilib_register_bank_context_t *bank_ctx[PCILIB_MAX_REGISTER_BANKS]; /**< Contexts for registers banks if required by register protocol */ - pcilib_dma_context_t *dma_ctx; /**< DMA context */ - pcilib_context_t *event_ctx; /**< Implmentation context */ - -// pcilib_dma_info_t dma_info; - -#ifdef PCILIB_FILE_IO - int file_io_handle; -#endif /* PCILIB_FILE_IO */ -}; - - -pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx); -const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx); - -int pcilib_map_register_space(pcilib_t *ctx); -int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr); -int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size); - -#endif /* _PCITOOL_PCI_H */ diff --git a/pcilib.h b/pcilib.h deleted file mode 100644 index 3518f75..0000000 --- a/pcilib.h +++ /dev/null @@ -1,226 +0,0 @@ -#ifndef _PCITOOL_PCILIB_H -#define _PCITOOL_PCILIB_H - -#include -#include -#include - -typedef struct pcilib_s pcilib_t; -typedef struct pcilib_event_context_s pcilib_context_t; - -typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */ -typedef uint16_t pcilib_register_t; /**< Type holding the register position within the field listing registers in the model */ -typedef uint32_t pcilib_register_addr_t; /**< Type holding the register address within address-space of BARs */ -typedef uint8_t pcilib_register_size_t; /**< Type holding the size in bits of the register */ -typedef uint32_t pcilib_register_value_t; /**< Type holding the register value */ -typedef uint8_t pcilib_dma_engine_addr_t; -typedef uint8_t pcilib_dma_engine_t; -typedef uint64_t pcilib_event_id_t; -typedef uint32_t pcilib_event_t; -typedef uint64_t pcilib_timeout_t; /**< In microseconds */ -typedef unsigned int pcilib_irq_hw_source_t; -typedef uint32_t pcilib_irq_source_t; - -typedef enum { - PCILIB_HOST_ENDIAN = 0, - PCILIB_LITTLE_ENDIAN, - PCILIB_BIG_ENDIAN -} pcilib_endianess_t; - -typedef enum { - PCILIB_DMA_IRQ = 1, - PCILIB_EVENT_IRQ = 2 -} pcilib_irq_type_t; - -typedef enum { /**< 0x8000 and up are reserved for driver-specific types */ - PCILIB_EVENT_DATA = 0, /**< default data format */ - PCILIB_EVENT_RAW_DATA = 1 /**< raw data */ -} pcilib_event_data_type_t; - -typedef enum { - PCILIB_DMA_TO_DEVICE = 1, - PCILIB_DMA_FROM_DEVICE = 2, - PCILIB_DMA_BIDIRECTIONAL = 3 -} pcilib_dma_direction_t; - -typedef enum { - PCILIB_DMA_FLAGS_DEFAULT = 0, - PCILIB_DMA_FLAG_EOP = 1, /**< last buffer of the packet */ - PCILIB_DMA_FLAG_WAIT = 2, /**< wait completion of write operation / wait for data during read operation */ - PCILIB_DMA_FLAG_MULTIPACKET = 4, /**< read multiple packets */ - PCILIB_DMA_FLAG_PERSISTENT = 8, /**< do not stop DMA engine on application termination / permanently close DMA engine on dma_stop */ - PCILIB_DMA_FLAG_IGNORE_ERRORS = 16 /**< do not crash on errors, but return appropriate error codes */ -} pcilib_dma_flags_t; - -typedef enum { - PCILIB_EVENT_FLAGS_DEFAULT = 0, - PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1, /**< Do not parse data, just read raw and pass it to rawdata callback. If passed to rawdata callback, idicates the data is not identified as event (most probably just padding) */ - PCILIB_EVENT_FLAG_STOP_ONLY = 1, /**< Do not cleanup, just stop acquiring new frames, the cleanup should be requested afterwards */ - PCILIB_EVENT_FLAG_EOF = 2, /**< Indicates that it is the last part of the frame (not required) */ - PCILIB_EVENT_FLAG_PREPROCESS = 4 /**< Enables preprocessing of the raw data (decoding frames, etc.) */ -} pcilib_event_flags_t; - -typedef enum { - PCILIB_EVENT_INFO_FLAG_BROKEN = 1 /**< Indicates broken frames (if this flag is fales, the frame still can be broken) */ -} pcilib_event_info_flags_t; - -typedef struct { - pcilib_event_t type; - uint64_t seqnum; /**< we will add seqnum_overflow if required */ - uint64_t offset; /**< nanoseconds */ - struct timeval timestamp; /**< most accurate timestamp */ - pcilib_event_info_flags_t flags; /**< flags */ -} pcilib_event_info_t; - - -#define PCILIB_BAR_DETECT ((pcilib_bar_t)-1) -#define PCILIB_BAR_INVALID ((pcilib_bar_t)-1) -#define PCILIB_BAR0 0 -#define PCILIB_BAR1 1 -#define PCILIB_DMA_ENGINE_INVALID ((pcilib_dma_engine_t)-1) -#define PCILIB_DMA_ENGINE_ALL ((pcilib_dma_engine_t)-1) -#define PCILIB_DMA_FLAGS_DEFAULT ((pcilib_dma_flags_t)0) -#define PCILIB_DMA_ENGINE_ADDR_INVALID ((pcilib_dma_engine_addr_t)-1) -#define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1) -#define PCILIB_ADDRESS_INVALID ((uintptr_t)-1) -#define PCILIB_EVENT0 1 -#define PCILIB_EVENT1 2 -#define PCILIB_EVENT2 4 -#define PCILIB_EVENT3 8 -#define PCILIB_EVENTS_ALL ((pcilib_event_t)-1) -#define PCILIB_EVENT_INVALID ((pcilib_event_t)-1) -#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 -#define PCILIB_MODEL_DETECT NULL - - -/**< - * Callback function called when new data is read by DMA streaming function - * @ctx - DMA Engine context - * @flags - DMA Flags - * @bufsize - size of data in bytes - * @buf - data - * @returns - * <0 - error, stop streaming (the value is negative error code) - * 0 - stop streaming (PCILIB_STREAMING_STOP) - * 1 - wait DMA timeout and return gracefuly if no data (PCILIB_STREAMING_CONTINUE) - * 2 - wait the specified timeout and return gracefuly if no data (PCILIB_STREAMING_WAIT) - * 3 - check if more data is available without waiting, return gracefuly if not (PCILIB_STREAMING_CHECK) - * 5 - wait DMA timeout and fail if no data (PCILIB_STREAMING_REQ_FRAGMENT) - * 6 - wait the specified timeout and fail if no data (PCILIB_STREAMING_REQ_PACKET) - */ -typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf); -typedef int (*pcilib_event_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user); -typedef int (*pcilib_event_rawdata_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user); - - - -int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)); - -pcilib_t *pcilib_open(const char *device, const char *model); -void pcilib_close(pcilib_t *ctx); - -int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); -int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); - - // Interrupt API is preliminary and can be significantly changed in future -int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags); -int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); -int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags); - -int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count); -int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source); - -void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar); -void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data); -char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr); // addr is offset if bar is specified -char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size); - -pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg); -pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event); -pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type); -pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma); - -int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf); -int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf); -int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf); -int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf); - -int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma); -int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); -int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written_bytes); -int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes); -int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes); -int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes); -double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); - -int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf); -int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf); -int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value); -int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value); -int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value); -int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value); - -int pcilib_reset(pcilib_t *ctx); -int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); - -/* - * The recording of new events will be stopped after reaching max_events records - * or when the specified amount of time is elapsed. However, the @pcilib_stop - * function should be called still. - * NOTE: This options may not be respected if the PCILIB_EVENT_FLAG_RAW_DATA_ONLY - * is specified. - */ -int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration); - -/* - * Request auto-triggering while grabbing - */ -int pcilib_configure_autotrigger(pcilib_t *ctx, pcilib_timeout_t interval, pcilib_event_t event, size_t trigger_size, void *trigger_data); -/* - * Request streaming the rawdata from the event engine. It is fastest way to acuqire data. - * No memory copies will be performed and DMA buffers will be directly passed to the user - * callback. However, to prevent data loss, no processing should be done on the data. The - * user callback is only expected to copy data into the appropriate place and return control - * to the event engine. - * The performance can be boosted further by disabling any data processing within the event - * engine. Just pass PCILIB_EVENT_FLAG_RAW_DATA_ONLY flag to the @pcilib_start function. - */ -int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user); - -/* - * Configures maximal number of preprocessing threads. Actual amount of threads - * may be bigger. For instance, additionaly a real-time reader thread will be - * executed for most of hardware - */ -int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads); - - -int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); -int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags); - -int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user); -int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); - -int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *retsize); -int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t size, void *buf, size_t *retsize); -void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size_or_err); -void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size_or_err); - -/* - * This function is provided to find potentially corrupted data. If the data is overwritten by - * the time return_data is called it will return error. - */ -int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); - -/* - * @param data - will be allocated and shuld be freed if NULL, otherwise used and size should contain correct size. - * In case of failure the content of data is undefined. - * @param timeout - will be autotriggered if NULL - */ -int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout); - -#endif /* _PCITOOL_PCILIB_H */ diff --git a/pcilib/CMakeLists.txt b/pcilib/CMakeLists.txt new file mode 100644 index 0000000..c5297ab --- /dev/null +++ b/pcilib/CMakeLists.txt @@ -0,0 +1,21 @@ +include_directories( + ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pcilib +) + +set(HEADERS pcilib.h pci.h config.h model.h bank.h register.h kmem.h irq.h dma.h event.h tools.h error.h) +add_library(pcilib SHARED pci.c config.c model.c bank.c register.c kmem.c irq.c dma.c event.c tools.c error.c) +target_link_libraries(pcilib dma protocols ${CMAKE_THREAD_LIBS_INIT} ${UFODECODE_LIBRARIES} ) +add_dependencies(pcilib dma protocols) + +install(TARGETS pcilib + LIBRARY DESTINATION lib${LIB_SUFFIX} +) + +install(FILES pcilib.h + DESTINATION include +) + +install(FILES bank.h register.h dma.h event.h model.h error.h tools.h config.h + DESTINATION include/pcilib +) diff --git a/pcilib/bank.c b/pcilib/bank.c new file mode 100644 index 0000000..91bd161 --- /dev/null +++ b/pcilib/bank.c @@ -0,0 +1,204 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#include "tools.h" +#include "error.h" + +int pcilib_init_register_banks(pcilib_t *ctx) { + int err; + + err = pcilib_map_register_space(ctx); + if (err) return err; + + for (; ctx->num_banks_init < ctx->num_banks; ctx->num_banks_init++) { + pcilib_register_bank_context_t *bank_ctx; + pcilib_register_protocol_t protocol; + const pcilib_register_protocol_api_description_t *bapi; + + protocol = pcilib_find_register_protocol_by_addr(ctx, ctx->banks[ctx->num_banks_init].protocol); + if (protocol == PCILIB_REGISTER_PROTOCOL_INVALID) { + const char *name = ctx->banks[ctx->num_banks_init].name; + if (!name) name = "unnamed"; + pcilib_error("Invalid register protocol address (%u) is specified for bank %i (%s)", ctx->banks[ctx->num_banks_init].protocol, ctx->banks[ctx->num_banks_init].addr, name); + return PCILIB_ERROR_INVALID_BANK; + } + + bapi = ctx->protocols[protocol].api; + + if (bapi->init) { + const char *model = ctx->protocols[protocol].model; + if (!model) model = ctx->model; + + bank_ctx = bapi->init(ctx, ctx->num_banks_init, model, ctx->protocols[protocol].args); + } else + bank_ctx = (pcilib_register_bank_context_t*)malloc(sizeof(pcilib_register_bank_context_t)); + + if (!bank_ctx) + return PCILIB_ERROR_FAILED; + + bank_ctx->bank = ctx->banks + ctx->num_banks_init; + bank_ctx->api = bapi; + ctx->bank_ctx[ctx->num_banks_init] = bank_ctx; + } + + return 0; +} + +void pcilib_free_register_banks(pcilib_t *ctx) { + size_t i; + + for (i = 0; i < ctx->num_banks_init; i++) { + const pcilib_register_protocol_api_description_t *bapi = ctx->bank_ctx[i]->api; + + if (ctx->bank_ctx[i]) { + if (bapi->free) + bapi->free(ctx->bank_ctx[i]); + else + free(ctx->bank_ctx[i]); + + ctx->bank_ctx[i] = NULL; + } + } + + ctx->num_banks_init = 0; +} + + +int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks) { + // DS: What we are doing if bank exists? + + if (!n) { + for (n = 0; banks[n].access; n++); + } + + if ((ctx->num_banks + n + 1) > PCILIB_MAX_REGISTER_BANKS) + return PCILIB_ERROR_TOOBIG; + + memset(ctx->banks + ctx->num_banks + n, 0, sizeof(pcilib_register_bank_description_t)); + memcpy(ctx->banks + ctx->num_banks, banks, n * sizeof(pcilib_register_bank_description_t)); + ctx->num_banks += n; + + // If banks are already initialized, we need to re-run the initialization code + // DS: Locking is currently missing + if (ctx->reg_bar_mapped) { + ctx->reg_bar_mapped = 0; + return pcilib_init_register_banks(ctx); + } + + return 0; +} + +pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank) { + pcilib_register_bank_t i; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_bank_description_t *banks = model_info->banks; + + for (i = 0; banks[i].access; i++) + if (banks[i].addr == bank) return i; + + return PCILIB_REGISTER_BANK_INVALID; +} + +pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname) { + pcilib_register_bank_t i; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_bank_description_t *banks = model_info->banks; + + for (i = 0; banks[i].access; i++) + if (!strcasecmp(banks[i].name, bankname)) return i; + + return PCILIB_REGISTER_BANK_INVALID; +} + +pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank) { + pcilib_register_bank_t res; + unsigned long addr; + + if (!bank) { + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_bank_description_t *banks = model_info->banks; + if ((banks)&&(banks[0].access)) return (pcilib_register_bank_t)0; + return PCILIB_REGISTER_BANK_INVALID; + } + + if (pcilib_isxnumber(bank)&&(sscanf(bank,"%lx", &addr) == 1)) { + res = pcilib_find_register_bank_by_addr(ctx, addr); + if (res != PCILIB_REGISTER_BANK_INVALID) return res; + } + + return pcilib_find_register_bank_by_name(ctx, bank); +} + + // DS: FIXME create hash during map_register space +pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg) { + pcilib_register_t i; + pcilib_register_bank_t bank_id; + pcilib_register_bank_addr_t bank_addr = 0; + + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_description_t *registers = model_info->registers; + + if (bank) { + bank_id = pcilib_find_register_bank(ctx, bank); + if (bank_id == PCILIB_REGISTER_BANK_INVALID) { + pcilib_error("Invalid bank (%s) is specified", bank); + return PCILIB_REGISTER_INVALID; + } + + bank_addr = model_info->banks[bank_id].addr; + } + + for (i = 0; registers[i].bits; i++) { + if ((!strcasecmp(registers[i].name, reg))&&((!bank)||(registers[i].bank == bank_addr))) return i; + } + + return PCILIB_REGISTER_INVALID; +}; + + +pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx, pcilib_register_protocol_addr_t protocol) { + pcilib_register_protocol_t i; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_protocol_description_t *protocols = model_info->protocols; + + for (i = 0; protocols[i].api; i++) + if (protocols[i].addr == protocol) return i; + + return PCILIB_REGISTER_PROTOCOL_INVALID; +} + +pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name) { + pcilib_register_protocol_t i; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_protocol_description_t *protocols = model_info->protocols; + + for (i = 0; protocols[i].api; i++) + if (!strcasecmp(protocols[i].name, name)) return i; + + return PCILIB_REGISTER_PROTOCOL_INVALID; +} + +pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *protocol) { + pcilib_register_bank_t res; + unsigned long addr; + + if (pcilib_isxnumber(protocol)&&(sscanf(protocol,"%lx", &addr) == 1)) { + res = pcilib_find_register_protocol_by_addr(ctx, addr); + if (res != PCILIB_REGISTER_BANK_INVALID) return res; + } + + return pcilib_find_register_protocol_by_name(ctx, protocol); +} diff --git a/pcilib/bank.h b/pcilib/bank.h new file mode 100644 index 0000000..f673169 --- /dev/null +++ b/pcilib/bank.h @@ -0,0 +1,102 @@ +#ifndef _PCILIB_BANK_H +#define _PCILIB_BANK_H + +#include + +#define PCILIB_REGISTER_BANK_INVALID ((pcilib_register_bank_t)-1) +#define PCILIB_REGISTER_BANK0 0 /**< First BANK to be used in the event engine */ +#define PCILIB_REGISTER_BANK1 1 +#define PCILIB_REGISTER_BANK2 2 +#define PCILIB_REGISTER_BANK3 3 +#define PCILIB_REGISTER_BANK_DMA 64 /**< First BANK address to be used by DMA engines */ +#define PCILIB_REGISTER_BANK_DYNAMIC 128 /**< First BANK address to map dynamic XML configuration */ +#define PCILIB_REGISTER_PROTOCOL_INVALID ((pcilib_register_protocol_t)-1) +#define PCILIB_REGISTER_PROTOCOL0 0 /**< First PROTOCOL address to be used in the event engine */ +#define PCILIB_REGISTER_PROTOCOL_DEFAULT 64 /**< Default memmap based protocol */ +#define PCILIB_REGISTER_PROTOCOL_DMA 96 /**< First PROTOCOL address to be used by DMA engines */ +#define PCILIB_REGISTER_PROTOCOL_DYNAMIC 128 /**< First PROTOCOL address to be used by plugins */ + +#define PCILIB_REGISTER_NO_BITS 0 +#define PCILIB_REGISTER_ALL_BITS ((pcilib_register_value_t)-1) + +typedef uint8_t pcilib_register_bank_t; /**< Type holding the bank position within the field listing register banks in the model */ +typedef uint8_t pcilib_register_bank_addr_t; /**< Type holding the bank address number */ +typedef uint8_t pcilib_register_protocol_t; /**< Type holding the protocol position within the field listing register protocols in the model */ +typedef uint8_t pcilib_register_protocol_addr_t; /**< Type holding the protocol address */ + + +typedef struct pcilib_register_bank_context_s pcilib_register_bank_context_t; + +typedef struct { + pcilib_register_bank_context_t *(*init)(pcilib_t *ctx, pcilib_register_bank_t bank, const char *model, const void *args); /**< Optional API call to initialize bank context */ + void (*free)(pcilib_register_bank_context_t *ctx); /**< Optional API call to cleanup bank context */ + int (*read)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t *value); /**< Read from register, mandatory for RO/RW registers */ + int (*write)(pcilib_t *pcilib, pcilib_register_bank_context_t *ctx, pcilib_register_addr_t addr, pcilib_register_value_t value); /**< Write to register, mandatory for WO/RW registers */ +} pcilib_register_protocol_api_description_t; + +typedef struct { + pcilib_register_protocol_addr_t addr; /**< Protocol address used in model for addressing the described protocol */ + const pcilib_register_protocol_api_description_t *api; /**< Defines all API functions for protocol */ + const char *model; /**< If NULL, the actually used model is used instead */ + const void *args; /**< Custom protocol-specific arguments. The actual structure may depend on the specified model */ + const char *name; /**< Short protocol name */ + const char *description; /**< A bit longer protocol description */ +} pcilib_register_protocol_description_t; + +typedef struct { + pcilib_register_bank_addr_t addr; /**< Bank address used in model for addressing the described register bank */ + + pcilib_register_protocol_addr_t protocol; /**< Defines a protocol to access registers */ + pcilib_bar_t bar; /**< Specifies the PCI BAR through which an access to the registers is provided (autodetcted if PCILIB_BAR_DETECT is specified) */ + uintptr_t read_addr; /**< protocol specific (normally offset in the BAR of the first address used to read registers) */ + uintptr_t write_addr; /**< protocol specific (normally offset in the BAR of the first address used to write registers) */ + + uint8_t access; /**< Default register size in bits (or word-size in plain addressing mode) */ + size_t size; /**< Number of register addresses (plain addressing) in the bank (more register names can be defined if bit-fields/views are used) */ + pcilib_endianess_t raw_endianess; /**< Specifies endianess in the plain-addressing mode, PCILIB_HOST_ENDIAN have to be specified if no conversion desired. + Conversion applied after protocol. This value does not get into the account in register-access mode */ + pcilib_endianess_t endianess; /**< Specifies endianess in the register-access mode, this may differ from raw_endianess if multi-word registers are used. + This is fully independent from raw_endianess. No double conversion is either performed */ + + const char *format; /**< printf format for the registers, either %lu for decimal output or 0x%lx for hexdecimal */ + const char *name; /**< short bank name */ + const char *description; /**< longer bank description */ +} pcilib_register_bank_description_t; + +/** + * Default mappings: defines virtual address to register mappings, i.e. how 0x9000 in the following command + * will be mapped to the actual register. By comparing with start and end-addresses, we find to which range + * 0x9000 belongs to and detect actual bank and offset in it. + * Simple example: pci -r 0x9000 + * if we specify range { 0x9000, 0x9100, 10, -0x9000}, the example command we print the value of the first + * register in the bank 10. + */ +typedef struct { + uintptr_t start; /**< The first virtual address of the register range */ + uintptr_t end; /**< The last virtual address of the register range */ + pcilib_register_bank_addr_t bank; /**< The bank mapped to the specified range */ + long addr_shift; /**< Address shift, i.e. how much we should add/substract to the virtual address to get address in the register bank */ +} pcilib_register_range_t; + + + +struct pcilib_register_bank_context_s { + const pcilib_register_bank_description_t *bank; /**< Corresponding bank description */ + const pcilib_register_protocol_api_description_t *api; /**< API functions */ +}; + + + // we don't copy strings, they should be statically allocated +int pcilib_init_register_banks(pcilib_t *ctx); +void pcilib_free_register_banks(pcilib_t *ctx); +int pcilib_add_register_banks(pcilib_t *ctx, size_t n, const pcilib_register_bank_description_t *banks); + +pcilib_register_bank_t pcilib_find_register_bank_by_addr(pcilib_t *ctx, pcilib_register_bank_addr_t bank); +pcilib_register_bank_t pcilib_find_register_bank_by_name(pcilib_t *ctx, const char *bankname); +pcilib_register_bank_t pcilib_find_register_bank(pcilib_t *ctx, const char *bank); + +pcilib_register_protocol_t pcilib_find_register_protocol_by_addr(pcilib_t *ctx, pcilib_register_protocol_addr_t protocol); +pcilib_register_protocol_t pcilib_find_register_protocol_by_name(pcilib_t *ctx, const char *name); +pcilib_register_protocol_t pcilib_find_register_protocol(pcilib_t *ctx, const char *name); + +#endif /* _PCILIB_BANK_H */ diff --git a/pcilib/config.c b/pcilib/config.c new file mode 100644 index 0000000..21a0e53 --- /dev/null +++ b/pcilib/config.c @@ -0,0 +1,37 @@ +#define _PCILIB_CONFIG_C + +#include + +#include "error.h" +#include "config.h" + +#include "protocols/default.h" + + +void (*pcilib_error)(const char *msg, ...) = pcilib_print_error; +void (*pcilib_warning)(const char *msg, ...) = pcilib_print_error; + + +const pcilib_register_protocol_description_t pcilib_protocols[] = { + { PCILIB_REGISTER_PROTOCOL_DEFAULT, &pcilib_default_protocol_api, NULL, NULL, "default", "" }, + { 0 } +}; + +#include "dma/nwl.h" +#include "dma/ipe.h" + + +const pcilib_dma_description_t pcilib_ipedma = + { &ipe_dma_api, ipe_dma_banks, ipe_dma_registers, ipe_dma_engines, NULL, NULL, "ipedma", "DMA engine developed by M. Caselle" }; + +const pcilib_dma_description_t pcilib_nwldma = + { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, NULL, NULL, "nwldma", "North West Logic DMA Engine" }; + +const pcilib_dma_description_t pcilib_dma[] = { + { &ipe_dma_api, ipe_dma_banks, ipe_dma_registers, ipe_dma_engines, NULL, NULL, "ipedma", "DMA engine developed by M. Caselle" }, + { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, NULL, NULL, "nwldma", "North West Logic DMA Engine" }, + { &nwl_dma_api, nwl_dma_banks, nwl_dma_registers, NULL, "ipecamera", NULL, "nwldma-ipe", "North West Logic DMA Engine" }, + { 0 } +}; + + diff --git a/pcilib/config.h b/pcilib/config.h new file mode 100644 index 0000000..710bff8 --- /dev/null +++ b/pcilib/config.h @@ -0,0 +1,17 @@ +#ifndef _PCILIB_CONFIG_H +#define _PCILIB_CONFIG_H + + +#include +#include +#include + +extern const pcilib_register_protocol_description_t pcilib_protocols[]; +extern const pcilib_dma_description_t pcilib_dma[]; + +extern const pcilib_register_protocol_api_description_t pcilib_default_protocol_api; + +extern const pcilib_dma_description_t pcilib_ipedma; +extern const pcilib_dma_description_t pcilib_nwldma; + +#endif /* _PCILIB_CONFIG_H */ diff --git a/pcilib/dma.c b/pcilib/dma.c new file mode 100644 index 0000000..f6b8053 --- /dev/null +++ b/pcilib/dma.c @@ -0,0 +1,360 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "error.h" +#include "pcilib.h" +#include "pci.h" +#include "dma.h" + +const pcilib_dma_description_t *pcilib_get_dma_description(pcilib_t *ctx) { + int err; + + err = pcilib_init_dma(ctx); + if (err) { + pcilib_error("Error (%i) while initializing DMA", err); + return NULL; + } + + if (!ctx->dma_ctx) return NULL; + + return &ctx->dma; +} + + +pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma) { + pcilib_dma_engine_t i; + + const pcilib_dma_description_t *dma_info = pcilib_get_dma_description(ctx); + if (!dma_info) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + for (i = 0; dma_info->engines[i].addr_bits; i++) { + if ((dma_info->engines[i].addr == dma)&&((dma_info->engines[i].direction&direction)==direction)) break; + } + + if (dma_info->engines[i].addr_bits) return i; + return PCILIB_DMA_ENGINE_INVALID; +} + + +pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_description_t *desc) { + pcilib_dma_engine_t engine = ctx->num_engines++; + memcpy (&ctx->engines[engine], desc, sizeof(pcilib_dma_engine_description_t)); + return engine; +} + + +int pcilib_init_dma(pcilib_t *ctx) { + int err; + pcilib_dma_context_t *dma_ctx = NULL; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + if (ctx->dma_ctx) + return 0; + + + if ((ctx->event_ctx)&&(model_info->api)&&(model_info->api->init_dma)) { + err = pcilib_init_register_banks(ctx); + if (err) { + pcilib_error("Error (%i) while initializing register banks", err); + return err; + } + + dma_ctx = model_info->api->init_dma(ctx->event_ctx); + } else if ((ctx->dma.api)&&(ctx->dma.api->init)) { + err = pcilib_init_register_banks(ctx); + if (err) { + pcilib_error("Error (%i) while initializing register banks", err); + return err; + } + + dma_ctx = ctx->dma.api->init(ctx, (ctx->dma.model?ctx->dma.model:ctx->model), ctx->dma.args); + } + + if (dma_ctx) { + dma_ctx->pcilib = ctx; + // DS: parameters? + ctx->dma_ctx = dma_ctx; + } + + return 0; +} + +int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!info->api->start_dma) { + return 0; + } + + return info->api->start_dma(ctx->dma_ctx, dma, flags); +} + +int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!info->api->stop_dma) { + return 0; + } + + return info->api->stop_dma(ctx->dma_ctx, dma, flags); +} + +int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + + if ((!info)||(!info->api)||(!info->api->enable_irq)) return 0; + + return info->api->enable_irq(ctx->dma_ctx, irq_type, flags); +} + +int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + + if ((!info)||(!info->api)||(!info->api->disable_irq)) return 0; + + return info->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_description_t *info = pcilib_get_dma_description(ctx); + + if ((!info)||(!info->api)||(!info->api->acknowledge_irq)) return 0; + + return info->api->acknowledge_irq(ctx->dma_ctx, irq_type, irq_source); +} + +typedef struct { + size_t size; + void *data; + size_t pos; + + pcilib_dma_flags_t flags; +} pcilib_dma_read_callback_context_t; + +static int pcilib_dma_read_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { + pcilib_dma_read_callback_context_t *ctx = (pcilib_dma_read_callback_context_t*)arg; + + if (ctx->pos + bufsize > ctx->size) { + if ((ctx->flags&PCILIB_DMA_FLAG_IGNORE_ERRORS) == 0) + pcilib_error("Buffer size (%li) is not large enough for DMA packet, at least %li bytes is required", ctx->size, ctx->pos + bufsize); + return -PCILIB_ERROR_TOOBIG; + } + + memcpy(ctx->data + ctx->pos, buf, bufsize); + ctx->pos += bufsize; + + if (flags & PCILIB_DMA_FLAG_EOP) { + if ((ctx->pos < ctx->size)&&(ctx->flags&PCILIB_DMA_FLAG_MULTIPACKET)) { + if (ctx->flags&PCILIB_DMA_FLAG_WAIT) return PCILIB_STREAMING_WAIT; + else return PCILIB_STREAMING_CONTINUE; + } + return PCILIB_STREAMING_STOP; + } + + return PCILIB_STREAMING_REQ_FRAGMENT; +} + +static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { + struct timeval *tv = (struct timeval*)arg; + struct timeval cur; + + if (tv) { + gettimeofday(&cur, NULL); + if ((cur.tv_sec > tv->tv_sec)||((cur.tv_sec == tv->tv_sec)&&(cur.tv_usec > tv->tv_usec))) return PCILIB_STREAMING_STOP; + } + + return PCILIB_STREAMING_REQ_PACKET; +} + +int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!info->api->stream) { + pcilib_error("The DMA read is not supported by configured DMA engine"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + // DS: We should check we are not going outside of allocated engine space + if (!info->engines[dma].addr_bits) { + pcilib_error("The DMA engine (%i) is not supported by device", dma); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if ((info->engines[dma].direction&PCILIB_DMA_FROM_DEVICE) == 0) { + pcilib_error("The selected engine (%i) is S2C-only and does not support reading", dma); + return PCILIB_ERROR_NOTSUPPORTED; + } + + return info->api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr); +} + +int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes) { + int err; + + pcilib_dma_read_callback_context_t opts = { + size, buf, 0, flags + }; + + err = pcilib_stream_dma(ctx, dma, addr, size, flags, timeout, pcilib_dma_read_callback, &opts); + if (read_bytes) *read_bytes = opts.pos; + return err; +} + +int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes) { + int err; + + pcilib_dma_read_callback_context_t opts = { + size, buf, 0, 0 + }; + + err = pcilib_stream_dma(ctx, dma, addr, size, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_read_callback, &opts); + if (read_bytes) *read_bytes = opts.pos; + return err; +} + + +int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) { + int err; + struct timeval tv, cur; + + gettimeofday(&tv, NULL); + tv.tv_usec += PCILIB_DMA_SKIP_TIMEOUT; + tv.tv_sec += tv.tv_usec / 1000000; + tv.tv_usec += tv.tv_usec % 1000000; + + do { + // IMMEDIATE timeout is not working properly, so default is set + err = pcilib_stream_dma(ctx, dma, 0, 0, PCILIB_DMA_FLAGS_DEFAULT, PCILIB_DMA_TIMEOUT, pcilib_dma_skip_callback, &tv); + gettimeofday(&cur, NULL); + } while ((!err)&&((cur.tv_sec < tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec < tv.tv_usec)))); + + if ((cur.tv_sec > tv.tv_sec)||((cur.tv_sec == tv.tv_sec)&&(cur.tv_usec > tv.tv_usec))) return PCILIB_ERROR_TIMEOUT; + + return 0; +} + + +int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if (!info->api->push) { + pcilib_error("The DMA write is not supported by configured DMA engine"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + // DS: We should check we don't exceed allocated engine range + if (!info->engines[dma].addr_bits) { + pcilib_error("The DMA engine (%i) is not supported by device", dma); + return PCILIB_ERROR_NOTAVAILABLE; + } + + if ((info->engines[dma].direction&PCILIB_DMA_TO_DEVICE) == 0) { + pcilib_error("The selected engine (%i) is C2S-only and does not support writes", dma); + return PCILIB_ERROR_NOTSUPPORTED; + } + + return info->api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written); +} + + +int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes) { + return pcilib_push_dma(ctx, dma, addr, size, PCILIB_DMA_FLAG_EOP|PCILIB_DMA_FLAG_WAIT, PCILIB_DMA_TIMEOUT, buf, written_bytes); +} + +double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return 0; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return -1; + } + + if (!info->api->benchmark) { + pcilib_error("The DMA benchmark is not supported by configured DMA engine"); + return -1; + } + + return info->api->benchmark(ctx->dma_ctx, dma, addr, size, iterations, direction); +} + +int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers) { + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); + if (!info) { + pcilib_error("DMA is not supported by the device"); + return 0; + } + + if (!info->api) { + pcilib_error("DMA Engine is not configured in the current model"); + return -1; + } + + if (!info->api->status) { + memset(status, 0, sizeof(pcilib_dma_engine_status_t)); + return -1; + } + + // DS: We should check we don't exceed allocated engine range + if (!info->engines[dma].addr_bits) { + pcilib_error("The DMA engine (%i) is not supported by device", dma); + return -1; + } + + return info->api->status(ctx->dma_ctx, dma, status, n_buffers, buffers); +} diff --git a/pcilib/dma.h b/pcilib/dma.h new file mode 100644 index 0000000..83bc0fd --- /dev/null +++ b/pcilib/dma.h @@ -0,0 +1,85 @@ +#ifndef _PCILIB_DMA_H +#define _PCILIB_DMA_H + +#define PCILIB_DMA_BUFFER_INVALID ((size_t)-1) + +typedef struct { + int used; /**< Indicates if buffer has unread data or empty and ready for DMA */ + int error; /**< Indicates if data is complete and correctly transfered or some error occured during the DMA transfer */ + int first; /**< Indicates the first buffer of the packet */ + int last; /**< Indicates the last buffer of the packet */ + size_t size; /**< Indicates number of bytes actually written to the buffer */ +} pcilib_dma_buffer_status_t; + +typedef struct { + int started; /**< Informs if the engine is currently started or not */ + size_t ring_size, buffer_size; /**< The number of allocated DMA buffers and size of each buffer in bytes */ + size_t ring_head, ring_tail; /**< The first and the last buffer containing the data */ +} pcilib_dma_engine_status_t; + +typedef enum { + PCILIB_DMA_TYPE_BLOCK, /**< Simple DMA engine */ + PCILIB_DMA_TYPE_PACKET, /**< Streaming (scatter-gather) DMA engine */ + PCILIB_DMA_TYPE_UNKNOWN +} pcilib_dma_engine_type_t; + +typedef struct { + pcilib_dma_engine_addr_t addr; /**< Address of DMA engine (from 0) */ + pcilib_dma_engine_type_t type; /**< Type of DMA engine */ + pcilib_dma_direction_t direction; /**< Defines which kind of transfer does engine support: C2S, S2C, or both */ + size_t addr_bits; /**< Number of addressable bits in the system memory (we currently work with 32-bits only) */ + + const char *name; /**< Defines a short name of engine (its main use, i.e. main, auxilliary, etc.) */ + const char *description; /**< Defines a longer description of the engine */ +} pcilib_dma_engine_description_t; + +/* +typedef struct { + int ignore_eop; +} pcilib_dma_parameters_t; +*/ + +typedef struct { +// pcilib_dma_parameters_t params; + pcilib_t *pcilib; /**< Reference to the pcilib context */ +} pcilib_dma_context_t; + +typedef struct { + pcilib_dma_context_t *(*init)(pcilib_t *ctx, const char *model, const void *arg); + void (*free)(pcilib_dma_context_t *ctx); + + int (*status)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); + + int (*enable_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags); + int (*disable_irq)(pcilib_dma_context_t *ctx, pcilib_dma_flags_t flags); + int (*acknowledge_irq)(pcilib_dma_context_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); + + int (*start_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); + int (*stop_dma)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); + + int (*push)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written); + int (*stream)(pcilib_dma_context_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); + + double (*benchmark)(pcilib_dma_context_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); +} pcilib_dma_api_description_t; + + +typedef struct { + const pcilib_dma_api_description_t *api; /**< Defines all API functions for DMA operation */ + const pcilib_register_bank_description_t *banks; /**< Pre-defined register banks exposed by DMA interface, additional banks can be defined during DMA initialization */ + const pcilib_register_description_t *registers; /**< Pre-defined registers exposed by DMA interface, additional registers can be defined during DMA initialization */ + const pcilib_dma_engine_description_t *engines; /**< List of DMA engines exposed by DMA interface, alternatively engines can be added during DMA initialization */ + const char *model; /**< If NULL, the actually used event model is used instead */ + const void *args; /**< Custom DMA-specific arguments. The actual structure may depend on the specified model */ + const char *name; /**< Short name of DMA interface */ + const char *description; /**< A bit longer description of DMA interface */ +} pcilib_dma_description_t; + + +const pcilib_dma_description_t *pcilib_get_dma_description(pcilib_t *ctx); +pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_description_t *desc); +int pcilib_get_dma_status(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_engine_status_t *status, size_t n_buffers, pcilib_dma_buffer_status_t *buffers); +int pcilib_init_dma(pcilib_t *ctx); + + +#endif /* _PCILIB_DMA_H */ diff --git a/pcilib/error.c b/pcilib/error.c new file mode 100644 index 0000000..f242209 --- /dev/null +++ b/pcilib/error.c @@ -0,0 +1,24 @@ +#include +#include + +#include "config.h" +#include "error.h" + +void pcilib_print_error(const char *msg, ...) { + va_list va; + + va_start(va, msg); + vprintf(msg, va); + va_end(va); + printf("\n"); +} + + +int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)) { + if (err) pcilib_error = err; + else pcilib_error = pcilib_print_error; + if (warn) pcilib_warning = warn; + else pcilib_warning = pcilib_print_error; + + return 0; +} diff --git a/pcilib/error.h b/pcilib/error.h new file mode 100644 index 0000000..d923d3f --- /dev/null +++ b/pcilib/error.h @@ -0,0 +1,32 @@ +#ifndef _PCILIB_ERROR_H +#define _PCILIB_ERROR_H + +#include + +enum { + PCILIB_ERROR_SUCCESS = 0, + PCILIB_ERROR_MEMORY = ENOMEM, + PCILIB_ERROR_INVALID_REQUEST = EBADR, + PCILIB_ERROR_INVALID_ADDRESS = EFAULT, + PCILIB_ERROR_INVALID_BANK = ENOENT, + PCILIB_ERROR_INVALID_DATA = EILSEQ, + PCILIB_ERROR_INVALID_STATE = EBADFD, + PCILIB_ERROR_INVALID_ARGUMENT = EINVAL, + PCILIB_ERROR_TIMEOUT = ETIME, + PCILIB_ERROR_FAILED = EBADE, + PCILIB_ERROR_VERIFY = EREMOTEIO, + PCILIB_ERROR_NOTSUPPORTED = ENOTSUP, + PCILIB_ERROR_NOTFOUND = ESRCH, + PCILIB_ERROR_OUTOFRANGE = ERANGE, + PCILIB_ERROR_NOTAVAILABLE = ENAVAIL, + PCILIB_ERROR_NOTINITIALIZED = EBADFD, + PCILIB_ERROR_TOOBIG = EFBIG, + PCILIB_ERROR_OVERWRITTEN = ESTALE, + PCILIB_ERROR_BUSY = EBUSY +} pcilib_errot_t; + +void pcilib_print_error(const char *msg, ...); +extern void (*pcilib_error)(const char *msg, ...); +extern void (*pcilib_warning)(const char *msg, ...); + +#endif /* _PCILIB_ERROR_H */ diff --git a/pcilib/event.c b/pcilib/event.c new file mode 100644 index 0000000..43bbf01 --- /dev/null +++ b/pcilib/event.c @@ -0,0 +1,436 @@ +#define _POSIX_C_SOURCE 199309L +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#include "tools.h" +#include "error.h" + +#ifndef __timespec_defined +struct timespec { + time_t tv_sec; + long tv_nsec; +}; +#endif /* __timespec_defined */ + + +pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event) { + int i; + + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_description_t *events = model_info->events; + + for (i = 0; events[i].name; i++) { + if (!strcasecmp(events[i].name, event)) return events[i].evid; + } + + return (pcilib_event_t)-1; +} + +pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type) { + int i; + + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_data_type_description_t *data_types = model_info->data_types; + + for (i = 0; data_types[i].name; i++) { + if ((data_types[i].evid&event)&&(!strcasecmp(data_types[i].name, data_type))) return data_types[i].data_type; + } + + return (pcilib_event_data_type_t)-1; +} + +int pcilib_init_event_engine(pcilib_t *ctx) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + + if ((api)&&(api->init)) { + ctx->event_ctx = api->init(ctx); + if (ctx->event_ctx) { + ctx->event_ctx->pcilib = ctx; + } + } + + return 0; +} + +int pcilib_reset(pcilib_t *ctx) { + const pcilib_event_api_description_t *api; + + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->reset) + return api->reset(ctx->event_ctx); + + return 0; +} + +int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + ctx->event_ctx->params.rawdata.callback = callback; + ctx->event_ctx->params.rawdata.user = user; + + return 0; +} + +int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + ctx->event_ctx->params.autostop.max_events = max_events; + ctx->event_ctx->params.autostop.duration = duration; + + return 0; +} + +int pcilib_configure_autotrigger(pcilib_t *ctx, pcilib_timeout_t interval, pcilib_event_t event, size_t trigger_size, void *trigger_data) { + /* To support hardware without autotriggering, we need to provide in event.c a code + to generate multiple triggers in a thread (available in cli). The function should + be re-enabled afterwards: just set parameters and let implementation decide if it + can make triggering in hardware or will use our emulation */ + + return PCILIB_ERROR_NOTSUPPORTED; +} + +int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + ctx->event_ctx->params.parallel.max_threads = max_threads; + + return 0; +} + +int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->start) + return api->start(ctx->event_ctx, event_mask, flags); + + return 0; +} + +int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->stop) + return api->stop(ctx->event_ctx, flags); + + return 0; +} + +int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->stream) + return api->stream(ctx->event_ctx, callback, user); + + if (api->next_event) { + pcilib_error("Streaming using next_event API is not implemented yet"); + } + + pcilib_error("Event enumeration is not suppored by API"); + return PCILIB_ERROR_NOTSUPPORTED; +} +/* +typedef struct { + pcilib_event_id_t event_id; + pcilib_event_info_t *info; +} pcilib_return_event_callback_context_t; + +static int pcilib_return_event_callback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) { + pcilib_return_event_callback_context_t *ctx = (pcilib_return_event_callback_context_t*)user; + ctx->event_id = event_id; + ctx->info = info; +} +*/ + +int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info) { + const pcilib_event_api_description_t *api; +// pcilib_return_event_callback_context_t user; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->next_event) + return api->next_event(ctx->event_ctx, timeout, evid, info_size, info); + +/* + if (api->stream) { + err = api->stream(ctx->event_ctx, 1, timeout, pcilib_return_event_callback, &user); + if (err) return err; + + if (evid) *evid = user->event_id; + if (info) *info = user->info; + + return 0; + } +*/ + + pcilib_error("Event enumeration is not suppored by API"); + return PCILIB_ERROR_NOTSUPPORTED; +} + +int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data) { + const pcilib_event_api_description_t *api; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->trigger) + return api->trigger(ctx->event_ctx, event, trigger_size, trigger_data); + + pcilib_error("Self triggering is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; +} + + +void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size) { + int err; + void *res = NULL; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *api = model_info->api; + if (!api) { + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; + pcilib_error("Event API is not supported by the selected model"); + return NULL; + } + + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, size, &res); + if (err) { + if (size) *size = (size_t)err; + return NULL; + } + return res; + } + + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; + return NULL; +} + +int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t size, void *buf, size_t *retsize) { + int err; + void *res = buf; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, arg_size, arg, &size, &res); + if (err) return err; + + if (buf != res) memcpy(buf, res, size); + + if (retsize) *retsize = size; + return 0; + } + + return PCILIB_ERROR_NOTSUPPORTED; +} + + +void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size) { + int err; + void *res = NULL; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; + return NULL; + } + + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, size, &res); + if (err) { + if (size) *size = (size_t)err; + return NULL; + } + return res; + } + + if (size) *size = (size_t)PCILIB_ERROR_NOTSUPPORTED; + return NULL; +} + +int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *ret_size) { + int err; + void *res = buf; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->get_data) { + err = api->get_data(ctx->event_ctx, event_id, data_type, 0, NULL, &size, &res); + if (err) return err; + + if (buf != res) memcpy(buf, res, size); + + if (ret_size) *ret_size = size; + return 0; + } + + return PCILIB_ERROR_NOTSUPPORTED; +} + +int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data) { + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *api = model_info->api; + if (!api) { + pcilib_error("Event API is not supported by the selected model"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (api->return_data) + return api->return_data(ctx->event_ctx, event_id, data_type, data); + + return 0; +} + + +typedef struct { + pcilib_t *ctx; + + size_t *size; + void **data; +} pcilib_grab_callback_user_data_t; + + +static int pcilib_grab_callback(pcilib_event_t event, pcilib_event_id_t event_id, void *vuser) { + int err; + void *data; + size_t size; + int allocated = 0; + + pcilib_grab_callback_user_data_t *user = (pcilib_grab_callback_user_data_t*)vuser; + + data = pcilib_get_data(user->ctx, event_id, PCILIB_EVENT_DATA, &size); + if (!data) { + pcilib_error("Error getting event data"); + return -(int)size; + } + + if (*(user->data)) { + if ((user->size)&&(*(user->size) < size)) { + pcilib_error("The supplied buffer does not have enough space to hold the event data. Buffer size is %z, but %z is required", user->size, size); + return -PCILIB_ERROR_MEMORY; + } + + *(user->size) = size; + } else { + *(user->data) = malloc(size); + if (!*(user->data)) { + pcilib_error("Memory allocation (%i bytes) for event data is failed"); + return -PCILIB_ERROR_MEMORY; + } + if (*(user->size)) *(user->size) = size; + allocated = 1; + } + + memcpy(*(user->data), data, size); + + err = pcilib_return_data(user->ctx, event_id, PCILIB_EVENT_DATA, data); + if (err) { + if (allocated) { + free(*(user->data)); + *(user->data) = NULL; + } + pcilib_error("The event data had been overwritten before it was returned, data corruption may occur"); + return -err; + } + + return PCILIB_STREAMING_CONTINUE; +} + +int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout) { + int err; + pcilib_event_id_t eid; + + pcilib_grab_callback_user_data_t user = {ctx, size, data}; + + err = pcilib_start(ctx, event_mask, PCILIB_EVENT_FLAGS_DEFAULT); + if (!err) err = pcilib_trigger(ctx, event_mask, 0, NULL); + if (!err) { + err = pcilib_get_next_event(ctx, timeout, &eid, 0, NULL); + if (!err) pcilib_grab_callback(event_mask, eid, &user); + } + pcilib_stop(ctx, PCILIB_EVENT_FLAGS_DEFAULT); + return err; +} diff --git a/pcilib/event.h b/pcilib/event.h new file mode 100644 index 0000000..93f659c --- /dev/null +++ b/pcilib/event.h @@ -0,0 +1,90 @@ +#ifndef _PCILIB_EVENT_H +#define _PCILIB_EVENT_H + +#include + +typedef struct { + size_t max_events; + pcilib_timeout_t duration; +} pcilib_autostop_parameters_t; + +typedef struct { + pcilib_event_rawdata_callback_t callback; + void *user; +} pcilib_rawdata_parameters_t; + +typedef struct { + size_t max_threads; +} pcilib_parallel_parameters_t; + +typedef struct { + pcilib_autostop_parameters_t autostop; + pcilib_rawdata_parameters_t rawdata; + pcilib_parallel_parameters_t parallel; +} pcilib_event_parameters_t; + +struct pcilib_event_context_s { + pcilib_event_parameters_t params; + pcilib_t *pcilib; +}; + +typedef struct { + pcilib_event_t evid; + const char *name; + const char *description; +} pcilib_event_description_t; + +typedef struct { + pcilib_event_data_type_t data_type; + pcilib_event_t evid; + const char *name; + const char *description; +} pcilib_event_data_type_description_t; + +typedef enum { + PCILIB_STREAMING_STOP = 0, /**< stop streaming */ + PCILIB_STREAMING_CONTINUE = 1, /**< wait the default DMA timeout for a new data */ + PCILIB_STREAMING_WAIT = 2, /**< wait the specified timeout for a new data */ + PCILIB_STREAMING_CHECK = 3, /**< do not wait for the data, bail out imideatly if no data ready */ + PCILIB_STREAMING_FAIL = 4, /**< fail if data is not available on timeout */ + PCILIB_STREAMING_REQ_FRAGMENT = 5, /**< only fragment of a packet is read, wait for next fragment and fail if no data during DMA timeout */ + PCILIB_STREAMING_REQ_PACKET = 6, /**< wait for next packet and fail if no data during the specified timeout */ + PCILIB_STREAMING_TIMEOUT_MASK = 3 /**< mask specifying all timeout modes */ +} pcilib_streaming_action_t; + +/* + * get_data: This call is used by get_data and copy_data functions of public + * interface. When copy_data is the caller, the data parameter will be passed. + * Therefore, depending on data the parameter, the function should behave + * diferently. If get get_data function is used (buf == NULL), the caller is + * expected to call return_data afterwards. Otherwise, if buf != NULL and + * copy_data is used, the return call will not be executed. + * Still, the get_data function is not obliged to return the data in the + * passed buf, but a reference to the staticaly allocated memory may be + * returned instead. The copy can be managed by the envelope function. + */ + +typedef struct { + pcilib_context_t *(*init)(pcilib_t *ctx); + void (*free)(pcilib_context_t *ctx); + + pcilib_dma_context_t *(*init_dma)(pcilib_context_t *ctx); + + int (*reset)(pcilib_context_t *ctx); + + int (*start)(pcilib_context_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); + int (*stop)(pcilib_context_t *ctx, pcilib_event_flags_t flags); + int (*trigger)(pcilib_context_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); + + int (*stream)(pcilib_context_t *ctx, pcilib_event_callback_t callback, void *user); + int (*next_event)(pcilib_context_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); + + int (*get_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size, void **data); + int (*return_data)(pcilib_context_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); +} pcilib_event_api_description_t; + + +int pcilib_init_event_engine(pcilib_t *ctx); + + +#endif /* _PCILIB_EVENT_H */ diff --git a/pcilib/irq.c b/pcilib/irq.c new file mode 100644 index 0000000..3d387bb --- /dev/null +++ b/pcilib/irq.c @@ -0,0 +1,55 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" + +#include "tools.h" +#include "error.h" + +int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count) { + int err; + + interrupt_wait_t arg = { 0 }; + + arg.source = source; + arg.timeout = timeout; + + if (count) arg.count = 1; + + err = ioctl(ctx->handle, PCIDRIVER_IOC_WAITI, &arg); + if (err) { + pcilib_error("PCIDRIVER_IOC_WAITI ioctl have failed"); + return PCILIB_ERROR_FAILED; + } + + if (!arg.count) return PCILIB_ERROR_TIMEOUT; + + if (count) *count = arg.count; + + return 0; +} + +int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source) { + int err; + + err = ioctl(ctx->handle, PCIDRIVER_IOC_CLEAR_IOQ, source); + if (err) { + pcilib_error("PCIDRIVER_IOC_CLEAR_IOQ ioctl have failed"); + return PCILIB_ERROR_FAILED; + } + + return 0; +} + + diff --git a/pcilib/irq.h b/pcilib/irq.h new file mode 100644 index 0000000..441e0e5 --- /dev/null +++ b/pcilib/irq.h @@ -0,0 +1,5 @@ +#ifndef _PCILIB_IRQ_H +#define _PCILIB_IRQ_H + + +#endif /* _PCILIB_IRQ_H */ diff --git a/pcilib/kmem.c b/pcilib/kmem.c new file mode 100644 index 0000000..8560eae --- /dev/null +++ b/pcilib/kmem.c @@ -0,0 +1,310 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcilib.h" +#include "pci.h" +#include "kmem.h" +#include "error.h" + +int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { + kmem_handle_t kh = {0}; + kh.use = use; + kh.flags = flags|PCILIB_KMEM_FLAG_MASS; + + return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); +} + + +static int pcilib_free_kernel_buffer(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, size_t i, pcilib_kmem_flags_t flags) { + kmem_handle_t kh = {0}; + + if (kbuf->buf.blocks[i].ua) munmap(kbuf->buf.blocks[i].ua, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); + kh.handle_id = kbuf->buf.blocks[i].handle_id; + kh.pa = kbuf->buf.blocks[i].pa; + kh.flags = flags; + + return ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_FREE, &kh); +} + +static void pcilib_cancel_kernel_memory(pcilib_t *ctx, pcilib_kmem_list_t *kbuf, pcilib_kmem_flags_t flags, int last_flags) { + int ret; + + if (!kbuf->buf.n_blocks) return; + + // consistency error during processing of last block, special treatment could be needed + if (last_flags) { + pcilib_kmem_flags_t failed_flags = flags; + + if (last_flags&KMEM_FLAG_REUSED_PERSISTENT) flags&=~PCILIB_KMEM_FLAG_PERSISTENT; + if (last_flags&KMEM_FLAG_REUSED_HW) flags&=~PCILIB_KMEM_FLAG_HARDWARE; + + if (failed_flags != flags) { + ret = pcilib_free_kernel_buffer(ctx, kbuf, --kbuf->buf.n_blocks, failed_flags); + if (ret) pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); + } + } + + pcilib_free_kernel_memory(ctx, kbuf, flags); +} + +pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags) { + int err = 0; + const char *error = NULL; + + int ret; + int i; + void *addr; + + pcilib_tristate_t reused = PCILIB_TRISTATE_NO; + int persistent = -1; + int hardware = -1; + + kmem_handle_t kh = {0}; + + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)malloc(sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); + if (!kbuf) { + pcilib_error("Memory allocation has failed"); + return NULL; + } + + memset(kbuf, 0, sizeof(pcilib_kmem_list_t) + nmemb * sizeof(pcilib_kmem_addr_t)); + + ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_KMEM ); + if (ret) { + pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed"); + return NULL; + } + + kh.type = type; + kh.size = size; + kh.align = alignment; + kh.use = use; + + if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { + kh.align = 0; + } else if ((type&PCILIB_KMEM_TYPE_MASK) != PCILIB_KMEM_TYPE_PAGE) { + kh.size += alignment; + } + + for ( i = 0; i < nmemb; i++) { + kh.item = i; + kh.flags = flags; + + if ((type&PCILIB_KMEM_TYPE_MASK) == PCILIB_KMEM_TYPE_REGION) { + kh.pa = alignment + i * size; + } + + ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_ALLOC, &kh); + if (ret) { + kbuf->buf.n_blocks = i; + error = "PCIDRIVER_IOC_KMEM_ALLOC ioctl have failed"; + break; + } + + kbuf->buf.blocks[i].handle_id = kh.handle_id; + kbuf->buf.blocks[i].pa = kh.pa; + kbuf->buf.blocks[i].size = kh.size; + + if (!i) reused = (kh.flags&KMEM_FLAG_REUSED)?PCILIB_TRISTATE_YES:PCILIB_TRISTATE_NO; + + if (kh.flags&KMEM_FLAG_REUSED) { + if (!i) reused = PCILIB_TRISTATE_YES; + else if (!reused) reused = PCILIB_TRISTATE_PARTIAL; + + if (persistent) { + if (persistent < 0) { + /*if (((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)&&(kh.flags&KMEM_FLAG_REUSED_PERSISTENT)) err = PCILIB_ERROR_INVALID_STATE; + else*/ persistent = (kh.flags&KMEM_FLAG_REUSED_PERSISTENT)?1:0; + } else if ((kh.flags&KMEM_FLAG_REUSED_PERSISTENT) == 0) err = PCILIB_ERROR_INVALID_STATE; + } else if (kh.flags&KMEM_FLAG_REUSED_PERSISTENT) err = PCILIB_ERROR_INVALID_STATE; + + if (hardware) { + if (hardware < 0) { + /*if (((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)&&(kh.flags&KMEM_FLAG_REUSED_HW)) err = PCILIB_ERROR_INVALID_STATE; + else*/ hardware = (kh.flags&KMEM_FLAG_REUSED_HW)?1:0; + } else if ((kh.flags&KMEM_FLAG_REUSED_HW) == 0) err = PCILIB_ERROR_INVALID_STATE; + } else if (kh.flags&KMEM_FLAG_REUSED_HW) err = PCILIB_ERROR_INVALID_STATE; + + } else { + if (!i) reused = PCILIB_TRISTATE_NO; + else if (reused) reused = PCILIB_TRISTATE_PARTIAL; + + if ((persistent > 0)&&((flags&PCILIB_KMEM_FLAG_PERSISTENT) == 0)) err = PCILIB_ERROR_INVALID_STATE; + if ((hardware > 0)&&((flags&PCILIB_KMEM_FLAG_HARDWARE) == 0)) err = PCILIB_ERROR_INVALID_STATE; + } + + if (err) { + kbuf->buf.n_blocks = i + 1; + break; + } + + 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; + error = "Failed to mmap allocated kernel memory"; + break; + } + + kbuf->buf.blocks[i].ua = addr; +// if (use == PCILIB_KMEM_USE_DMA_PAGES) { +// memset(addr, 10, kbuf->buf.blocks[i].size + kbuf->buf.blocks[i].alignment_offset); +// } + + kbuf->buf.blocks[i].mmap_offset = kh.pa & ctx->page_mask; + } + + //This is possible in the case of error (nothing is allocated yet) or if buffers are not reused + if (persistent < 0) persistent = 0; + if (hardware < 0) hardware = 0; + + if (err||error) { + pcilib_kmem_flags_t free_flags = 0; + + // for the sake of simplicity always clean partialy reused buffers + if ((persistent == PCILIB_TRISTATE_PARTIAL)||((persistent <= 0)&&(flags&PCILIB_KMEM_FLAG_PERSISTENT))) { + free_flags |= PCILIB_KMEM_FLAG_PERSISTENT; + } + + if ((hardware <= 0)&&(flags&PCILIB_KMEM_FLAG_HARDWARE)) { + free_flags |= PCILIB_KMEM_FLAG_HARDWARE; + } + + // do not clean if we have reused peresistent buffers + // we don't care about -1, because it will be the value only if no buffers actually allocated + if ((!persistent)||(reused != PCILIB_TRISTATE_YES)) { + pcilib_cancel_kernel_memory(ctx, kbuf, free_flags, err?kh.flags:0); + } + + if (!error) error = "Reused buffers are inconsistent"; + pcilib_error(error); + + return NULL; + } + + if (nmemb == 1) { + memcpy(&kbuf->buf.addr, &kbuf->buf.blocks[0], sizeof(pcilib_kmem_addr_t)); + } + + kbuf->buf.reused = reused|(persistent?PCILIB_KMEM_REUSE_PERSISTENT:0)|(hardware?PCILIB_KMEM_REUSE_HARDWARE:0); + kbuf->buf.n_blocks = nmemb; + + kbuf->prev = NULL; + kbuf->next = ctx->kmem_list; + if (ctx->kmem_list) ctx->kmem_list->prev = kbuf; + ctx->kmem_list = kbuf; + + return (pcilib_kmem_handle_t*)kbuf; +} + +void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags) { + int ret, err = 0; + int i; + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + + // if linked in to the list + if (kbuf->next) kbuf->next->prev = kbuf->prev; + if (kbuf->prev) kbuf->prev->next = kbuf->next; + else if (ctx->kmem_list == kbuf) ctx->kmem_list = kbuf->next; + + for (i = 0; i < kbuf->buf.n_blocks; i++) { + ret = pcilib_free_kernel_buffer(ctx, kbuf, i, flags); + if ((ret)&&(!err)) err = ret; + } + + free(kbuf); + + if (err) { + pcilib_error("PCIDRIVER_IOC_KMEM_FREE ioctl have failed"); + } +} + +/* +int pcilib_kmem_sync(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir) { + int i; + int ret; + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + + for (i = 0; i < kbuf->buf.n_blocks; i++) { + ret = pcilib_kmem_sync_block(ctx, k, dir, i); + if (ret) { + pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed"); + return PCILIB_ERROR_FAILED; + } + } + + return 0; +} +*/ + +int pcilib_kmem_sync_block(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir, size_t block) { + int ret; + kmem_sync_t ks; + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + + ks.dir = dir; + ks.handle.handle_id = kbuf->buf.blocks[block].handle_id; + ks.handle.pa = kbuf->buf.blocks[block].pa; + ret = ioctl(ctx->handle, PCIDRIVER_IOC_KMEM_SYNC, &ks); + if (ret) { + pcilib_error("PCIDRIVER_IOC_KMEM_SYNC ioctl have failed"); + return PCILIB_ERROR_FAILED; + } + + return 0; +} + +void *pcilib_kmem_get_ua(pcilib_t *ctx, pcilib_kmem_handle_t *k) { + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + return kbuf->buf.addr.ua + kbuf->buf.addr.alignment_offset + kbuf->buf.addr.mmap_offset; +} + +uintptr_t pcilib_kmem_get_pa(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; +} + +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; +} + +uintptr_t pcilib_kmem_get_block_pa(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; +} + +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; +} + +pcilib_kmem_reuse_state_t pcilib_kmem_is_reused(pcilib_t *ctx, pcilib_kmem_handle_t *k) { + pcilib_kmem_list_t *kbuf = (pcilib_kmem_list_t*)k; + return kbuf->buf.reused; +} diff --git a/pcilib/kmem.h b/pcilib/kmem.h new file mode 100644 index 0000000..8302b6a --- /dev/null +++ b/pcilib/kmem.h @@ -0,0 +1,110 @@ +#ifndef _PCILIB_KMEM_H +#define _PCILIB_KMEM_H + +typedef struct pcilib_s pcilib_t; +typedef struct pcilib_kmem_list_s pcilib_kmem_list_t; + +typedef enum { + PCILIB_TRISTATE_NO = 0, + PCILIB_TRISTATE_PARTIAL = 1, + PCILIB_TRISTATE_YES = 2 +} pcilib_tristate_t; + +#define PCILIB_KMEM_TYPE_MASK 0xFFFF0000 +#define PCILIB_KMEM_USE(type, subtype) (((type) << 16)|(subtype)) + +typedef enum { + PCILIB_KMEM_TYPE_CONSISTENT = 0x00000, + PCILIB_KMEM_TYPE_PAGE = 0x10000, + PCILIB_KMEM_TYPE_DMA_S2C_PAGE = 0x10001, + PCILIB_KMEM_TYPE_DMA_C2S_PAGE = 0x10002, + PCILIB_KMEM_TYPE_REGION = 0x20000, + PCILIB_KMEM_TYPE_REGION_S2C = 0x20001, + PCILIB_KMEM_TYPE_REGION_C2S = 0x20002 +} pcilib_kmem_type_t; + +typedef enum { + PCILIB_KMEM_USE_STANDARD = 0, + PCILIB_KMEM_USE_DMA_RING = 1, + PCILIB_KMEM_USE_DMA_PAGES = 2, + PCILIB_KMEM_USE_USER = 0x10 +} pcilib_kmem_use_t; + +typedef enum { + PCILIB_KMEM_SYNC_BIDIRECTIONAL = 0, + PCILIB_KMEM_SYNC_TODEVICE = 1, + PCILIB_KMEM_SYNC_FROMDEVICE = 2 +} pcilib_kmem_sync_direction_t; + +typedef enum { + PCILIB_KMEM_FLAG_REUSE = 1, /**< Try to reuse existing buffer with the same use & item */ + PCILIB_KMEM_FLAG_EXCLUSIVE = 2, /**< Allow only a single application accessing a specified use & item */ + PCILIB_KMEM_FLAG_PERSISTENT = 4, /**< Sets persistent mode */ + PCILIB_KMEM_FLAG_HARDWARE = 8, /**< The buffer may be accessed by hardware, the hardware access will not occur any more if passed to _free function */ + PCILIB_KMEM_FLAG_FORCE = 16, /**< Force memory cleanup even if references are present */ + PCILIB_KMEM_FLAG_MASS = 32, /**< Apply to all buffers of selected use */ + PCILIB_KMEM_FLAG_TRY = 64 /**< Do not allocate buffers, try to reuse and fail if not possible */ +} pcilib_kmem_flags_t; + + +typedef enum { + PCILIB_KMEM_REUSE_ALLOCATED = PCILIB_TRISTATE_NO, + PCILIB_KMEM_REUSE_REUSED = PCILIB_TRISTATE_YES, + PCILIB_KMEM_REUSE_PARTIAL = PCILIB_TRISTATE_PARTIAL, + PCILIB_KMEM_REUSE_PERSISTENT = 0x100, + PCILIB_KMEM_REUSE_HARDWARE = 0x200 +} pcilib_kmem_reuse_state_t; + + +typedef struct { + int handle_id; + pcilib_kmem_reuse_state_t reused; + + uintptr_t pa; +// uintptr_t va; + void *ua; + size_t size; + + size_t alignment_offset; + size_t mmap_offset; +} pcilib_kmem_addr_t; + +/** + * single allocation - we set only addr, n_blocks = 0 + * multiple allocation - addr is not set, blocks are set, n_blocks > 0 + * sgmap allocation - addr contains ua, but pa's are set in blocks, n_blocks > 0 + */ +typedef struct { + pcilib_kmem_addr_t addr; + + pcilib_kmem_reuse_state_t reused; + + size_t n_blocks; + pcilib_kmem_addr_t blocks[]; +} pcilib_kmem_buffer_t; + +typedef void pcilib_kmem_handle_t; + + +struct pcilib_kmem_list_s { + pcilib_kmem_list_t *next, *prev; + + pcilib_kmem_buffer_t buf; // variable size, should be last item in struct +}; + +pcilib_kmem_handle_t *pcilib_alloc_kernel_memory(pcilib_t *ctx, pcilib_kmem_type_t type, size_t nmemb, size_t size, size_t alignment, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags); +void pcilib_free_kernel_memory(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_flags_t flags); +//int pcilib_kmem_sync(pcilib_t *ctx, pcilib_kmem_handle_t *k, pcilib_kmem_sync_direction_t dir); +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); + +int pcilib_clean_kernel_memory(pcilib_t *ctx, pcilib_kmem_use_t use, pcilib_kmem_flags_t flags); + +#endif /* _PCILIB_KMEM_H */ diff --git a/pcilib/linux-3.10.h b/pcilib/linux-3.10.h new file mode 100644 index 0000000..161d2aa --- /dev/null +++ b/pcilib/linux-3.10.h @@ -0,0 +1,81 @@ +/* + * Extract from kernel headers + * iomap.h + */ + +/* + * IO resources have these defined flags. + */ +#define IORESOURCE_BITS 0x000000ff /* Bus-specific bits */ + +#define IORESOURCE_TYPE_BITS 0x00000f00 /* Resource type */ +#define IORESOURCE_IO 0x00000100 +#define IORESOURCE_MEM 0x00000200 +#define IORESOURCE_IRQ 0x00000400 +#define IORESOURCE_DMA 0x00000800 + +#define IORESOURCE_PREFETCH 0x00001000 /* No side effects */ +#define IORESOURCE_READONLY 0x00002000 +#define IORESOURCE_CACHEABLE 0x00004000 +#define IORESOURCE_RANGELENGTH 0x00008000 +#define IORESOURCE_SHADOWABLE 0x00010000 + +#define IORESOURCE_SIZEALIGN 0x00020000 /* size indicates alignment */ +#define IORESOURCE_STARTALIGN 0x00040000 /* start field is alignment */ + +#define IORESOURCE_MEM_64 0x00100000 + +#define IORESOURCE_EXCLUSIVE 0x08000000 /* Userland may not map this resource */ +#define IORESOURCE_DISABLED 0x10000000 +#define IORESOURCE_UNSET 0x20000000 +#define IORESOURCE_AUTO 0x40000000 +#define IORESOURCE_BUSY 0x80000000 /* Driver has marked this resource busy */ + +/* PnP IRQ specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_IRQ_HIGHEDGE (1<<0) +#define IORESOURCE_IRQ_LOWEDGE (1<<1) +#define IORESOURCE_IRQ_HIGHLEVEL (1<<2) +#define IORESOURCE_IRQ_LOWLEVEL (1<<3) +#define IORESOURCE_IRQ_SHAREABLE (1<<4) +#define IORESOURCE_IRQ_OPTIONAL (1<<5) + +/* PnP DMA specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_DMA_TYPE_MASK (3<<0) +#define IORESOURCE_DMA_8BIT (0<<0) +#define IORESOURCE_DMA_8AND16BIT (1<<0) +#define IORESOURCE_DMA_16BIT (2<<0) + +#define IORESOURCE_DMA_MASTER (1<<2) +#define IORESOURCE_DMA_BYTE (1<<3) +#define IORESOURCE_DMA_WORD (1<<4) + +#define IORESOURCE_DMA_SPEED_MASK (3<<6) +#define IORESOURCE_DMA_COMPATIBLE (0<<6) +#define IORESOURCE_DMA_TYPEA (1<<6) +#define IORESOURCE_DMA_TYPEB (2<<6) +#define IORESOURCE_DMA_TYPEF (3<<6) + +/* PnP memory I/O specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_MEM_WRITEABLE (1<<0) /* dup: IORESOURCE_READONLY */ +#define IORESOURCE_MEM_CACHEABLE (1<<1) /* dup: IORESOURCE_CACHEABLE */ +#define IORESOURCE_MEM_RANGELENGTH (1<<2) /* dup: IORESOURCE_RANGELENGTH */ +#define IORESOURCE_MEM_TYPE_MASK (3<<3) +#define IORESOURCE_MEM_8BIT (0<<3) +#define IORESOURCE_MEM_16BIT (1<<3) +#define IORESOURCE_MEM_8AND16BIT (2<<3) +#define IORESOURCE_MEM_32BIT (3<<3) +#define IORESOURCE_MEM_SHADOWABLE (1<<5) /* dup: IORESOURCE_SHADOWABLE */ +#define IORESOURCE_MEM_EXPANSIONROM (1<<6) + +/* PnP I/O specific bits (IORESOURCE_BITS) */ +#define IORESOURCE_IO_16BIT_ADDR (1<<0) +#define IORESOURCE_IO_FIXED (1<<1) + +/* PCI ROM control bits (IORESOURCE_BITS) */ +#define IORESOURCE_ROM_ENABLE (1<<0) /* ROM is enabled, same as PCI_ROM_ADDRESS_ENABLE */ +#define IORESOURCE_ROM_SHADOW (1<<1) /* ROM is copy at C000:0 */ +#define IORESOURCE_ROM_COPY (1<<2) /* ROM is alloc'd copy, resource field overlaid */ +#define IORESOURCE_ROM_BIOS_COPY (1<<3) /* ROM is BIOS copy, resource field overlaid */ + +/* PCI control bits. Shares IORESOURCE_BITS with above PCI ROM. */ +#define IORESOURCE_PCI_FIXED (1<<4) /* Do not move resource */ diff --git a/pcilib/model.c b/pcilib/model.c new file mode 100644 index 0000000..65f96aa --- /dev/null +++ b/pcilib/model.c @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcilib.h" +#include "pci.h" +#include "tools.h" +#include "error.h" + + +const pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx) { + return &ctx->model_info; +} diff --git a/pcilib/model.h b/pcilib/model.h new file mode 100644 index 0000000..0b18c59 --- /dev/null +++ b/pcilib/model.h @@ -0,0 +1,29 @@ +#ifndef _PCILIB_MODEL_H +#define _PCILIB_MODEL_H + +#include +#include +#include +#include +#include + +typedef struct { + const pcilib_event_api_description_t *api; + const pcilib_dma_description_t *dma; + + const pcilib_register_description_t *registers; + const pcilib_register_bank_description_t *banks; + const pcilib_register_protocol_description_t *protocols; + const pcilib_register_range_t *ranges; + + const pcilib_event_description_t *events; + const pcilib_event_data_type_description_t *data_types; + + const char *name; + const char *description; +} pcilib_model_description_t; + + +const pcilib_model_description_t *pcilib_get_model_description(pcilib_t *ctx); + +#endif /* _PCILIB_MODEL_H */ diff --git a/pcilib/pci.c b/pcilib/pci.c new file mode 100644 index 0000000..426ae91 --- /dev/null +++ b/pcilib/pci.c @@ -0,0 +1,540 @@ +//#define PCILIB_FILE_IO +#define _BSD_SOURCE +#define _POSIX_C_SOURCE 200809L + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pcilib.h" +#include "pci.h" +#include "tools.h" +#include "error.h" +#include "model.h" + +static int pcilib_detect_model(pcilib_t *ctx, const char *model) { + int i, j; + + // Registers & Banks must be copied! + + if (model) { + // Check for DMA models + for (i = 0; pcilib_dma[i].name; i++) { + if (!strcasecmp(model, pcilib_dma[i].name)) + break; + } + + if (pcilib_dma[i].api) { + memcpy(&ctx->dma, &pcilib_dma[i], sizeof(pcilib_dma_description_t)); + ctx->model_info.dma = &ctx->dma; + + if (pcilib_dma[i].banks) + pcilib_add_register_banks(ctx, 0, pcilib_dma[i].banks); + + if (pcilib_dma[i].registers) + pcilib_add_registers(ctx, 0, pcilib_dma[i].registers); + + if (pcilib_dma[i].engines) { + for (j = 0; pcilib_dma[i].engines[j].addr_bits; j++) + memcpy(ctx->engines, pcilib_dma[i].engines, j * sizeof(pcilib_dma_engine_description_t)); + ctx->num_engines = j; + } else + ctx->dma.engines = ctx->engines; + + return 0; + } + + // Check for XML models (DMA + XML registers) + + // Check for specified model + + // Iterate other all other models + } + + // Check for all installed models + // memcpy(&ctx->model_info, model, sizeof(pcilib_model_description_t)); + // how we reconcile the banks from event model and dma description? The banks specified in the DMA description should override corresponding banks of events... + + + if (model) + return PCILIB_ERROR_NOTFOUND; + + // Otherwise, simple pci access (all model members are set to NULL) + + return 0; +} + + + +pcilib_t *pcilib_open(const char *device, const char *model) { + int err; + size_t i; + pcilib_t *ctx = malloc(sizeof(pcilib_t)); + + if (ctx) { + memset(ctx, 0, sizeof(pcilib_t)); + + ctx->handle = open(device, O_RDWR); + if (ctx->handle < 0) { + pcilib_error("Error opening device (%s)", device); + free(ctx); + return NULL; + } + + ctx->page_mask = (uintptr_t)-1; + ctx->model = model?strdup(model):NULL; + + ctx->alloc_reg = PCILIB_DEFAULT_REGISTER_SPACE; + ctx->registers = (pcilib_register_description_t *)malloc(PCILIB_DEFAULT_REGISTER_SPACE * sizeof(pcilib_register_description_t)); +/* ctx->banks = (pcilib_register_bank_context_t *)malloc(PCILIB_MAX_BANKS * sizeof(pcilib_register_bank_context_t)); + ctx->ranges = (pcilib_register_range_t *)malloc(PCILIB_MAX_RANGES * sizeof(pcilib_register_range_t)); + ctx->protocols + ctx->engines*/ + + if ((!ctx->registers)/*||(!ctx->banks)||(!ctx->ranges)*/) { + pcilib_error("Error allocating memory for register model"); + pcilib_close(ctx); + free(ctx); + return NULL; + } + + memset(ctx->registers, 0, sizeof(pcilib_register_description_t)); + memset(ctx->banks, 0, sizeof(pcilib_register_bank_description_t)); + memset(ctx->ranges, 0, sizeof(pcilib_register_range_t)); + + for (i = 0; pcilib_protocols[i].api; i++); + memcpy(ctx->protocols, pcilib_protocols, i * sizeof(pcilib_register_protocol_description_t)); + + ctx->model_info.registers = ctx->registers; + ctx->model_info.banks = ctx->banks; + ctx->model_info.protocols = ctx->protocols; + ctx->model_info.ranges = ctx->ranges; + + err = pcilib_detect_model(ctx, model); + if (err) { + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); + if (board_info) + pcilib_error("Error (%i) configuring model %s (%x:%x)", err, (model?model:""), board_info->vendor_id, board_info->device_id); + else + pcilib_error("Error (%i) configuring model %s", err, (model?model:"")); + pcilib_close(ctx); + free(ctx); + return NULL; + } + + err = pcilib_init_register_banks(ctx); + if (err) { + pcilib_error("Error (%i) initializing regiser banks\n", err); + pcilib_close(ctx); + free(ctx); + return NULL; + } + + err = pcilib_init_event_engine(ctx); + if (err) { + pcilib_error("Error (%i) initializing event engine\n", err); + pcilib_close(ctx); + free(ctx); + return NULL; + } + } + + return ctx; +} + + +const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx) { + int ret; + + if (ctx->page_mask == (uintptr_t)-1) { + ret = ioctl( ctx->handle, PCIDRIVER_IOC_PCI_INFO, &ctx->board_info ); + if (ret) { + pcilib_error("PCIDRIVER_IOC_PCI_INFO ioctl have failed"); + return NULL; + } + + ctx->page_mask = pcilib_get_page_mask(); + } + + return &ctx->board_info; +} + + +pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx) { + return ctx->event_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_BARS; 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; +} + +int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size) { + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); + if (!board_info) return PCILIB_ERROR_NOTFOUND; + + if (*bar == PCILIB_BAR_DETECT) { + *bar = pcilib_detect_bar(ctx, *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 %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; +} + +void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar) { + void *res; + int ret; + + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); + if (!board_info) return NULL; + + if (ctx->bar_space[bar]) return ctx->bar_space[bar]; + + ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_MODE, PCIDRIVER_MMAP_PCI ); + if (ret) { + pcilib_error("PCIDRIVER_IOC_MMAP_MODE ioctl have failed", bar); + return NULL; + } + + ret = ioctl( ctx->handle, PCIDRIVER_IOC_MMAP_AREA, PCIDRIVER_BAR0 + bar ); + if (ret) { + pcilib_error("PCIDRIVER_IOC_MMAP_AREA ioctl have failed for bank %i", bar); + return NULL; + } + +#ifdef PCILIB_FILE_IO + file_io_handle = open("/root/data", O_RDWR); + res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->file_io_handle, 0 ); +#else + res = mmap( 0, board_info->bar_length[bar], PROT_WRITE | PROT_READ, MAP_SHARED, ctx->handle, 0 ); +#endif + if ((!res)||(res == MAP_FAILED)) { + pcilib_error("Failed to mmap data bank %i", bar); + return NULL; + } + + + return res; +} + +void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data) { + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); + if (!board_info) return; + + if (ctx->bar_space[bar]) return; + + munmap(data, board_info->bar_length[bar]); +#ifdef PCILIB_FILE_IO + close(ctx->file_io_handle); +#endif +} + +int pcilib_map_register_space(pcilib_t *ctx) { + int err; + pcilib_register_bank_t i; + + if (!ctx->reg_bar_mapped) { + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_register_bank_description_t *banks = model_info->banks; + + for (i = 0; ((banks)&&(banks[i].access)); i++) { +// uint32_t buf[2]; + void *reg_space; + pcilib_bar_t bar = banks[i].bar; + + if (bar == PCILIB_BAR_DETECT) { + uintptr_t addr = banks[0].read_addr; + + err = pcilib_detect_address(ctx, &bar, &addr, 1); + if (err) return err; + + if (!ctx->bar_space[bar]) { + reg_space = pcilib_map_bar(ctx, bar); +// pcilib_memcpy(&buf, reg_space, 8); + + if (reg_space) { + ctx->bar_space[bar] = reg_space; + } else { + return PCILIB_ERROR_FAILED; + } + } + } else if (!ctx->bar_space[bar]) { + reg_space = pcilib_map_bar(ctx, bar); + if (reg_space) { + ctx->bar_space[bar] = reg_space; + } else { + return PCILIB_ERROR_FAILED; + } +// pcilib_memcpy(&buf, reg_space, 8); + + } + + if (!i) ctx->reg_bar = bar; + } + + + ctx->reg_bar_mapped = 1; + } + + return 0; +} + +int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr) { + int err; + pcilib_bar_t i; + + if (!ctx->data_bar_mapped) { + const pcilib_board_info_t *board_info = pcilib_get_board_info(ctx); + if (!board_info) return PCILIB_ERROR_FAILED; + + err = pcilib_map_register_space(ctx); + if (err) { + pcilib_error("Error mapping register space"); + return err; + } + + int data_bar = -1; + + for (i = 0; i < PCILIB_MAX_BARS; i++) { + if ((ctx->bar_space[i])||(!board_info->bar_length[i])) continue; + + if (addr) { + if (board_info->bar_start[i] == addr) { + data_bar = i; + break; + } + } else { + if (data_bar >= 0) { + data_bar = -1; + break; + } + + data_bar = i; + } + } + + + if (data_bar < 0) { + if (addr) pcilib_error("Unable to find the specified data space (%lx)", addr); + else pcilib_error("Unable to find the data space"); + return PCILIB_ERROR_NOTFOUND; + } + + ctx->data_bar = data_bar; + + if (!ctx->bar_space[data_bar]) { + char *data_space = pcilib_map_bar(ctx, data_bar); + if (data_space) ctx->bar_space[data_bar] = data_space; + else { + pcilib_error("Unable to map the data space"); + return PCILIB_ERROR_FAILED; + } + } + + ctx->data_bar_mapped = 0; + } + + return 0; +} + +char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr) { + if (bar == PCILIB_BAR_DETECT) { + // First checking the default register bar + size_t offset = addr - ctx->board_info.bar_start[ctx->reg_bar]; + if ((addr > ctx->board_info.bar_start[ctx->reg_bar])&&(offset < ctx->board_info.bar_length[ctx->reg_bar])) { + if (!ctx->bar_space[ctx->reg_bar]) { + pcilib_error("The register bar is not mapped"); + return NULL; + } + + return ctx->bar_space[ctx->reg_bar] + offset + (ctx->board_info.bar_start[ctx->reg_bar] & ctx->page_mask); + } + + // Otherwise trying to detect + bar = pcilib_detect_bar(ctx, addr, 1); + if (bar != PCILIB_BAR_INVALID) { + size_t offset = addr - ctx->board_info.bar_start[bar]; + if ((offset < ctx->board_info.bar_length[bar])&&(ctx->bar_space[bar])) { + if (!ctx->bar_space[bar]) { + pcilib_error("The requested bar (%i) is not mapped", bar); + return NULL; + } + return ctx->bar_space[bar] + offset + (ctx->board_info.bar_start[bar] & ctx->page_mask); + } + } + } else { + if (!ctx->bar_space[bar]) { + pcilib_error("The requested bar (%i) is not mapped", bar); + return NULL; + } + + if (addr < ctx->board_info.bar_length[bar]) { + return ctx->bar_space[bar] + addr + (ctx->board_info.bar_start[bar] & ctx->page_mask); + } + + if ((addr >= ctx->board_info.bar_start[bar])&&(addr < (ctx->board_info.bar_start[bar] + ctx->board_info.bar_length[ctx->reg_bar]))) { + return ctx->bar_space[bar] + (addr - ctx->board_info.bar_start[bar]) + (ctx->board_info.bar_start[bar] & ctx->page_mask); + } + } + + return NULL; +} + +char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size) { + int err; + + err = pcilib_map_data_space(ctx, addr); + if (err) { + pcilib_error("Failed to map the specified address space (%lx)", addr); + return NULL; + } + + if (size) *size = ctx->board_info.bar_length[ctx->data_bar]; + + return ctx->bar_space[ctx->data_bar] + (ctx->board_info.bar_start[ctx->data_bar] & ctx->page_mask); +} + + +void pcilib_close(pcilib_t *ctx) { + pcilib_bar_t i; + + if (ctx) { + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + const pcilib_event_api_description_t *eapi = model_info->api; + const pcilib_dma_api_description_t *dapi = ctx->dma.api; + + if ((eapi)&&(eapi->free)) eapi->free(ctx->event_ctx); + if ((dapi)&&(dapi->free)) dapi->free(ctx->dma_ctx); + + pcilib_free_register_banks(ctx); + + if (ctx->kmem_list) { + pcilib_warning("Not all kernel buffers are properly cleaned"); + + while (ctx->kmem_list) { + pcilib_free_kernel_memory(ctx, ctx->kmem_list, 0); + } + } + + for (i = 0; i < PCILIB_MAX_BARS; i++) { + if (ctx->bar_space[i]) { + char *ptr = ctx->bar_space[i]; + ctx->bar_space[i] = NULL; + pcilib_unmap_bar(ctx, i, ptr); + } + } + + if (ctx->registers) + free(ctx->registers); + + if (ctx->model) + free(ctx->model); + + if (ctx->handle >= 0) + close(ctx->handle); + + free(ctx); + } +} + +int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { + void *data; + + pcilib_detect_address(ctx, &bar, &addr, size); + data = pcilib_map_bar(ctx, bar); + + pcilib_memcpy(buf, data + addr, size); + + pcilib_unmap_bar(ctx, bar, data); + + return 0; +} + +int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf) { + void *data; + + pcilib_detect_address(ctx, &bar, &addr, size); + data = pcilib_map_bar(ctx, bar); + + pcilib_memcpy(data + addr, buf, size); + + pcilib_unmap_bar(ctx, bar, data); + + return 0; +} + + +int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { + int i; + void *data; + + pcilib_detect_address(ctx, &bar, &addr, fifo_size); + data = pcilib_map_bar(ctx, bar); + + for (i = 0; i < n; i++) { + pcilib_memcpy(buf + i * fifo_size, data + addr, fifo_size); + } + + pcilib_unmap_bar(ctx, bar, data); + + return 0; +} + +int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf) { + int i; + void *data; + + pcilib_detect_address(ctx, &bar, &addr, fifo_size); + data = pcilib_map_bar(ctx, bar); + + for (i = 0; i < n; i++) { + pcilib_memcpy(data + addr, buf + i * fifo_size, fifo_size); + } + + pcilib_unmap_bar(ctx, bar, data); + + return 0; +} diff --git a/pcilib/pci.h b/pcilib/pci.h new file mode 100644 index 0000000..fe2ff8a --- /dev/null +++ b/pcilib/pci.h @@ -0,0 +1,77 @@ +#ifndef _PCITOOL_PCI_H +#define _PCITOOL_PCI_H + +#define PCILIB_DEFAULT_CPU_COUNT 2 +#define PCILIB_EVENT_TIMEOUT 1000000 /**< us */ +#define PCILIB_TRIGGER_TIMEOUT 100000 /**< us */ +#define PCILIB_DMA_TIMEOUT 10000 /**< us */ +#define PCILIB_DMA_SKIP_TIMEOUT 1000000 /**< us */ +#define PCILIB_REGISTER_TIMEOUT 10000 /**< us */ +#define PCILIB_MAX_BARS 6 /**< this is defined by PCI specification */ +#define PCILIB_DEFAULT_REGISTER_SPACE 1024 /**< number of registers to allocate on init */ +#define PCILIB_MAX_REGISTER_BANKS 32 /**< maximum number of register banks to allocate space for */ +#define PCILIB_MAX_REGISTER_RANGES 32 /**< maximum number of register ranges to allocate space for */ +#define PCILIB_MAX_REGISTER_PROTOCOLS 32 /**< maximum number of register protocols to support */ +#define PCILIB_MAX_DMA_ENGINES 32 /**< maximum number of supported DMA engines */ + +#include "linux-3.10.h" +#include "driver/pciDriver.h" + +#include "pcilib.h" +#include "register.h" +#include "kmem.h" +#include "irq.h" +#include "dma.h" +#include "event.h" +#include "model.h" +#include "config.h" + +struct pcilib_s { + int handle; /**< file handle of device */ + + uintptr_t page_mask; /**< Selects bits which define offset within the page */ + pcilib_board_info_t board_info; /**< The mandatory information about board as defined by PCI specification */ + char *bar_space[PCILIB_MAX_BARS]; /**< Pointers to the mapped BARs in virtual address space */ + + int reg_bar_mapped; /**< Indicates that all BARs used to access registers are mapped */ + pcilib_bar_t reg_bar; /**< Default BAR to look for registers, other BARs will be looked as well */ + int data_bar_mapped; /**< Indicates that a BAR for large PIO is mapped */ + pcilib_bar_t data_bar; /**< BAR for large PIO operations */ + + pcilib_kmem_list_t *kmem_list; /**< List of currently allocated kernel memory */ + + char *model; /**< Requested model */ + pcilib_model_description_t model_info; /**< Current model description combined from the information returned by the event plugin and all dynamic sources (XML, DMA registers, etc.). Contains only pointers, no deep copy of information returned by event plugin */ + + size_t num_banks_init; /**< Number of initialized banks */ + size_t num_reg, alloc_reg; /**< Number of registered and allocated registers */ + size_t num_banks, num_ranges; /**< Number of registered banks and register ranges */ + size_t num_engines; /**> Number of configured DMA engines */ + pcilib_register_description_t *registers; /**< List of currently defined registers (from all sources) */ + pcilib_register_bank_description_t banks[PCILIB_MAX_REGISTER_BANKS + 1]; /**< List of currently defined register banks (from all sources) */ + pcilib_register_range_t ranges[PCILIB_MAX_REGISTER_RANGES + 1]; /**< List of currently defined register ranges (from all sources) */ + pcilib_register_protocol_description_t protocols[PCILIB_MAX_REGISTER_PROTOCOLS + 1];/**< List of currently defined register protocols (from all sources) */ + pcilib_dma_description_t dma; /**< Configuration of used DMA implementation */ + pcilib_dma_engine_description_t engines[PCILIB_MAX_DMA_ENGINES + 1]; /**< List of engines defined by the DMA implementation */ + +// pcilib_register_context_t *register_ctx; /**< Contexts for registers */ + pcilib_register_bank_context_t *bank_ctx[PCILIB_MAX_REGISTER_BANKS]; /**< Contexts for registers banks if required by register protocol */ + pcilib_dma_context_t *dma_ctx; /**< DMA context */ + pcilib_context_t *event_ctx; /**< Implmentation context */ + +// pcilib_dma_info_t dma_info; + +#ifdef PCILIB_FILE_IO + int file_io_handle; +#endif /* PCILIB_FILE_IO */ +}; + + +pcilib_context_t *pcilib_get_implementation_context(pcilib_t *ctx); +const pcilib_board_info_t *pcilib_get_board_info(pcilib_t *ctx); + +int pcilib_map_register_space(pcilib_t *ctx); +int pcilib_map_data_space(pcilib_t *ctx, uintptr_t addr); +int pcilib_detect_address(pcilib_t *ctx, pcilib_bar_t *bar, uintptr_t *addr, size_t size); + +#endif /* _PCITOOL_PCI_H */ diff --git a/pcilib/pcilib.h b/pcilib/pcilib.h new file mode 100644 index 0000000..3518f75 --- /dev/null +++ b/pcilib/pcilib.h @@ -0,0 +1,226 @@ +#ifndef _PCITOOL_PCILIB_H +#define _PCITOOL_PCILIB_H + +#include +#include +#include + +typedef struct pcilib_s pcilib_t; +typedef struct pcilib_event_context_s pcilib_context_t; + +typedef uint8_t pcilib_bar_t; /**< Type holding the PCI Bar number */ +typedef uint16_t pcilib_register_t; /**< Type holding the register position within the field listing registers in the model */ +typedef uint32_t pcilib_register_addr_t; /**< Type holding the register address within address-space of BARs */ +typedef uint8_t pcilib_register_size_t; /**< Type holding the size in bits of the register */ +typedef uint32_t pcilib_register_value_t; /**< Type holding the register value */ +typedef uint8_t pcilib_dma_engine_addr_t; +typedef uint8_t pcilib_dma_engine_t; +typedef uint64_t pcilib_event_id_t; +typedef uint32_t pcilib_event_t; +typedef uint64_t pcilib_timeout_t; /**< In microseconds */ +typedef unsigned int pcilib_irq_hw_source_t; +typedef uint32_t pcilib_irq_source_t; + +typedef enum { + PCILIB_HOST_ENDIAN = 0, + PCILIB_LITTLE_ENDIAN, + PCILIB_BIG_ENDIAN +} pcilib_endianess_t; + +typedef enum { + PCILIB_DMA_IRQ = 1, + PCILIB_EVENT_IRQ = 2 +} pcilib_irq_type_t; + +typedef enum { /**< 0x8000 and up are reserved for driver-specific types */ + PCILIB_EVENT_DATA = 0, /**< default data format */ + PCILIB_EVENT_RAW_DATA = 1 /**< raw data */ +} pcilib_event_data_type_t; + +typedef enum { + PCILIB_DMA_TO_DEVICE = 1, + PCILIB_DMA_FROM_DEVICE = 2, + PCILIB_DMA_BIDIRECTIONAL = 3 +} pcilib_dma_direction_t; + +typedef enum { + PCILIB_DMA_FLAGS_DEFAULT = 0, + PCILIB_DMA_FLAG_EOP = 1, /**< last buffer of the packet */ + PCILIB_DMA_FLAG_WAIT = 2, /**< wait completion of write operation / wait for data during read operation */ + PCILIB_DMA_FLAG_MULTIPACKET = 4, /**< read multiple packets */ + PCILIB_DMA_FLAG_PERSISTENT = 8, /**< do not stop DMA engine on application termination / permanently close DMA engine on dma_stop */ + PCILIB_DMA_FLAG_IGNORE_ERRORS = 16 /**< do not crash on errors, but return appropriate error codes */ +} pcilib_dma_flags_t; + +typedef enum { + PCILIB_EVENT_FLAGS_DEFAULT = 0, + PCILIB_EVENT_FLAG_RAW_DATA_ONLY = 1, /**< Do not parse data, just read raw and pass it to rawdata callback. If passed to rawdata callback, idicates the data is not identified as event (most probably just padding) */ + PCILIB_EVENT_FLAG_STOP_ONLY = 1, /**< Do not cleanup, just stop acquiring new frames, the cleanup should be requested afterwards */ + PCILIB_EVENT_FLAG_EOF = 2, /**< Indicates that it is the last part of the frame (not required) */ + PCILIB_EVENT_FLAG_PREPROCESS = 4 /**< Enables preprocessing of the raw data (decoding frames, etc.) */ +} pcilib_event_flags_t; + +typedef enum { + PCILIB_EVENT_INFO_FLAG_BROKEN = 1 /**< Indicates broken frames (if this flag is fales, the frame still can be broken) */ +} pcilib_event_info_flags_t; + +typedef struct { + pcilib_event_t type; + uint64_t seqnum; /**< we will add seqnum_overflow if required */ + uint64_t offset; /**< nanoseconds */ + struct timeval timestamp; /**< most accurate timestamp */ + pcilib_event_info_flags_t flags; /**< flags */ +} pcilib_event_info_t; + + +#define PCILIB_BAR_DETECT ((pcilib_bar_t)-1) +#define PCILIB_BAR_INVALID ((pcilib_bar_t)-1) +#define PCILIB_BAR0 0 +#define PCILIB_BAR1 1 +#define PCILIB_DMA_ENGINE_INVALID ((pcilib_dma_engine_t)-1) +#define PCILIB_DMA_ENGINE_ALL ((pcilib_dma_engine_t)-1) +#define PCILIB_DMA_FLAGS_DEFAULT ((pcilib_dma_flags_t)0) +#define PCILIB_DMA_ENGINE_ADDR_INVALID ((pcilib_dma_engine_addr_t)-1) +#define PCILIB_REGISTER_INVALID ((pcilib_register_t)-1) +#define PCILIB_ADDRESS_INVALID ((uintptr_t)-1) +#define PCILIB_EVENT0 1 +#define PCILIB_EVENT1 2 +#define PCILIB_EVENT2 4 +#define PCILIB_EVENT3 8 +#define PCILIB_EVENTS_ALL ((pcilib_event_t)-1) +#define PCILIB_EVENT_INVALID ((pcilib_event_t)-1) +#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 +#define PCILIB_MODEL_DETECT NULL + + +/**< + * Callback function called when new data is read by DMA streaming function + * @ctx - DMA Engine context + * @flags - DMA Flags + * @bufsize - size of data in bytes + * @buf - data + * @returns + * <0 - error, stop streaming (the value is negative error code) + * 0 - stop streaming (PCILIB_STREAMING_STOP) + * 1 - wait DMA timeout and return gracefuly if no data (PCILIB_STREAMING_CONTINUE) + * 2 - wait the specified timeout and return gracefuly if no data (PCILIB_STREAMING_WAIT) + * 3 - check if more data is available without waiting, return gracefuly if not (PCILIB_STREAMING_CHECK) + * 5 - wait DMA timeout and fail if no data (PCILIB_STREAMING_REQ_FRAGMENT) + * 6 - wait the specified timeout and fail if no data (PCILIB_STREAMING_REQ_PACKET) + */ +typedef int (*pcilib_dma_callback_t)(void *ctx, pcilib_dma_flags_t flags, size_t bufsize, void *buf); +typedef int (*pcilib_event_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user); +typedef int (*pcilib_event_rawdata_callback_t)(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user); + + + +int pcilib_set_error_handler(void (*err)(const char *msg, ...), void (*warn)(const char *msg, ...)); + +pcilib_t *pcilib_open(const char *device, const char *model); +void pcilib_close(pcilib_t *ctx); + +int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); +int pcilib_stop_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags); + + // Interrupt API is preliminary and can be significantly changed in future +int pcilib_enable_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_dma_flags_t flags); +int pcilib_acknowledge_irq(pcilib_t *ctx, pcilib_irq_type_t irq_type, pcilib_irq_source_t irq_source); +int pcilib_disable_irq(pcilib_t *ctx, pcilib_dma_flags_t flags); + +int pcilib_wait_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source, pcilib_timeout_t timeout, size_t *count); +int pcilib_clear_irq(pcilib_t *ctx, pcilib_irq_hw_source_t source); + +void *pcilib_map_bar(pcilib_t *ctx, pcilib_bar_t bar); +void pcilib_unmap_bar(pcilib_t *ctx, pcilib_bar_t bar, void *data); +char *pcilib_resolve_register_address(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr); // addr is offset if bar is specified +char *pcilib_resolve_data_space(pcilib_t *ctx, uintptr_t addr, size_t *size); + +pcilib_register_t pcilib_find_register(pcilib_t *ctx, const char *bank, const char *reg); +pcilib_event_t pcilib_find_event(pcilib_t *ctx, const char *event); +pcilib_event_data_type_t pcilib_find_event_data_type(pcilib_t *ctx, pcilib_event_t event, const char *data_type); +pcilib_dma_engine_t pcilib_find_dma_by_addr(pcilib_t *ctx, pcilib_dma_direction_t direction, pcilib_dma_engine_addr_t dma); + +int pcilib_read(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf); +int pcilib_write(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, size_t size, void *buf); +int pcilib_write_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf); +int pcilib_read_fifo(pcilib_t *ctx, pcilib_bar_t bar, uintptr_t addr, uint8_t fifo_size, size_t n, void *buf); + +int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma); +int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, pcilib_dma_callback_t cb, void *cbattr); +int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *written_bytes); +int pcilib_read_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *read_bytes); +int pcilib_read_dma_custom(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, pcilib_dma_flags_t flags, pcilib_timeout_t timeout, void *buf, size_t *read_bytes); +int pcilib_write_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size_t size, void *buf, size_t *written_bytes); +double pcilib_benchmark_dma(pcilib_t *ctx, pcilib_dma_engine_addr_t dma, uintptr_t addr, size_t size, size_t iterations, pcilib_dma_direction_t direction); + +int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf); +int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf); +int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value); +int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value); +int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value); +int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value); + +int pcilib_reset(pcilib_t *ctx); +int pcilib_trigger(pcilib_t *ctx, pcilib_event_t event, size_t trigger_size, void *trigger_data); + +/* + * The recording of new events will be stopped after reaching max_events records + * or when the specified amount of time is elapsed. However, the @pcilib_stop + * function should be called still. + * NOTE: This options may not be respected if the PCILIB_EVENT_FLAG_RAW_DATA_ONLY + * is specified. + */ +int pcilib_configure_autostop(pcilib_t *ctx, size_t max_events, pcilib_timeout_t duration); + +/* + * Request auto-triggering while grabbing + */ +int pcilib_configure_autotrigger(pcilib_t *ctx, pcilib_timeout_t interval, pcilib_event_t event, size_t trigger_size, void *trigger_data); +/* + * Request streaming the rawdata from the event engine. It is fastest way to acuqire data. + * No memory copies will be performed and DMA buffers will be directly passed to the user + * callback. However, to prevent data loss, no processing should be done on the data. The + * user callback is only expected to copy data into the appropriate place and return control + * to the event engine. + * The performance can be boosted further by disabling any data processing within the event + * engine. Just pass PCILIB_EVENT_FLAG_RAW_DATA_ONLY flag to the @pcilib_start function. + */ +int pcilib_configure_rawdata_callback(pcilib_t *ctx, pcilib_event_rawdata_callback_t callback, void *user); + +/* + * Configures maximal number of preprocessing threads. Actual amount of threads + * may be bigger. For instance, additionaly a real-time reader thread will be + * executed for most of hardware + */ +int pcilib_configure_preprocessing_threads(pcilib_t *ctx, size_t max_threads); + + +int pcilib_start(pcilib_t *ctx, pcilib_event_t event_mask, pcilib_event_flags_t flags); +int pcilib_stop(pcilib_t *ctx, pcilib_event_flags_t flags); + +int pcilib_stream(pcilib_t *ctx, pcilib_event_callback_t callback, void *user); +int pcilib_get_next_event(pcilib_t *ctx, pcilib_timeout_t timeout, pcilib_event_id_t *evid, size_t info_size, pcilib_event_info_t *info); + +int pcilib_copy_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t size, void *buf, size_t *retsize); +int pcilib_copy_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t size, void *buf, size_t *retsize); +void *pcilib_get_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t *size_or_err); +void *pcilib_get_data_with_argument(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, size_t arg_size, void *arg, size_t *size_or_err); + +/* + * This function is provided to find potentially corrupted data. If the data is overwritten by + * the time return_data is called it will return error. + */ +int pcilib_return_data(pcilib_t *ctx, pcilib_event_id_t event_id, pcilib_event_data_type_t data_type, void *data); + +/* + * @param data - will be allocated and shuld be freed if NULL, otherwise used and size should contain correct size. + * In case of failure the content of data is undefined. + * @param timeout - will be autotriggered if NULL + */ +int pcilib_grab(pcilib_t *ctx, pcilib_event_t event_mask, size_t *size, void **data, pcilib_timeout_t timeout); + +#endif /* _PCITOOL_PCILIB_H */ diff --git a/pcilib/register.c b/pcilib/register.c new file mode 100644 index 0000000..8d138b8 --- /dev/null +++ b/pcilib/register.c @@ -0,0 +1,290 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "bank.h" + +#include "tools.h" +#include "error.h" + + +int pcilib_add_registers(pcilib_t *ctx, size_t n, const pcilib_register_description_t *registers) { + // DS: What we are doing if register exists? + + pcilib_register_description_t *regs; + size_t size; + + if (!n) { + for (n = 0; registers[n].bits; n++); + } + + if ((ctx->num_reg + n + 1) > ctx->alloc_reg) { + for (size = ctx->alloc_reg; size < 2 * (n + ctx->num_reg + 1); size<<=1); + + regs = (pcilib_register_description_t*)realloc(ctx->registers, size * sizeof(pcilib_register_description_t)); + if (!regs) return PCILIB_ERROR_MEMORY; + + ctx->registers = regs; + ctx->model_info.registers = regs; + ctx->alloc_reg = size; + } + + memcpy(ctx->registers + ctx->num_reg, registers, n * sizeof(pcilib_register_description_t)); + memset(ctx->registers + ctx->num_reg + n, 0, sizeof(pcilib_register_description_t)); + ctx->num_reg += n; + + return 0; +} + + +static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) { + int err; + size_t i; + + pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; + const pcilib_register_protocol_api_description_t *bapi = bctx->api; + const pcilib_register_bank_description_t *b = bctx->bank; + + int access = b->access / 8; + + assert(bits < 8 * sizeof(pcilib_register_value_t)); + + if (!bapi->read) { + pcilib_error("Used register protocol does not define a way to read register value"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { + if ((b->format)&&(strchr(b->format, 'x'))) + pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + else + pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + return PCILIB_ERROR_OUTOFRANGE; + } + + //err = pcilib_init_register_banks(ctx); + //if (err) return err; + + //n += bits / b->access; + //bits %= b->access; + + for (i = 0; i < n; i++) { + err = bapi->read(ctx, bctx, addr + i * access, buf + i); + if (err) break; + } + + if ((bits > 0)&&(!err)) { + pcilib_register_value_t val = 0; + err = bapi->read(ctx, bctx, addr + n * access, &val); + + val = (val >> offset)&BIT_MASK(bits); + memcpy(buf + n, &val, sizeof(pcilib_register_value_t)); + } + + return err; +} + +int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) { + pcilib_register_bank_t bank_id = pcilib_find_register_bank(ctx, bank); + if (bank_id == PCILIB_REGISTER_BANK_INVALID) { + if (bank) pcilib_error("Invalid register bank is specified (%s)", bank); + else pcilib_error("Register bank should be specified"); + return PCILIB_ERROR_INVALID_BANK; + } + + return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, 0, buf); +} + +int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) { + int err; + size_t i, n; + pcilib_register_size_t bits; + pcilib_register_value_t res; + pcilib_register_bank_t bank; + const pcilib_register_description_t *r; + const pcilib_register_bank_description_t *b; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + r = model_info->registers + reg; + + bank = pcilib_find_register_bank_by_addr(ctx, r->bank); + if (bank == PCILIB_REGISTER_BANK_INVALID) return PCILIB_ERROR_INVALID_BANK; + + b = model_info->banks + bank; + + n = r->bits / b->access; + bits = r->bits % b->access; + + pcilib_register_value_t buf[n + 1]; + err = pcilib_read_register_space_internal(ctx, bank, r->addr, n, r->offset, bits, buf); + + if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) { + pcilib_error("Big-endian byte order support is not implemented"); + return PCILIB_ERROR_NOTSUPPORTED; + } else { + res = 0; + if (bits) ++n; + for (i = 0; i < n; i++) { + res |= buf[i] << (i * b->access); + } + } + + *value = res; + + return err; +} + + +int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) { + int reg; + + reg = pcilib_find_register(ctx, bank, regname); + if (reg < 0) { + pcilib_error("Register (%s) is not found", regname); + return PCILIB_ERROR_NOTFOUND; + } + + return pcilib_read_register_by_id(ctx, reg, value); +} + + +static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t rwmask, pcilib_register_value_t *buf) { + int err; + size_t i; + + pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; + const pcilib_register_protocol_api_description_t *bapi = bctx->api; + const pcilib_register_bank_description_t *b = bctx->bank; + + int access = b->access / 8; + + assert(bits < 8 * sizeof(pcilib_register_value_t)); + + if (!bapi->write) { + pcilib_error("Used register protocol does not define a way to write value into the register"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { + if ((b->format)&&(strchr(b->format, 'x'))) + pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + else + pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); + return PCILIB_ERROR_OUTOFRANGE; + } + + //err = pcilib_init_register_banks(ctx); + //if (err) return err; + + //n += bits / b->access; + //bits %= b->access; + + for (i = 0; i < n; i++) { + err = bapi->write(ctx, bctx, addr + i * access, buf[i]); + if (err) break; + } + + if ((bits > 0)&&(!err)) { + pcilib_register_value_t val = (buf[n]&BIT_MASK(bits))<read) { + pcilib_error("Used register protocol does not define a way to read register. Therefore, it is only possible to write a full bank word, not partial as required by the accessed register"); + return PCILIB_ERROR_NOTSUPPORTED; + } + + err = bapi->read(ctx, bctx, addr + n * access, &rval); + if (err) return err; + + val |= (rval & rwmask & ~mask); + } + + err = bapi->write(ctx, bctx, addr + n * access, val); + } + + return err; +} + +int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) { + pcilib_register_bank_t bank_id = pcilib_find_register_bank(ctx, bank); + if (bank_id == PCILIB_REGISTER_BANK_INVALID) { + if (bank) pcilib_error("Invalid register bank is specified (%s)", bank); + else pcilib_error("Register bank should be specified"); + return PCILIB_ERROR_INVALID_BANK; + } + + return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, 0, 0, buf); +} + + +int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) { + int err; + size_t i, n; + pcilib_register_size_t bits; + pcilib_register_bank_t bank; + pcilib_register_value_t res; + const pcilib_register_description_t *r; + const pcilib_register_bank_description_t *b; + const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + + r = model_info->registers + reg; + + bank = pcilib_find_register_bank_by_addr(ctx, r->bank); + if (bank == PCILIB_REGISTER_BANK_INVALID) return PCILIB_ERROR_INVALID_BANK; + + b = model_info->banks + bank; + + n = r->bits / b->access; + bits = r->bits % b->access; + + pcilib_register_value_t buf[n + 1]; + memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t)); + + if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) { + pcilib_error("Big-endian byte order support is not implemented"); + return PCILIB_ERROR_NOTSUPPORTED; + } else { + if (b->access == sizeof(pcilib_register_value_t) * 8) { + buf[0] = value; + } else { + for (i = 0, res = value; (res > 0)&&(i <= n); ++i) { + buf[i] = res & BIT_MASK(b->access); + res >>= b->access; + } + + if (res) { + pcilib_error("Value %i is too big to fit in the register %s", value, r->name); + return PCILIB_ERROR_OUTOFRANGE; + } + } + } + + err = pcilib_write_register_space_internal(ctx, bank, r->addr, n, r->offset, bits, r->rwmask, buf); + return err; +} + +int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) { + int reg; + + reg = pcilib_find_register(ctx, bank, regname); + if (reg < 0) { + pcilib_error("Register (%s) is not found", regname); + return PCILIB_ERROR_NOTFOUND; + } + + return pcilib_write_register_by_id(ctx, reg, value); +} diff --git a/pcilib/register.h b/pcilib/register.h new file mode 100644 index 0000000..89673ec --- /dev/null +++ b/pcilib/register.h @@ -0,0 +1,51 @@ +#ifndef _PCILIB_REGISTER_H +#define _PCILIB_REGISTER_H + +#include +#include + +typedef enum { + PCILIB_REGISTER_R = 1, /**< reading from register is allowed */ + PCILIB_REGISTER_W = 2, /**< normal writting to register is allowed */ + PCILIB_REGISTER_RW = 3, + PCILIB_REGISTER_W1C = 4, /**< writting 1 resets the bit, writting 0 keeps the value */ + PCILIB_REGISTER_RW1C = 5, + PCILIB_REGISTER_W1I = 8, /**< writting 1 inversts the bit, writting 0 keeps the value */ + PCILIB_REGISTER_RW1I = 9, +} pcilib_register_mode_t; + +typedef enum { + PCILIB_REGISTER_STANDARD = 0, + PCILIB_REGISTER_FIFO, + PCILIB_REGISTER_BITS +} pcilib_register_type_t; + +typedef struct { + pcilib_register_addr_t addr; /**< Register address in the bank */ + pcilib_register_size_t offset; /**< Register offset in the byte (in bits) */ + pcilib_register_size_t bits; /**< Register size in bits */ + pcilib_register_value_t defvalue; /**< Default register value (some protocols, i.e. software registers, may set it during the initialization) */ + pcilib_register_value_t rwmask; /**< Used to define how external bits of PCILIB_REGISTER_BITS registers are treated. + To keep bit value unchanged, we need to observe the following behavior depending on status of corresponding bit in this field: + 1 - standard bit (i.e. if we want to keep the bit value we need to read it, and, the write back), + 0 - non-standard bit which behavior is defined by mode (only partially implemented. + so far only 1C/1I modes (zero should be written to preserve the value) are supported */ + pcilib_register_mode_t mode; /**< Register access (ro/wo/rw) and how writting to register works (if value just set as specified or, for instance, the bits which + are on in the value are cleared/inverted). For information only, no preprocessing on bits is performed. */ + pcilib_register_type_t type; /**< Defines type of register is it standard register, subregister for bit fields or view, fifo */ + pcilib_register_bank_addr_t bank; /**< Specified the address of the bank this register belongs to */ + + const char *name; /**< The access name of the register */ + const char *description; /**< Brief description of the register */ +} pcilib_register_description_t; + +/* +typedef struct { + pcilib_register_bank_t bank; +} pcilib_register_context_t; +*/ + +int pcilib_add_registers(pcilib_t *ctx, size_t n, const pcilib_register_description_t *registers); + + +#endif /* _PCILIB_REGISTER_H */ diff --git a/pcilib/tools.c b/pcilib/tools.c new file mode 100644 index 0000000..352127d --- /dev/null +++ b/pcilib/tools.c @@ -0,0 +1,355 @@ +#define _POSIX_C_SOURCE 200112L +#define _GNU_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "pci.h" +#include "tools.h" +#include "error.h" + +int pcilib_isnumber(const char *str) { + int i = 0; + for (i = 0; str[i]; i++) + if (!isdigit(str[i])) return 0; + return 1; +} + +int pcilib_isxnumber(const char *str) { + int i = 0; + + if ((str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) i += 2; + + for (; str[i]; i++) + if (!isxdigit(str[i])) return 0; + + return 1; +} + +int pcilib_isnumber_n(const char *str, size_t len) { + int i = 0; + for (i = 0; (str[i])&&(i < len); i++) + if (!isdigit(str[i])) return 0; + return 1; +} + +int pcilib_isxnumber_n(const char *str, size_t len) { + int i = 0; + + if ((len > 1)&&(str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) i += 2; + + for (; (str[i])&&(i < len); i++) + if (!isxdigit(str[i])) return 0; + + return 1; +} + + +uint16_t pcilib_swap16(uint16_t x) { + return (((x<<8)&0xFFFF) | ((x>>8)&0xFFFF)); +} + +uint32_t pcilib_swap32(uint32_t x) { + return ((x & 0xFF) << 24) | \ + ((x & 0xFF00) << 8) | \ + ((x & 0xFF0000) >> 8) | \ + ((x & 0xFF000000) >> 24); +} + +uint64_t pcilib_swap64(uint64_t x) { + return (((uint64_t)(x) << 56) | \ + (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ + (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ + (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ + (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ + (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ + (((uint64_t)(x) >> 40) & 0xff00ULL) | \ + ((uint64_t)(x) >> 56)); +} + +void pcilib_swap(void *dst, void *src, size_t size, size_t n) { + int i; + switch (size) { + case 1: + if (src != dst) memcpy(dst, src, n); + break; + case 2: + for (i = 0; i < n; i++) { + ((uint16_t*)dst)[i] = pcilib_swap16(((uint16_t*)src)[i]); + } + break; + case 4: + for (i = 0; i < n; i++) { + ((uint32_t*)dst)[i] = pcilib_swap32(((uint32_t*)src)[i]); + } + break; + case 8: + for (i = 0; i < n; i++) { + ((uint64_t*)dst)[i] = pcilib_swap64(((uint64_t*)src)[i]); + } + break; + default: + pcilib_error("Invalid word size: %i", size); + } +} + +void *pcilib_memcpy8(void * dst, void const * src, size_t len) { + int i; + for (i = 0; i < len; i++) ((char*)dst)[i] = ((char*)src)[i]; + return dst; +} + +void *pcilib_memcpy32(void * dst, void const * src, size_t len) { + uint32_t * plDst = (uint32_t *) dst; + uint32_t const * plSrc = (uint32_t const *) src; + + while (len >= 4) { +// *plDst = ntohl(*plSrc); + *plDst = *plSrc; + plSrc++; + plDst++; + len -= 4; + } + + char * pcDst = (char *) plDst; + char const * pcSrc = (char const *) plSrc; + + while (len--) { + *pcDst++ = *pcSrc++; + } + + return (dst); +} + + +void *pcilib_memcpy64(void * dst, void const * src, size_t len) { + uint64_t * plDst = (uint64_t *) dst; + uint64_t const * plSrc = (uint64_t const *) src; + + while (len >= 8) { + *plDst++ = *plSrc++; + len -= 8; + } + + char * pcDst = (char *) plDst; + char const * pcSrc = (char const *) plSrc; + + while (len--) { + *pcDst++ = *pcSrc++; + } + + return (dst); +} + +/* +void *memcpy128(void * dst, void const * src, size_t len) { + + long pos = - (len>>2); + char * plDst = (char *) dst - 4 * pos; + char const * plSrc = (char const *) src - 4 * pos; + + if (pos) { + __asm__ __volatile__ ( + "1: \n\t" + "mov (%0,%2,4), %%edi \n\t" + "mov %%edi, (%1,%2,4) \n\t" + "inc %2 \n\t" + "jnz 1b \n\t" + : + : "r" (plSrc), "r" (plDst), "r" (pos) + : "%edi" + ); + } + + + + long pos = - ((len>>4)<<4); + char * plDst = (char *) dst - pos; + char const * plSrc = (char const *) src - pos; + + if (pos) { + __asm__ __volatile__ ( + "1: \n\t" +// "movdqa (%0,%2), %%xmm0 \n\t" + "mov (%0,%2), %%esi \n\t" + "movd %%esi, %%xmm0 \n\t" + "mov 4(%0,%2), %%esi \n\t" + "movd %%esi, %%xmm1 \n\t" + "mov 8(%0,%2), %%esi \n\t" + "movd %%esi, %%xmm2 \n\t" + "mov 12(%0,%2), %%esi \n\t" + "movd %%esi, %%xmm3 \n\t" + "pslldq $4, %%xmm1 \n\t" + "por %%xmm1, %%xmm0 \n\t" + "pslldq $8, %%xmm2 \n\t" + "por %%xmm2, %%xmm0 \n\t" + "pslldq $12, %%xmm3 \n\t" + "por %%xmm3, %%xmm0 \n\t" + + "movntdq %%xmm0, (%1,%2) \n\t" + "add $16, %2 \n\t" + "jnz 1b \n\t" + : + : "r" (plSrc), "r" (plDst), "r" (pos) + : "%rsi" + ); + } + + + + len &= 0x3; + + char * pcDst = (char *) plDst; + char const * pcSrc = (char const *) plSrc; + + while (len--) { + *pcDst++ = *pcSrc++; + } + + return (dst); +} +*/ + +void *pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pcilib_endianess_t endianess) { + uint32_t * plDst = (uint32_t *) dst; + uint32_t const * plSrc = (uint32_t const *) src; + + int swap = 0; + + if (endianess) + swap = (endianess == PCILIB_BIG_ENDIAN)?(ntohs(1)!=1):(ntohs(1)==1); + + assert(size == 4); // only 32 bit at the moment + + if (swap) { + while (n > 0) { + *plDst = ntohl(*plSrc); + ++plSrc; + ++plDst; + --n; + } + } else { + while (n > 0) { + *plDst = *plSrc; + ++plSrc; + ++plDst; + --n; + } + } + + return dst; +} + +int pcilib_get_page_mask() { + int pagesize,pagemask,temp; + + pagesize = sysconf(_SC_PAGESIZE); + + for( pagemask=0, temp = pagesize; temp != 1; ) { + temp = (temp >> 1); + pagemask = (pagemask << 1)+1; + } + return pagemask; +} + +int pcilib_get_cpu_count() { + int err; + + int cpu_count; + cpu_set_t mask; + + err = sched_getaffinity(getpid(), sizeof(mask), &mask); + if (err) return 1; + +#ifdef CPU_COUNT + cpu_count = CPU_COUNT(&mask); +#else + for (cpu_count = 0; cpu_count < CPU_SETSIZE; cpu_count++) { + if (!CPU_ISSET(cpu_count, &mask)) break; + } +#endif + + if (!cpu_count) cpu_count = PCILIB_DEFAULT_CPU_COUNT; + return cpu_count; +} + + +int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout) { + tv->tv_usec += timeout%1000000; + if (tv->tv_usec > 999999) { + tv->tv_usec -= 1000000; + tv->tv_sec += 1 + timeout/1000000; + } else { + tv->tv_sec += timeout/1000000; + } + + return 0; +} + +int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) { + gettimeofday(tv, NULL); + pcilib_add_timeout(tv, timeout); + + return 0; +} + +int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout) { + int64_t res; + struct timeval tvs; + + if (!tve->tv_sec) return 0; + + gettimeofday(&tvs, NULL); + res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec)); + // Hm... Some problems comparing signed and unsigned. So, sign check first + if ((res < 0)||(res < timeout)) { + return 1; + } + + return 0; +} + +pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve) { + int64_t res; + struct timeval tvs; + + gettimeofday(&tvs, NULL); + res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec)); + + if (res < 0) return 0; + return res; +} + +int pcilib_sleep_until_deadline(struct timeval *tv) { + struct timespec wait; + pcilib_timeout_t duration; + + duration = pcilib_calc_time_to_deadline(tv); + if (duration > 0) { + wait.tv_sec = duration / 1000000; + wait.tv_nsec = 1000 * (duration % 1000000); + nanosleep(&wait, NULL); + } + + return 0; +} + +pcilib_timeout_t pcilib_timediff(struct timeval *tvs, struct timeval *tve) { + return ((tve->tv_sec - tvs->tv_sec)*1000000 + (tve->tv_usec - tvs->tv_usec)); +} + +int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2) { + if (tv1->tv_sec > tv2->tv_sec) return 1; + else if (tv1->tv_sec < tv2->tv_sec) return -1; + else if (tv1->tv_usec > tv2->tv_usec) return 1; + else if (tv1->tv_usec < tv2->tv_usec) return -1; + return 0; +} diff --git a/pcilib/tools.h b/pcilib/tools.h new file mode 100644 index 0000000..41dc071 --- /dev/null +++ b/pcilib/tools.h @@ -0,0 +1,44 @@ +#ifndef _PCITOOL_TOOLS_H +#define _PCITOOL_TOOLS_H + +#include +#include + +#include + +#define pcilib_memcpy pcilib_memcpy32 +#define pcilib_datacpy pcilib_datacpy32 + +#define BIT_MASK(bits) ((1ll << (bits)) - 1) + +#define min2(a, b) (((a)<(b))?(a):(b)) + + +int pcilib_isnumber(const char *str); +int pcilib_isxnumber(const char *str); +int pcilib_isnumber_n(const char *str, size_t len); +int pcilib_isxnumber_n(const char *str, size_t len); + +uint16_t pcilib_swap16(uint16_t x); +uint32_t pcilib_swap32(uint32_t x); +uint64_t pcilib_swap64(uint64_t x); +void pcilib_swap(void *dst, void *src, size_t size, size_t n); + +void * pcilib_memcpy8(void * dst, void const * src, size_t len); +void * pcilib_memcpy32(void * dst, void const * src, size_t len); +void * pcilib_memcpy64(void * dst, void const * src, size_t len); +void * pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pcilib_endianess_t endianess); + +int pcilib_get_page_mask(); +int pcilib_get_cpu_count(); + + +int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout); +int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout); +int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout); +pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve); +int pcilib_sleep_until_deadline(struct timeval *tv); +int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2); +pcilib_timeout_t pcilib_timediff(struct timeval *tve, struct timeval *tvs); + +#endif /* _PCITOOL_TOOS_H */ diff --git a/pcitool/CMakeLists.txt b/pcitool/CMakeLists.txt index 6dc7942..1b21041 100644 --- a/pcitool/CMakeLists.txt +++ b/pcitool/CMakeLists.txt @@ -1,8 +1,32 @@ include_directories( ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pcilib + ${FASTWRITER_INCLUDE_DIRS} ) -set(HEADERS ${HEADERS} sysinfo.h formaters.h) +link_directories( + ${FASTWRITER_LIBRARY_DIRS} + ${CMAKE_SOURCE_DIR}/pcilib +) + +if (NOT DISABLE_PCITOOL) + add_executable(pci cli.c sysinfo.c formaters.c) + set(HEADERS ${HEADERS} sysinfo.h formaters.h) + add_dependencies(pci pcitool) + target_link_libraries(pci pcilib ${FASTWRITER_LIBRARIES}) + set_target_properties(pci PROPERTIES + LINK_FLAGS ${CMAKE_THREAD_LIBS_INIT} + ) + +#set_target_properties(pci PROPERTIES +# LINK_FLAGS "-Wl,pcitool/libpcitool.a" +#) -add_library(pcitool STATIC sysinfo.c formaters.c) + if(NOT DEFINED BIN_INSTALL_DIR) + set(BIN_INSTALL_DIR "${CMAKE_INSTALL_PREFIX}/bin") + endif(NOT DEFINED BIN_INSTALL_DIR) + install(TARGETS pci + DESTINATION ${BIN_INSTALL_DIR} + ) +endif (NOT DISABLE_PCITOOL) diff --git a/pcitool/cli.c b/pcitool/cli.c new file mode 100644 index 0000000..a5c4290 --- /dev/null +++ b/pcitool/cli.c @@ -0,0 +1,3110 @@ +#define _POSIX_C_SOURCE 200112L +#define _BSD_SOURCE + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "pcitool/sysinfo.h" +#include "pcitool/formaters.h" + +#include "pci.h" +#include "tools.h" +#include "kmem.h" +#include "error.h" +#include "model.h" + +/* defines */ +#define MAX_KBUF 14 +//#define BIGBUFSIZE (512*1024*1024) +#define BIGBUFSIZE (1024*1024) + + +#define DEFAULT_FPGA_DEVICE "/dev/fpga0" + +#define LINE_WIDTH 80 +#define SEPARATOR_WIDTH 2 +#define BLOCK_SEPARATOR_WIDTH 2 +#define BLOCK_SIZE 8 +#define BENCHMARK_ITERATIONS 128 +#define STATUS_MESSAGE_INTERVAL 5 /* seconds */ + + +#define isnumber pcilib_isnumber +#define isxnumber pcilib_isxnumber +#define isnumber_n pcilib_isnumber_n +#define isxnumber_n pcilib_isxnumber_n + +typedef uint8_t access_t; + +typedef enum { + GRAB_MODE_GRAB = 1, + GRAB_MODE_TRIGGER = 2 +} GRAB_MODE; + +typedef enum { + MODE_INVALID, + MODE_INFO, + MODE_LIST, + MODE_BENCHMARK, + MODE_READ, + MODE_READ_REGISTER, + MODE_WRITE, + MODE_WRITE_REGISTER, + MODE_RESET, + MODE_GRAB, + MODE_START_DMA, + MODE_STOP_DMA, + 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 +} MODE; + +typedef enum { + ACCESS_BAR, + ACCESS_DMA, + ACCESS_FIFO, + ACCESS_CONFIG +} ACCESS_MODE; + +typedef enum { + FLAG_MULTIPACKET = 1, + FLAG_WAIT = 2 +} FLAGS; + + +typedef enum { + FORMAT_DEFAULT = 0, + FORMAT_RAW, + FORMAT_HEADER, + FORMAT_RINGFS +} FORMAT; + +typedef enum { + PARTITION_UNKNOWN, + PARTITION_RAW, + PARTITION_EXT4, + PARTITION_NULL +} PARTITION; + +typedef enum { + OPT_DEVICE = 'd', + OPT_MODEL = 'm', + OPT_BAR = 'b', + OPT_ACCESS = 'a', + OPT_ENDIANESS = 'e', + OPT_SIZE = 's', + OPT_OUTPUT = 'o', + OPT_TIMEOUT = 't', + OPT_INFO = 'i', + OPT_LIST = 'l', + OPT_READ = 'r', + OPT_WRITE = 'w', + OPT_GRAB = 'g', + OPT_QUIETE = 'q', + OPT_HELP = 'h', + OPT_RESET = 128, + OPT_BENCHMARK, + OPT_TRIGGER, + OPT_DATA_TYPE, + OPT_EVENT, + OPT_TRIGGER_RATE, + OPT_TRIGGER_TIME, + OPT_RUN_TIME, + OPT_FORMAT, + OPT_BUFFER, + OPT_THREADS, + OPT_LIST_DMA, + OPT_LIST_DMA_BUFFERS, + 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 +} OPTIONS; + +static struct option long_options[] = { + {"device", required_argument, 0, OPT_DEVICE }, + {"model", required_argument, 0, OPT_MODEL }, + {"bar", required_argument, 0, OPT_BAR }, + {"access", required_argument, 0, OPT_ACCESS }, + {"endianess", required_argument, 0, OPT_ENDIANESS }, + {"size", required_argument, 0, OPT_SIZE }, + {"output", required_argument, 0, OPT_OUTPUT }, + {"timeout", required_argument, 0, OPT_TIMEOUT }, + {"iterations", required_argument, 0, OPT_ITERATIONS }, + {"info", no_argument, 0, OPT_INFO }, + {"list", no_argument, 0, OPT_LIST }, + {"reset", no_argument, 0, OPT_RESET }, + {"benchmark", optional_argument, 0, OPT_BENCHMARK }, + {"read", optional_argument, 0, OPT_READ }, + {"write", optional_argument, 0, OPT_WRITE }, + {"grab", optional_argument, 0, OPT_GRAB }, + {"trigger", optional_argument, 0, OPT_TRIGGER }, + {"data", required_argument, 0, OPT_DATA_TYPE }, + {"event", required_argument, 0, OPT_EVENT }, + {"run-time", required_argument, 0, OPT_RUN_TIME }, + {"trigger-rate", required_argument, 0, OPT_TRIGGER_RATE }, + {"trigger-time", required_argument, 0, OPT_TRIGGER_TIME }, + {"format", required_argument, 0, OPT_FORMAT }, + {"buffer", optional_argument, 0, OPT_BUFFER }, + {"threads", optional_argument, 0, OPT_THREADS }, + {"start-dma", required_argument, 0, OPT_START_DMA }, + {"stop-dma", optional_argument, 0, OPT_STOP_DMA }, + {"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", 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 }, + { 0, 0, 0, 0 } +}; + + +void Usage(int argc, char *argv[], const char *format, ...) { + if (format) { + va_list ap; + + va_start(ap, format); + printf("Error %i: ", errno); + vprintf(format, ap); + printf("\n"); + va_end(ap); + + printf("\n"); + } + + + printf( +"Usage:\n" +" %s [options] [hex data]\n" +" Modes:\n" +" -i - Device Info\n" +" -l[l] - List (detailed) Data Banks & Registers\n" +" -r - Read Data/Register\n" +" -w - Write Data/Register\n" +" --benchmark - Performance Evaluation\n" +" --reset - Reset board\n" +" --help - Help message\n" +"\n" +" Event Modes:\n" +" --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 - Clean IRQ queue\n" +" --wait-irq - Wait for IRQ\n" + +" DMA Modes:\n" +" --start-dma [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 - List buffers for specified DMA engine\n" +" --read-dma-buffer - Read the specified buffer\n" +"\n" +" Kernel Modes:\n" +" --list-kernel-memory [use] - List kernel buffers\n" +" --read-kernel-memory - Read the specified block of the kernel memory\n" +" block is specified as: use:block_number\n" +" --alloc-kernel-memory - Allocate kernel buffers (DANGEROUS)\n" +" --free-kernel-memory - 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" +"\n" +" Addressing:\n" +" -d - FPGA device (/dev/fpga0)\n" +" -m - Memory model (autodetected)\n" +" pci - Plain\n" +" ipecamera - IPE Camera\n" +" -b - PCI bar, Register bank, or DMA channel\n" +"\n" +" Options:\n" +" -s - Number of words (default: 1)\n" +" -a [fifo|dma|config] - Access type and bits per word (default: 32)\n" +" -e - Endianess Little/Big (default: host)\n" +" -o - Append output to file (default: stdout)\n" +" -t - Timeout in microseconds\n" +" --check - Verify write operations\n" +"\n" +" Event Options:\n" +" --event - Specifies event for trigger and grab modes\n" +" --data - Data type to request for the events\n" +" --run-time - Limit time to grab/trigger events\n" +" -t - Timeout to stop if no events triggered\n" +" --trigger-rate - Generate tps triggers per second\n" +" --trigger-time - Specifies delay between triggers (us)\n" +" -s - Number of events to grab and trigger\n" +" --format [type] - Specifies how event data should be stored\n" +" raw - Just write all events sequentially\n" +" add_header - Prefix events with 512 bit header:\n" +" event(64), data(64), nope(64), size(64)\n" +" seqnum(64), offset(64), timestamp(128)\n" +//" ringfs - Write to RingFS\n" +" --buffer [size] - Request data buffering, size in MB\n" +" --threads [num] - Allow multithreaded processing\n" +"\n" +" DMA Options:\n" +" --multipacket - Read multiple packets\n" +" --wait - Wait until data arrives\n" +"\n" +" Kernel Options:\n" +" --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 of kernel buffer in bytes (default: page)\n" +" -s - Number of buffers to allocate (default: 1)\n" +" --allignment - Buffer alignment (default: page)\n" +"\n" +" Information:\n" +" --verbose [level] - Announce details of ongoing operations\n" +" -q - Quiete mode (suppress warnings)\n" +"\n" +" Data:\n" +" Data can be specified as sequence of hexdecimal number or\n" +" a single value prefixed with '*'. In this case it will be\n" +" replicated the specified amount of times\n" +"\n\n", +argv[0]); + + exit(0); +} + +static int StopFlag = 0; + +static void signal_exit_handler(int signo) { + if (++StopFlag > 2) + exit(-1); +} + + +void Error(const char *format, ...) { + va_list ap; + + va_start(ap, format); + printf("Error %i: ", errno); + vprintf(format, ap); + if (errno) printf("\n errno: %s", strerror(errno)); + printf("\n\n"); + va_end(ap); + + exit(-1); +} + +void Silence(const char *format, ...) { +} + +void List(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, int details) { + int i,j; + const pcilib_register_bank_description_t *banks; + const pcilib_register_description_t *registers; + const pcilib_event_description_t *events; + const pcilib_event_data_type_description_t *types; + + const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); + const pcilib_dma_description_t *dma_info = pcilib_get_dma_description(handle); + + for (i = 0; i < PCILIB_MAX_BARS; i++) { + if (board_info->bar_length[i] > 0) { + printf(" BAR %d - ", i); + + switch ( board_info->bar_flags[i]&IORESOURCE_TYPE_BITS) { + case IORESOURCE_IO: printf(" IO"); break; + case IORESOURCE_MEM: printf("MEM"); break; + case IORESOURCE_IRQ: printf("IRQ"); break; + case IORESOURCE_DMA: printf("DMA"); break; + } + + if (board_info->bar_flags[i]&IORESOURCE_MEM_64) printf("64"); + else printf("32"); + + printf(", Start: 0x%08lx, Length: 0x%8lx, Flags: 0x%08lx\n", board_info->bar_start[i], board_info->bar_length[i], board_info->bar_flags[i] ); + } + } + printf("\n"); + + if ((dma_info)&&(dma_info->engines)) { + printf("DMA Engines: \n"); + for (i = 0; dma_info->engines[i].addr_bits; i++) { + const pcilib_dma_engine_description_t *engine = &dma_info->engines[i]; + printf(" DMA %2d ", engine->addr); + switch (engine->direction) { + case PCILIB_DMA_FROM_DEVICE: + printf("C2S"); + break; + case PCILIB_DMA_TO_DEVICE: + printf("S2C"); + break; + case PCILIB_DMA_BIDIRECTIONAL: + printf("BI "); + break; + } + printf(" - Type: "); + switch (engine->type) { + case PCILIB_DMA_TYPE_BLOCK: + printf("Block"); + break; + case PCILIB_DMA_TYPE_PACKET: + printf("Packet"); + break; + default: + printf("Unknown"); + } + + printf(", Address Width: %02lu bits\n", engine->addr_bits); + } + printf("\n"); + } + + if ((bank)&&(bank != (char*)-1)) banks = NULL; + else banks = model_info->banks; + + if (banks) { + printf("Banks: \n"); + for (i = 0; banks[i].access; i++) { + printf(" 0x%02x %s", banks[i].addr, banks[i].name); + if ((banks[i].description)&&(banks[i].description[0])) { + printf(": %s", banks[i].description); + } + printf("\n"); + } + printf("\n"); + } + + if (bank == (char*)-1) registers = NULL; + else registers = model_info->registers; + + if (registers) { + pcilib_register_bank_addr_t bank_addr = 0; + if (bank) { + pcilib_register_bank_t bank_id = pcilib_find_register_bank(handle, bank); + const pcilib_register_bank_description_t *b = model_info->banks + bank_id; + + bank_addr = b->addr; + if (b->description) printf("%s:\n", b->description); + else if (b->name) printf("Registers of bank %s:\n", b->name); + else printf("Registers of bank 0x%x:\n", b->addr); + } else { + printf("Registers: \n"); + } + for (i = 0; registers[i].bits; i++) { + const char *mode; + + if ((bank)&&(registers[i].bank != bank_addr)) continue; + if (registers[i].type == PCILIB_REGISTER_BITS) { + if (!details) continue; + + if (registers[i].bits > 1) { + printf(" [%2u:%2u] - %s\n", registers[i].offset, registers[i].offset + registers[i].bits, registers[i].name); + } else { + printf(" [ %2u] - %s\n", registers[i].offset, registers[i].name); + } + + continue; + } + + if (registers[i].mode == PCILIB_REGISTER_RW) mode = "RW"; + else if (registers[i].mode == PCILIB_REGISTER_R) mode = "R "; + else if (registers[i].mode == PCILIB_REGISTER_W) mode = " W"; + else mode = " "; + + printf(" 0x%02x (%2i %s) %s", registers[i].addr, registers[i].bits, mode, registers[i].name); + if ((details > 0)&&(registers[i].description)&&(registers[i].description[0])) { + printf(": %s", registers[i].description); + } + printf("\n"); + + } + printf("\n"); + } + + if (bank == (char*)-1) events = NULL; + else { + events = model_info->events; + types = model_info->data_types; + } + + if (events) { + printf("Events: \n"); + for (i = 0; events[i].name; i++) { + printf(" %s", events[i].name); + if ((events[i].description)&&(events[i].description[0])) { + printf(": %s", events[i].description); + } + + if (types) { + for (j = 0; types[j].name; j++) { + if (types[j].evid & events[i].evid) { + printf("\n %s", types[j].name); + if ((types[j].description)&&(types[j].description[0])) { + printf(": %s", types[j].description); + } + } + } + } + } + printf("\n"); + } +} + +void Info(pcilib_t *handle, const pcilib_model_description_t *model_info) { + const pcilib_board_info_t *board_info = pcilib_get_board_info(handle); + + 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); +} + + +#define BENCH_MAX_DMA_SIZE 4 * 1024 * 1024 +#define BENCH_MAX_FIFO_SIZE 1024 * 1024 + +int Benchmark(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, size_t iterations) { + int err; + int i, j, errors; + void *data, *buf, *check; + void *fifo = NULL; + struct timeval start, end; + unsigned long time; + size_t size, min_size, max_size; + double mbs_in, mbs_out, mbs; + 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) { + min_size = n * access; + max_size = n * access; + } else { + min_size = 1024; + max_size = BENCH_MAX_DMA_SIZE; + } + + for (size = min_size; size <= max_size; size *= 4) { + mbs_in = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_FROM_DEVICE); + mbs_out = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_TO_DEVICE); + mbs = pcilib_benchmark_dma(handle, dma, addr, size, iterations, PCILIB_DMA_BIDIRECTIONAL); + err = pcilib_wait_irq(handle, 0, 0, &irqs); + if (err) irqs = 0; + + printf("%8zu KB - ", size / 1024); + + printf("RW: "); + if (mbs < 0) printf("failed ... "); + else printf("%8.2lf MB/s", mbs); + + printf(", R: "); + if (mbs_in < 0) printf("failed ... "); + else printf("%8.2lf MB/s", mbs_in); + + printf(", W: "); + if (mbs_out < 0) printf("failed ... "); + else printf("%8.2lf MB/s", mbs_out); + + if (irqs) { + printf(", IRQs: %lu", irqs); + } + + printf("\n"); + } + + return 0; + } + + if (bar == PCILIB_BAR_INVALID) { + unsigned long maxlength = 0; + + + for (i = 0; i < PCILIB_MAX_REGISTER_BANKS; i++) { + if ((addr >= board_info->bar_start[i])&&((board_info->bar_start[i] + board_info->bar_length[i]) >= (addr + access))) { + bar = i; + break; + } + + if (board_info->bar_length[i] > maxlength) { + maxlength = board_info->bar_length[i]; + bar = i; + } + } + + if (bar < 0) Error("Data banks are not available"); + } + + if (n) { + if ((mode == ACCESS_BAR)&&(n * access > board_info->bar_length[bar])) Error("The specified size (%i) exceeds the size of bar (%i)", n * access, board_info->bar_length[bar]); + + min_size = n * access; + max_size = n * access; + } else { + min_size = access; + if (mode == ACCESS_BAR) max_size = board_info->bar_length[bar]; + else max_size = BENCH_MAX_FIFO_SIZE; + } + + err = posix_memalign( (void**)&buf, 256, max_size ); + if (!err) err = posix_memalign( (void**)&check, 256, max_size ); + if ((err)||(!buf)||(!check)) Error("Allocation of %i bytes of memory have failed", max_size); + + data = pcilib_map_bar(handle, bar); + if (!data) Error("Can't map bar %i", bar); + + if (mode == ACCESS_FIFO) { + fifo = data + (addr - board_info->bar_start[bar]) + (board_info->bar_start[bar] & pcilib_get_page_mask()); +// pcilib_resolve_register_address(handle, bar, addr); + if (!fifo) Error("Can't resolve address (%lx) in bar (%u)", addr, bar); + } + + if (mode == ACCESS_FIFO) + printf("Transfer time (Bank: %i, Fifo: %lx):\n", bar, addr); + else + printf("Transfer time (Bank: %i):\n", bar); + + for (size = min_size ; size < max_size; size *= 8) { + gettimeofday(&start,NULL); + if (mode == ACCESS_BAR) { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_memcpy(buf, data, size); + } + } else { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + for (j = 0; j < (size/access); j++) { + pcilib_memcpy(buf + j * access, fifo, access); + } + } + } + gettimeofday(&end,NULL); + + time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); + printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + + fflush(0); + + gettimeofday(&start,NULL); + if (mode == ACCESS_BAR) { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_memcpy(data, buf, size); + } + } else { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + for (j = 0; j < (size/access); j++) { + pcilib_memcpy(fifo, buf + j * access, access); + } + } + } + gettimeofday(&end,NULL); + + time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); + printf(", write: %8.2lf MB/s\n", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + } + + pcilib_unmap_bar(handle, bar, data); + + printf("\n\nOpen-Transfer-Close time: \n"); + + for (size = 4 ; size < max_size; size *= 8) { + gettimeofday(&start,NULL); + if (mode == ACCESS_BAR) { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_read(handle, bar, 0, size, buf); + } + } else { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_read_fifo(handle, bar, addr, access, size / access, buf); + } + } + gettimeofday(&end,NULL); + + time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); + printf("%8zu bytes - read: %8.2lf MB/s", size, 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + + fflush(0); + + gettimeofday(&start,NULL); + if (mode == ACCESS_BAR) { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_write(handle, bar, 0, size, buf); + } + } else { + for (i = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_write_fifo(handle, bar, addr, access, size / access, buf); + } + } + + gettimeofday(&end,NULL); + + time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); + printf(", write: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + + if (mode == ACCESS_BAR) { + gettimeofday(&start,NULL); + for (i = 0, errors = 0; i < BENCHMARK_ITERATIONS; i++) { + pcilib_write(handle, bar, 0, size, buf); + pcilib_read(handle, bar, 0, size, check); + if (memcmp(buf, check, size)) ++errors; + } + gettimeofday(&end,NULL); + + time = (end.tv_sec - start.tv_sec)*1000000 + (end.tv_usec - start.tv_usec); + printf(", write-verify: %8.2lf MB/s", 1000000. * size * BENCHMARK_ITERATIONS / (time * 1024. * 1024.)); + if (errors) printf(", errors: %u of %u", errors, BENCHMARK_ITERATIONS); + } + printf("\n"); + } + + printf("\n\n"); + + free(check); + free(buf); + + return 0; +} + +#define pci2host16(endianess, value) endianess? + +/* +typedef struct { + size_t size; + void *data; + size_t pos; + + int multi_mode; +} DMACallbackContext; + +static int DMACallback(void *arg, pcilib_dma_flags_t flags, size_t bufsize, void *buf) { + DMACallbackContext *ctx = (DMACallbackContext*)arg; + + if ((ctx->pos + bufsize > ctx->size)||(!ctx->data)) { + ctx->size *= 2; + ctx->data = realloc(ctx->data, ctx->size); + if (!ctx->data) { + Error("Allocation of %i bytes of memory have failed", ctx->size); + return 0; + } + } + + memcpy(ctx->data + ctx->pos, buf, bufsize); + ctx->pos += bufsize; + + if (flags & PCILIB_DMA_FLAG_EOP) return 0; + return 1; +} +*/ + + +int ReadData(pcilib_t *handle, ACCESS_MODE mode, FLAGS flags, pcilib_dma_engine_addr_t dma, pcilib_bar_t bar, uintptr_t addr, size_t n, access_t access, int endianess, size_t timeout, FILE *o) { + void *buf; + int i, err; + size_t ret, bytes; + size_t size = n * abs(access); + int block_width, blocks_per_line; + 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); + blocks_per_line = (LINE_WIDTH - 10) / (block_width + BLOCK_SEPARATOR_WIDTH); + if ((blocks_per_line > 1)&&(blocks_per_line % 2)) --blocks_per_line; + numbers_per_line = blocks_per_line * numbers_per_block; + + if (size) { + buf = malloc(size); + if (!buf) Error("Allocation of %zu bytes of memory has failed", size); + } else { + buf = NULL; + } + + switch (mode) { + case ACCESS_DMA: + if (timeout == (size_t)-1) timeout = PCILIB_DMA_TIMEOUT; + + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); + + if (flags&FLAG_MULTIPACKET) dma_flags |= PCILIB_DMA_FLAG_MULTIPACKET; + if (flags&FLAG_WAIT) dma_flags |= PCILIB_DMA_FLAG_WAIT; + + if (size) { + err = pcilib_read_dma_custom(handle, dmaid, addr, size, dma_flags, timeout, buf, &bytes); + if (err) Error("Error (%i) is reported by DMA engine", err); + } else { + dma_flags |= PCILIB_DMA_FLAG_IGNORE_ERRORS; + + size = 2048; bytes = 0; + do { + size *= 2; + buf = realloc(buf, size); + if (!buf) Error("Allocation of %zu bytes of memory has failed", size); + err = pcilib_read_dma_custom(handle, dmaid, addr, size - bytes, dma_flags, timeout, buf + bytes, &ret); + bytes += ret; + + if ((!err)&&(flags&FLAG_MULTIPACKET)) { + err = PCILIB_ERROR_TOOBIG; + if ((flags&FLAG_WAIT)==0) timeout = 0; + } + } while (err == PCILIB_ERROR_TOOBIG); + } + + if ((err)&&(err != PCILIB_ERROR_TIMEOUT)) { + Error("Error (%i) during DMA read", err); + } + if (bytes <= 0) { + pcilib_warning("No data is returned by DMA engine"); + return 0; + } + size = bytes; + n = bytes / abs(access); + addr = 0; + break; + case ACCESS_FIFO: + 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); + } + + if (endianess) pcilib_swap(buf, buf, abs(access), n); + + if (o) { + printf("Writting output (%zu bytes) to file (append to the end)...\n", n * abs(access)); + fwrite(buf, abs(access), n, o); + } else { + for (i = 0; i < n; i++) { + if (i) { + if (i%numbers_per_line == 0) printf("\n"); + else { + printf("%*s", SEPARATOR_WIDTH, ""); + if (i%numbers_per_block == 0) printf("%*s", BLOCK_SEPARATOR_WIDTH, ""); + } + } + + if (i%numbers_per_line == 0) printf("%8lx: ", addr + i * abs(access)); + + switch (access) { + case 1: printf("%0*hhx", access * 2, ((uint8_t*)buf)[i]); break; + case 2: printf("%0*hx", access * 2, ((uint16_t*)buf)[i]); break; + case 4: printf("%0*x", access * 2, ((uint32_t*)buf)[i]); break; + case 8: printf("%0*lx", access * 2, ((uint64_t*)buf)[i]); break; + } + } + printf("\n\n"); + } + + + free(buf); + return 0; +} + + + + +int ReadRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg) { + int i; + int err; + const char *format; + + pcilib_register_bank_t bank_id; + pcilib_register_bank_addr_t bank_addr = 0; + + pcilib_register_value_t value; + + if (reg) { + pcilib_register_t regid = pcilib_find_register(handle, bank, reg); + bank_id = pcilib_find_register_bank_by_addr(handle, model_info->registers[regid].bank); + format = model_info->banks[bank_id].format; + if (!format) format = "%lu"; + + err = pcilib_read_register_by_id(handle, regid, &value); + // err = pcilib_read_register(handle, bank, reg, &value); + if (err) printf("Error reading register %s\n", reg); + else { + printf("%s = ", reg); + printf(format, value); + printf("\n"); + } + } else { + // Adding DMA registers + pcilib_get_dma_description(handle); + + if (model_info->registers) { + if (bank) { + bank_id = pcilib_find_register_bank(handle, bank); + bank_addr = model_info->banks[bank_id].addr; + } + + printf("Registers:\n"); + for (i = 0; model_info->registers[i].bits; i++) { + if ((model_info->registers[i].mode & PCILIB_REGISTER_R)&&((!bank)||(model_info->registers[i].bank == bank_addr))&&(model_info->registers[i].type != PCILIB_REGISTER_BITS)) { + bank_id = pcilib_find_register_bank_by_addr(handle, model_info->registers[i].bank); + format = model_info->banks[bank_id].format; + if (!format) format = "%lu"; + + err = pcilib_read_register_by_id(handle, i, &value); + if (err) printf(" %s = error reading value", model_info->registers[i].name); + else { + printf(" %s = ", model_info->registers[i].name); + printf(format, value); + } + + printf(" ["); + printf(format, model_info->registers[i].defvalue); + printf("]"); + printf("\n"); + } + } + } else { + printf("No registers"); + } + printf("\n"); + } + + return 0; +} + +#define WRITE_REGVAL(buf, n, access, o) {\ + uint##access##_t tbuf[n]; \ + for (i = 0; i < n; i++) { \ + tbuf[i] = (uint##access##_t)buf[i]; \ + } \ + fwrite(tbuf, access/8, n, o); \ +} + +int ReadRegisterRange(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, uintptr_t addr, long addr_shift, size_t n, FILE *o) { + int err; + int i; + + const pcilib_register_bank_description_t *banks = model_info->banks; + pcilib_register_bank_t bank_id = pcilib_find_register_bank(handle, bank); + + if (bank_id == PCILIB_REGISTER_BANK_INVALID) { + if (bank) Error("Invalid register bank is specified (%s)", bank); + else Error("Register bank should be specified"); + } + + int access = banks[bank_id].access / 8; +// int size = n * abs(access); + int block_width, blocks_per_line; + int numbers_per_block, numbers_per_line; + + numbers_per_block = BLOCK_SIZE / access; + + block_width = numbers_per_block * ((access * 2) + SEPARATOR_WIDTH); + blocks_per_line = (LINE_WIDTH - 6) / (block_width + BLOCK_SEPARATOR_WIDTH); + if ((blocks_per_line > 1)&&(blocks_per_line % 2)) --blocks_per_line; + numbers_per_line = blocks_per_line * numbers_per_block; + + + pcilib_register_value_t buf[n]; + err = pcilib_read_register_space(handle, bank, addr, n, buf); + if (err) Error("Error reading register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); + + + if (o) { + printf("Writting output (%zu bytes) to file (append to the end)...\n", n * abs(access)); + switch (access) { + case 1: WRITE_REGVAL(buf, n, 8, o) break; + case 2: WRITE_REGVAL(buf, n, 16, o) break; + case 4: WRITE_REGVAL(buf, n, 32, o) break; + case 8: WRITE_REGVAL(buf, n, 64, o) break; + } + } else { + for (i = 0; i < n; i++) { + if (i) { + if (i%numbers_per_line == 0) printf("\n"); + else { + printf("%*s", SEPARATOR_WIDTH, ""); + if (i%numbers_per_block == 0) printf("%*s", BLOCK_SEPARATOR_WIDTH, ""); + } + } + + if (i%numbers_per_line == 0) printf("%4lx: ", addr + 4 * i - addr_shift); + printf("%0*lx", access * 2, (unsigned long)buf[i]); + } + printf("\n\n"); + } + + 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 verify) { + int read_back = 0; + void *buf, *check; + int res = 0, i, err; + int size = n * abs(access); + 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); + + for (i = 0; i < n; i++) { + switch (access) { + case 1: res = sscanf(data[i], "%hhx", ((uint8_t*)buf)+i); break; + case 2: res = sscanf(data[i], "%hx", ((uint16_t*)buf)+i); break; + case 4: res = sscanf(data[i], "%x", ((uint32_t*)buf)+i); break; + case 8: res = sscanf(data[i], "%lx", ((uint64_t*)buf)+i); break; + default: Error("Unexpected data size (%lu)", access); + } + if ((res != 1)||(!isxnumber(data[i]))) Error("Can't parse data value at poition %i, (%s) is not valid hex number", i, data[i]); + } + + if (endianess) pcilib_swap(buf, buf, abs(access), n); + + switch (mode) { + case ACCESS_DMA: + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (%lu) is specified", dma); + err = pcilib_write_dma(handle, dmaid, addr, size, buf, &ret); + if ((err)||(ret != size)) { + if (err == PCILIB_ERROR_TIMEOUT) Error("Timeout writting the data to DMA"); + else if (err) Error("DMA engine returned a error while writing the data"); + else if (!ret) Error("No data is written by DMA engine"); + else Error("Only %lu bytes of %lu is written by DMA engine", ret, size); + } + break; + case ACCESS_FIFO: + pcilib_write_fifo(handle, bar, addr, access, n, buf); + break; + default: + pcilib_write(handle, bar, addr, size, buf); + if (verify) { + pcilib_read(handle, bar, addr, size, check); + read_back = 1; + } + } + + if ((read_back)&&(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, mode, 0, dma, bar, addr, n, access, endianess, (size_t)-1, NULL); + exit(-1); + } + + free(check); + free(buf); + + return 0; +} + +int WriteRegisterRange(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, uintptr_t addr, long addr_shift, size_t n, char ** data) { + pcilib_register_value_t *buf, *check; + int res, i, err; + unsigned long value; + int size = n * sizeof(pcilib_register_value_t); + + 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); + + for (i = 0; i < n; i++) { + res = sscanf(data[i], "%lx", &value); + if ((res != 1)||(!isxnumber(data[i]))) Error("Can't parse data value at poition %i, (%s) is not valid hex number", i, data[i]); + buf[i] = value; + } + + err = pcilib_write_register_space(handle, bank, addr, n, buf); + if (err) Error("Error writting register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); + + err = pcilib_read_register_space(handle, bank, addr, n, check); + if (err) Error("Error reading register space for bank \"%s\" at address %lx, size %lu", bank?bank:"default", addr, n); + + if (memcmp(buf, check, size)) { + printf("Write failed: the data written and read differ, the foolowing is read back:\n"); + ReadRegisterRange(handle, model_info, bank, addr, addr_shift, n, NULL); + exit(-1); + } + + free(check); + free(buf); + + return 0; + +} + +int WriteRegister(pcilib_t *handle, const pcilib_model_description_t *model_info, const char *bank, const char *reg, char ** data) { + int err; + + unsigned long val; + pcilib_register_value_t value; + + const char *format = NULL; + + pcilib_register_t regid = pcilib_find_register(handle, bank, reg); + if (regid == PCILIB_REGISTER_INVALID) Error("Can't find register (%s) from bank (%s)", reg, bank?bank:"autodetected"); + +/* + pcilib_register_bank_t bank_id; + pcilib_register_bank_addr_t bank_addr; + + bank_id = pcilib_find_bank_by_addr(handle, model_info->registers[regid].bank); + if (bank_id == PCILIB_REGISTER_BANK_INVALID) Error("Can't find bank of the register (%s)", reg); + format = model_info->banks[bank_id].format; + if (!format) format = "%lu"; +*/ + + if (isnumber(*data)) { + if (sscanf(*data, "%li", &val) != 1) { + Error("Can't parse data value (%s) is not valid decimal number", *data); + } + + format = "%li"; + } else if (isxnumber(*data)) { + if (sscanf(*data, "%lx", &val) != 1) { + Error("Can't parse data value (%s) is not valid decimal number", *data); + } + + format = "0x%lx"; + } else { + Error("Can't parse data value (%s) is not valid decimal number", *data); + } + + value = val; + + err = pcilib_write_register(handle, bank, reg, value); + if (err) Error("Error writting register %s\n", reg); + + if ((model_info->registers[regid].mode&PCILIB_REGISTER_RW) == PCILIB_REGISTER_RW) { + err = pcilib_read_register(handle, bank, reg, &value); + if (err) Error("Error reading back register %s for verification\n", reg); + + if (val != value) { + Error("Failed to write register %s: %lu is written and %lu is read back", reg, val, value); + } else { + printf("%s = ", reg); + printf(format, value); + printf("\n"); + } + } else { + printf("%s is written\n ", reg); + } + + return 0; +} + +typedef struct { + pcilib_t *handle; + pcilib_event_t event; + pcilib_event_data_type_t data; + + fastwriter_t *writer; + + int verbose; + pcilib_timeout_t timeout; + size_t run_time; + size_t trigger_time; + size_t max_triggers; + pcilib_event_flags_t flags; + FORMAT format; + + volatile int event_pending; /**< Used to detect that we have read previously triggered event */ + volatile int trigger_thread_started; /**< Indicates that trigger thread is ready and we can't procced to start event recording */ + volatile int started; /**< Indicates that recording is started */ + + volatile int run_flag; + volatile int writing_flag; + + struct timeval first_frame; + struct timeval last_frame; + size_t last_num; + + size_t trigger_failed; + size_t trigger_count; + size_t event_count; + size_t incomplete_count; + size_t broken_count; + size_t missing_count; + size_t storage_count; + + struct timeval start_time; + struct timeval stop_time; +} GRABContext; + +int GrabCallback(pcilib_event_id_t event_id, pcilib_event_info_t *info, void *user) { + int err = 0; + void *data; + size_t size; + + GRABContext *ctx = (GRABContext*)user; + pcilib_t *handle = ctx->handle; + + gettimeofday(&ctx->last_frame, NULL); + + if (!ctx->event_count) { + memcpy(&ctx->first_frame, &ctx->last_frame, sizeof(struct timeval)); + } + + ctx->event_pending = 0; + ctx->event_count++; + + ctx->missing_count += (info->seqnum - ctx->last_num) - 1; + ctx->last_num = info->seqnum; + + if (info->flags&PCILIB_EVENT_INFO_FLAG_BROKEN) { + ctx->incomplete_count++; + return PCILIB_STREAMING_CONTINUE; + } + + switch (ctx->format) { + case FORMAT_DEFAULT: + data = pcilib_get_data(handle, event_id, PCILIB_EVENT_DATA, &size); + break; + default: + data = pcilib_get_data(handle, event_id, PCILIB_EVENT_RAW_DATA, &size); + } + + if (!data) { + ctx->broken_count++; + return PCILIB_STREAMING_CONTINUE; + } + + if (ctx->format == FORMAT_HEADER) { + uint64_t header[8]; + header[0] = info->type; + header[1] = ctx->data; + header[2] = 0; + header[3] = size; + header[4] = info->seqnum; + header[5] = info->offset; + memcpy(header + 6, &info->timestamp, 16); + + err = fastwriter_push(ctx->writer, 64, header); + } + + if (!err) + err = fastwriter_push(ctx->writer, size, data); + + if (err) { + fastwriter_cancel(ctx->writer); + + if (err != EWOULDBLOCK) + Error("Storage error %i", err); + + ctx->storage_count++; + pcilib_return_data(handle, event_id, ctx->data, data); + return PCILIB_STREAMING_CONTINUE; + } + + err = pcilib_return_data(handle, event_id, ctx->data, data); + if (err) { + ctx->missing_count++; + fastwriter_cancel(ctx->writer); + return PCILIB_STREAMING_CONTINUE; + } + + err = fastwriter_commit(ctx->writer); + if (err) Error("Error commiting data to storage, Error: %i", err); + + return PCILIB_STREAMING_CONTINUE; +} + +int raw_data(pcilib_event_id_t event_id, pcilib_event_info_t *info, pcilib_event_flags_t flags, size_t size, void *data, void *user) { + int err; + + GRABContext *ctx = (GRABContext*)user; +// pcilib_t *handle = ctx->handle; + + + if ((info)&&(info->seqnum != ctx->last_num)) { + gettimeofday(&ctx->last_frame, NULL); + if (!ctx->event_count) { + memcpy(&ctx->first_frame, &ctx->last_frame, sizeof(struct timeval)); + } + + ctx->event_count++; + ctx->missing_count += (info->seqnum - ctx->last_num) - 1; + ctx->last_num = info->seqnum; + } + + err = fastwriter_push_data(ctx->writer, size, data); + if (err) { + if (err == EWOULDBLOCK) Error("Storage is not able to handle the data stream, buffer overrun"); + Error("Storage error %i", err); + } + + return PCILIB_STREAMING_CONTINUE; +} + + +void *Trigger(void *user) { + int err; + struct timeval start; + + GRABContext *ctx = (GRABContext*)user; + size_t trigger_time = ctx->trigger_time; + size_t max_triggers = ctx->max_triggers; + + ctx->trigger_thread_started = 1; + ctx->event_pending = 1; + + while (!ctx->started) ; + + gettimeofday(&start, NULL); + do { + err = pcilib_trigger(ctx->handle, ctx->event, 0, NULL); + if (err) ctx->trigger_failed++; + if ((++ctx->trigger_count == max_triggers)&&(max_triggers)) break; + + if (trigger_time) { + pcilib_add_timeout(&start, trigger_time); + if ((ctx->stop_time.tv_sec)&&(pcilib_timecmp(&start, &ctx->stop_time)>0)) break; + pcilib_sleep_until_deadline(&start); + } else { + while ((ctx->event_pending)&&(ctx->run_flag)) usleep(10); + ctx->event_pending = 1; + } + } while (ctx->run_flag); + + ctx->trigger_thread_started = 0; + + return NULL; +} + +void GrabStats(GRABContext *ctx, struct timeval *end_time) { + int verbose; + pcilib_timeout_t duration, fps_duration; + struct timeval cur; + double fps = 0, good_fps = 0; + size_t total, good, pending = 0; + + verbose = ctx->verbose; + + if (end_time) { + if (verbose++) { + printf("-------------------------------------------------------------------------------\n"); + } + } else { + gettimeofday(&cur, NULL); + end_time = &cur; + } + +// if ((ctx->event_count + ctx->missing_count) == 0) +// return; + + duration = pcilib_timediff(&ctx->start_time, end_time); + fps_duration = pcilib_timediff(&ctx->first_frame, &ctx->last_frame); + + if (ctx->trigger_count) { + total = ctx->trigger_count; + pending = ctx->trigger_count - ctx->event_count - ctx->missing_count - ctx->trigger_failed; + } else { + total = ctx->event_count + ctx->missing_count; + } + + good = ctx->event_count - ctx->broken_count - ctx->incomplete_count - ctx->storage_count; + + if (ctx->event_count > 1) { + fps = (ctx->event_count - 1) / (1.*fps_duration/1000000); + } + + if (good > 1) { + good_fps = (good - 1) / (1.*fps_duration/1000000); + } + + printf("Run: "); + PrintTime(duration); + + if (ctx->trigger_count) { + printf(", Triggers: "); + PrintNumber(ctx->trigger_count); + } + + printf(", Captured: "); + PrintNumber(ctx->event_count); + printf(" FPS %5.0lf", fps); + + if ((ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) == 0) { + printf(", Stored: "); + PrintNumber(good); + printf(" FPS %5.0lf", good_fps); + } + + printf("\n"); + + if (verbose > 2) { + if (ctx->trigger_count) { + printf("Trig: "); + PrintNumber(ctx->trigger_count); + printf(" Issued: "); + PrintNumber(ctx->trigger_count - ctx->trigger_failed); + printf(" ("); + PrintPercent(ctx->trigger_count - ctx->trigger_failed, ctx->trigger_count); + printf("%%) Failed: "); + PrintNumber(ctx->trigger_failed); + printf( " ("); + PrintPercent(ctx->trigger_failed, ctx->trigger_count); + printf( "%%); Pending: "); + PrintNumber(pending); + printf( " ("); + PrintPercent(pending, ctx->trigger_count); + printf( "%%)\n"); + } + + if (ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { + printf("Captured: "); + PrintNumber(good); + } else { + printf("Good: "); + PrintNumber(good); + printf(", Dropped: "); + PrintNumber(ctx->storage_count); + printf(", Bad: "); + PrintNumber(ctx->incomplete_count); + printf(", Empty: "); + PrintNumber(ctx->broken_count); + } + printf(", Lost: "); + PrintNumber(ctx->missing_count); + printf("\n"); + } + + if (verbose > 1) { + if (ctx->flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { + printf("Captured: "); + PrintPercent(good, total); + } else { + printf("Good: "); + PrintPercent(good, total); + printf("%% Dropped: "); + PrintPercent(ctx->storage_count, total); + printf("%% Bad: "); + PrintPercent(ctx->incomplete_count, total); + printf("%% Empty: "); + PrintPercent(ctx->broken_count, total); + } + + printf("%% Lost: "); + PrintPercent(ctx->missing_count, total); + printf("%%"); + printf("\n"); + } +} + +void StorageStats(GRABContext *ctx) { + int err; + fastwriter_stats_t st; + + pcilib_timeout_t duration; + struct timeval cur; + + gettimeofday(&cur, NULL); + duration = pcilib_timediff(&ctx->start_time, &cur); + + + err = fastwriter_get_stats(ctx->writer, &st); + if (err) return; + + printf("Wrote "); + PrintSize(st.written); + printf(" of "); + PrintSize(st.commited); + printf(" at "); + PrintSize(1000000.*st.written / duration); + printf("/s, %6.2lf%% ", 100.*st.buffer_used / st.buffer_size); + printf(" of "); + PrintSize(st.buffer_size); + printf(" buffer (%6.2lf%% max)\n", 100.*st.buffer_max / st.buffer_size); +} + +void *Monitor(void *user) { + struct timeval deadline; + struct timeval nextinfo; + + GRABContext *ctx = (GRABContext*)user; + int verbose = ctx->verbose; + pcilib_timeout_t timeout = ctx->timeout; + + + if (timeout == PCILIB_TIMEOUT_INFINITE) timeout = 0; + +// while (!ctx->started); + + if (timeout) { + memcpy(&deadline, (struct timeval*)&ctx->last_frame, sizeof(struct timeval)); + pcilib_add_timeout(&deadline, timeout); + } + + if (verbose > 0) { + pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); + } + + while (ctx->run_flag) { + if (StopFlag) { + pcilib_stop(ctx->handle, PCILIB_EVENT_FLAG_STOP_ONLY); + break; + } + + if (timeout) { + if (pcilib_calc_time_to_deadline(&deadline) == 0) { + memcpy(&deadline, (struct timeval*)&ctx->last_frame, sizeof(struct timeval)); + pcilib_add_timeout(&deadline, timeout); + + if (pcilib_calc_time_to_deadline(&deadline) == 0) { + pcilib_stop(ctx->handle, PCILIB_EVENT_FLAG_STOP_ONLY); + break; + } + } + } + + if (verbose > 0) { + if (pcilib_calc_time_to_deadline(&nextinfo) == 0) { + GrabStats(ctx, NULL); + StorageStats(ctx); + pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); + } + } + + usleep(100000); + } + + pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); + while (ctx->writing_flag) { + if (pcilib_calc_time_to_deadline(&nextinfo) == 0) { + if (verbose >= 0) StorageStats(ctx); + pcilib_calc_deadline(&nextinfo, STATUS_MESSAGE_INTERVAL*1000000); + } + + usleep(100000); + } + + return NULL; +} + +int TriggerAndGrab(pcilib_t *handle, GRAB_MODE grab_mode, const char *evname, const char *data_type, size_t num, size_t run_time, size_t trigger_time, pcilib_timeout_t timeout, PARTITION partition, FORMAT format, size_t buffer_size, size_t threads, int verbose, const char *output) { + int err; + GRABContext ctx; +// void *data = NULL; +// size_t size, written; + + pcilib_event_t event; + pcilib_event_t listen_events; + pcilib_event_data_type_t data; + + pthread_t monitor_thread; + pthread_t trigger_thread; + pthread_attr_t attr; + struct sched_param sched; + + struct timeval end_time; + pcilib_event_flags_t flags; + + if (evname) { + event = pcilib_find_event(handle, evname); + if (event == PCILIB_EVENT_INVALID) + Error("Can't find event (%s)", evname); + + listen_events = event; + } else { + listen_events = PCILIB_EVENTS_ALL; + event = PCILIB_EVENT0; + } + + if (data_type) { + data = pcilib_find_event_data_type(handle, event, data_type); + if (data == PCILIB_EVENT_DATA_TYPE_INVALID) + Error("Can't find data type (%s)", data_type); + } else { + data = PCILIB_EVENT_DATA; + } + + memset(&ctx, 0, sizeof(GRABContext)); + + ctx.handle = handle; + ctx.event = event; + ctx.data = data; + ctx.run_time = run_time; + ctx.timeout = timeout; + ctx.format = format; + + if (grab_mode&GRAB_MODE_GRAB) ctx.verbose = verbose; + else ctx.verbose = 0; + + if (grab_mode&GRAB_MODE_GRAB) { + ctx.writer = fastwriter_init(output, 0); + if (!ctx.writer) + Error("Can't initialize fastwritter library"); + + fastwriter_set_buffer_size(ctx.writer, buffer_size); + + err = fastwriter_open(ctx.writer, output, 0); + if (err) + Error("Error opening file (%s), Error: %i\n", output, err); + + ctx.writing_flag = 1; + } + + ctx.run_flag = 1; + + flags = PCILIB_EVENT_FLAGS_DEFAULT; + + if (data == PCILIB_EVENT_RAW_DATA) { + if (format == FORMAT_RAW) { + flags |= PCILIB_EVENT_FLAG_RAW_DATA_ONLY; + } + } else { + flags |= PCILIB_EVENT_FLAG_PREPROCESS; + } + + ctx.flags = flags; + +// printf("Limits: %lu %lu %lu\n", num, run_time, timeout); + pcilib_configure_autostop(handle, num, run_time); + + if (flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY) { + pcilib_configure_rawdata_callback(handle, &raw_data, &ctx); + } + + if (flags&PCILIB_EVENT_FLAG_PREPROCESS) { + pcilib_configure_preprocessing_threads(handle, threads); + } + + if (grab_mode&GRAB_MODE_TRIGGER) { + if (trigger_time) { + if ((timeout)&&(trigger_time * 2 > timeout)) { + timeout = 2 * trigger_time; + ctx.timeout = timeout; + } + } else { + // Otherwise, we will trigger next event after previous one is read + if (((grab_mode&GRAB_MODE_GRAB) == 0)||(flags&PCILIB_EVENT_FLAG_RAW_DATA_ONLY)) trigger_time = PCILIB_TRIGGER_TIMEOUT; + } + + ctx.max_triggers = num; + ctx.trigger_count = 0; + ctx.trigger_time = trigger_time; + + // We don't really care if RT priority is imposible + pthread_attr_init(&attr); + if (!pthread_attr_setschedpolicy(&attr, SCHED_FIFO)) { + sched.sched_priority = sched_get_priority_min(SCHED_FIFO); + pthread_attr_setschedparam(&attr, &sched); + } + + // Start triggering thread and wait until it is schedulled + if (pthread_create(&trigger_thread, &attr, Trigger, (void*)&ctx)) + Error("Error spawning trigger thread"); + + while (!ctx.trigger_thread_started) usleep(10); + } + + gettimeofday(&ctx.start_time, NULL); + + if (grab_mode&GRAB_MODE_GRAB) { + err = pcilib_start(handle, listen_events, flags); + if (err) Error("Failed to start event engine, error %i", err); + } + + ctx.started = 1; + + if (run_time) { + ctx.stop_time.tv_usec = ctx.start_time.tv_usec + run_time%1000000; + if (ctx.stop_time.tv_usec > 999999) { + ctx.stop_time.tv_usec -= 1000000; + __sync_synchronize(); + ctx.stop_time.tv_sec = ctx.start_time.tv_sec + 1 + run_time / 1000000; + } else { + __sync_synchronize(); + ctx.stop_time.tv_sec = ctx.start_time.tv_sec + run_time / 1000000; + } + } + + memcpy(&ctx.last_frame, &ctx.start_time, sizeof(struct timeval)); + if (pthread_create(&monitor_thread, NULL, Monitor, (void*)&ctx)) + Error("Error spawning monitoring thread"); + + if (grab_mode&GRAB_MODE_GRAB) { + err = pcilib_stream(handle, &GrabCallback, &ctx); + if (err) Error("Error streaming events, error %i", err); + } + + ctx.run_flag = 0; + + if (grab_mode&GRAB_MODE_TRIGGER) { + while (ctx.trigger_thread_started) usleep(10); + } + + if (grab_mode&GRAB_MODE_GRAB) { + pcilib_stop(handle, PCILIB_EVENT_FLAGS_DEFAULT); + } + + gettimeofday(&end_time, NULL); + + if (grab_mode&GRAB_MODE_TRIGGER) { + pthread_join(trigger_thread, NULL); + } + + + if (grab_mode&GRAB_MODE_GRAB) { + if (verbose >= 0) + printf("Grabbing is finished, flushing results....\n"); + + err = fastwriter_close(ctx.writer); + if (err) Error("Storage problems, error %i", err); + } + + ctx.writing_flag = 0; + + pthread_join(monitor_thread, NULL); + + if ((grab_mode&GRAB_MODE_GRAB)&&(verbose>=0)) { + GrabStats(&ctx, &end_time); + StorageStats(&ctx); + } + + fastwriter_destroy(ctx.writer); + + return 0; +} + +int StartStopDMA(pcilib_t *handle, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, int start) { + int err; + pcilib_dma_engine_t dmaid; + + if (dma == PCILIB_DMA_ENGINE_ADDR_INVALID) { + const pcilib_dma_description_t *dma_info = pcilib_get_dma_description(handle); + + if (start) Error("DMA engine should be specified"); + + for (dmaid = 0; dma_info->engines[dmaid].addr_bits; dmaid++) { + err = pcilib_start_dma(handle, dmaid, 0); + if (err) Error("Error starting DMA Engine (%s %i)", ((dma_info->engines[dmaid].direction == PCILIB_DMA_FROM_DEVICE)?"C2S":"S2C"), dma_info->engines[dmaid].addr); + err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); + if (err) Error("Error stopping DMA Engine (%s %i)", ((dma_info->engines[dmaid].direction == PCILIB_DMA_FROM_DEVICE)?"C2S":"S2C"), dma_info->engines[dmaid].addr); + } + + return 0; + } + + if (dma_direction&PCILIB_DMA_FROM_DEVICE) { + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (C2S %lu) is specified", dma); + + if (start) { + err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); + if (err) Error("Error starting DMA engine (C2S %lu)", dma); + } else { + err = pcilib_start_dma(handle, dmaid, 0); + if (err) Error("Error starting DMA engine (C2S %lu)", dma); + err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); + if (err) Error("Error stopping DMA engine (C2S %lu)", dma); + } + } + + if (dma_direction&PCILIB_DMA_TO_DEVICE) { + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("Invalid DMA engine (S2C %lu) is specified", dma); + + if (start) { + err = pcilib_start_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); + if (err) Error("Error starting DMA engine (S2C %lu)", dma); + } else { + err = pcilib_start_dma(handle, dmaid, 0); + if (err) Error("Error starting DMA engine (S2C %lu)", dma); + err = pcilib_stop_dma(handle, dmaid, PCILIB_DMA_FLAG_PERSISTENT); + if (err) Error("Error stopping DMA engine (S2C %lu)", dma); + } + } + + return 0; +} + + +typedef struct { + pcilib_kmem_use_t use; + + int referenced; + int hw_lock; + int reusable; + int persistent; + int open; + + size_t count; + size_t size; +} kmem_use_info_t; + +#define MAX_USES 64 + +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; + + for (i = 1; i < (n - 1); i++) { + if (uses[i].use == use) return i; + } + + if (n == MAX_USES) return 0; + + memset(&uses[n], 0, sizeof(pcilib_kmem_use_t)); + uses[n].use = use; + return (*n_uses)++; +} + + +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]; + + size_t useid, n_uses = 1; // Use 0 is for others + + memset(uses, 0, sizeof(kmem_use_info_t)); + + pos = strrchr(device, '/'); + if (pos) ++pos; + else pos = device; + + snprintf(sysdir, 255, "/sys/class/fpga/%s", pos); + + dir = opendir(sysdir); + if (!dir) Error("Can't open directory (%s)", sysdir); + + while ((entry = readdir(dir)) != NULL) { + FILE *f; + unsigned long use = 0; + unsigned long size = 0; + unsigned long refs = 0; + unsigned long mode = 0; + unsigned long hwref = 0; + + if (strncmp(entry->d_name, "kbuf", 4)) continue; + if (!isnumber(entry->d_name+4)) continue; + + snprintf(fname, 255, "%s/%s", sysdir, entry->d_name); + f = fopen(fname, "r"); + if (!f) Error("Can't access file (%s)", fname); + + while(!feof(f)) { + if (!fgets(info, 256, f)) + break; + + 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, "mode:", 5)) mode = strtoul(info+5, NULL, 16); + if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); + + } + fclose(f); + + useid = FindUse(&n_uses, uses, use); + uses[useid].count++; + uses[useid].size += size; + if (refs) uses[useid].referenced = 1; + if (hwref) uses[useid].hw_lock = 1; + if (mode&KMEM_MODE_REUSABLE) uses[useid].reusable = 1; + if (mode&KMEM_MODE_PERSISTENT) uses[useid].persistent = 1; + if (mode&KMEM_MODE_COUNT) uses[useid].open = 1; + } + 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; + } + + printf("Use Type Count Total Size REF Mode \n"); + printf("--------------------------------------------------------------------------------\n"); + for (useid = 0; useid < n_uses; useid++) { + if (useid + 1 == n_uses) { + if (!uses[0].count) continue; + i = 0; + } else i = useid + 1; + + printf("%08x ", uses[i].use); + if (!i) printf("All Others "); + 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("%6zu", uses[i].count); + printf(" "); + printf("%10s", GetPrintSize(stmp, uses[i].size)); + printf(" "); + if (uses[i].referenced&&uses[i].hw_lock) printf("HW+SW"); + else if (uses[i].referenced) printf(" SW"); + else if (uses[i].hw_lock) printf("HW "); + else printf(" - "); + printf(" "); + if (uses[i].persistent) printf("Persistent"); + else if (uses[i].open) printf("Open "); + else if (uses[i].reusable) printf("Reusable "); + else printf("Closed "); + printf("\n"); + } + printf("--------------------------------------------------------------------------------\n"); + printf("REF - Software/Hardware Reference, MODE - Reusable/Persistent/Open\n"); + + + return 0; +} + +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; + + 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; + } + + err = pcilib_kmem_sync_block(handle, kbuf, PCILIB_KMEM_SYNC_FROMDEVICE, block); + if (err) { + pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); + Error("The synchronization of kernel buffer has failed\n"); + return 0; + } + + data = pcilib_kmem_get_block_ua(handle, kbuf, block); + if (data) { + size = pcilib_kmem_get_block_size(handle, kbuf, block); + if ((max_size)&&(size > max_size)) size = max_size; + + fwrite(data, 1, size, o?o:stdout); + } else { + pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); + Error("The specified block is not existing\n"); + return 0; + } + + pcilib_free_kernel_memory(handle, kbuf, KMEM_FLAG_REUSE); + + 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; + + 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. + + if (!strcasecmp(use, "dma")) { + for (i = 0; i < PCILIB_MAX_DMA_ENGINES; i++) { + err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, i), flags); + if (err) Error("Error cleaning DMA%i C2S Ring buffer", i); + err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_RING, 0x80|i), flags); + if (err) Error("Error cleaning DMA%i S2C Ring buffer", i); + err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, i), flags); + if (err) Error("Error cleaning DMA%i C2S Page buffers", i); + err = pcilib_clean_kernel_memory(handle, PCILIB_KMEM_USE(PCILIB_KMEM_USE_DMA_PAGES, 0x80|i), flags); + if (err) Error("Error cleaning DMA%i S2C Page buffers", i); + } + + return 0; + } + + useid = ParseUse(use); + err = pcilib_clean_kernel_memory(handle, useid, flags); + if (err) Error("Error cleaning kernel buffers for use (0x%lx)", useid); + + return 0; +} + +int ListDMA(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info) { + int err; + + DIR *dir; + struct dirent *entry; + const char *pos; + char sysdir[256]; + char fname[256]; + char info[256]; + char stmp[256]; + + pcilib_dma_engine_t dmaid; + pcilib_dma_engine_status_t status; + + pos = strrchr(device, '/'); + if (pos) ++pos; + else pos = device; + + snprintf(sysdir, 255, "/sys/class/fpga/%s", pos); + + dir = opendir(sysdir); + if (!dir) Error("Can't open directory (%s)", sysdir); + + printf("DMA Engine Status Total Size Buffer Ring (1st used - 1st free)\n"); + printf("--------------------------------------------------------------------------------\n"); + while ((entry = readdir(dir)) != NULL) { + FILE *f; + unsigned long use = 0; +// unsigned long size = 0; +// unsigned long refs = 0; + unsigned long mode = 0; +// unsigned long hwref = 0; + + if (strncmp(entry->d_name, "kbuf", 4)) continue; + if (!isnumber(entry->d_name+4)) continue; + + snprintf(fname, 255, "%s/%s", sysdir, entry->d_name); + f = fopen(fname, "r"); + if (!f) Error("Can't access file (%s)", fname); + + while(!feof(f)) { + if (!fgets(info, 256, f)) + break; + + 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, "mode:", 5)) mode = strtoul(info+5, NULL, 16); +// if (!strncmp(info, "hw ref:", 7)) hwref = strtoul(info+7, NULL, 10); + } + fclose(f); + + if ((mode&(KMEM_MODE_REUSABLE|KMEM_MODE_PERSISTENT|KMEM_MODE_COUNT)) == 0) continue; // closed + if ((use >> 16) != PCILIB_KMEM_USE_DMA_RING) continue; + + if (use&0x80) { + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_TO_DEVICE, use&0x7F); + } else { + dmaid = pcilib_find_dma_by_addr(handle, PCILIB_DMA_FROM_DEVICE, use&0x7F); + } + + if (dmaid == PCILIB_DMA_ENGINE_INVALID) continue; + + + printf("DMA%lu %s ", use&0x7F, (use&0x80)?"S2C":"C2S"); + err = pcilib_start_dma(handle, dmaid, 0); + if (err) { + printf("-- Wrong state, start is failed\n"); + continue; + } + + err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); + if (err) { + printf("-- Wrong state, failed to obtain status\n"); + pcilib_stop_dma(handle, dmaid, 0); + continue; + } + + pcilib_stop_dma(handle, dmaid, 0); + + if (status.started) printf("S"); + else printf(" "); + + if (status.ring_head == status.ring_tail) printf(" "); + else printf("D"); + + printf(" "); + printf("%10s", GetPrintSize(stmp, status.ring_size * status.buffer_size)); + + printf(" "); + printf("%zu - %zu (of %zu)", status.ring_tail, status.ring_head, status.ring_size); + + printf("\n"); + + } + closedir(dir); + + printf("--------------------------------------------------------------------------------\n"); + printf("S - Started, D - Data in buffers\n"); + + return 0; +} + +int ListBuffers(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction) { + int err; + size_t i; + pcilib_dma_engine_t dmaid; + pcilib_dma_engine_status_t status; + pcilib_dma_buffer_status_t *buffer; + char stmp[256]; + + dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); + + err = pcilib_start_dma(handle, dmaid, 0); + if (err) Error("Error starting the specified DMA engine"); + + err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); + if (err) Error("Failed to obtain status of the specified DMA engine"); + + buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t)); + if (!buffer) Error("Failed to allocate memory for status buffer"); + + err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer); + if (err) Error("Failed to obtain extended status of the specified DMA engine"); + + + printf("Buffer Status Total Size \n"); + printf("--------------------------------------------------------------------------------\n"); + + for (i = 0; i < status.ring_size; i++) { + printf("%8zu ", i); + printf("%c%c %c%c ", buffer[i].used?'U':' ', buffer[i].error?'E':' ', buffer[i].first?'F':' ', buffer[i].last?'L':' '); + printf("%10s", GetPrintSize(stmp, buffer[i].size)); + printf("\n"); + } + + printf("--------------------------------------------------------------------------------\n"); + printf("U - Used, E - Error, F - First block, L - Last Block\n"); + + free(buffer); + + pcilib_stop_dma(handle, dmaid, 0); + + return 0; +} + +int ReadBuffer(pcilib_t *handle, const char *device, const pcilib_model_description_t *model_info, pcilib_dma_engine_addr_t dma, pcilib_dma_direction_t dma_direction, size_t block, FILE *o) { + int err; + pcilib_dma_engine_t dmaid; + pcilib_dma_engine_status_t status; + pcilib_dma_buffer_status_t *buffer; + size_t size; + + dmaid = pcilib_find_dma_by_addr(handle, dma_direction, dma); + if (dmaid == PCILIB_DMA_ENGINE_INVALID) Error("The specified DMA engine is not found"); + + err = pcilib_start_dma(handle, dmaid, 0); + if (err) Error("Error starting the specified DMA engine"); + + err = pcilib_get_dma_status(handle, dmaid, &status, 0, NULL); + if (err) Error("Failed to obtain status of the specified DMA engine"); + + buffer = (pcilib_dma_buffer_status_t*)malloc(status.ring_size*sizeof(pcilib_dma_buffer_status_t)); + if (!buffer) Error("Failed to allocate memory for status buffer"); + + err = pcilib_get_dma_status(handle, dmaid, &status, status.ring_size, buffer); + if (err) Error("Failed to obtain extended status of the specified DMA engine"); + + if (block == (size_t)-1) { + // get current + } + + size = buffer[block].size; + + free(buffer); + + pcilib_stop_dma(handle, dmaid, 0); + + return ReadKMEM(handle, device, ((dma&0x7F)|((dma_direction == PCILIB_DMA_TO_DEVICE)?0x80:0x00))|(PCILIB_KMEM_USE_DMA_PAGES<<16), block, size, o); +} + + +int EnableIRQ(pcilib_t *handle, const 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, const 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, const 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, const pcilib_model_description_t *model_info, pcilib_irq_hw_source_t irq_source, pcilib_timeout_t timeout) { + int err; + size_t count; + + err = pcilib_wait_irq(handle, irq_source, timeout, &count); + if (err) { + if (err == PCILIB_ERROR_TIMEOUT) Error("Timeout waiting for IRQ"); + else Error("Error waiting for IRQ"); + } + + return 0; +} + + +int main(int argc, char **argv) { + int i; + long itmp; + size_t ztmp; + unsigned char c; + + const char *stmp; + const char *num_offset; + + int details = 0; + int verbose = 0; + int quiete = 0; + int force = 0; + int verify = 0; + + const char *model = NULL; + const pcilib_model_description_t *model_info; + const pcilib_dma_description_t *dma_info; + MODE mode = MODE_INVALID; + GRAB_MODE grab_mode = 0; + size_t trigger_time = 0; + size_t run_time = 0; + size_t buffer = 0; + size_t threads = 1; + 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; + pcilib_bar_t bar = PCILIB_BAR_DETECT; + const char *addr = NULL; + const char *reg = NULL; + const char *bank = NULL; + char **data = NULL; + const char *event = NULL; + const char *data_type = NULL; + const char *dma_channel = NULL; + const char *use = NULL; + 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; + + pcilib_t *handle; + + int size_set = 0; + int timeout_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) { + case OPT_HELP: + Usage(argc, argv, NULL); + break; + case OPT_INFO: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_INFO; + break; + case OPT_LIST: + if (mode == MODE_LIST) details++; + else if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_LIST; + break; + case OPT_RESET: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_RESET; + break; + case OPT_BENCHMARK: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_BENCHMARK; + + if (optarg) addr = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; + break; + case OPT_READ: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_READ; + if (optarg) addr = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; + break; + case OPT_WRITE: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_WRITE; + if (optarg) addr = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) addr = argv[optind++]; + break; + case OPT_GRAB: + if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_GRAB))) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_GRAB; + grab_mode |= GRAB_MODE_GRAB; + + stmp = NULL; + if (optarg) stmp = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++]; + + if (stmp) { + if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event"); + event = stmp; + } + break; + case OPT_TRIGGER: + if ((mode != MODE_INVALID)&&((mode != MODE_GRAB)||(grab_mode&GRAB_MODE_TRIGGER))) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_GRAB; + grab_mode |= GRAB_MODE_TRIGGER; + + stmp = NULL; + if (optarg) stmp = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) stmp = argv[optind++]; + + if (stmp) { + if ((event)&&(strcasecmp(stmp,event))) Usage(argc, argv, "Redefinition of considered event"); + event = stmp; + } + break; + case OPT_LIST_DMA: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_LIST_DMA; + break; + case OPT_LIST_DMA_BUFFERS: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_LIST_DMA_BUFFERS; + dma_channel = optarg; + break; + case OPT_READ_DMA_BUFFER: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_READ_DMA_BUFFER; + + num_offset = strchr(optarg, ':'); + + if (num_offset) { + if (sscanf(num_offset + 1, "%zu", &block) != 1) + Usage(argc, argv, "Invalid buffer is specified (%s)", num_offset + 1); + + *(char*)num_offset = 0; + } else block = (size_t)-1; + + dma_channel = optarg; + break; + case OPT_START_DMA: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_START_DMA; + if (optarg) dma_channel = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) dma_channel = argv[optind++]; + break; + case OPT_STOP_DMA: + if (mode != MODE_INVALID) Usage(argc, argv, "Multiple operations are not supported"); + + mode = MODE_STOP_DMA; + 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"); + + mode = MODE_WAIT_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_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"); + mode = MODE_READ_KMEM; + + num_offset = strchr(optarg, ':'); + + 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; + } + + 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"); + mode = MODE_FREE_KMEM; + + if (optarg) use = optarg; + else if ((optind < argc)&&(argv[optind][0] != '-')) use = argv[optind++]; + break; + case OPT_DEVICE: + fpga_device = optarg; + break; + case OPT_MODEL: + model = optarg; +/* if (!strcasecmp(optarg, "pci")) model = PCILIB_MODEL_PCI; + else if (!strcasecmp(optarg, "ipecamera")) model = PCILIB_MODEL_IPECAMERA; + else if (!strcasecmp(optarg, "kapture")) model = PCILIB_MODEL_KAPTURE; + else Usage(argc, argv, "Invalid memory model (%s) is specified", optarg);*/ + break; + case OPT_BAR: + bank = optarg; +// 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)) { + atype = "fifo"; + num_offset = optarg + 4; + amode = ACCESS_FIFO; + } else if (!strncasecmp(optarg, "dma", 3)) { + atype = "dma"; + num_offset = optarg + 3; + amode = ACCESS_DMA; + } else if (!strncasecmp(optarg, "bar", 3)) { + 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)) { + atype = "plain"; + num_offset = optarg + 5; + amode = ACCESS_BAR; + } else { + num_offset = optarg; + } + + if (*num_offset) { + if ((!isnumber(num_offset))||(sscanf(num_offset, "%li", &itmp) != 1)) + Usage(argc, argv, "Invalid access type (%s) is specified", optarg); + + switch (itmp) { + case 8: access = 1; break; + case 16: access = 2; break; + case 32: access = 4; break; + case 64: access = 8; break; + default: Usage(argc, argv, "Invalid data width (%s) is specified", num_offset); + } + } + break; + case OPT_SIZE: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &size) != 1)) { + if (strcasecmp(optarg, "unlimited")) + Usage(argc, argv, "Invalid size is specified (%s)", optarg); + else + size = 0;//(size_t)-1; + } + + 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; + else endianess = 1; + } else if ((*optarg == 'l')||(*optarg == 'L')) { + if (ntohs(1) == 1) endianess = 1; + else endianess = 0; + } else Usage(argc, argv, "Invalid endianess is specified (%s)", optarg); + + break; + case OPT_TIMEOUT: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &timeout) != 1)) { + if (strcasecmp(optarg, "unlimited")) + Usage(argc, argv, "Invalid timeout is specified (%s)", optarg); + else + timeout = PCILIB_TIMEOUT_INFINITE; + } + timeout_set = 1; + break; + case OPT_OUTPUT: + output = optarg; + break; + case OPT_ITERATIONS: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &iterations) != 1)) + Usage(argc, argv, "Invalid number of iterations is specified (%s)", optarg); + break; + case OPT_EVENT: + event = optarg; + break; + case OPT_TYPE: + type = optarg; + break; + case OPT_DATA_TYPE: + data_type = optarg; + break; + case OPT_RUN_TIME: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &run_time) != 1)) { + if (strcasecmp(optarg, "unlimited")) + Usage(argc, argv, "Invalid run-time is specified (%s)", optarg); + else + run_time = 0; + } +// run_time_set = 1; + break; + case OPT_TRIGGER_TIME: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &trigger_time) != 1)) + Usage(argc, argv, "Invalid trigger-time is specified (%s)", optarg); + break; + case OPT_TRIGGER_RATE: + if ((!isnumber(optarg))||(sscanf(optarg, "%zu", &ztmp) != 1)) + Usage(argc, argv, "Invalid trigger-rate is specified (%s)", optarg); + + trigger_time = (1000000 / ztmp) + ((1000000 % ztmp)?1:0); + break; + case OPT_BUFFER: + 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, "%zu", &buffer) != 1)) + Usage(argc, argv, "Invalid buffer size is specified (%s)", num_offset); + buffer *= 1024 * 1024; + } else { + buffer = get_free_memory(); + if (buffer < 256) Error("Not enough free memory (%lz MB) for buffering", buffer / 1024 / 1024); + + buffer -= 128 + buffer/16; + } + break; + case OPT_THREADS: + 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, "%zu", &threads) != 1)) + Usage(argc, argv, "Invalid threads number is specified (%s)", num_offset); + } else { + threads = 0; + } + break; + case OPT_FORMAT: + if (!strcasecmp(optarg, "raw")) format = FORMAT_RAW; + else if (!strcasecmp(optarg, "add_header")) format = FORMAT_HEADER; +// else if (!strcasecmp(optarg, "ringfs")) format = FORMAT_RINGFS; + else if (strcasecmp(optarg, "default")) Error("Invalid format (%s) is specified", optarg); + break; + case OPT_QUIETE: + quiete = 1; + verbose = -1; + break; + case OPT_VERBOSE: + 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, "%i", &verbose) != 1)) + Usage(argc, argv, "Invalid verbosity level is specified (%s)", num_offset); + } else { + verbose = 1; + } + break; + case OPT_FORCE: + force = 1; + break; + case OPT_VERIFY: + verify = 1; + break; + case OPT_MULTIPACKET: + flags |= FLAG_MULTIPACKET; + break; + case OPT_WAIT: + flags |= FLAG_WAIT; + break; + default: + Usage(argc, argv, "Unknown option (%s) with argument (%s)", optarg?argv[optind-2]:argv[optind-1], optarg?optarg:"(null)"); + } + } + + if (mode == MODE_INVALID) { + if (argc > 1) Usage(argc, argv, "Operation is not specified"); + else Usage(argc, argv, NULL); + } + + pcilib_set_error_handler(&Error, quiete?Silence:NULL); + + handle = pcilib_open(fpga_device, model); + if (handle < 0) Error("Failed to open FPGA device: %s", fpga_device); + + model_info = pcilib_get_model_description(handle); + dma_info = pcilib_get_dma_description(handle); + + switch (mode) { + case MODE_WRITE: + if (((argc - optind) == 1)&&(*argv[optind] == '*')) { + int vallen = strlen(argv[optind]); + if (vallen > 1) { + data = (char**)malloc(size * (vallen + sizeof(char*))); + if (!data) Error("Error allocating memory for data array"); + + for (i = 0; i < size; i++) { + data[i] = ((char*)data) + size * sizeof(char*) + i * vallen; + strcpy(data[i], argv[optind] + 1); + } + } else { + data = (char**)malloc(size * (9 + sizeof(char*))); + if (!data) Error("Error allocating memory for data array"); + + for (i = 0; i < size; i++) { + data[i] = ((char*)data) + size * sizeof(char*) + i * 9; + sprintf(data[i], "%x", i); + } + } + } else if ((argc - optind) == size) data = argv + optind; + else Usage(argc, argv, "The %i data values is specified, but %i required", argc - optind, size); + case MODE_READ: + if (!addr) { + if (((!dma_info)||(!dma_info->api))&&(!model_info->api)) { +// if (model == PCILIB_MODEL_PCI) { + if ((amode != ACCESS_DMA)&&(amode != ACCESS_CONFIG)) + Usage(argc, argv, "The address is not specified"); + } else ++mode; + } + break; + case MODE_START_DMA: + case MODE_STOP_DMA: + case MODE_LIST_DMA_BUFFERS: + case MODE_READ_DMA_BUFFER: + if ((dma_channel)&&(*dma_channel)) { + itmp = strlen(dma_channel) - 1; + if (dma_channel[itmp] == 'r') dma_direction = PCILIB_DMA_FROM_DEVICE; + else if (dma_channel[itmp] == 'w') dma_direction = PCILIB_DMA_TO_DEVICE; + + if (dma_direction != PCILIB_DMA_BIDIRECTIONAL) itmp--; + + if (strncmp(dma_channel, "dma", 3)) num_offset = dma_channel; + else { + num_offset = dma_channel + 3; + itmp -= 3; + } + + if (bank) { + if (strncmp(num_offset, bank, itmp)) Usage(argc, argv, "Conflicting DMA channels are specified in mode parameter (%s) and bank parameter (%s)", dma_channel, bank); + } + + if (!isnumber_n(num_offset, itmp)) + Usage(argc, argv, "Invalid DMA channel (%s) is specified", dma_channel); + + dma = atoi(num_offset); + } + break; + default: + if (argc > optind) Usage(argc, argv, "Invalid non-option parameters are supplied"); + } + + + if (addr) { + if ((!strncmp(addr, "dma", 3))&&((addr[3]==0)||isnumber(addr+3))) { + 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 { + if (addr[3] == 0) Usage(argc, argv, "The DMA channel is not specified"); + } + dma = atoi(addr + 3); + amode = ACCESS_DMA; + addr = NULL; + } else if ((!strncmp(addr, "bar", 3))&&((addr[3]==0)||isnumber(addr+3))) { + 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 + const pcilib_register_range_t *ranges = model_info->ranges; + + if (ranges) { + for (i = 0; ranges[i].start != ranges[i].end; i++) + if ((start >= ranges[i].start)&&(start <= ranges[i].end)) break; + + // register access in plain mode + if (ranges[i].start != ranges[i].end) { + pcilib_register_bank_t regbank = pcilib_find_register_bank_by_addr(handle, ranges[i].bank); + if (regbank == PCILIB_REGISTER_BANK_INVALID) Error("Configuration error: register bank specified in the address range is not found"); + + bank = model_info->banks[regbank].name; + start += ranges[i].addr_shift; + addr_shift = ranges[i].addr_shift; + ++mode; + } + } + } else { + if (pcilib_find_register(handle, bank, addr) == PCILIB_REGISTER_INVALID) { + Usage(argc, argv, "Invalid address (%s) is specified", addr); + } else { + reg = addr; + ++mode; + } + } + } + + if (mode == MODE_GRAB) { + if (output) { + char fsname[128]; + if (!get_file_fs(output, 127, fsname)) { + if (!strcmp(fsname, "ext4")) partition = PARTITION_EXT4; + else if (!strcmp(fsname, "raw")) partition = PARTITION_RAW; + } + } else { + output = "/dev/null"; + partition = PARTITION_NULL; + } + + if (!timeout_set) { + if (run_time) timeout = PCILIB_TIMEOUT_INFINITE; + else timeout = PCILIB_EVENT_TIMEOUT; + } + + if (!size_set) { + if (run_time) size = 0; + } + } + + if (mode != MODE_GRAB) { + if (size == (size_t)-1) + Usage(argc, argv, "Unlimited size is not supported in selected operation mode"); + } + + + if ((bank)&&(amode == ACCESS_DMA)) { + if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0)) + Usage(argc, argv, "Invalid DMA channel (%s) is specified", bank); + else dma = itmp; + } else if (bank) { + switch (mode) { + case MODE_BENCHMARK: + case MODE_READ: + case MODE_WRITE: + if ((!isnumber(bank))||(sscanf(bank,"%li", &itmp) != 1)||(itmp < 0)||(itmp >= PCILIB_MAX_REGISTER_BANKS)) + Usage(argc, argv, "Invalid data bank (%s) is specified", bank); + else bar = itmp; + break; + default: + if (pcilib_find_register_bank(handle, bank) == PCILIB_REGISTER_BANK_INVALID) + Usage(argc, argv, "Invalid data bank (%s) is specified", bank); + } + } + + signal(SIGINT, signal_exit_handler); + + if ((mode != MODE_GRAB)&&(output)) { + ofile = fopen(output, "a+"); + if (!ofile) { + Error("Failed to open file \"%s\"", output); + } + } + + switch (mode) { + case MODE_INFO: + Info(handle, model_info); + break; + case MODE_LIST: + List(handle, model_info, bank, details); + break; + case MODE_BENCHMARK: + Benchmark(handle, amode, dma, bar, start, size_set?size:0, access, iterations); + break; + 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 { + Error("Address to read is not specified"); + } + break; + case MODE_READ_REGISTER: + if ((reg)||(!addr)) ReadRegister(handle, model_info, bank, reg); + 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, verify); + break; + case MODE_WRITE_REGISTER: + if (reg) WriteRegister(handle, model_info, bank, reg, data); + else WriteRegisterRange(handle, model_info, bank, start, addr_shift, size, data); + break; + case MODE_RESET: + pcilib_reset(handle); + break; + case MODE_GRAB: + TriggerAndGrab(handle, grab_mode, event, data_type, size, run_time, trigger_time, timeout, partition, format, buffer, threads, verbose, output); + break; + case MODE_LIST_DMA: + ListDMA(handle, fpga_device, model_info); + break; + case MODE_LIST_DMA_BUFFERS: + ListBuffers(handle, fpga_device, model_info, dma, dma_direction); + break; + case MODE_READ_DMA_BUFFER: + ReadBuffer(handle, fpga_device, model_info, dma, dma_direction, block, ofile); + break; + case MODE_START_DMA: + StartStopDMA(handle, model_info, dma, dma_direction, 1); + break; + 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: + if (use) DetailKMEM(handle, fpga_device, use, block); + else ListKMEM(handle, fpga_device); + break; + case MODE_READ_KMEM: + 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); + break; + case MODE_INVALID: + break; + } + + if (ofile) fclose(ofile); + + pcilib_close(handle); + + if (data != argv + optind) free(data); +} diff --git a/protocols/CMakeLists.txt b/protocols/CMakeLists.txt index 5f64a43..3c1d75b 100644 --- a/protocols/CMakeLists.txt +++ b/protocols/CMakeLists.txt @@ -1,8 +1,8 @@ include_directories( ${CMAKE_SOURCE_DIR} + ${CMAKE_SOURCE_DIR}/pcilib ) - set(HEADERS ${HEADERS} default.h) add_library(protocols STATIC default.c) diff --git a/protocols/default.h b/protocols/default.h index f8685f1..f535550 100644 --- a/protocols/default.h +++ b/protocols/default.h @@ -8,7 +8,7 @@ int pcilib_default_read(pcilib_t *ctx, pcilib_register_bank_context_t *bank, pci int pcilib_default_write(pcilib_t *ctx, pcilib_register_bank_context_t *bank, pcilib_register_addr_t addr, pcilib_register_value_t value); #ifdef _PCILIB_CONFIG_C -static pcilib_register_protocol_api_description_t pcilib_default_protocol_api = +const pcilib_register_protocol_api_description_t pcilib_default_protocol_api = { NULL, NULL, pcilib_default_read, pcilib_default_write }; #endif /* _PCILIB_CONFIG_C */ diff --git a/register.c b/register.c deleted file mode 100644 index 8d138b8..0000000 --- a/register.c +++ /dev/null @@ -1,290 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" -#include "bank.h" - -#include "tools.h" -#include "error.h" - - -int pcilib_add_registers(pcilib_t *ctx, size_t n, const pcilib_register_description_t *registers) { - // DS: What we are doing if register exists? - - pcilib_register_description_t *regs; - size_t size; - - if (!n) { - for (n = 0; registers[n].bits; n++); - } - - if ((ctx->num_reg + n + 1) > ctx->alloc_reg) { - for (size = ctx->alloc_reg; size < 2 * (n + ctx->num_reg + 1); size<<=1); - - regs = (pcilib_register_description_t*)realloc(ctx->registers, size * sizeof(pcilib_register_description_t)); - if (!regs) return PCILIB_ERROR_MEMORY; - - ctx->registers = regs; - ctx->model_info.registers = regs; - ctx->alloc_reg = size; - } - - memcpy(ctx->registers + ctx->num_reg, registers, n * sizeof(pcilib_register_description_t)); - memset(ctx->registers + ctx->num_reg + n, 0, sizeof(pcilib_register_description_t)); - ctx->num_reg += n; - - return 0; -} - - -static int pcilib_read_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t *buf) { - int err; - size_t i; - - pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; - const pcilib_register_protocol_api_description_t *bapi = bctx->api; - const pcilib_register_bank_description_t *b = bctx->bank; - - int access = b->access / 8; - - assert(bits < 8 * sizeof(pcilib_register_value_t)); - - if (!bapi->read) { - pcilib_error("Used register protocol does not define a way to read register value"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { - if ((b->format)&&(strchr(b->format, 'x'))) - pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); - else - pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); - return PCILIB_ERROR_OUTOFRANGE; - } - - //err = pcilib_init_register_banks(ctx); - //if (err) return err; - - //n += bits / b->access; - //bits %= b->access; - - for (i = 0; i < n; i++) { - err = bapi->read(ctx, bctx, addr + i * access, buf + i); - if (err) break; - } - - if ((bits > 0)&&(!err)) { - pcilib_register_value_t val = 0; - err = bapi->read(ctx, bctx, addr + n * access, &val); - - val = (val >> offset)&BIT_MASK(bits); - memcpy(buf + n, &val, sizeof(pcilib_register_value_t)); - } - - return err; -} - -int pcilib_read_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) { - pcilib_register_bank_t bank_id = pcilib_find_register_bank(ctx, bank); - if (bank_id == PCILIB_REGISTER_BANK_INVALID) { - if (bank) pcilib_error("Invalid register bank is specified (%s)", bank); - else pcilib_error("Register bank should be specified"); - return PCILIB_ERROR_INVALID_BANK; - } - - return pcilib_read_register_space_internal(ctx, bank_id, addr, n, 0, 0, buf); -} - -int pcilib_read_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t *value) { - int err; - size_t i, n; - pcilib_register_size_t bits; - pcilib_register_value_t res; - pcilib_register_bank_t bank; - const pcilib_register_description_t *r; - const pcilib_register_bank_description_t *b; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - r = model_info->registers + reg; - - bank = pcilib_find_register_bank_by_addr(ctx, r->bank); - if (bank == PCILIB_REGISTER_BANK_INVALID) return PCILIB_ERROR_INVALID_BANK; - - b = model_info->banks + bank; - - n = r->bits / b->access; - bits = r->bits % b->access; - - pcilib_register_value_t buf[n + 1]; - err = pcilib_read_register_space_internal(ctx, bank, r->addr, n, r->offset, bits, buf); - - if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) { - pcilib_error("Big-endian byte order support is not implemented"); - return PCILIB_ERROR_NOTSUPPORTED; - } else { - res = 0; - if (bits) ++n; - for (i = 0; i < n; i++) { - res |= buf[i] << (i * b->access); - } - } - - *value = res; - - return err; -} - - -int pcilib_read_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t *value) { - int reg; - - reg = pcilib_find_register(ctx, bank, regname); - if (reg < 0) { - pcilib_error("Register (%s) is not found", regname); - return PCILIB_ERROR_NOTFOUND; - } - - return pcilib_read_register_by_id(ctx, reg, value); -} - - -static int pcilib_write_register_space_internal(pcilib_t *ctx, pcilib_register_bank_t bank, pcilib_register_addr_t addr, size_t n, pcilib_register_size_t offset, pcilib_register_size_t bits, pcilib_register_value_t rwmask, pcilib_register_value_t *buf) { - int err; - size_t i; - - pcilib_register_bank_context_t *bctx = ctx->bank_ctx[bank]; - const pcilib_register_protocol_api_description_t *bapi = bctx->api; - const pcilib_register_bank_description_t *b = bctx->bank; - - int access = b->access / 8; - - assert(bits < 8 * sizeof(pcilib_register_value_t)); - - if (!bapi->write) { - pcilib_error("Used register protocol does not define a way to write value into the register"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (((addr + n) > b->size)||(((addr + n) == b->size)&&(bits))) { - if ((b->format)&&(strchr(b->format, 'x'))) - pcilib_error("Accessing register (%u regs at addr 0x%x) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); - else - pcilib_error("Accessing register (%u regs at addr %u) out of register space (%u registers total)", bits?(n+1):n, addr, b->size); - return PCILIB_ERROR_OUTOFRANGE; - } - - //err = pcilib_init_register_banks(ctx); - //if (err) return err; - - //n += bits / b->access; - //bits %= b->access; - - for (i = 0; i < n; i++) { - err = bapi->write(ctx, bctx, addr + i * access, buf[i]); - if (err) break; - } - - if ((bits > 0)&&(!err)) { - pcilib_register_value_t val = (buf[n]&BIT_MASK(bits))<read) { - pcilib_error("Used register protocol does not define a way to read register. Therefore, it is only possible to write a full bank word, not partial as required by the accessed register"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - err = bapi->read(ctx, bctx, addr + n * access, &rval); - if (err) return err; - - val |= (rval & rwmask & ~mask); - } - - err = bapi->write(ctx, bctx, addr + n * access, val); - } - - return err; -} - -int pcilib_write_register_space(pcilib_t *ctx, const char *bank, pcilib_register_addr_t addr, size_t n, pcilib_register_value_t *buf) { - pcilib_register_bank_t bank_id = pcilib_find_register_bank(ctx, bank); - if (bank_id == PCILIB_REGISTER_BANK_INVALID) { - if (bank) pcilib_error("Invalid register bank is specified (%s)", bank); - else pcilib_error("Register bank should be specified"); - return PCILIB_ERROR_INVALID_BANK; - } - - return pcilib_write_register_space_internal(ctx, bank_id, addr, n, 0, 0, 0, buf); -} - - -int pcilib_write_register_by_id(pcilib_t *ctx, pcilib_register_t reg, pcilib_register_value_t value) { - int err; - size_t i, n; - pcilib_register_size_t bits; - pcilib_register_bank_t bank; - pcilib_register_value_t res; - const pcilib_register_description_t *r; - const pcilib_register_bank_description_t *b; - const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - r = model_info->registers + reg; - - bank = pcilib_find_register_bank_by_addr(ctx, r->bank); - if (bank == PCILIB_REGISTER_BANK_INVALID) return PCILIB_ERROR_INVALID_BANK; - - b = model_info->banks + bank; - - n = r->bits / b->access; - bits = r->bits % b->access; - - pcilib_register_value_t buf[n + 1]; - memset(buf, 0, (n + 1) * sizeof(pcilib_register_value_t)); - - if ((b->endianess == PCILIB_BIG_ENDIAN)||((b->endianess == PCILIB_HOST_ENDIAN)&&(ntohs(1) == 1))) { - pcilib_error("Big-endian byte order support is not implemented"); - return PCILIB_ERROR_NOTSUPPORTED; - } else { - if (b->access == sizeof(pcilib_register_value_t) * 8) { - buf[0] = value; - } else { - for (i = 0, res = value; (res > 0)&&(i <= n); ++i) { - buf[i] = res & BIT_MASK(b->access); - res >>= b->access; - } - - if (res) { - pcilib_error("Value %i is too big to fit in the register %s", value, r->name); - return PCILIB_ERROR_OUTOFRANGE; - } - } - } - - err = pcilib_write_register_space_internal(ctx, bank, r->addr, n, r->offset, bits, r->rwmask, buf); - return err; -} - -int pcilib_write_register(pcilib_t *ctx, const char *bank, const char *regname, pcilib_register_value_t value) { - int reg; - - reg = pcilib_find_register(ctx, bank, regname); - if (reg < 0) { - pcilib_error("Register (%s) is not found", regname); - return PCILIB_ERROR_NOTFOUND; - } - - return pcilib_write_register_by_id(ctx, reg, value); -} diff --git a/register.h b/register.h deleted file mode 100644 index cd13522..0000000 --- a/register.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef _PCILIB_REGISTER_H -#define _PCILIB_REGISTER_H - -#include -#include - -typedef enum { - PCILIB_REGISTER_R = 1, /**< reading from register is allowed */ - PCILIB_REGISTER_W = 2, /**< normal writting to register is allowed */ - PCILIB_REGISTER_RW = 3, - PCILIB_REGISTER_W1C = 4, /**< writting 1 resets the bit, writting 0 keeps the value */ - PCILIB_REGISTER_RW1C = 5, - PCILIB_REGISTER_W1I = 8, /**< writting 1 inversts the bit, writting 0 keeps the value */ - PCILIB_REGISTER_RW1I = 9, -} pcilib_register_mode_t; - -typedef enum { - PCILIB_REGISTER_STANDARD = 0, - PCILIB_REGISTER_FIFO, - PCILIB_REGISTER_BITS -} pcilib_register_type_t; - -typedef struct { - pcilib_register_addr_t addr; /**< Register address in the bank */ - pcilib_register_size_t offset; /**< Register offset in the byte (in bits) */ - pcilib_register_size_t bits; /**< Register size in bits */ - pcilib_register_value_t defvalue; /**< Default register value (some protocols, i.e. software registers, may set it during the initialization) */ - pcilib_register_value_t rwmask; /**< Used to define how external bits of PCILIB_REGISTER_BITS registers are treated. - To keep bit value unchanged, we need to observe the following behavior depending on status of corresponding bit in this field: - 1 - standard bit (i.e. if we want to keep the bit value we need to read it, and, the write back), - 0 - non-standard bit which behavior is defined by mode (only partially implemented. - so far only 1C/1I modes (zero should be written to preserve the value) are supported */ - pcilib_register_mode_t mode; /**< Register access (ro/wo/rw) and how writting to register works (if value just set as specified or, for instance, the bits which - are on in the value are cleared/inverted). For information only, no preprocessing on bits is performed. */ - pcilib_register_type_t type; /**< Defines type of register is it standard register, subregister for bit fields or view, fifo */ - pcilib_register_bank_addr_t bank; /**< Specified the address of the bank this register belongs to */ - - const char *name; /**< The access name of the register */ - const char *description; /**< Brief description of the register */ -} pcilib_register_description_t; - -/* -typedef struct { - pcilib_register_bank_t bank; -} pcilib_register_context_t; -*/ - -int pcilib_add_registers(pcilib_t *ctx, size_t n, const pcilib_register_description_t *registers); - - -#endif /* _PCILIB_REGISTER_H */ diff --git a/tests/grab.sh b/tests/grab.sh index daf142e..daa08c1 100755 --- a/tests/grab.sh +++ b/tests/grab.sh @@ -1,8 +1,8 @@ #! /bin/bash function pci { - PCILIB_PATH="/root/pcitool" - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* + PCILIB_PATH=".." + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* } rm -f images.raw diff --git a/tests/ipedma/ipecamera-frame.sh b/tests/ipedma/ipecamera-frame.sh index 9862432..5e72c6c 100755 --- a/tests/ipedma/ipecamera-frame.sh +++ b/tests/ipedma/ipecamera-frame.sh @@ -5,7 +5,7 @@ TESTS_PATH="`( cd \"$TESTS_PATH\" && pwd )`" function pci { PCILIB_PATH=$TESTS_PATH/../.. - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci -m ipedma $* + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci -m ipedma $* } diff --git a/tests/ipedma/ipecamera-test.sh b/tests/ipedma/ipecamera-test.sh index 3984c82..cd21391 100755 --- a/tests/ipedma/ipecamera-test.sh +++ b/tests/ipedma/ipecamera-test.sh @@ -4,7 +4,7 @@ size=65536 function pci { PCILIB_PATH=`pwd`/../.. - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci -m ipedma $* + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci -m ipedma $* } diff --git a/tests/ipedma/test.sh b/tests/ipedma/test.sh index 4054f8a..62c391a 100755 --- a/tests/ipedma/test.sh +++ b/tests/ipedma/test.sh @@ -4,7 +4,7 @@ size=65536 function pci { PCILIB_PATH=`pwd`/../.. - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci -m ipedma $* + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci -m ipedma $* } diff --git a/tests/nwldma/bench.sh b/tests/nwldma/bench.sh index b36c251..d0bf323 100755 --- a/tests/nwldma/bench.sh +++ b/tests/nwldma/bench.sh @@ -1,8 +1,8 @@ #!/bin/bash function pci { - PCILIB_PATH="/root/pcitool" - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* + PCILIB_PATH="../.." + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* } size=16 diff --git a/tests/nwldma/cleanup.sh b/tests/nwldma/cleanup.sh index 5ef568e..87e1517 100755 --- a/tests/nwldma/cleanup.sh +++ b/tests/nwldma/cleanup.sh @@ -1,8 +1,8 @@ #!/bin/bash function pci { - PCILIB_PATH="/root/pcitool" - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* + PCILIB_PATH="../.." + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* } pci --start-dma dma1r diff --git a/tests/test-iommu.sh b/tests/test-iommu.sh index 74e3ece..5a5924b 100755 --- a/tests/test-iommu.sh +++ b/tests/test-iommu.sh @@ -1,5 +1,10 @@ #! /bin/bash +function pci { + PCILIB_PATH=".." + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* +} + i=1 while [ 1 ]; do pci --start-dma dma1r diff --git a/tests/xilinxdma/xilinx_dma.sh b/tests/xilinxdma/xilinx_dma.sh index 6aada8b..4fedac3 100755 --- a/tests/xilinxdma/xilinx_dma.sh +++ b/tests/xilinxdma/xilinx_dma.sh @@ -6,8 +6,8 @@ ITERATIONS=2 BUFFERS=16 function pci { - PCILIB_PATH=`pwd`/.. - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* + PCILIB_PATH=`pwd`/../.. + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* } diff --git a/tests/xilinxdma/xilinx_dma_static_mem.sh b/tests/xilinxdma/xilinx_dma_static_mem.sh index e3ba0f5..23ee5c9 100755 --- a/tests/xilinxdma/xilinx_dma_static_mem.sh +++ b/tests/xilinxdma/xilinx_dma_static_mem.sh @@ -8,7 +8,7 @@ BUFFER_SIZE=8 function pci { PCILIB_PATH=`pwd`/.. - LD_LIBRARY_PATH="$PCILIB_PATH" $PCILIB_PATH/pci $* + LD_LIBRARY_PATH="$PCILIB_PATH/pcilib" $PCILIB_PATH/pcitool/pci $* } diff --git a/tools.c b/tools.c deleted file mode 100644 index 352127d..0000000 --- a/tools.c +++ /dev/null @@ -1,355 +0,0 @@ -#define _POSIX_C_SOURCE 200112L -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "pci.h" -#include "tools.h" -#include "error.h" - -int pcilib_isnumber(const char *str) { - int i = 0; - for (i = 0; str[i]; i++) - if (!isdigit(str[i])) return 0; - return 1; -} - -int pcilib_isxnumber(const char *str) { - int i = 0; - - if ((str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) i += 2; - - for (; str[i]; i++) - if (!isxdigit(str[i])) return 0; - - return 1; -} - -int pcilib_isnumber_n(const char *str, size_t len) { - int i = 0; - for (i = 0; (str[i])&&(i < len); i++) - if (!isdigit(str[i])) return 0; - return 1; -} - -int pcilib_isxnumber_n(const char *str, size_t len) { - int i = 0; - - if ((len > 1)&&(str[0] == '0')&&((str[1] == 'x')||(str[1] == 'X'))) i += 2; - - for (; (str[i])&&(i < len); i++) - if (!isxdigit(str[i])) return 0; - - return 1; -} - - -uint16_t pcilib_swap16(uint16_t x) { - return (((x<<8)&0xFFFF) | ((x>>8)&0xFFFF)); -} - -uint32_t pcilib_swap32(uint32_t x) { - return ((x & 0xFF) << 24) | \ - ((x & 0xFF00) << 8) | \ - ((x & 0xFF0000) >> 8) | \ - ((x & 0xFF000000) >> 24); -} - -uint64_t pcilib_swap64(uint64_t x) { - return (((uint64_t)(x) << 56) | \ - (((uint64_t)(x) << 40) & 0xff000000000000ULL) | \ - (((uint64_t)(x) << 24) & 0xff0000000000ULL) | \ - (((uint64_t)(x) << 8) & 0xff00000000ULL) | \ - (((uint64_t)(x) >> 8) & 0xff000000ULL) | \ - (((uint64_t)(x) >> 24) & 0xff0000ULL) | \ - (((uint64_t)(x) >> 40) & 0xff00ULL) | \ - ((uint64_t)(x) >> 56)); -} - -void pcilib_swap(void *dst, void *src, size_t size, size_t n) { - int i; - switch (size) { - case 1: - if (src != dst) memcpy(dst, src, n); - break; - case 2: - for (i = 0; i < n; i++) { - ((uint16_t*)dst)[i] = pcilib_swap16(((uint16_t*)src)[i]); - } - break; - case 4: - for (i = 0; i < n; i++) { - ((uint32_t*)dst)[i] = pcilib_swap32(((uint32_t*)src)[i]); - } - break; - case 8: - for (i = 0; i < n; i++) { - ((uint64_t*)dst)[i] = pcilib_swap64(((uint64_t*)src)[i]); - } - break; - default: - pcilib_error("Invalid word size: %i", size); - } -} - -void *pcilib_memcpy8(void * dst, void const * src, size_t len) { - int i; - for (i = 0; i < len; i++) ((char*)dst)[i] = ((char*)src)[i]; - return dst; -} - -void *pcilib_memcpy32(void * dst, void const * src, size_t len) { - uint32_t * plDst = (uint32_t *) dst; - uint32_t const * plSrc = (uint32_t const *) src; - - while (len >= 4) { -// *plDst = ntohl(*plSrc); - *plDst = *plSrc; - plSrc++; - plDst++; - len -= 4; - } - - char * pcDst = (char *) plDst; - char const * pcSrc = (char const *) plSrc; - - while (len--) { - *pcDst++ = *pcSrc++; - } - - return (dst); -} - - -void *pcilib_memcpy64(void * dst, void const * src, size_t len) { - uint64_t * plDst = (uint64_t *) dst; - uint64_t const * plSrc = (uint64_t const *) src; - - while (len >= 8) { - *plDst++ = *plSrc++; - len -= 8; - } - - char * pcDst = (char *) plDst; - char const * pcSrc = (char const *) plSrc; - - while (len--) { - *pcDst++ = *pcSrc++; - } - - return (dst); -} - -/* -void *memcpy128(void * dst, void const * src, size_t len) { - - long pos = - (len>>2); - char * plDst = (char *) dst - 4 * pos; - char const * plSrc = (char const *) src - 4 * pos; - - if (pos) { - __asm__ __volatile__ ( - "1: \n\t" - "mov (%0,%2,4), %%edi \n\t" - "mov %%edi, (%1,%2,4) \n\t" - "inc %2 \n\t" - "jnz 1b \n\t" - : - : "r" (plSrc), "r" (plDst), "r" (pos) - : "%edi" - ); - } - - - - long pos = - ((len>>4)<<4); - char * plDst = (char *) dst - pos; - char const * plSrc = (char const *) src - pos; - - if (pos) { - __asm__ __volatile__ ( - "1: \n\t" -// "movdqa (%0,%2), %%xmm0 \n\t" - "mov (%0,%2), %%esi \n\t" - "movd %%esi, %%xmm0 \n\t" - "mov 4(%0,%2), %%esi \n\t" - "movd %%esi, %%xmm1 \n\t" - "mov 8(%0,%2), %%esi \n\t" - "movd %%esi, %%xmm2 \n\t" - "mov 12(%0,%2), %%esi \n\t" - "movd %%esi, %%xmm3 \n\t" - "pslldq $4, %%xmm1 \n\t" - "por %%xmm1, %%xmm0 \n\t" - "pslldq $8, %%xmm2 \n\t" - "por %%xmm2, %%xmm0 \n\t" - "pslldq $12, %%xmm3 \n\t" - "por %%xmm3, %%xmm0 \n\t" - - "movntdq %%xmm0, (%1,%2) \n\t" - "add $16, %2 \n\t" - "jnz 1b \n\t" - : - : "r" (plSrc), "r" (plDst), "r" (pos) - : "%rsi" - ); - } - - - - len &= 0x3; - - char * pcDst = (char *) plDst; - char const * pcSrc = (char const *) plSrc; - - while (len--) { - *pcDst++ = *pcSrc++; - } - - return (dst); -} -*/ - -void *pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pcilib_endianess_t endianess) { - uint32_t * plDst = (uint32_t *) dst; - uint32_t const * plSrc = (uint32_t const *) src; - - int swap = 0; - - if (endianess) - swap = (endianess == PCILIB_BIG_ENDIAN)?(ntohs(1)!=1):(ntohs(1)==1); - - assert(size == 4); // only 32 bit at the moment - - if (swap) { - while (n > 0) { - *plDst = ntohl(*plSrc); - ++plSrc; - ++plDst; - --n; - } - } else { - while (n > 0) { - *plDst = *plSrc; - ++plSrc; - ++plDst; - --n; - } - } - - return dst; -} - -int pcilib_get_page_mask() { - int pagesize,pagemask,temp; - - pagesize = sysconf(_SC_PAGESIZE); - - for( pagemask=0, temp = pagesize; temp != 1; ) { - temp = (temp >> 1); - pagemask = (pagemask << 1)+1; - } - return pagemask; -} - -int pcilib_get_cpu_count() { - int err; - - int cpu_count; - cpu_set_t mask; - - err = sched_getaffinity(getpid(), sizeof(mask), &mask); - if (err) return 1; - -#ifdef CPU_COUNT - cpu_count = CPU_COUNT(&mask); -#else - for (cpu_count = 0; cpu_count < CPU_SETSIZE; cpu_count++) { - if (!CPU_ISSET(cpu_count, &mask)) break; - } -#endif - - if (!cpu_count) cpu_count = PCILIB_DEFAULT_CPU_COUNT; - return cpu_count; -} - - -int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout) { - tv->tv_usec += timeout%1000000; - if (tv->tv_usec > 999999) { - tv->tv_usec -= 1000000; - tv->tv_sec += 1 + timeout/1000000; - } else { - tv->tv_sec += timeout/1000000; - } - - return 0; -} - -int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout) { - gettimeofday(tv, NULL); - pcilib_add_timeout(tv, timeout); - - return 0; -} - -int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout) { - int64_t res; - struct timeval tvs; - - if (!tve->tv_sec) return 0; - - gettimeofday(&tvs, NULL); - res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec)); - // Hm... Some problems comparing signed and unsigned. So, sign check first - if ((res < 0)||(res < timeout)) { - return 1; - } - - return 0; -} - -pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve) { - int64_t res; - struct timeval tvs; - - gettimeofday(&tvs, NULL); - res = ((tve->tv_sec - tvs.tv_sec)*1000000 + (tve->tv_usec - tvs.tv_usec)); - - if (res < 0) return 0; - return res; -} - -int pcilib_sleep_until_deadline(struct timeval *tv) { - struct timespec wait; - pcilib_timeout_t duration; - - duration = pcilib_calc_time_to_deadline(tv); - if (duration > 0) { - wait.tv_sec = duration / 1000000; - wait.tv_nsec = 1000 * (duration % 1000000); - nanosleep(&wait, NULL); - } - - return 0; -} - -pcilib_timeout_t pcilib_timediff(struct timeval *tvs, struct timeval *tve) { - return ((tve->tv_sec - tvs->tv_sec)*1000000 + (tve->tv_usec - tvs->tv_usec)); -} - -int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2) { - if (tv1->tv_sec > tv2->tv_sec) return 1; - else if (tv1->tv_sec < tv2->tv_sec) return -1; - else if (tv1->tv_usec > tv2->tv_usec) return 1; - else if (tv1->tv_usec < tv2->tv_usec) return -1; - return 0; -} diff --git a/tools.h b/tools.h deleted file mode 100644 index 41dc071..0000000 --- a/tools.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef _PCITOOL_TOOLS_H -#define _PCITOOL_TOOLS_H - -#include -#include - -#include - -#define pcilib_memcpy pcilib_memcpy32 -#define pcilib_datacpy pcilib_datacpy32 - -#define BIT_MASK(bits) ((1ll << (bits)) - 1) - -#define min2(a, b) (((a)<(b))?(a):(b)) - - -int pcilib_isnumber(const char *str); -int pcilib_isxnumber(const char *str); -int pcilib_isnumber_n(const char *str, size_t len); -int pcilib_isxnumber_n(const char *str, size_t len); - -uint16_t pcilib_swap16(uint16_t x); -uint32_t pcilib_swap32(uint32_t x); -uint64_t pcilib_swap64(uint64_t x); -void pcilib_swap(void *dst, void *src, size_t size, size_t n); - -void * pcilib_memcpy8(void * dst, void const * src, size_t len); -void * pcilib_memcpy32(void * dst, void const * src, size_t len); -void * pcilib_memcpy64(void * dst, void const * src, size_t len); -void * pcilib_datacpy32(void * dst, void const * src, uint8_t size, size_t n, pcilib_endianess_t endianess); - -int pcilib_get_page_mask(); -int pcilib_get_cpu_count(); - - -int pcilib_add_timeout(struct timeval *tv, pcilib_timeout_t timeout); -int pcilib_calc_deadline(struct timeval *tv, pcilib_timeout_t timeout); -int pcilib_check_deadline(struct timeval *tve, pcilib_timeout_t timeout); -pcilib_timeout_t pcilib_calc_time_to_deadline(struct timeval *tve); -int pcilib_sleep_until_deadline(struct timeval *tv); -int pcilib_timecmp(struct timeval *tv1, struct timeval *tv2); -pcilib_timeout_t pcilib_timediff(struct timeval *tve, struct timeval *tvs); - -#endif /* _PCITOOL_TOOS_H */ -- cgit v1.2.3