1d58439d3SEugene Kobyak /* SPDX-License-Identifier: BSD-3-Clause
2d58439d3SEugene Kobyak * Copyright (C) 2023 Intel Corporation.
3*ee020824SAlexey Marchuk * Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
4d58439d3SEugene Kobyak * All rights reserved.
5d58439d3SEugene Kobyak */
6d58439d3SEugene Kobyak
7d58439d3SEugene Kobyak #include "spdk/accel.h"
8d58439d3SEugene Kobyak #include "spdk/accel_module.h"
9d58439d3SEugene Kobyak #include "spdk/thread.h"
10d58439d3SEugene Kobyak
11d58439d3SEugene Kobyak static struct spdk_accel_module_if g_ex_module;
12d58439d3SEugene Kobyak
13d58439d3SEugene Kobyak struct ex_accel_io_channel {
14d58439d3SEugene Kobyak struct spdk_poller *completion_poller;
15*ee020824SAlexey Marchuk STAILQ_HEAD(, spdk_accel_task) tasks_to_complete;
16d58439d3SEugene Kobyak };
17d58439d3SEugene Kobyak
18d58439d3SEugene Kobyak static int
ex_accel_copy_iovs(struct iovec * dst_iovs,uint32_t dst_iovcnt,struct iovec * src_iovs,uint32_t src_iovcnt)19d58439d3SEugene Kobyak ex_accel_copy_iovs(struct iovec *dst_iovs, uint32_t dst_iovcnt,
20d58439d3SEugene Kobyak struct iovec *src_iovs, uint32_t src_iovcnt)
21d58439d3SEugene Kobyak {
22d58439d3SEugene Kobyak struct spdk_ioviter iter;
23d58439d3SEugene Kobyak void *src, *dst;
24d58439d3SEugene Kobyak size_t len;
25d58439d3SEugene Kobyak
26d58439d3SEugene Kobyak for (len = spdk_ioviter_first(&iter, src_iovs, src_iovcnt,
27d58439d3SEugene Kobyak dst_iovs, dst_iovcnt, &src, &dst);
28d58439d3SEugene Kobyak len != 0;
29d58439d3SEugene Kobyak len = spdk_ioviter_next(&iter, &src, &dst)) {
30d58439d3SEugene Kobyak memcpy(dst, src, len);
31d58439d3SEugene Kobyak }
32d58439d3SEugene Kobyak
33d58439d3SEugene Kobyak return 0;
34d58439d3SEugene Kobyak }
35d58439d3SEugene Kobyak
36d58439d3SEugene Kobyak static int
ex_accel_compare(struct iovec * src_iovs,uint32_t src_iovcnt,struct iovec * src2_iovs,uint32_t src2_iovcnt)37d58439d3SEugene Kobyak ex_accel_compare(struct iovec *src_iovs, uint32_t src_iovcnt,
38d58439d3SEugene Kobyak struct iovec *src2_iovs, uint32_t src2_iovcnt)
39d58439d3SEugene Kobyak {
40d58439d3SEugene Kobyak if (spdk_unlikely(src_iovcnt != 1 || src2_iovcnt != 1)) {
41d58439d3SEugene Kobyak return -EINVAL;
42d58439d3SEugene Kobyak }
43d58439d3SEugene Kobyak
44d58439d3SEugene Kobyak if (spdk_unlikely(src_iovs[0].iov_len != src2_iovs[0].iov_len)) {
45d58439d3SEugene Kobyak return -EINVAL;
46d58439d3SEugene Kobyak }
47d58439d3SEugene Kobyak
48d58439d3SEugene Kobyak return memcmp(src_iovs[0].iov_base, src2_iovs[0].iov_base, src_iovs[0].iov_len);
49d58439d3SEugene Kobyak }
50d58439d3SEugene Kobyak
51d58439d3SEugene Kobyak static int
ex_accel_fill(struct iovec * iovs,uint32_t iovcnt,uint8_t fill)52d58439d3SEugene Kobyak ex_accel_fill(struct iovec *iovs, uint32_t iovcnt, uint8_t fill)
53d58439d3SEugene Kobyak {
54d58439d3SEugene Kobyak void *dst;
55d58439d3SEugene Kobyak size_t nbytes;
56d58439d3SEugene Kobyak
57d58439d3SEugene Kobyak if (spdk_unlikely(iovcnt != 1)) {
58d58439d3SEugene Kobyak fprintf(stderr, "Unexpected number of iovs: %" PRIu32 "\n", iovcnt);
59d58439d3SEugene Kobyak return -EINVAL;
60d58439d3SEugene Kobyak }
61d58439d3SEugene Kobyak
62d58439d3SEugene Kobyak dst = iovs[0].iov_base;
63d58439d3SEugene Kobyak nbytes = iovs[0].iov_len;
64d58439d3SEugene Kobyak
65d58439d3SEugene Kobyak memset(dst, fill, nbytes);
66d58439d3SEugene Kobyak
67d58439d3SEugene Kobyak return 0;
68d58439d3SEugene Kobyak }
69d58439d3SEugene Kobyak
70d58439d3SEugene Kobyak static int
ex_accel_comp_poll(void * arg)71d58439d3SEugene Kobyak ex_accel_comp_poll(void *arg)
72d58439d3SEugene Kobyak {
73d58439d3SEugene Kobyak struct ex_accel_io_channel *ex_ch = arg;
74*ee020824SAlexey Marchuk STAILQ_HEAD(, spdk_accel_task) tasks_to_complete;
75d58439d3SEugene Kobyak struct spdk_accel_task *accel_task;
76d58439d3SEugene Kobyak
77*ee020824SAlexey Marchuk if (STAILQ_EMPTY(&ex_ch->tasks_to_complete)) {
78d58439d3SEugene Kobyak return SPDK_POLLER_IDLE;
79d58439d3SEugene Kobyak }
80d58439d3SEugene Kobyak
81*ee020824SAlexey Marchuk STAILQ_INIT(&tasks_to_complete);
82*ee020824SAlexey Marchuk STAILQ_SWAP(&tasks_to_complete, &ex_ch->tasks_to_complete, spdk_accel_task);
83d58439d3SEugene Kobyak
84*ee020824SAlexey Marchuk while ((accel_task = STAILQ_FIRST(&tasks_to_complete))) {
85*ee020824SAlexey Marchuk STAILQ_REMOVE_HEAD(&tasks_to_complete, link);
86d58439d3SEugene Kobyak spdk_accel_task_complete(accel_task, accel_task->status);
87d58439d3SEugene Kobyak }
88d58439d3SEugene Kobyak
89d58439d3SEugene Kobyak return SPDK_POLLER_BUSY;
90d58439d3SEugene Kobyak }
91d58439d3SEugene Kobyak
92d58439d3SEugene Kobyak static int
ex_accel_create_cb(void * io_device,void * ctx_buf)93d58439d3SEugene Kobyak ex_accel_create_cb(void *io_device, void *ctx_buf)
94d58439d3SEugene Kobyak {
95d58439d3SEugene Kobyak struct ex_accel_io_channel *ex_ch = ctx_buf;
96d58439d3SEugene Kobyak
97*ee020824SAlexey Marchuk STAILQ_INIT(&ex_ch->tasks_to_complete);
98d58439d3SEugene Kobyak ex_ch->completion_poller = SPDK_POLLER_REGISTER(ex_accel_comp_poll, ex_ch, 0);
99d58439d3SEugene Kobyak
100d58439d3SEugene Kobyak return 0;
101d58439d3SEugene Kobyak }
102d58439d3SEugene Kobyak
103d58439d3SEugene Kobyak static void
ex_accel_destroy_cb(void * io_device,void * ctx_buf)104d58439d3SEugene Kobyak ex_accel_destroy_cb(void *io_device, void *ctx_buf)
105d58439d3SEugene Kobyak {
106d58439d3SEugene Kobyak struct ex_accel_io_channel *ex_ch = ctx_buf;
107d58439d3SEugene Kobyak
108d58439d3SEugene Kobyak spdk_poller_unregister(&ex_ch->completion_poller);
109d58439d3SEugene Kobyak }
110d58439d3SEugene Kobyak
111d58439d3SEugene Kobyak static int
ex_accel_module_init(void)112d58439d3SEugene Kobyak ex_accel_module_init(void)
113d58439d3SEugene Kobyak {
114d58439d3SEugene Kobyak spdk_io_device_register(&g_ex_module, ex_accel_create_cb, ex_accel_destroy_cb,
115d58439d3SEugene Kobyak sizeof(struct ex_accel_io_channel), "external_accel_module");
116d58439d3SEugene Kobyak
117d58439d3SEugene Kobyak return 0;
118d58439d3SEugene Kobyak }
119d58439d3SEugene Kobyak
120d58439d3SEugene Kobyak static void
ex_accel_module_fini(void * ctx)121d58439d3SEugene Kobyak ex_accel_module_fini(void *ctx)
122d58439d3SEugene Kobyak {
123d58439d3SEugene Kobyak spdk_io_device_unregister(&g_ex_module, NULL);
124d58439d3SEugene Kobyak spdk_accel_module_finish();
125d58439d3SEugene Kobyak }
126d58439d3SEugene Kobyak
127d58439d3SEugene Kobyak static size_t
ex_accel_module_get_ctx_size(void)128d58439d3SEugene Kobyak ex_accel_module_get_ctx_size(void)
129d58439d3SEugene Kobyak {
130d58439d3SEugene Kobyak return sizeof(struct spdk_accel_task);
131d58439d3SEugene Kobyak }
132d58439d3SEugene Kobyak
133d58439d3SEugene Kobyak inline static void
add_to_comp_list(struct ex_accel_io_channel * ex_ch,struct spdk_accel_task * accel_task)134d58439d3SEugene Kobyak add_to_comp_list(struct ex_accel_io_channel *ex_ch, struct spdk_accel_task *accel_task)
135d58439d3SEugene Kobyak {
136*ee020824SAlexey Marchuk STAILQ_INSERT_TAIL(&ex_ch->tasks_to_complete, accel_task, link);
137d58439d3SEugene Kobyak }
138d58439d3SEugene Kobyak
139d58439d3SEugene Kobyak static bool
ex_accel_supports_opcode(enum spdk_accel_opcode opc)140d58439d3SEugene Kobyak ex_accel_supports_opcode(enum spdk_accel_opcode opc)
141d58439d3SEugene Kobyak {
142d58439d3SEugene Kobyak switch (opc) {
143d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_COPY:
144d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_FILL:
145d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_COMPARE:
146d58439d3SEugene Kobyak return true;
147d58439d3SEugene Kobyak default:
148d58439d3SEugene Kobyak return false;
149d58439d3SEugene Kobyak }
150d58439d3SEugene Kobyak }
151d58439d3SEugene Kobyak
152d58439d3SEugene Kobyak static struct spdk_io_channel *
ex_accel_get_io_channel(void)153d58439d3SEugene Kobyak ex_accel_get_io_channel(void)
154d58439d3SEugene Kobyak {
155d58439d3SEugene Kobyak return spdk_get_io_channel(&g_ex_module);
156d58439d3SEugene Kobyak }
157d58439d3SEugene Kobyak
158d58439d3SEugene Kobyak static int
ex_accel_submit_tasks(struct spdk_io_channel * ch,struct spdk_accel_task * accel_task)159d58439d3SEugene Kobyak ex_accel_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *accel_task)
160d58439d3SEugene Kobyak {
161d58439d3SEugene Kobyak struct ex_accel_io_channel *ex_ch = spdk_io_channel_get_ctx(ch);
162d58439d3SEugene Kobyak
163d58439d3SEugene Kobyak printf("Running on accel module task with code: %" PRIu8 "\n", accel_task->op_code);
164d58439d3SEugene Kobyak switch (accel_task->op_code) {
165d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_COPY:
166d58439d3SEugene Kobyak accel_task->status = ex_accel_copy_iovs(accel_task->d.iovs, accel_task->d.iovcnt,
167d58439d3SEugene Kobyak accel_task->s.iovs, accel_task->s.iovcnt);
168d58439d3SEugene Kobyak break;
169d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_FILL:
170d58439d3SEugene Kobyak accel_task->status = ex_accel_fill(accel_task->d.iovs, accel_task->d.iovcnt,
171d58439d3SEugene Kobyak accel_task->fill_pattern);
172d58439d3SEugene Kobyak break;
173d58439d3SEugene Kobyak case SPDK_ACCEL_OPC_COMPARE:
174d58439d3SEugene Kobyak accel_task->status = ex_accel_compare(accel_task->s.iovs, accel_task->s.iovcnt,
175d58439d3SEugene Kobyak accel_task->s2.iovs, accel_task->s2.iovcnt);
176d58439d3SEugene Kobyak break;
177d58439d3SEugene Kobyak default:
178d58439d3SEugene Kobyak fprintf(stderr, "Unsupported accel opcode: %" PRIu8 "\n", accel_task->op_code);
179d58439d3SEugene Kobyak accel_task->status = 1;
180d58439d3SEugene Kobyak break;
181d58439d3SEugene Kobyak }
182d58439d3SEugene Kobyak
183d58439d3SEugene Kobyak add_to_comp_list(ex_ch, accel_task);
184d58439d3SEugene Kobyak
185d58439d3SEugene Kobyak return accel_task->status;
186d58439d3SEugene Kobyak }
187d58439d3SEugene Kobyak
188d58439d3SEugene Kobyak static struct spdk_accel_module_if g_ex_module = {
189d58439d3SEugene Kobyak .module_init = ex_accel_module_init,
190d58439d3SEugene Kobyak .module_fini = ex_accel_module_fini,
191d58439d3SEugene Kobyak .get_ctx_size = ex_accel_module_get_ctx_size,
192d58439d3SEugene Kobyak .name = "external",
193d58439d3SEugene Kobyak .supports_opcode = ex_accel_supports_opcode,
194d58439d3SEugene Kobyak .get_io_channel = ex_accel_get_io_channel,
195d58439d3SEugene Kobyak .submit_tasks = ex_accel_submit_tasks,
196d58439d3SEugene Kobyak };
197d58439d3SEugene Kobyak
198d58439d3SEugene Kobyak SPDK_ACCEL_MODULE_REGISTER(external, &g_ex_module)
199