This patch introduces the concept of chaining multiple accel operations and executing them all at once in a single step. This means that it will be possible to schedule accel operations at different layers of the stack (e.g. copy in NVMe-oF transport, crypto in bdev_crypto), but execute them all in a single place. Thanks to this, we can take advantage of hardware accelerators that supports executing multiple operations as a single operation (e.g. copy + crypto). This operation group is called spdk_accel_sequence and operations can be appended to that object via one of the spdk_accel_append_* functions. New operations are always added at the end of a sequence. Users can specify a callback to be notified when a particular operation in a sequence is completed, but they don't receive the status of whether it was successful or not. This is by design, as they shouldn't care about the status of an individual operation and should rely on other means to receive the status of the whole sequence. It's also important to note that any intermediate steps within a sequence may not produce observable results. For instance, appending a copy from A to B and then a copy from B to C, it's indeterminate whether A's data will be in B after a sequence is executed. It is only guaranteed that A's data will be in C. A sequence can also be reversed using spdk_accel_sequence_reverse(), meaning that the first operation becomes last and vice versa. It's especially useful in read paths, as it makes it possible to build the sequence during submission, then, once the data is read from storage, reverse the sequence and execute it. Finally, there are two ways to terminate a sequence: aborting or executing. It can be aborted via spdk_accel_sequence_abort() which will execute individual operations' callbacks and free any allocated resources. To execute it, one must use spdk_accel_sequence_finish(). For now, each operation is executed one by one and is submitted to the appropriate accel module. Executing multiple operations as a single one will be added in the future. Also, currently, only fill and copy operations can be appended to a sequence. Support for more operations will be added in subsequent patches. Signed-off-by: Konrad Sztyber <konrad.sztyber@intel.com> Change-Id: Id35d093e14feb59b996f780ef77e000e10bfcd20 Reviewed-on: https://review.spdk.io/gerrit/c/spdk/spdk/+/15529 Tested-by: SPDK CI Jenkins <sys_sgci@intel.com> Reviewed-by: Ben Walker <benjamin.walker@intel.com> Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Aleksey Marchuk <alexeymar@nvidia.com>
109 lines
2.6 KiB
C
109 lines
2.6 KiB
C
/* SPDX-License-Identifier: BSD-3-Clause
|
|
* Copyright (C) 2020 Intel Corporation.
|
|
* All rights reserved.
|
|
*/
|
|
|
|
#ifndef SPDK_ACCEL_MODULE_H
|
|
#define SPDK_ACCEL_MODULE_H
|
|
|
|
#include "spdk/stdinc.h"
|
|
|
|
#include "spdk/accel.h"
|
|
#include "spdk/queue.h"
|
|
#include "spdk/config.h"
|
|
|
|
struct spdk_accel_task;
|
|
|
|
void spdk_accel_task_complete(struct spdk_accel_task *task, int status);
|
|
|
|
struct spdk_accel_task {
|
|
struct accel_io_channel *accel_ch;
|
|
spdk_accel_completion_cb cb_fn;
|
|
void *cb_arg;
|
|
spdk_accel_step_cb step_cb_fn;
|
|
void *step_cb_arg;
|
|
struct spdk_memory_domain *src_domain;
|
|
void *src_domain_ctx;
|
|
struct spdk_memory_domain *dst_domain;
|
|
void *dst_domain_ctx;
|
|
union {
|
|
struct {
|
|
struct iovec *iovs; /* iovs passed by the caller */
|
|
uint32_t iovcnt; /* iovcnt passed by the caller */
|
|
} s;
|
|
void *src;
|
|
};
|
|
union {
|
|
struct {
|
|
struct iovec *iovs; /* iovs passed by the caller */
|
|
uint32_t iovcnt; /* iovcnt passed by the caller */
|
|
} d;
|
|
void *dst;
|
|
void *src2;
|
|
};
|
|
union {
|
|
void *dst2;
|
|
uint32_t seed;
|
|
uint64_t fill_pattern;
|
|
};
|
|
union {
|
|
uint32_t *crc_dst;
|
|
uint32_t *output_size;
|
|
};
|
|
enum accel_opcode op_code;
|
|
uint64_t nbytes;
|
|
uint64_t nbytes_dst;
|
|
int flags;
|
|
int status;
|
|
TAILQ_ENTRY(spdk_accel_task) link;
|
|
TAILQ_ENTRY(spdk_accel_task) seq_link;
|
|
};
|
|
|
|
struct spdk_accel_module_if {
|
|
/** Initialization function for the module. Called by the spdk
|
|
* application during startup.
|
|
*
|
|
* Modules are required to define this function.
|
|
*/
|
|
int (*module_init)(void);
|
|
|
|
/** Finish function for the module. Called by the spdk application
|
|
* before the spdk application exits to perform any necessary cleanup.
|
|
*
|
|
* Modules are not required to define this function.
|
|
*/
|
|
void (*module_fini)(void *ctx);
|
|
|
|
/**
|
|
* Write Acceleration module configuration into provided JSON context.
|
|
*/
|
|
void (*write_config_json)(struct spdk_json_write_ctx *w);
|
|
|
|
/**
|
|
* Returns the allocation size required for the modules to use for context.
|
|
*/
|
|
size_t (*get_ctx_size)(void);
|
|
|
|
const char *name;
|
|
bool (*supports_opcode)(enum accel_opcode);
|
|
struct spdk_io_channel *(*get_io_channel)(void);
|
|
int (*submit_tasks)(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task);
|
|
|
|
TAILQ_ENTRY(spdk_accel_module_if) tailq;
|
|
};
|
|
|
|
void spdk_accel_module_list_add(struct spdk_accel_module_if *accel_module);
|
|
|
|
#define SPDK_ACCEL_MODULE_REGISTER(name, module) \
|
|
static void __attribute__((constructor)) _spdk_accel_module_register_##name(void) \
|
|
{ \
|
|
spdk_accel_module_list_add(module); \
|
|
}
|
|
|
|
/**
|
|
* Called by an accel module when cleanup initiated during .module_fini has completed
|
|
*/
|
|
void spdk_accel_module_finish(void);
|
|
|
|
#endif
|