diff --git a/doc/jsonrpc.md b/doc/jsonrpc.md index a712d2a0f..b256db36e 100644 --- a/doc/jsonrpc.md +++ b/doc/jsonrpc.md @@ -1904,6 +1904,42 @@ Example response: } ~~~ +### accel_set_driver {#rpc_accel_set_driver} + +Select platform driver to execute operation chains. Until a driver is selected, all operations are +executed through accel modules. + +#### Parameters + +Name | Optional | Type | Description +----------------------- |----------| ----------- | ----------------- +name | Required | string | Name of the platform driver + +#### Example + +Example request: + +~~~json +{ + "jsonrpc": "2.0", + "method": "accel_set_driver", + "id": 1 + "params": { + "name": "xeon" + } +} +~~~ + +Example response: + +~~~json +{ + "jsonrpc": "2.0", + "id": 1, + "result": true +} +~~~ + ### compressdev_scan_accel_module {#rpc_compressdev_scan_accel_module} Set config and enable compressdev accel module offload. diff --git a/include/spdk/accel.h b/include/spdk/accel.h index dd90c6465..cbbaeca73 100644 --- a/include/spdk/accel.h +++ b/include/spdk/accel.h @@ -611,6 +611,15 @@ struct spdk_json_write_ctx; */ void spdk_accel_write_config_json(struct spdk_json_write_ctx *w); +/** + * Select platform driver to execute operation chains. + * + * \param name Name of the driver. + * + * \return 0 on success, negetive errno otherwise. + */ +int spdk_accel_set_driver(const char *name); + #ifdef __cplusplus } #endif diff --git a/include/spdk_internal/accel_module.h b/include/spdk_internal/accel_module.h index 0f92cf691..12633d83e 100644 --- a/include/spdk_internal/accel_module.h +++ b/include/spdk_internal/accel_module.h @@ -169,4 +169,45 @@ static void __attribute__((constructor)) _spdk_accel_module_register_##name(void */ void spdk_accel_module_finish(void); +/** + * Platform driver responsible for executing tasks in a sequence. If no driver is selected, tasks + * are submitted to accel modules. All drivers are required to be aware of memory domains. + */ +struct spdk_accel_driver { + /** Name of the driver */ + const char *name; + /** + * Executes a sequence of accel operations. The driver should notify accel about each + * completed task using `spdk_accel_task_complete()`. Once all tasks are completed or the + * driver cannot proceed with a given task (e.g. because it doesn't handle specific opcode), + * accel should be notified via `spdk_accel_sequence_continue()`. If there are tasks left + * in a sequence, the first will be submitted to a module, while the rest will be sent back + * to the driver. `spdk_accel_sequence_continue()` should only be called if this function + * succeeds (i.e. returns 0). + * + * \param Sequence of tasks to execute. + * + * \return 0 on success, negative errno on failure. + */ + int (*execute_sequence)(struct spdk_accel_sequence *seq); + + TAILQ_ENTRY(spdk_accel_driver) tailq; +}; + +/** + * Notifies accel that a driver has finished executing a sequence (or its part) and accel should + * continue processing it. + * + * \param seq Sequence object. + */ +void spdk_accel_sequence_continue(struct spdk_accel_sequence *seq); + +void spdk_accel_driver_register(struct spdk_accel_driver *driver); + +#define SPDK_ACCEL_DRIVER_REGISTER(name, driver) \ +static void __attribute__((constructor)) _spdk_accel_driver_register_##name(void) \ +{ \ + spdk_accel_driver_register(driver); \ +} + #endif diff --git a/lib/accel/accel.c b/lib/accel/accel.c index fdc294c53..5af5a294c 100644 --- a/lib/accel/accel.c +++ b/lib/accel/accel.c @@ -60,6 +60,8 @@ static struct spdk_spinlock g_keyring_spin; /* Global array mapping capabilities to modules */ static struct accel_module g_modules_opc[ACCEL_OPC_LAST] = {}; static char *g_modules_opc_override[ACCEL_OPC_LAST] = {}; +TAILQ_HEAD(, spdk_accel_driver) g_accel_drivers = TAILQ_HEAD_INITIALIZER(g_accel_drivers); +static struct spdk_accel_driver *g_accel_driver; static const char *g_opcode_strings[ACCEL_OPC_LAST] = { "copy", "fill", "dualcast", "compare", "crc32c", "copy_crc32c", @@ -1548,6 +1550,12 @@ accel_sequence_task_cb(void *cb_arg, int status) accel_process_sequence(seq); } +void +spdk_accel_sequence_continue(struct spdk_accel_sequence *seq) +{ + assert(0 && "unsupported"); +} + static bool accel_compare_iovs(struct iovec *iova, uint32_t iovacnt, struct iovec *iovb, uint32_t iovbcnt) { @@ -2279,4 +2287,46 @@ spdk_accel_finish(spdk_accel_fini_cb cb_fn, void *cb_arg) spdk_accel_module_finish(); } +static struct spdk_accel_driver * +accel_find_driver(const char *name) +{ + struct spdk_accel_driver *driver; + + TAILQ_FOREACH(driver, &g_accel_drivers, tailq) { + if (strcmp(driver->name, name) == 0) { + return driver; + } + } + + return NULL; +} + +int +spdk_accel_set_driver(const char *name) +{ + struct spdk_accel_driver *driver; + + driver = accel_find_driver(name); + if (driver == NULL) { + SPDK_ERRLOG("Couldn't find driver named '%s'\n", name); + return -ENODEV; + } + + g_accel_driver = driver; + + return 0; +} + +void +spdk_accel_driver_register(struct spdk_accel_driver *driver) +{ + if (accel_find_driver(driver->name)) { + SPDK_ERRLOG("Driver named '%s' has already been registered\n", driver->name); + assert(0); + return; + } + + TAILQ_INSERT_TAIL(&g_accel_drivers, driver, tailq); +} + SPDK_LOG_REGISTER_COMPONENT(accel) diff --git a/lib/accel/accel_internal.h b/lib/accel/accel_internal.h index 2cb1cca91..69cdfeaf6 100644 --- a/lib/accel/accel_internal.h +++ b/lib/accel/accel_internal.h @@ -26,5 +26,4 @@ int _accel_get_opc_name(enum accel_opcode opcode, const char **opcode_name); void _accel_crypto_key_dump_param(struct spdk_json_write_ctx *w, struct spdk_accel_crypto_key *key); void _accel_crypto_keys_dump_param(struct spdk_json_write_ctx *w); - #endif diff --git a/lib/accel/accel_rpc.c b/lib/accel/accel_rpc.c index a5fd3252d..83595ea43 100644 --- a/lib/accel/accel_rpc.c +++ b/lib/accel/accel_rpc.c @@ -11,6 +11,7 @@ #include "spdk/util.h" #include "spdk/event.h" #include "spdk/stdinc.h" +#include "spdk/string.h" #include "spdk/env.h" #include "spdk/util.h" @@ -313,3 +314,43 @@ rpc_accel_crypto_key_destroy(struct spdk_jsonrpc_request *request, free(req.key_name); } SPDK_RPC_REGISTER("accel_crypto_key_destroy", rpc_accel_crypto_key_destroy, SPDK_RPC_RUNTIME) + +struct rpc_accel_set_driver { + char *name; +}; + +static const struct spdk_json_object_decoder rpc_accel_set_driver_decoders[] = { + {"name", offsetof(struct rpc_accel_set_driver, name), spdk_json_decode_string}, +}; + +static void +free_rpc_accel_set_driver(struct rpc_accel_set_driver *r) +{ + free(r->name); +} + +static void +rpc_accel_set_driver(struct spdk_jsonrpc_request *request, const struct spdk_json_val *params) +{ + struct rpc_accel_set_driver req = {}; + int rc; + + if (spdk_json_decode_object(params, rpc_accel_set_driver_decoders, + SPDK_COUNTOF(rpc_accel_set_driver_decoders), &req)) { + spdk_jsonrpc_send_error_response(request, SPDK_JSONRPC_ERROR_PARSE_ERROR, + "spdk_json_decode_object failed"); + return; + } + + rc = spdk_accel_set_driver(req.name); + if (rc != 0) { + spdk_jsonrpc_send_error_response(request, rc, spdk_strerror(-rc)); + goto cleanup; + } + + SPDK_NOTICELOG("Using accel driver: %s\n", req.name); + spdk_jsonrpc_send_bool_response(request, true); +cleanup: + free_rpc_accel_set_driver(&req); +} +SPDK_RPC_REGISTER("accel_set_driver", rpc_accel_set_driver, SPDK_RPC_STARTUP) diff --git a/lib/accel/spdk_accel.map b/lib/accel/spdk_accel.map index 0c053d3c2..30469a285 100644 --- a/lib/accel/spdk_accel.map +++ b/lib/accel/spdk_accel.map @@ -33,11 +33,14 @@ spdk_accel_crypto_key_create; spdk_accel_crypto_key_destroy; spdk_accel_crypto_key_get; + spdk_accel_set_driver; # functions needed by modules spdk_accel_module_list_add; spdk_accel_module_finish; spdk_accel_task_complete; + spdk_accel_sequence_continue; + spdk_accel_driver_register; local: *; }; diff --git a/python/spdk/rpc/accel.py b/python/spdk/rpc/accel.py index e4cccc208..07de1b875 100644 --- a/python/spdk/rpc/accel.py +++ b/python/spdk/rpc/accel.py @@ -79,3 +79,12 @@ def accel_crypto_keys_get(client, key_name): params['key_name'] = key_name return client.call('accel_crypto_keys_get', params) + + +def accel_set_driver(client, name): + """Select accel platform driver to execute operation chains. + + Args: + name: name of the driver + """ + return client.call('accel_set_driver', {'name': name}) diff --git a/scripts/rpc.py b/scripts/rpc.py index f6b127e1e..fd6f35862 100755 --- a/scripts/rpc.py +++ b/scripts/rpc.py @@ -2894,6 +2894,14 @@ Format: 'user:u1 secret:s1 muser:mu1 msecret:ms1,user:u2 secret:s2 muser:mu2 mse p.add_argument('-k', '--key-name', help='Get information about a specific key', type=str) p.set_defaults(func=accel_crypto_keys_get) + def accel_set_driver(args): + rpc.accel.accel_set_driver(args.client, name=args.name) + + p = subparsers.add_parser('accel_set_driver', help='Select accel platform driver to execute ' + + 'operation chains') + p.add_argument('name', help='name of the platform driver') + p.set_defaults(func=accel_set_driver) + # ioat def ioat_scan_accel_module(args): rpc.ioat.ioat_scan_accel_module(args.client)