diff options
Diffstat (limited to 'dma.c')
-rw-r--r-- | dma.c | 327 |
1 files changed, 0 insertions, 327 deletions
@@ -1,327 +0,0 @@ -#include <stdio.h> -#include <string.h> -#include <strings.h> -#include <stdlib.h> -#include <stdint.h> -#include <stdarg.h> -#include <fcntl.h> -#include <unistd.h> -#include <sys/ioctl.h> -#include <sys/mman.h> -#include <arpa/inet.h> -#include <sys/time.h> -#include <errno.h> -#include <assert.h> - -#include "error.h" -#include "pcilib.h" -#include "pci.h" -#include "dma.h" - -const pcilib_dma_info_t *pcilib_get_dma_info(pcilib_t *ctx) { - if (!ctx->dma_ctx) { - pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); - - if ((ctx->event_ctx)&&(model_info->event_api->init_dma)) { - pcilib_map_register_space(ctx); - ctx->dma_ctx = model_info->event_api->init_dma(ctx->event_ctx); - } else if ((model_info->dma_api)&&(model_info->dma_api->init)) { - pcilib_map_register_space(ctx); - ctx->dma_ctx = model_info->dma_api->init(ctx, PCILIB_DMA_MODIFICATION_DEFAULT, NULL); - } - - if (!ctx->dma_ctx) return NULL; - } - - return &ctx->dma_info; -} - -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_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - for (i = 0; info->engines[i]; i++) { - if ((info->engines[i]->addr == dma)&&((info->engines[i]->direction&direction)==direction)) break; - } - - if (info->engines[i]) return i; - return PCILIB_DMA_ENGINE_INVALID; -} - -int pcilib_set_dma_engine_description(pcilib_t *ctx, pcilib_dma_engine_t engine, pcilib_dma_engine_description_t *desc) { - ctx->dma_info.engines[engine] = desc; - - return 0; -} - -int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t flags) { - const pcilib_dma_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - 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_info_t *info = pcilib_get_dma_info(ctx); - - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->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_info_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_info_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_info_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_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->stream) { - pcilib_error("The DMA read is not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (!info->engines[dma]) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - return PCILIB_ERROR_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_info_t *info = pcilib_get_dma_info(ctx); - if (!info) { - pcilib_error("DMA is not supported by the device"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (!ctx->model_info.dma_api) { - pcilib_error("DMA Engine is not configured in the current model"); - return PCILIB_ERROR_NOTAVAILABLE; - } - - if (!ctx->model_info.dma_api->push) { - pcilib_error("The DMA write is not supported by configured DMA engine"); - return PCILIB_ERROR_NOTSUPPORTED; - } - - if (!info->engines[dma]) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - return PCILIB_ERROR_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_info_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; - } - - if (!info->engines[dma]) { - pcilib_error("The DMA engine (%i) is not supported by device", dma); - 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_info_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; - } - - if (!info->engines[dma]) { - 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); -} |