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