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