diff options
author | Suren A. Chilingaryan <csa@suren.me> | 2015-08-06 04:24:58 +0200 |
---|---|---|
committer | Suren A. Chilingaryan <csa@suren.me> | 2015-08-06 04:24:58 +0200 |
commit | d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa (patch) | |
tree | 5dac744f57edafe76e73648509a19bfa275097f5 /pcilib | |
parent | 8b8a2bee0bce0bc9cc78d43f236c6a3d8a0bd2e4 (diff) | |
download | pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.gz pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.bz2 pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.xz pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.zip |
Protect access to the DMA engine with locks
Diffstat (limited to 'pcilib')
-rw-r--r-- | pcilib/dma.c | 62 | ||||
-rw-r--r-- | pcilib/pci.c | 8 | ||||
-rw-r--r-- | pcilib/pci.h | 3 |
3 files changed, 68 insertions, 5 deletions
diff --git a/pcilib/dma.c b/pcilib/dma.c index f6b8053..be02c21 100644 --- a/pcilib/dma.c +++ b/pcilib/dma.c @@ -61,8 +61,11 @@ pcilib_dma_engine_t pcilib_add_dma_engine(pcilib_t *ctx, pcilib_dma_engine_descr int pcilib_init_dma(pcilib_t *ctx) { int err; pcilib_dma_context_t *dma_ctx = NULL; + const pcilib_dma_description_t *info = &ctx->dma; const pcilib_model_description_t *model_info = pcilib_get_model_description(ctx); + pcilib_dma_engine_t dma; + if (ctx->dma_ctx) return 0; @@ -86,6 +89,24 @@ int pcilib_init_dma(pcilib_t *ctx) { } if (dma_ctx) { + for (dma = 0; info->engines[dma].addr_bits; dma++) { + if (info->engines[dma].direction&PCILIB_DMA_FROM_DEVICE) { + ctx->dma_rlock[dma] = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "dma%ir/%s", info->engines[dma].addr, info->name); + if (!ctx->dma_rlock[dma]) break; + } + if (info->engines[dma].direction&PCILIB_DMA_TO_DEVICE) { + ctx->dma_wlock[dma] = pcilib_get_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, "dma%iw/%s", info->engines[dma].addr, info->name); + if (!ctx->dma_wlock[dma]) break; + } + } + + if (info->engines[dma].addr_bits) { + if (ctx->dma.api->free) + ctx->dma.api->free(dma_ctx); + pcilib_error("Failed to intialize DMA locks"); + return PCILIB_ERROR_FAILED; + } + dma_ctx->pcilib = ctx; // DS: parameters? ctx->dma_ctx = dma_ctx; @@ -105,11 +126,11 @@ int pcilib_start_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, pcilib_dma_flags_t 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); } @@ -201,6 +222,7 @@ static int pcilib_dma_skip_callback(void *arg, pcilib_dma_flags_t flags, size_t } 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 err; const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -228,7 +250,21 @@ int pcilib_stream_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, si return PCILIB_ERROR_NOTSUPPORTED; } - return info->api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr); + err = pcilib_try_lock(ctx->dma_rlock[dma]); + if (err) { + if ((err == PCILIB_ERROR_BUSY)||(err == PCILIB_ERROR_TIMEOUT)) + pcilib_error("DMA engine (%i) is busy", dma); + else + pcilib_error("Error (%i) locking DMA engine (%i)", err, dma); + + return err; + } + + err = info->api->stream(ctx->dma_ctx, dma, addr, size, flags, timeout, cb, cbattr); + + pcilib_unlock(ctx->dma_rlock[dma]); + + return err; } 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) { @@ -278,6 +314,8 @@ int pcilib_skip_dma(pcilib_t *ctx, pcilib_dma_engine_t dma) { 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) { + int err; + const pcilib_dma_description_t *info = pcilib_get_dma_description(ctx); if (!info) { pcilib_error("DMA is not supported by the device"); @@ -304,8 +342,22 @@ int pcilib_push_dma(pcilib_t *ctx, pcilib_dma_engine_t dma, uintptr_t addr, size 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); + + err = pcilib_try_lock(ctx->dma_wlock[dma]); + if (err) { + if (err == PCILIB_ERROR_BUSY) + pcilib_error("DMA engine (%i) is busy", dma); + else + pcilib_error("Error (%i) locking DMA engine (%i)", err, dma); + + return err; + } + + err = info->api->push(ctx->dma_ctx, dma, addr, size, flags, timeout, buf, written); + + pcilib_unlock(ctx->dma_wlock[dma]); + + return err; } diff --git a/pcilib/pci.c b/pcilib/pci.c index 6078a6e..4351c1e 100644 --- a/pcilib/pci.c +++ b/pcilib/pci.c @@ -337,6 +337,7 @@ void pcilib_close(pcilib_t *ctx) { pcilib_bar_t i; if (ctx) { + pcilib_dma_engine_t dma; 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; @@ -344,6 +345,13 @@ void pcilib_close(pcilib_t *ctx) { if ((eapi)&&(eapi->free)) eapi->free(ctx->event_ctx); if ((dapi)&&(dapi->free)) dapi->free(ctx->dma_ctx); + for (dma = 0; dma < PCILIB_MAX_DMA_ENGINES; dma++) { + if (ctx->dma_rlock[dma]) + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, ctx->dma_rlock[dma]); + if (ctx->dma_wlock[dma]) + pcilib_return_lock(ctx, PCILIB_LOCK_FLAGS_DEFAULT, ctx->dma_wlock[dma]); + } + pcilib_free_register_banks(ctx); if (ctx->register_ctx) diff --git a/pcilib/pci.h b/pcilib/pci.h index c97f753..51bb352 100644 --- a/pcilib/pci.h +++ b/pcilib/pci.h @@ -71,6 +71,9 @@ struct pcilib_s { pcilib_dma_context_t *dma_ctx; /**< DMA context */ pcilib_context_t *event_ctx; /**< Implmentation context */ + pcilib_lock_t *dma_rlock[PCILIB_MAX_DMA_ENGINES]; /**< Per-engine locks to serialize streaming and read operations */ + pcilib_lock_t *dma_wlock[PCILIB_MAX_DMA_ENGINES]; /**< Per-engine locks to serialize write operations */ + struct pcilib_locking_s locks; /**< Context of locking subsystem */ #ifdef PCILIB_FILE_IO |