summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSuren A. Chilingaryan <csa@suren.me>2015-08-06 04:24:58 +0200
committerSuren A. Chilingaryan <csa@suren.me>2015-08-06 04:24:58 +0200
commitd60dd48eec0ef5d7bf2feca9b3f06374a2f444aa (patch)
tree5dac744f57edafe76e73648509a19bfa275097f5
parent8b8a2bee0bce0bc9cc78d43f236c6a3d8a0bd2e4 (diff)
downloadpcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.gz
pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.bz2
pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.tar.xz
pcitool-d60dd48eec0ef5d7bf2feca9b3f06374a2f444aa.zip
Protect access to the DMA engine with locks
-rw-r--r--pcilib/dma.c62
-rw-r--r--pcilib/pci.c8
-rw-r--r--pcilib/pci.h3
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