From f11869c44d3c81ba4a7e80f2b8ea9c11e15cd628 Mon Sep 17 00:00:00 2001 From: Ben Walker Date: Wed, 17 Nov 2021 09:55:55 -0700 Subject: [PATCH] idxd: Add support for vectored compare operations Compare two scattered memory regions Change-Id: I6ce5c9e7bc1ee1ef0e9173c00e86628d43a1e41f Signed-off-by: Ben Walker Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/10287 Community-CI: Broadcom CI Community-CI: Mellanox Build Bot Tested-by: SPDK CI Jenkins Reviewed-by: Jim Harris Reviewed-by: Changpeng Liu --- examples/idxd/perf/perf.c | 7 ++- include/spdk/idxd.h | 10 ++-- lib/idxd/idxd.c | 67 +++++++++++++++++++++++++-- module/accel/idxd/accel_engine_idxd.c | 6 ++- 4 files changed, 80 insertions(+), 10 deletions(-) diff --git a/examples/idxd/perf/perf.c b/examples/idxd/perf/perf.c index bacb70304..76563c4e1 100644 --- a/examples/idxd/perf/perf.c +++ b/examples/idxd/perf/perf.c @@ -652,8 +652,11 @@ _submit_ops(struct idxd_chan_entry *t, struct idxd_task *task) task->expected_status = 0; *(uint8_t *)task->dst = DATA_PATTERN; } - rc = spdk_idxd_submit_compare(t->ch, task->dst, task->src, - g_xfer_size_bytes, idxd_done, task); + siov.iov_base = task->src; + siov.iov_len = g_xfer_size_bytes; + diov.iov_base = task->dst; + diov.iov_len = g_xfer_size_bytes; + rc = spdk_idxd_submit_compare(t->ch, &siov, 1, &diov, 1, idxd_done, task); break; case IDXD_DUALCAST: rc = spdk_idxd_submit_dualcast(t->ch, task->dst, task->dst2, diff --git a/include/spdk/idxd.h b/include/spdk/idxd.h index a2034e4e4..bf7226554 100644 --- a/include/spdk/idxd.h +++ b/include/spdk/idxd.h @@ -281,9 +281,10 @@ int spdk_idxd_batch_prep_compare(struct spdk_idxd_io_channel *chan, struct idxd_ * by writing to the proper device portal. * * \param chan IDXD channel to submit request. - * \param src1 First source to compare. - * \param src2 Second source to compare. - * \param nbytes Number of bytes to compare. + * \param siov1 First source iovec + * \param siov1cnt Number of elements in siov1 + * \param siov2 Second source iovec + * \param siov2cnt Number of elements in siov2 * \param cb_fn Callback function which will be called when the request is complete. * \param cb_arg Opaque value which will be passed back as the arg parameter in * the completion callback. @@ -291,7 +292,8 @@ int spdk_idxd_batch_prep_compare(struct spdk_idxd_io_channel *chan, struct idxd_ * \return 0 on success, negative errno on failure. */ int spdk_idxd_submit_compare(struct spdk_idxd_io_channel *chan, - void *src1, const void *src2, uint64_t nbytes, + struct iovec *siov1, size_t siov1cnt, + struct iovec *siov2, size_t siov2cnt, spdk_idxd_req_cb cb_fn, void *cb_arg); /** diff --git a/lib/idxd/idxd.c b/lib/idxd/idxd.c index 477ba5152..3bbaf83b2 100644 --- a/lib/idxd/idxd.c +++ b/lib/idxd/idxd.c @@ -625,9 +625,9 @@ error: return rc; } -int -spdk_idxd_submit_compare(struct spdk_idxd_io_channel *chan, void *src1, const void *src2, - uint64_t nbytes, spdk_idxd_req_cb cb_fn, void *cb_arg) +static inline int +_idxd_submit_compare_single(struct spdk_idxd_io_channel *chan, void *src1, const void *src2, + uint64_t nbytes, spdk_idxd_req_cb cb_fn, void *cb_arg) { struct idxd_hw_desc *desc; struct idxd_ops *op; @@ -669,6 +669,67 @@ error: return rc; } +int +spdk_idxd_submit_compare(struct spdk_idxd_io_channel *chan, + struct iovec *siov1, size_t siov1cnt, + struct iovec *siov2, size_t siov2cnt, + spdk_idxd_req_cb cb_fn, void *cb_arg) +{ + struct idxd_hw_desc *desc; + struct idxd_ops *op; + void *src1, *src2; + uint64_t src1_addr, src2_addr; + int rc; + size_t len; + struct idxd_batch *batch; + struct spdk_ioviter iter; + + if (siov1cnt == 1 && siov2cnt == 1) { + /* Simple case - comparing one buffer to another */ + if (siov1[0].iov_len != siov2[0].iov_len) { + return -EINVAL; + } + + return _idxd_submit_compare_single(chan, siov1[0].iov_base, siov2[0].iov_base, siov1[0].iov_len, + cb_fn, cb_arg); + } + + batch = spdk_idxd_batch_create(chan); + if (!batch) { + return -EBUSY; + } + + for (len = spdk_ioviter_first(&iter, siov1, siov1cnt, siov2, siov2cnt, &src1, &src2); + len > 0; + len = spdk_ioviter_next(&iter, &src1, &src2)) { + rc = _idxd_prep_batch_cmd(chan, NULL, NULL, batch, &desc, &op); + if (rc) { + goto err; + } + + rc = _vtophys(src1, &src1_addr, len); + if (rc) { + goto err; + } + + rc = _vtophys(src2, &src2_addr, len); + if (rc) { + goto err; + } + + desc->opcode = IDXD_OPCODE_COMPARE; + desc->src_addr = src1_addr; + desc->src2_addr = src2_addr; + desc->xfer_size = len; + } + + return spdk_idxd_batch_submit(chan, batch, cb_fn, cb_arg); + +err: + spdk_idxd_batch_cancel(chan, batch); + return rc; +} + int spdk_idxd_submit_fill(struct spdk_idxd_io_channel *chan, void *dst, uint64_t fill_pattern, uint64_t nbytes, spdk_idxd_req_cb cb_fn, void *cb_arg) diff --git a/module/accel/idxd/accel_engine_idxd.c b/module/accel/idxd/accel_engine_idxd.c index 18097e821..29eacce92 100644 --- a/module/accel/idxd/accel_engine_idxd.c +++ b/module/accel/idxd/accel_engine_idxd.c @@ -173,7 +173,11 @@ _process_single_task(struct spdk_io_channel *ch, struct spdk_accel_task *task) idxd_done, task); break; case ACCEL_OPCODE_COMPARE: - rc = spdk_idxd_submit_compare(chan->chan, task->src, task->src2, task->nbytes, idxd_done, task); + siov.iov_base = task->src; + siov.iov_len = task->nbytes; + diov.iov_base = task->dst; + diov.iov_len = task->nbytes; + rc = spdk_idxd_submit_compare(chan->chan, &siov, 1, &diov, 1, idxd_done, task); break; case ACCEL_OPCODE_MEMFILL: memset(&task->fill_pattern, fill_pattern, sizeof(uint64_t));