lib/accel: add batch capability and prep_copy() to sw engine

Doesn't provide any performance benefit but lets apps consistently
use the batch interface regardless of engine. Additional functions
and test code to follow.

Signed-off-by: paul luse <paul.e.luse@intel.com>
Change-Id: Ia737045560ddd5117a689f7715fa206268bbc13d
Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/2911
Community-CI: Mellanox Build Bot
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
This commit is contained in:
paul luse 2020-06-16 09:56:16 -04:00 committed by Tomasz Zawadzki
parent 93a5e08fc8
commit 90c4ae4582

View File

@ -288,6 +288,7 @@ spdk_accel_engine_initialize(void)
{
SPDK_NOTICELOG("Accel engine initialized to use software engine.\n");
accel_engine_module_initialize();
/*
* We need a unique identifier for the accel engine framework, so use the
* spdk_accel_module_list address for this purpose.
@ -371,13 +372,144 @@ spdk_accel_engine_config_text(FILE *fp)
}
}
/* The SW Accelerator module is "built in" here (rest of file) */
/*
* The SW Accelerator module is "built in" here (rest of file)
*/
#define SW_ACCEL_BATCH_SIZE 2048
enum sw_accel_opcode {
SW_ACCEL_OPCODE_MEMMOVE = 0,
SW_ACCEL_OPCODE_MEMFILL = 1,
SW_ACCEL_OPCODE_COMPARE = 2,
SW_ACCEL_OPCODE_CRC32C = 3,
SW_ACCEL_OPCODE_DUALCAST = 4,
};
struct sw_accel_op {
struct sw_accel_io_channel *sw_ch;
void *cb_arg;
spdk_accel_completion_cb cb_fn;
void *src;
union {
void *dst;
void *src2;
};
void *dst2;
uint32_t seed;
uint64_t fill_pattern;
enum sw_accel_opcode op_code;
uint64_t nbytes;
TAILQ_ENTRY(sw_accel_op) link;
};
/* The sw accel engine only supports one outstanding batch at a time. */
struct sw_accel_io_channel {
TAILQ_HEAD(, sw_accel_op) op_pool;
TAILQ_HEAD(, sw_accel_op) batch;
};
static uint64_t
sw_accel_get_capabilities(void)
{
return ACCEL_COPY | ACCEL_FILL | ACCEL_CRC32C | ACCEL_COMPARE |
ACCEL_DUALCAST;
ACCEL_DUALCAST | ACCEL_BATCH;
}
static uint32_t
sw_accel_batch_get_max(void)
{
return SW_ACCEL_BATCH_SIZE;
}
/* The sw engine plug-in does not ahve a public API, it is only callable
* from the accel fw and thus does not need to have its own struct definition
* of a batch, it just simply casts the address of the single supported batch
* as the struct spdk_accel_batch pointer.
*/
static struct spdk_accel_batch *
sw_accel_batch_start(struct spdk_io_channel *ch)
{
struct sw_accel_io_channel *sw_ch = spdk_io_channel_get_ctx(ch);
if (!TAILQ_EMPTY(&sw_ch->batch)) {
SPDK_ERRLOG("SW accel engine only supports one batch at a time.\n");
return NULL;
}
return (struct spdk_accel_batch *)&sw_ch->batch;
}
static int
sw_accel_batch_prep_copy(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch,
void *dst, void *src, uint64_t nbytes, spdk_accel_completion_cb cb)
{
struct sw_accel_op *op;
struct sw_accel_io_channel *sw_ch = spdk_io_channel_get_ctx(ch);
if ((struct spdk_accel_batch *)&sw_ch->batch != batch) {
SPDK_ERRLOG("Invalid batch\n");
return -EINVAL;
}
if (!TAILQ_EMPTY(&sw_ch->op_pool)) {
op = TAILQ_FIRST(&sw_ch->op_pool);
TAILQ_REMOVE(&sw_ch->op_pool, op, link);
} else {
SPDK_ERRLOG("Ran out of operations for batch\n");
return -ENOMEM;
}
op->cb_arg = cb_arg;
op->cb_fn = cb;
op->sw_ch = sw_ch;
op->src = src;
op->dst = dst;
op->nbytes = nbytes;
op->op_code = SW_ACCEL_OPCODE_MEMMOVE;
TAILQ_INSERT_TAIL(&sw_ch->batch, op, link);
return 0;
}
static int
sw_accel_batch_submit(void *cb_arg, struct spdk_io_channel *ch, struct spdk_accel_batch *batch,
spdk_accel_completion_cb cb)
{
struct sw_accel_op *op;
struct sw_accel_io_channel *sw_ch = spdk_io_channel_get_ctx(ch);
struct spdk_accel_task *accel_req;
if ((struct spdk_accel_batch *)&sw_ch->batch != batch) {
SPDK_ERRLOG("Invalid batch\n");
return -EINVAL;
}
/* Complete the batch items. */
while ((op = TAILQ_FIRST(&sw_ch->batch))) {
TAILQ_REMOVE(&sw_ch->batch, op, link);
accel_req = (struct spdk_accel_task *)((uintptr_t)op->cb_arg -
offsetof(struct spdk_accel_task, offload_ctx));
switch (op->op_code) {
case SW_ACCEL_OPCODE_MEMMOVE:
memcpy(op->dst, op->src, op->nbytes);
break;
default:
assert(false);
break;
}
op->cb_fn(accel_req, 0);
TAILQ_INSERT_TAIL(&sw_ch->op_pool, op, link);
}
/* Now complete the batch request itself. */
accel_req = (struct spdk_accel_task *)((uintptr_t)cb_arg -
offsetof(struct spdk_accel_task, offload_ctx));
cb(accel_req, 0);
return 0;
}
static int
@ -463,10 +595,10 @@ static struct spdk_accel_engine sw_accel_engine = {
.get_capabilities = sw_accel_get_capabilities,
.copy = sw_accel_submit_copy,
.dualcast = sw_accel_submit_dualcast,
.batch_get_max = NULL, /* TODO */
.batch_create = NULL, /* TODO */
.batch_prep_copy = NULL, /* TODO */
.batch_submit = NULL, /* TODO */
.batch_get_max = sw_accel_batch_get_max,
.batch_create = sw_accel_batch_start,
.batch_prep_copy = sw_accel_batch_prep_copy,
.batch_submit = sw_accel_batch_submit,
.compare = sw_accel_submit_compare,
.fill = sw_accel_submit_fill,
.crc32c = sw_accel_submit_crc32c,
@ -476,12 +608,39 @@ static struct spdk_accel_engine sw_accel_engine = {
static int
sw_accel_create_cb(void *io_device, void *ctx_buf)
{
struct sw_accel_io_channel *sw_ch = ctx_buf;
struct sw_accel_op *op;
int i;
TAILQ_INIT(&sw_ch->batch);
TAILQ_INIT(&sw_ch->op_pool);
for (i = 0 ; i < SW_ACCEL_BATCH_SIZE ; i++) {
op = calloc(1, sizeof(struct sw_accel_op));
if (op == NULL) {
SPDK_ERRLOG("Failed to allocate operation for batch.\n");
while ((op = TAILQ_FIRST(&sw_ch->op_pool))) {
TAILQ_REMOVE(&sw_ch->op_pool, op, link);
free(op);
}
return -ENOMEM;
}
TAILQ_INSERT_TAIL(&sw_ch->op_pool, op, link);
}
return 0;
}
static void
sw_accel_destroy_cb(void *io_device, void *ctx_buf)
{
struct sw_accel_io_channel *sw_ch = ctx_buf;
struct sw_accel_op *op;
while ((op = TAILQ_FIRST(&sw_ch->op_pool))) {
TAILQ_REMOVE(&sw_ch->op_pool, op, link);
free(op);
}
}
static struct spdk_io_channel *sw_accel_get_io_channel(void)
@ -499,8 +658,8 @@ static int
sw_accel_engine_init(void)
{
accel_sw_register(&sw_accel_engine);
spdk_io_device_register(&sw_accel_engine, sw_accel_create_cb, sw_accel_destroy_cb, 0,
"sw_accel_engine");
spdk_io_device_register(&sw_accel_engine, sw_accel_create_cb, sw_accel_destroy_cb,
sizeof(struct sw_accel_io_channel), "sw_accel_engine");
return 0;
}