xref: /spdk/module/accel/dsa/accel_dsa.c (revision 0eae01067000f31cb6c9dbdf792411c1957754f3)
1712e8cb7SBen Walker /*   SPDX-License-Identifier: BSD-3-Clause
2a6dbe372Spaul luse  *   Copyright (C) 2022 Intel Corporation.
30cd6ba66SAlexey Marchuk  *   Copyright (c) 2023 NVIDIA CORPORATION & AFFILIATES.
4712e8cb7SBen Walker  *   All rights reserved.
5712e8cb7SBen Walker  */
6712e8cb7SBen Walker 
7712e8cb7SBen Walker #include "accel_dsa.h"
8712e8cb7SBen Walker 
9712e8cb7SBen Walker #include "spdk/stdinc.h"
10712e8cb7SBen Walker 
115d2d59beSKonrad Sztyber #include "spdk/accel_module.h"
12712e8cb7SBen Walker #include "spdk/log.h"
13712e8cb7SBen Walker #include "spdk_internal/idxd.h"
14712e8cb7SBen Walker 
15712e8cb7SBen Walker #include "spdk/env.h"
16712e8cb7SBen Walker #include "spdk/event.h"
17135396b0SKonrad Sztyber #include "spdk/likely.h"
18712e8cb7SBen Walker #include "spdk/thread.h"
19712e8cb7SBen Walker #include "spdk/idxd.h"
20712e8cb7SBen Walker #include "spdk/util.h"
21712e8cb7SBen Walker #include "spdk/json.h"
22712e8cb7SBen Walker #include "spdk/trace.h"
23712e8cb7SBen Walker #include "spdk_internal/trace_defs.h"
24712e8cb7SBen Walker 
25f74d16beSSlawomir Ptak #define ACCEL_DSA_MD_IOBUF_SMALL_CACHE_SIZE			128
26f74d16beSSlawomir Ptak #define ACCEL_DSA_MD_IOBUF_LARGE_CACHE_SIZE			32
27f74d16beSSlawomir Ptak 
28712e8cb7SBen Walker static bool g_dsa_enable = false;
29712e8cb7SBen Walker static bool g_kernel_mode = false;
30712e8cb7SBen Walker 
31712e8cb7SBen Walker enum channel_state {
32712e8cb7SBen Walker 	IDXD_CHANNEL_ACTIVE,
33712e8cb7SBen Walker 	IDXD_CHANNEL_ERROR,
34712e8cb7SBen Walker };
35712e8cb7SBen Walker 
36712e8cb7SBen Walker static bool g_dsa_initialized = false;
37712e8cb7SBen Walker 
38712e8cb7SBen Walker struct idxd_device {
39712e8cb7SBen Walker 	struct				spdk_idxd_device *dsa;
40712e8cb7SBen Walker 	TAILQ_ENTRY(idxd_device)	tailq;
41712e8cb7SBen Walker };
42712e8cb7SBen Walker static TAILQ_HEAD(, idxd_device) g_dsa_devices = TAILQ_HEAD_INITIALIZER(g_dsa_devices);
43712e8cb7SBen Walker static struct idxd_device *g_next_dev = NULL;
44712e8cb7SBen Walker static uint32_t g_num_devices = 0;
45712e8cb7SBen Walker static pthread_mutex_t g_dev_lock = PTHREAD_MUTEX_INITIALIZER;
46712e8cb7SBen Walker 
47712e8cb7SBen Walker struct idxd_task {
48712e8cb7SBen Walker 	struct spdk_accel_task	task;
49712e8cb7SBen Walker 	struct idxd_io_channel	*chan;
50f74d16beSSlawomir Ptak 	struct iovec		md_iov;
51f74d16beSSlawomir Ptak 	struct spdk_iobuf_entry	iobuf;
52712e8cb7SBen Walker };
53712e8cb7SBen Walker 
54712e8cb7SBen Walker struct idxd_io_channel {
55712e8cb7SBen Walker 	struct spdk_idxd_io_channel	*chan;
56712e8cb7SBen Walker 	struct idxd_device		*dev;
57712e8cb7SBen Walker 	enum channel_state		state;
58712e8cb7SBen Walker 	struct spdk_poller		*poller;
59712e8cb7SBen Walker 	uint32_t			num_outstanding;
60ee020824SAlexey Marchuk 	STAILQ_HEAD(, spdk_accel_task)	queued_tasks;
61f74d16beSSlawomir Ptak 	struct spdk_iobuf_channel	iobuf;
62712e8cb7SBen Walker };
63712e8cb7SBen Walker 
64712e8cb7SBen Walker static struct spdk_io_channel *dsa_get_io_channel(void);
65712e8cb7SBen Walker 
66712e8cb7SBen Walker static struct idxd_device *
67712e8cb7SBen Walker idxd_select_device(struct idxd_io_channel *chan)
68712e8cb7SBen Walker {
69712e8cb7SBen Walker 	uint32_t count = 0;
70712e8cb7SBen Walker 	struct idxd_device *dev;
7138b1eaa4SJim Harris 	uint32_t numa_id = spdk_env_get_numa_id(spdk_env_get_current_core());
72712e8cb7SBen Walker 
73712e8cb7SBen Walker 	/*
74712e8cb7SBen Walker 	 * We allow channels to share underlying devices,
75712e8cb7SBen Walker 	 * selection is round-robin based with a limitation
76712e8cb7SBen Walker 	 * on how many channel can share one device.
77712e8cb7SBen Walker 	 */
78712e8cb7SBen Walker 	do {
79712e8cb7SBen Walker 		/* select next device */
80712e8cb7SBen Walker 		pthread_mutex_lock(&g_dev_lock);
81712e8cb7SBen Walker 		g_next_dev = TAILQ_NEXT(g_next_dev, tailq);
82712e8cb7SBen Walker 		if (g_next_dev == NULL) {
83712e8cb7SBen Walker 			g_next_dev = TAILQ_FIRST(&g_dsa_devices);
84712e8cb7SBen Walker 		}
85712e8cb7SBen Walker 		dev = g_next_dev;
86712e8cb7SBen Walker 		pthread_mutex_unlock(&g_dev_lock);
87712e8cb7SBen Walker 
8838b1eaa4SJim Harris 		if (numa_id != spdk_idxd_get_socket(dev->dsa)) {
89712e8cb7SBen Walker 			continue;
90712e8cb7SBen Walker 		}
91712e8cb7SBen Walker 
92712e8cb7SBen Walker 		/*
93712e8cb7SBen Walker 		 * Now see if a channel is available on this one. We only
94712e8cb7SBen Walker 		 * allow a specific number of channels to share a device
95712e8cb7SBen Walker 		 * to limit outstanding IO for flow control purposes.
96712e8cb7SBen Walker 		 */
97712e8cb7SBen Walker 		chan->chan = spdk_idxd_get_channel(dev->dsa);
98712e8cb7SBen Walker 		if (chan->chan != NULL) {
9938b1eaa4SJim Harris 			SPDK_DEBUGLOG(accel_dsa, "On socket %d using device on numa %d\n",
10038b1eaa4SJim Harris 				      numa_id, spdk_idxd_get_socket(dev->dsa));
101712e8cb7SBen Walker 			return dev;
102712e8cb7SBen Walker 		}
10397f445d7STomasz Zawadzki 	} while (++count < g_num_devices);
104712e8cb7SBen Walker 
105712e8cb7SBen Walker 	/* We are out of available channels and/or devices for the local socket. We fix the number
106712e8cb7SBen Walker 	 * of channels that we allocate per device and only allocate devices on the same socket
107712e8cb7SBen Walker 	 * that the current thread is on. If on a 2 socket system it may be possible to avoid
108712e8cb7SBen Walker 	 * this situation by spreading threads across the sockets.
109712e8cb7SBen Walker 	 */
110712e8cb7SBen Walker 	SPDK_ERRLOG("No more DSA devices available on the local socket.\n");
111712e8cb7SBen Walker 	return NULL;
112712e8cb7SBen Walker }
113712e8cb7SBen Walker 
114712e8cb7SBen Walker static void
115712e8cb7SBen Walker dsa_done(void *cb_arg, int status)
116712e8cb7SBen Walker {
117712e8cb7SBen Walker 	struct idxd_task *idxd_task = cb_arg;
118712e8cb7SBen Walker 	struct idxd_io_channel *chan;
119ac8071d6SKrzysztof Sprzaczkowski 	int rc;
120712e8cb7SBen Walker 
121712e8cb7SBen Walker 	chan = idxd_task->chan;
122712e8cb7SBen Walker 
123ac8071d6SKrzysztof Sprzaczkowski 	/* If the DSA DIF Check operation detects an error, detailed info about
124ac8071d6SKrzysztof Sprzaczkowski 	 * this error (like actual/expected values) needs to be obtained by
125ac8071d6SKrzysztof Sprzaczkowski 	 * calling the software DIF Verify operation.
126ac8071d6SKrzysztof Sprzaczkowski 	 */
127ac8071d6SKrzysztof Sprzaczkowski 	if (spdk_unlikely(status == -EIO)) {
128d8bf4182SKrzysztof Sprzaczkowski 		if (idxd_task->task.op_code == SPDK_ACCEL_OPC_DIF_VERIFY ||
129d8bf4182SKrzysztof Sprzaczkowski 		    idxd_task->task.op_code == SPDK_ACCEL_OPC_DIF_VERIFY_COPY) {
130ac8071d6SKrzysztof Sprzaczkowski 			rc = spdk_dif_verify(idxd_task->task.s.iovs, idxd_task->task.s.iovcnt,
131ac8071d6SKrzysztof Sprzaczkowski 					     idxd_task->task.dif.num_blocks,
132ac8071d6SKrzysztof Sprzaczkowski 					     idxd_task->task.dif.ctx, idxd_task->task.dif.err);
133ac8071d6SKrzysztof Sprzaczkowski 			if (rc != 0) {
134ac8071d6SKrzysztof Sprzaczkowski 				SPDK_ERRLOG("DIF error detected. type=%d, offset=%" PRIu32 "\n",
135ac8071d6SKrzysztof Sprzaczkowski 					    idxd_task->task.dif.err->err_type,
136ac8071d6SKrzysztof Sprzaczkowski 					    idxd_task->task.dif.err->err_offset);
137ac8071d6SKrzysztof Sprzaczkowski 			}
138ac8071d6SKrzysztof Sprzaczkowski 		}
139ac8071d6SKrzysztof Sprzaczkowski 	}
140ac8071d6SKrzysztof Sprzaczkowski 
141712e8cb7SBen Walker 	assert(chan->num_outstanding > 0);
142712e8cb7SBen Walker 	spdk_trace_record(TRACE_ACCEL_DSA_OP_COMPLETE, 0, 0, 0, chan->num_outstanding - 1);
143712e8cb7SBen Walker 	chan->num_outstanding--;
144712e8cb7SBen Walker 
145712e8cb7SBen Walker 	spdk_accel_task_complete(&idxd_task->task, status);
146712e8cb7SBen Walker }
147712e8cb7SBen Walker 
148712e8cb7SBen Walker static int
149135396b0SKonrad Sztyber idxd_submit_dualcast(struct idxd_io_channel *ch, struct idxd_task *idxd_task, int flags)
150135396b0SKonrad Sztyber {
151135396b0SKonrad Sztyber 	struct spdk_accel_task *task = &idxd_task->task;
152135396b0SKonrad Sztyber 
153135396b0SKonrad Sztyber 	if (spdk_unlikely(task->d.iovcnt != 1 || task->d2.iovcnt != 1 || task->s.iovcnt != 1)) {
154135396b0SKonrad Sztyber 		return -EINVAL;
155135396b0SKonrad Sztyber 	}
156135396b0SKonrad Sztyber 
157135396b0SKonrad Sztyber 	if (spdk_unlikely(task->d.iovs[0].iov_len != task->s.iovs[0].iov_len ||
158135396b0SKonrad Sztyber 			  task->d.iovs[0].iov_len != task->d2.iovs[0].iov_len)) {
159135396b0SKonrad Sztyber 		return -EINVAL;
160135396b0SKonrad Sztyber 	}
161135396b0SKonrad Sztyber 
162135396b0SKonrad Sztyber 	return spdk_idxd_submit_dualcast(ch->chan, task->d.iovs[0].iov_base,
163135396b0SKonrad Sztyber 					 task->d2.iovs[0].iov_base, task->s.iovs[0].iov_base,
164135396b0SKonrad Sztyber 					 task->d.iovs[0].iov_len, flags, dsa_done, idxd_task);
165135396b0SKonrad Sztyber }
166135396b0SKonrad Sztyber 
167135396b0SKonrad Sztyber static int
168d8bf4182SKrzysztof Sprzaczkowski check_dsa_dif_strip_overlap_bufs(struct spdk_accel_task *task)
169d8bf4182SKrzysztof Sprzaczkowski {
170d8bf4182SKrzysztof Sprzaczkowski 	uint64_t src_seg_addr_end_ext;
171d8bf4182SKrzysztof Sprzaczkowski 	uint64_t dst_seg_addr_end_ext;
172d8bf4182SKrzysztof Sprzaczkowski 	size_t i;
173d8bf4182SKrzysztof Sprzaczkowski 
174d8bf4182SKrzysztof Sprzaczkowski 	/* The number of source and destination iovecs must be the same.
175d8bf4182SKrzysztof Sprzaczkowski 	 * If so, one of them can be used to iterate over both vectors
176d8bf4182SKrzysztof Sprzaczkowski 	 * later in the loop. */
177d8bf4182SKrzysztof Sprzaczkowski 	if (task->d.iovcnt != task->s.iovcnt) {
178d8bf4182SKrzysztof Sprzaczkowski 		SPDK_ERRLOG("Mismatched iovcnts: src=%d, dst=%d\n",
179d8bf4182SKrzysztof Sprzaczkowski 			    task->s.iovcnt, task->d.iovcnt);
180d8bf4182SKrzysztof Sprzaczkowski 		return -EINVAL;
181d8bf4182SKrzysztof Sprzaczkowski 	}
182d8bf4182SKrzysztof Sprzaczkowski 
183d8bf4182SKrzysztof Sprzaczkowski 	for (i = 0; i < task->s.iovcnt; i++) {
184d8bf4182SKrzysztof Sprzaczkowski 		src_seg_addr_end_ext = (uint64_t)task->s.iovs[i].iov_base +
185d8bf4182SKrzysztof Sprzaczkowski 				       task->s.iovs[i].iov_len;
186d8bf4182SKrzysztof Sprzaczkowski 
187d8bf4182SKrzysztof Sprzaczkowski 		dst_seg_addr_end_ext = (uint64_t)task->d.iovs[i].iov_base +
188d8bf4182SKrzysztof Sprzaczkowski 				       task->s.iovs[i].iov_len;
189d8bf4182SKrzysztof Sprzaczkowski 
190d8bf4182SKrzysztof Sprzaczkowski 		if ((dst_seg_addr_end_ext >= (uint64_t)task->s.iovs[i].iov_base) &&
191d8bf4182SKrzysztof Sprzaczkowski 		    (dst_seg_addr_end_ext <= src_seg_addr_end_ext)) {
192d8bf4182SKrzysztof Sprzaczkowski 			return -EFAULT;
193d8bf4182SKrzysztof Sprzaczkowski 		}
194d8bf4182SKrzysztof Sprzaczkowski 	}
195d8bf4182SKrzysztof Sprzaczkowski 
196d8bf4182SKrzysztof Sprzaczkowski 	return 0;
197d8bf4182SKrzysztof Sprzaczkowski }
198d8bf4182SKrzysztof Sprzaczkowski 
199d8bf4182SKrzysztof Sprzaczkowski static void
200d8bf4182SKrzysztof Sprzaczkowski spdk_accel_sw_task_complete(void *ctx)
201d8bf4182SKrzysztof Sprzaczkowski {
202d8bf4182SKrzysztof Sprzaczkowski 	struct spdk_accel_task *task = (struct spdk_accel_task *)ctx;
203d8bf4182SKrzysztof Sprzaczkowski 
204d8bf4182SKrzysztof Sprzaczkowski 	spdk_accel_task_complete(task, task->status);
205d8bf4182SKrzysztof Sprzaczkowski }
206d8bf4182SKrzysztof Sprzaczkowski 
207f74d16beSSlawomir Ptak static void
208f74d16beSSlawomir Ptak _accel_dsa_dix_verify_generate_cb(void *cb_arg, int status)
209f74d16beSSlawomir Ptak {
210f74d16beSSlawomir Ptak 	struct idxd_task *idxd_task = cb_arg;
211f74d16beSSlawomir Ptak 	struct iovec *original_mdiov = idxd_task->task.d.iovs;
212f74d16beSSlawomir Ptak 	size_t mdiov_len = idxd_task->md_iov.iov_len;
213f74d16beSSlawomir Ptak 	int rc;
214f74d16beSSlawomir Ptak 
215f74d16beSSlawomir Ptak 	if (status != 0) {
216f74d16beSSlawomir Ptak 		SPDK_ERRLOG("Unable to complete DIX Verify (DIX Generate failed)\n");
217f74d16beSSlawomir Ptak 		goto end;
218f74d16beSSlawomir Ptak 	}
219f74d16beSSlawomir Ptak 
220f74d16beSSlawomir Ptak 	rc = memcmp(original_mdiov->iov_base, idxd_task->md_iov.iov_base, mdiov_len);
221f74d16beSSlawomir Ptak 	if (rc != 0) {
222f74d16beSSlawomir Ptak 		SPDK_ERRLOG("DIX Verify failed\n");
223f74d16beSSlawomir Ptak 		status = -EINVAL;
224f74d16beSSlawomir Ptak 		rc = spdk_dix_verify(idxd_task->task.s.iovs, idxd_task->task.s.iovcnt,
225f74d16beSSlawomir Ptak 				     original_mdiov, idxd_task->task.dif.num_blocks,
226f74d16beSSlawomir Ptak 				     idxd_task->task.dif.ctx, idxd_task->task.dif.err);
227f74d16beSSlawomir Ptak 		if (rc != 0) {
228f74d16beSSlawomir Ptak 			SPDK_ERRLOG("DIX error detected. type=%d, offset=%" PRIu32 "\n",
229f74d16beSSlawomir Ptak 				    idxd_task->task.dif.err->err_type,
230f74d16beSSlawomir Ptak 				    idxd_task->task.dif.err->err_offset);
231f74d16beSSlawomir Ptak 		}
232f74d16beSSlawomir Ptak 	}
233f74d16beSSlawomir Ptak 
234f74d16beSSlawomir Ptak end:
235f74d16beSSlawomir Ptak 	spdk_iobuf_put(&idxd_task->chan->iobuf, idxd_task->md_iov.iov_base, mdiov_len);
236f74d16beSSlawomir Ptak 	dsa_done(idxd_task, status);
237f74d16beSSlawomir Ptak }
238f74d16beSSlawomir Ptak 
239f74d16beSSlawomir Ptak static void
240f74d16beSSlawomir Ptak _accel_dsa_dix_verify(struct idxd_task *idxd_task)
241f74d16beSSlawomir Ptak {
242f74d16beSSlawomir Ptak 	int rc;
243f74d16beSSlawomir Ptak 
244f74d16beSSlawomir Ptak 	/* Since Intel DSA doesn't provide a separate DIX Verify operation, it is done
245f74d16beSSlawomir Ptak 	 * in two steps: DIX Generate to a new buffer and mem compare.
246f74d16beSSlawomir Ptak 	 */
247f74d16beSSlawomir Ptak 	rc = spdk_idxd_submit_dix_generate(idxd_task->chan->chan, idxd_task->task.s.iovs,
248f74d16beSSlawomir Ptak 					   idxd_task->task.s.iovcnt, &idxd_task->md_iov, idxd_task->task.dif.num_blocks,
249f74d16beSSlawomir Ptak 					   idxd_task->task.dif.ctx, 0, _accel_dsa_dix_verify_generate_cb, idxd_task);
250f74d16beSSlawomir Ptak 	if (rc != 0) {
251f74d16beSSlawomir Ptak 		SPDK_ERRLOG("Unable to complete DIX Verify (DIX Generate failed)\n");
252f74d16beSSlawomir Ptak 		spdk_iobuf_put(&idxd_task->chan->iobuf, idxd_task->md_iov.iov_base,
253f74d16beSSlawomir Ptak 			       idxd_task->md_iov.iov_len);
254f74d16beSSlawomir Ptak 		dsa_done(idxd_task, rc);
255f74d16beSSlawomir Ptak 	}
256f74d16beSSlawomir Ptak }
257f74d16beSSlawomir Ptak 
258f74d16beSSlawomir Ptak static void
259f74d16beSSlawomir Ptak accel_dsa_dix_verify_get_iobuf_cb(struct spdk_iobuf_entry *iobuf, void *buf)
260f74d16beSSlawomir Ptak {
261f74d16beSSlawomir Ptak 	struct idxd_task *idxd_task;
262f74d16beSSlawomir Ptak 
263f74d16beSSlawomir Ptak 	idxd_task = SPDK_CONTAINEROF(iobuf, struct idxd_task, iobuf);
264f74d16beSSlawomir Ptak 	idxd_task->md_iov.iov_base = buf;
265f74d16beSSlawomir Ptak 	_accel_dsa_dix_verify(idxd_task);
266f74d16beSSlawomir Ptak }
267f74d16beSSlawomir Ptak 
268f74d16beSSlawomir Ptak static int
269f74d16beSSlawomir Ptak accel_dsa_dix_verify(struct idxd_io_channel *chan, int flags,
270f74d16beSSlawomir Ptak 		     struct idxd_task *idxd_task)
271f74d16beSSlawomir Ptak {
272f74d16beSSlawomir Ptak 	idxd_task->md_iov.iov_len = idxd_task->task.d.iovs[0].iov_len;
273f74d16beSSlawomir Ptak 	idxd_task->md_iov.iov_base = spdk_iobuf_get(&chan->iobuf, idxd_task->md_iov.iov_len,
274f74d16beSSlawomir Ptak 				     &idxd_task->iobuf, accel_dsa_dix_verify_get_iobuf_cb);
275f74d16beSSlawomir Ptak 
276f74d16beSSlawomir Ptak 	if (idxd_task->md_iov.iov_base != NULL) {
277f74d16beSSlawomir Ptak 		_accel_dsa_dix_verify(idxd_task);
278f74d16beSSlawomir Ptak 	}
279f74d16beSSlawomir Ptak 
280f74d16beSSlawomir Ptak 	return 0;
281f74d16beSSlawomir Ptak }
282f74d16beSSlawomir Ptak 
283d8bf4182SKrzysztof Sprzaczkowski static int
284712e8cb7SBen Walker _process_single_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
285712e8cb7SBen Walker {
286712e8cb7SBen Walker 	struct idxd_io_channel *chan = spdk_io_channel_get_ctx(ch);
287712e8cb7SBen Walker 	struct idxd_task *idxd_task;
288a374f8baSKonrad Sztyber 	int rc = 0, flags = 0;
289712e8cb7SBen Walker 
290712e8cb7SBen Walker 	idxd_task = SPDK_CONTAINEROF(task, struct idxd_task, task);
291712e8cb7SBen Walker 	idxd_task->chan = chan;
292712e8cb7SBen Walker 
293712e8cb7SBen Walker 	switch (task->op_code) {
2945105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY:
295dee8e1f4SKonrad Sztyber 		rc = spdk_idxd_submit_copy(chan->chan, task->d.iovs, task->d.iovcnt,
296dee8e1f4SKonrad Sztyber 					   task->s.iovs, task->s.iovcnt, flags, dsa_done, idxd_task);
297712e8cb7SBen Walker 		break;
2985105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_DUALCAST:
299135396b0SKonrad Sztyber 		rc = idxd_submit_dualcast(chan, idxd_task, flags);
300712e8cb7SBen Walker 		break;
3015105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COMPARE:
3024d1ba5f2SKonrad Sztyber 		rc = spdk_idxd_submit_compare(chan->chan, task->s.iovs, task->s.iovcnt,
3034d1ba5f2SKonrad Sztyber 					      task->s2.iovs, task->s2.iovcnt, flags,
3044d1ba5f2SKonrad Sztyber 					      dsa_done, idxd_task);
305712e8cb7SBen Walker 		break;
3065105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_FILL:
307bc6a1463SKonrad Sztyber 		rc = spdk_idxd_submit_fill(chan->chan, task->d.iovs, task->d.iovcnt,
308bc6a1463SKonrad Sztyber 					   task->fill_pattern, flags, dsa_done, idxd_task);
309712e8cb7SBen Walker 		break;
3105105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_CRC32C:
3113d1d5452SKonrad Sztyber 		rc = spdk_idxd_submit_crc32c(chan->chan, task->s.iovs, task->s.iovcnt, task->seed,
3123d1d5452SKonrad Sztyber 					     task->crc_dst, flags, dsa_done, idxd_task);
313712e8cb7SBen Walker 		break;
3145105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY_CRC32C:
315a374f8baSKonrad Sztyber 		rc = spdk_idxd_submit_copy_crc32c(chan->chan, task->d.iovs, task->d.iovcnt,
316a374f8baSKonrad Sztyber 						  task->s.iovs, task->s.iovcnt,
317712e8cb7SBen Walker 						  task->seed, task->crc_dst, flags,
318712e8cb7SBen Walker 						  dsa_done, idxd_task);
319712e8cb7SBen Walker 		break;
320ac8071d6SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY:
321ac8071d6SKrzysztof Sprzaczkowski 		rc = spdk_idxd_submit_dif_check(chan->chan,
322ac8071d6SKrzysztof Sprzaczkowski 						task->s.iovs, task->s.iovcnt,
323ac8071d6SKrzysztof Sprzaczkowski 						task->dif.num_blocks, task->dif.ctx, flags,
324ac8071d6SKrzysztof Sprzaczkowski 						dsa_done, idxd_task);
325ac8071d6SKrzysztof Sprzaczkowski 		break;
326da954d0aSKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
327da954d0aSKrzysztof Sprzaczkowski 		rc = spdk_idxd_submit_dif_insert(chan->chan,
328da954d0aSKrzysztof Sprzaczkowski 						 task->d.iovs, task->d.iovcnt,
329da954d0aSKrzysztof Sprzaczkowski 						 task->s.iovs, task->s.iovcnt,
330da954d0aSKrzysztof Sprzaczkowski 						 task->dif.num_blocks, task->dif.ctx, flags,
331da954d0aSKrzysztof Sprzaczkowski 						 dsa_done, idxd_task);
332da954d0aSKrzysztof Sprzaczkowski 		break;
333d8bf4182SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY_COPY:
334d8bf4182SKrzysztof Sprzaczkowski 		/* For DIF strip operations, DSA may incorrectly report an overlapping buffer
335d8bf4182SKrzysztof Sprzaczkowski 		 * error if the destination buffer immediately precedes the source buffer.
336d8bf4182SKrzysztof Sprzaczkowski 		 * This is because DSA uses the transfer size in the descriptor for both
337d8bf4182SKrzysztof Sprzaczkowski 		 * the source and destination buffers when checking for buffer overlap.
338d8bf4182SKrzysztof Sprzaczkowski 		 * Since the transfer size applies to the source buffer, which is larger
339d8bf4182SKrzysztof Sprzaczkowski 		 * than the destination buffer by metadata, it should not be used as
340d8bf4182SKrzysztof Sprzaczkowski 		 * the destination buffer size. To avoid reporting errors by DSA, the software
341d8bf4182SKrzysztof Sprzaczkowski 		 * checks whether such an error condition can occur, and if so the software
342d8bf4182SKrzysztof Sprzaczkowski 		 * fallback is performed. */
343d8bf4182SKrzysztof Sprzaczkowski 		rc = check_dsa_dif_strip_overlap_bufs(task);
344d8bf4182SKrzysztof Sprzaczkowski 		if (rc == 0) {
345d8bf4182SKrzysztof Sprzaczkowski 			rc = spdk_idxd_submit_dif_strip(chan->chan,
346d8bf4182SKrzysztof Sprzaczkowski 							task->d.iovs, task->d.iovcnt,
347d8bf4182SKrzysztof Sprzaczkowski 							task->s.iovs, task->s.iovcnt,
348d8bf4182SKrzysztof Sprzaczkowski 							task->dif.num_blocks, task->dif.ctx, flags,
349d8bf4182SKrzysztof Sprzaczkowski 							dsa_done, idxd_task);
350d8bf4182SKrzysztof Sprzaczkowski 		} else if (rc == -EFAULT) {
351d8bf4182SKrzysztof Sprzaczkowski 			rc = spdk_dif_verify_copy(task->d.iovs,
352d8bf4182SKrzysztof Sprzaczkowski 						  task->d.iovcnt,
353d8bf4182SKrzysztof Sprzaczkowski 						  task->s.iovs,
354d8bf4182SKrzysztof Sprzaczkowski 						  task->s.iovcnt,
355d8bf4182SKrzysztof Sprzaczkowski 						  task->dif.num_blocks,
356d8bf4182SKrzysztof Sprzaczkowski 						  task->dif.ctx,
357d8bf4182SKrzysztof Sprzaczkowski 						  task->dif.err);
358d8bf4182SKrzysztof Sprzaczkowski 			idxd_task->task.status = rc;
359d8bf4182SKrzysztof Sprzaczkowski 			spdk_thread_send_msg(spdk_get_thread(), spdk_accel_sw_task_complete, (void *)&idxd_task->task);
360d8bf4182SKrzysztof Sprzaczkowski 			rc = 0;
361d8bf4182SKrzysztof Sprzaczkowski 		}
362d8bf4182SKrzysztof Sprzaczkowski 		break;
363a6867721SKrzysztof Karas 	case SPDK_ACCEL_OPC_DIX_GENERATE:
364a6867721SKrzysztof Karas 		rc = spdk_idxd_submit_dix_generate(chan->chan, task->s.iovs, task->s.iovcnt,
365a6867721SKrzysztof Karas 						   task->d.iovs, task->dif.num_blocks,
366a6867721SKrzysztof Karas 						   task->dif.ctx, flags, dsa_done, idxd_task);
367a6867721SKrzysztof Karas 		break;
368f74d16beSSlawomir Ptak 	case SPDK_ACCEL_OPC_DIX_VERIFY:
369f74d16beSSlawomir Ptak 		rc = accel_dsa_dix_verify(chan, flags, idxd_task);
370f74d16beSSlawomir Ptak 		break;
371712e8cb7SBen Walker 	default:
372712e8cb7SBen Walker 		assert(false);
373712e8cb7SBen Walker 		rc = -EINVAL;
374712e8cb7SBen Walker 		break;
375712e8cb7SBen Walker 	}
376712e8cb7SBen Walker 
377712e8cb7SBen Walker 	if (rc == 0) {
378712e8cb7SBen Walker 		chan->num_outstanding++;
379712e8cb7SBen Walker 		spdk_trace_record(TRACE_ACCEL_DSA_OP_SUBMIT, 0, 0, 0, chan->num_outstanding);
380712e8cb7SBen Walker 	}
381712e8cb7SBen Walker 
382712e8cb7SBen Walker 	return rc;
383712e8cb7SBen Walker }
384712e8cb7SBen Walker 
385712e8cb7SBen Walker static int
3866f5ba1bdSTomasz Zawadzki dsa_submit_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
387712e8cb7SBen Walker {
388712e8cb7SBen Walker 	struct idxd_io_channel *chan = spdk_io_channel_get_ctx(ch);
389712e8cb7SBen Walker 	int rc = 0;
390712e8cb7SBen Walker 
391ee020824SAlexey Marchuk 	assert(STAILQ_NEXT(task, link) == NULL);
392712e8cb7SBen Walker 
3936f5ba1bdSTomasz Zawadzki 	if (spdk_unlikely(chan->state == IDXD_CHANNEL_ERROR)) {
394712e8cb7SBen Walker 		spdk_accel_task_complete(task, -EINVAL);
395712e8cb7SBen Walker 		return 0;
396712e8cb7SBen Walker 	}
397712e8cb7SBen Walker 
398ee020824SAlexey Marchuk 	if (!STAILQ_EMPTY(&chan->queued_tasks)) {
399ee020824SAlexey Marchuk 		STAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
4006f5ba1bdSTomasz Zawadzki 		return 0;
401712e8cb7SBen Walker 	}
402712e8cb7SBen Walker 
403712e8cb7SBen Walker 	rc = _process_single_task(ch, task);
404712e8cb7SBen Walker 	if (rc == -EBUSY) {
405ee020824SAlexey Marchuk 		STAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
406712e8cb7SBen Walker 	} else if (rc) {
407712e8cb7SBen Walker 		spdk_accel_task_complete(task, rc);
408712e8cb7SBen Walker 	}
409712e8cb7SBen Walker 
410712e8cb7SBen Walker 	return 0;
411712e8cb7SBen Walker }
4126f5ba1bdSTomasz Zawadzki 
4136f5ba1bdSTomasz Zawadzki static int
4146f5ba1bdSTomasz Zawadzki dsa_submit_queued_tasks(struct idxd_io_channel *chan)
4156f5ba1bdSTomasz Zawadzki {
4166f5ba1bdSTomasz Zawadzki 	struct spdk_accel_task *task, *tmp;
4176f5ba1bdSTomasz Zawadzki 	struct spdk_io_channel *ch = spdk_io_channel_from_ctx(chan);
4186f5ba1bdSTomasz Zawadzki 	int rc = 0;
4196f5ba1bdSTomasz Zawadzki 
4206f5ba1bdSTomasz Zawadzki 	if (spdk_unlikely(chan->state == IDXD_CHANNEL_ERROR)) {
4216f5ba1bdSTomasz Zawadzki 		/* Complete queued tasks with error and clear the list */
422ee020824SAlexey Marchuk 		while ((task = STAILQ_FIRST(&chan->queued_tasks))) {
423ee020824SAlexey Marchuk 			STAILQ_REMOVE_HEAD(&chan->queued_tasks, link);
4246f5ba1bdSTomasz Zawadzki 			spdk_accel_task_complete(task, -EINVAL);
4256f5ba1bdSTomasz Zawadzki 		}
4266f5ba1bdSTomasz Zawadzki 		return 0;
4276f5ba1bdSTomasz Zawadzki 	}
4286f5ba1bdSTomasz Zawadzki 
429ee020824SAlexey Marchuk 	STAILQ_FOREACH_SAFE(task, &chan->queued_tasks, link, tmp) {
4306f5ba1bdSTomasz Zawadzki 		rc = _process_single_task(ch, task);
4316f5ba1bdSTomasz Zawadzki 		if (rc == -EBUSY) {
4326f5ba1bdSTomasz Zawadzki 			return rc;
4336f5ba1bdSTomasz Zawadzki 		}
434ee020824SAlexey Marchuk 		STAILQ_REMOVE_HEAD(&chan->queued_tasks, link);
4356f5ba1bdSTomasz Zawadzki 		if (rc) {
4366f5ba1bdSTomasz Zawadzki 			spdk_accel_task_complete(task, rc);
4376f5ba1bdSTomasz Zawadzki 		}
4386f5ba1bdSTomasz Zawadzki 	}
4396f5ba1bdSTomasz Zawadzki 
440712e8cb7SBen Walker 	return 0;
441712e8cb7SBen Walker }
442712e8cb7SBen Walker 
443712e8cb7SBen Walker static int
444712e8cb7SBen Walker idxd_poll(void *arg)
445712e8cb7SBen Walker {
446712e8cb7SBen Walker 	struct idxd_io_channel *chan = arg;
447712e8cb7SBen Walker 	int count;
448712e8cb7SBen Walker 
449712e8cb7SBen Walker 	count = spdk_idxd_process_events(chan->chan);
450712e8cb7SBen Walker 
451712e8cb7SBen Walker 	/* Check if there are any pending ops to process if the channel is active */
452ee020824SAlexey Marchuk 	if (!STAILQ_EMPTY(&chan->queued_tasks)) {
4536f5ba1bdSTomasz Zawadzki 		dsa_submit_queued_tasks(chan);
454712e8cb7SBen Walker 	}
455712e8cb7SBen Walker 
456712e8cb7SBen Walker 	return count > 0 ? SPDK_POLLER_BUSY : SPDK_POLLER_IDLE;
457712e8cb7SBen Walker }
458712e8cb7SBen Walker 
459712e8cb7SBen Walker static size_t
460712e8cb7SBen Walker accel_dsa_get_ctx_size(void)
461712e8cb7SBen Walker {
462712e8cb7SBen Walker 	return sizeof(struct idxd_task);
463712e8cb7SBen Walker }
464712e8cb7SBen Walker 
465712e8cb7SBen Walker static bool
4665105dc5dSKonrad Sztyber dsa_supports_opcode(enum spdk_accel_opcode opc)
467712e8cb7SBen Walker {
468712e8cb7SBen Walker 	if (!g_dsa_initialized) {
4690cd6ba66SAlexey Marchuk 		assert(0);
470712e8cb7SBen Walker 		return false;
471712e8cb7SBen Walker 	}
472712e8cb7SBen Walker 
473712e8cb7SBen Walker 	switch (opc) {
4745105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY:
4755105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_FILL:
4765105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_DUALCAST:
4775105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COMPARE:
4785105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_CRC32C:
4795105dc5dSKonrad Sztyber 	case SPDK_ACCEL_OPC_COPY_CRC32C:
480712e8cb7SBen Walker 		return true;
481ac8071d6SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY:
482da954d0aSKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_GENERATE_COPY:
483d8bf4182SKrzysztof Sprzaczkowski 	case SPDK_ACCEL_OPC_DIF_VERIFY_COPY:
484a6867721SKrzysztof Karas 	/* In theory, DIX Generate could work without the iommu, but iommu is required
485a6867721SKrzysztof Karas 	 * for consistency with other DIF operations.
486a6867721SKrzysztof Karas 	 */
487a6867721SKrzysztof Karas 	case SPDK_ACCEL_OPC_DIX_GENERATE:
488f74d16beSSlawomir Ptak 	case SPDK_ACCEL_OPC_DIX_VERIFY:
489ac8071d6SKrzysztof Sprzaczkowski 		/* Supported only if the IOMMU is enabled */
490ac8071d6SKrzysztof Sprzaczkowski 		return spdk_iommu_is_enabled();
491712e8cb7SBen Walker 	default:
492712e8cb7SBen Walker 		return false;
493712e8cb7SBen Walker 	}
494712e8cb7SBen Walker }
495712e8cb7SBen Walker 
496712e8cb7SBen Walker static int accel_dsa_init(void);
497712e8cb7SBen Walker static void accel_dsa_exit(void *ctx);
498712e8cb7SBen Walker static void accel_dsa_write_config_json(struct spdk_json_write_ctx *w);
499712e8cb7SBen Walker 
500712e8cb7SBen Walker static struct spdk_accel_module_if g_dsa_module = {
501712e8cb7SBen Walker 	.module_init = accel_dsa_init,
502712e8cb7SBen Walker 	.module_fini = accel_dsa_exit,
503712e8cb7SBen Walker 	.write_config_json = accel_dsa_write_config_json,
504712e8cb7SBen Walker 	.get_ctx_size = accel_dsa_get_ctx_size,
505712e8cb7SBen Walker 	.name			= "dsa",
506712e8cb7SBen Walker 	.supports_opcode	= dsa_supports_opcode,
507712e8cb7SBen Walker 	.get_io_channel		= dsa_get_io_channel,
5086f5ba1bdSTomasz Zawadzki 	.submit_tasks		= dsa_submit_task
509712e8cb7SBen Walker };
510712e8cb7SBen Walker 
511712e8cb7SBen Walker static int
512712e8cb7SBen Walker dsa_create_cb(void *io_device, void *ctx_buf)
513712e8cb7SBen Walker {
514712e8cb7SBen Walker 	struct idxd_io_channel *chan = ctx_buf;
515712e8cb7SBen Walker 	struct idxd_device *dsa;
516f74d16beSSlawomir Ptak 	int rc;
517712e8cb7SBen Walker 
518712e8cb7SBen Walker 	dsa = idxd_select_device(chan);
519712e8cb7SBen Walker 	if (dsa == NULL) {
520712e8cb7SBen Walker 		SPDK_ERRLOG("Failed to get an idxd channel\n");
521712e8cb7SBen Walker 		return -EINVAL;
522712e8cb7SBen Walker 	}
523712e8cb7SBen Walker 
524712e8cb7SBen Walker 	chan->dev = dsa;
525712e8cb7SBen Walker 	chan->poller = SPDK_POLLER_REGISTER(idxd_poll, chan, 0);
526ee020824SAlexey Marchuk 	STAILQ_INIT(&chan->queued_tasks);
527712e8cb7SBen Walker 	chan->num_outstanding = 0;
528712e8cb7SBen Walker 	chan->state = IDXD_CHANNEL_ACTIVE;
529f74d16beSSlawomir Ptak 	rc = spdk_iobuf_channel_init(&chan->iobuf, "accel_dsa",
530f74d16beSSlawomir Ptak 				     ACCEL_DSA_MD_IOBUF_SMALL_CACHE_SIZE,
531f74d16beSSlawomir Ptak 				     ACCEL_DSA_MD_IOBUF_LARGE_CACHE_SIZE);
532f74d16beSSlawomir Ptak 	if (rc != 0) {
533f74d16beSSlawomir Ptak 		SPDK_ERRLOG("Failed to create an iobuf channel in accel dsa\n");
534f74d16beSSlawomir Ptak 		return -ENOMEM;
535f74d16beSSlawomir Ptak 	}
536712e8cb7SBen Walker 
537712e8cb7SBen Walker 	return 0;
538712e8cb7SBen Walker }
539712e8cb7SBen Walker 
540712e8cb7SBen Walker static void
541712e8cb7SBen Walker dsa_destroy_cb(void *io_device, void *ctx_buf)
542712e8cb7SBen Walker {
543712e8cb7SBen Walker 	struct idxd_io_channel *chan = ctx_buf;
544712e8cb7SBen Walker 
545f74d16beSSlawomir Ptak 	spdk_iobuf_channel_fini(&chan->iobuf);
546712e8cb7SBen Walker 	spdk_poller_unregister(&chan->poller);
547712e8cb7SBen Walker 	spdk_idxd_put_channel(chan->chan);
548712e8cb7SBen Walker }
549712e8cb7SBen Walker 
550712e8cb7SBen Walker static struct spdk_io_channel *
551712e8cb7SBen Walker dsa_get_io_channel(void)
552712e8cb7SBen Walker {
553712e8cb7SBen Walker 	return spdk_get_io_channel(&g_dsa_module);
554712e8cb7SBen Walker }
555712e8cb7SBen Walker 
556712e8cb7SBen Walker static void
557712e8cb7SBen Walker attach_cb(void *cb_ctx, struct spdk_idxd_device *idxd)
558712e8cb7SBen Walker {
559712e8cb7SBen Walker 	struct idxd_device *dev;
560712e8cb7SBen Walker 
561712e8cb7SBen Walker 	dev = calloc(1, sizeof(*dev));
562712e8cb7SBen Walker 	if (dev == NULL) {
563712e8cb7SBen Walker 		SPDK_ERRLOG("Failed to allocate device struct\n");
564712e8cb7SBen Walker 		return;
565712e8cb7SBen Walker 	}
566712e8cb7SBen Walker 
567712e8cb7SBen Walker 	dev->dsa = idxd;
568712e8cb7SBen Walker 	if (g_next_dev == NULL) {
569712e8cb7SBen Walker 		g_next_dev = dev;
570712e8cb7SBen Walker 	}
571712e8cb7SBen Walker 
572712e8cb7SBen Walker 	TAILQ_INSERT_TAIL(&g_dsa_devices, dev, tailq);
573712e8cb7SBen Walker 	g_num_devices++;
574712e8cb7SBen Walker }
575712e8cb7SBen Walker 
5763cac0518SKrzysztof Sprzaczkowski int
577712e8cb7SBen Walker accel_dsa_enable_probe(bool kernel_mode)
578712e8cb7SBen Walker {
5793cac0518SKrzysztof Sprzaczkowski 	int rc;
5803cac0518SKrzysztof Sprzaczkowski 
5813cac0518SKrzysztof Sprzaczkowski 	if (g_dsa_enable) {
5823cac0518SKrzysztof Sprzaczkowski 		return -EALREADY;
5833cac0518SKrzysztof Sprzaczkowski 	}
5843cac0518SKrzysztof Sprzaczkowski 
5853cac0518SKrzysztof Sprzaczkowski 	rc = spdk_idxd_set_config(kernel_mode);
5863cac0518SKrzysztof Sprzaczkowski 	if (rc != 0) {
5873cac0518SKrzysztof Sprzaczkowski 		return rc;
5883cac0518SKrzysztof Sprzaczkowski 	}
5893cac0518SKrzysztof Sprzaczkowski 
5903cac0518SKrzysztof Sprzaczkowski 	spdk_accel_module_list_add(&g_dsa_module);
591712e8cb7SBen Walker 	g_kernel_mode = kernel_mode;
592712e8cb7SBen Walker 	g_dsa_enable = true;
5933cac0518SKrzysztof Sprzaczkowski 
5943cac0518SKrzysztof Sprzaczkowski 	return 0;
595712e8cb7SBen Walker }
596712e8cb7SBen Walker 
597712e8cb7SBen Walker static bool
598712e8cb7SBen Walker probe_cb(void *cb_ctx, struct spdk_pci_device *dev)
599712e8cb7SBen Walker {
600712e8cb7SBen Walker 	if (dev->id.device_id == PCI_DEVICE_ID_INTEL_DSA) {
601712e8cb7SBen Walker 		return true;
602712e8cb7SBen Walker 	}
603712e8cb7SBen Walker 
604712e8cb7SBen Walker 	return false;
605712e8cb7SBen Walker }
606712e8cb7SBen Walker 
607712e8cb7SBen Walker static int
608712e8cb7SBen Walker accel_dsa_init(void)
609712e8cb7SBen Walker {
610f74d16beSSlawomir Ptak 	int rc;
611f74d16beSSlawomir Ptak 
612712e8cb7SBen Walker 	if (!g_dsa_enable) {
613712e8cb7SBen Walker 		return -EINVAL;
614712e8cb7SBen Walker 	}
615712e8cb7SBen Walker 
616712e8cb7SBen Walker 	if (spdk_idxd_probe(NULL, attach_cb, probe_cb) != 0) {
617712e8cb7SBen Walker 		SPDK_ERRLOG("spdk_idxd_probe() failed\n");
618712e8cb7SBen Walker 		return -EINVAL;
619712e8cb7SBen Walker 	}
620712e8cb7SBen Walker 
621712e8cb7SBen Walker 	if (TAILQ_EMPTY(&g_dsa_devices)) {
6221f88c365STomasz Zawadzki 		return -ENODEV;
623712e8cb7SBen Walker 	}
624712e8cb7SBen Walker 
625f74d16beSSlawomir Ptak 	rc = spdk_iobuf_register_module("accel_dsa");
626f74d16beSSlawomir Ptak 	if (rc != 0) {
627f74d16beSSlawomir Ptak 		SPDK_ERRLOG("Failed to register accel_dsa iobuf module\n");
628f74d16beSSlawomir Ptak 		return rc;
629f74d16beSSlawomir Ptak 	}
630f74d16beSSlawomir Ptak 
631712e8cb7SBen Walker 	g_dsa_initialized = true;
632712e8cb7SBen Walker 	spdk_io_device_register(&g_dsa_module, dsa_create_cb, dsa_destroy_cb,
633712e8cb7SBen Walker 				sizeof(struct idxd_io_channel), "dsa_accel_module");
634712e8cb7SBen Walker 	return 0;
635712e8cb7SBen Walker }
636712e8cb7SBen Walker 
637712e8cb7SBen Walker static void
638712e8cb7SBen Walker accel_dsa_exit(void *ctx)
639712e8cb7SBen Walker {
640712e8cb7SBen Walker 	struct idxd_device *dev;
641712e8cb7SBen Walker 
642712e8cb7SBen Walker 	if (g_dsa_initialized) {
643712e8cb7SBen Walker 		spdk_io_device_unregister(&g_dsa_module, NULL);
644712e8cb7SBen Walker 		g_dsa_initialized = false;
645712e8cb7SBen Walker 	}
646712e8cb7SBen Walker 
647712e8cb7SBen Walker 	while (!TAILQ_EMPTY(&g_dsa_devices)) {
648712e8cb7SBen Walker 		dev = TAILQ_FIRST(&g_dsa_devices);
649712e8cb7SBen Walker 		TAILQ_REMOVE(&g_dsa_devices, dev, tailq);
650712e8cb7SBen Walker 		spdk_idxd_detach(dev->dsa);
651712e8cb7SBen Walker 		free(dev);
652712e8cb7SBen Walker 	}
653712e8cb7SBen Walker 
654712e8cb7SBen Walker 	spdk_accel_module_finish();
655712e8cb7SBen Walker }
656712e8cb7SBen Walker 
657712e8cb7SBen Walker static void
658712e8cb7SBen Walker accel_dsa_write_config_json(struct spdk_json_write_ctx *w)
659712e8cb7SBen Walker {
660712e8cb7SBen Walker 	if (g_dsa_enable) {
661712e8cb7SBen Walker 		spdk_json_write_object_begin(w);
662712e8cb7SBen Walker 		spdk_json_write_named_string(w, "method", "dsa_scan_accel_module");
663712e8cb7SBen Walker 		spdk_json_write_named_object_begin(w, "params");
664712e8cb7SBen Walker 		spdk_json_write_named_bool(w, "config_kernel_mode", g_kernel_mode);
665712e8cb7SBen Walker 		spdk_json_write_object_end(w);
666712e8cb7SBen Walker 		spdk_json_write_object_end(w);
667712e8cb7SBen Walker 	}
668712e8cb7SBen Walker }
669712e8cb7SBen Walker 
670*0eae0106SJim Harris static void
671*0eae0106SJim Harris dsa_trace(void)
672712e8cb7SBen Walker {
67326d44a12SJim Harris 	spdk_trace_register_description("DSA_OP_SUBMIT", TRACE_ACCEL_DSA_OP_SUBMIT, OWNER_TYPE_NONE,
67426d44a12SJim Harris 					OBJECT_NONE, 0,
675712e8cb7SBen Walker 					SPDK_TRACE_ARG_TYPE_INT, "count");
67626d44a12SJim Harris 	spdk_trace_register_description("DSA_OP_COMPLETE", TRACE_ACCEL_DSA_OP_COMPLETE, OWNER_TYPE_NONE,
677712e8cb7SBen Walker 					OBJECT_NONE,
678712e8cb7SBen Walker 					0, SPDK_TRACE_ARG_TYPE_INT, "count");
679712e8cb7SBen Walker }
680*0eae0106SJim Harris SPDK_TRACE_REGISTER_FN(dsa_trace, "dsa", TRACE_GROUP_ACCEL_DSA)
681712e8cb7SBen Walker 
682712e8cb7SBen Walker SPDK_LOG_REGISTER_COMPONENT(accel_dsa)
683