Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (C) 2018 Intel Corporation.
3 : : * All rights reserved.
4 : : * Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
5 : : */
6 : :
7 : : #include "accel_dpdk_compressdev.h"
8 : : #include "spdk/accel_module.h"
9 : :
10 : : #include "spdk/stdinc.h"
11 : : #include "spdk/rpc.h"
12 : : #include "spdk/env.h"
13 : : #include "spdk/endian.h"
14 : : #include "spdk/string.h"
15 : : #include "spdk/thread.h"
16 : : #include "spdk/util.h"
17 : : #include "spdk/likely.h"
18 : :
19 : : #include "spdk/log.h"
20 : :
21 : : #include <rte_config.h>
22 : : #include <rte_bus_vdev.h>
23 : : #include <rte_compressdev.h>
24 : : #include <rte_comp.h>
25 : : #include <rte_mbuf_dyn.h>
26 : :
27 : : /* Used to store IO context in mbuf */
28 : : static const struct rte_mbuf_dynfield rte_mbuf_dynfield_io_context = {
29 : : .name = "context_accel_comp",
30 : : .size = sizeof(uint64_t),
31 : : .align = __alignof__(uint64_t),
32 : : .flags = 0,
33 : : };
34 : : static int g_mbuf_offset;
35 : : static enum compress_pmd g_opts;
36 : : static bool g_compressdev_enable = false;
37 : : static bool g_compressdev_initialized = false;
38 : :
39 : : #define NUM_MAX_XFORMS 2
40 : : #define NUM_MAX_INFLIGHT_OPS 128
41 : : #define DEFAULT_WINDOW_SIZE 15
42 : : #define MBUF_SPLIT (1UL << DEFAULT_WINDOW_SIZE)
43 : : #define QAT_PMD "compress_qat"
44 : : #define MLX5_PMD "mlx5_pci"
45 : : #define NUM_MBUFS 65536
46 : : #define POOL_CACHE_SIZE 256
47 : :
48 : : /* Global list of available compression devices. */
49 : : struct compress_dev {
50 : : struct rte_compressdev_info cdev_info; /* includes device friendly name */
51 : : uint8_t cdev_id; /* identifier for the device */
52 : : void *comp_xform; /* shared private xform for comp on this PMD */
53 : : void *decomp_xform; /* shared private xform for decomp on this PMD */
54 : : bool sgl_in;
55 : : bool sgl_out;
56 : : TAILQ_ENTRY(compress_dev) link;
57 : : };
58 : : static TAILQ_HEAD(, compress_dev) g_compress_devs = TAILQ_HEAD_INITIALIZER(g_compress_devs);
59 : :
60 : : #define MAX_NUM_QP 48
61 : : /* Global list and lock for unique device/queue pair combos */
62 : : struct comp_device_qp {
63 : : struct compress_dev *device; /* ptr to compression device */
64 : : uint8_t qp; /* queue pair for this node */
65 : : struct compress_io_channel *chan;
66 : : TAILQ_ENTRY(comp_device_qp) link;
67 : : };
68 : : static TAILQ_HEAD(, comp_device_qp) g_comp_device_qp = TAILQ_HEAD_INITIALIZER(g_comp_device_qp);
69 : : static pthread_mutex_t g_comp_device_qp_lock = PTHREAD_MUTEX_INITIALIZER;
70 : :
71 : : struct compress_io_channel {
72 : : char *drv_name; /* name of the compression device driver */
73 : : struct comp_device_qp *device_qp;
74 : : struct spdk_poller *poller;
75 : : struct rte_mbuf **src_mbufs;
76 : : struct rte_mbuf **dst_mbufs;
77 : : STAILQ_HEAD(, spdk_accel_task) queued_tasks;
78 : : };
79 : :
80 : : /* Shared mempools between all devices on this system */
81 : : static struct rte_mempool *g_mbuf_mp = NULL; /* mbuf mempool */
82 : : static struct rte_mempool *g_comp_op_mp = NULL; /* comp operations, must be rte* mempool */
83 : : static struct rte_mbuf_ext_shared_info g_shinfo = {}; /* used by DPDK mbuf macros */
84 : : static bool g_qat_available = false;
85 : : static bool g_mlx5_pci_available = false;
86 : :
87 : : /* Create shared (between all ops per PMD) compress xforms. */
88 : : static struct rte_comp_xform g_comp_xform = {
89 : : .type = RTE_COMP_COMPRESS,
90 : : .compress = {
91 : : .algo = RTE_COMP_ALGO_DEFLATE,
92 : : .deflate.huffman = RTE_COMP_HUFFMAN_DEFAULT,
93 : : .level = RTE_COMP_LEVEL_MAX,
94 : : .window_size = DEFAULT_WINDOW_SIZE,
95 : : .chksum = RTE_COMP_CHECKSUM_NONE,
96 : : .hash_algo = RTE_COMP_HASH_ALGO_NONE
97 : : }
98 : : };
99 : : /* Create shared (between all ops per PMD) decompress xforms. */
100 : : static struct rte_comp_xform g_decomp_xform = {
101 : : .type = RTE_COMP_DECOMPRESS,
102 : : .decompress = {
103 : : .algo = RTE_COMP_ALGO_DEFLATE,
104 : : .chksum = RTE_COMP_CHECKSUM_NONE,
105 : : .window_size = DEFAULT_WINDOW_SIZE,
106 : : .hash_algo = RTE_COMP_HASH_ALGO_NONE
107 : : }
108 : : };
109 : :
110 : : /* Dummy function used by DPDK to free ext attached buffers
111 : : * to mbufs, we free them ourselves but this callback has to
112 : : * be here.
113 : : */
114 : : static void
115 : 43 : shinfo_free_cb(void *arg1, void *arg2)
116 : : {
117 : 43 : }
118 : :
119 : : /* Called by accel_init_compress_drivers() to init each discovered compression device */
120 : : static int
121 : 576 : create_compress_dev(uint8_t index)
122 : : {
123 : : struct compress_dev *device;
124 : : uint16_t q_pairs;
125 : : uint8_t cdev_id;
126 : : int rc, i;
127 : : struct comp_device_qp *dev_qp;
128 : : struct comp_device_qp *tmp_qp;
129 : :
130 : 576 : device = calloc(1, sizeof(struct compress_dev));
131 [ - + ]: 576 : if (!device) {
132 : 0 : return -ENOMEM;
133 : : }
134 : :
135 : : /* Get details about this device. */
136 : 576 : rte_compressdev_info_get(index, &device->cdev_info);
137 : :
138 : 576 : cdev_id = device->cdev_id = index;
139 : :
140 : : /* Zero means no limit so choose number of lcores. */
141 [ - + ]: 576 : if (device->cdev_info.max_nb_queue_pairs == 0) {
142 : 0 : q_pairs = MAX_NUM_QP;
143 : : } else {
144 : 576 : q_pairs = spdk_min(device->cdev_info.max_nb_queue_pairs, MAX_NUM_QP);
145 : : }
146 : :
147 : : /* Configure the compression device. */
148 : 576 : struct rte_compressdev_config config = {
149 : 576 : .socket_id = rte_socket_id(),
150 : : .nb_queue_pairs = q_pairs,
151 : : .max_nb_priv_xforms = NUM_MAX_XFORMS,
152 : : .max_nb_streams = 0
153 : : };
154 : 576 : rc = rte_compressdev_configure(cdev_id, &config);
155 [ - + ]: 576 : if (rc < 0) {
156 : 0 : SPDK_ERRLOG("Failed to configure compressdev %u\n", cdev_id);
157 : 0 : goto err;
158 : : }
159 : :
160 : : /* Pre-setup all potential qpairs now and assign them in the channel
161 : : * callback.
162 : : */
163 [ + + ]: 1728 : for (i = 0; i < q_pairs; i++) {
164 : 1152 : rc = rte_compressdev_queue_pair_setup(cdev_id, i,
165 : : NUM_MAX_INFLIGHT_OPS,
166 : 1152 : rte_socket_id());
167 [ - + ]: 1152 : if (rc) {
168 [ # # ]: 0 : if (i > 0) {
169 : 0 : q_pairs = i;
170 : 0 : SPDK_NOTICELOG("FYI failed to setup a queue pair on "
171 : : "compressdev %u with error %u "
172 : : "so limiting to %u qpairs\n",
173 : : cdev_id, rc, q_pairs);
174 : 0 : break;
175 : : } else {
176 : 0 : SPDK_ERRLOG("Failed to setup queue pair on "
177 : : "compressdev %u with error %u\n", cdev_id, rc);
178 : 0 : rc = -EINVAL;
179 : 0 : goto err;
180 : : }
181 : : }
182 : : }
183 : :
184 : 576 : rc = rte_compressdev_start(cdev_id);
185 [ - + ]: 576 : if (rc < 0) {
186 : 0 : SPDK_ERRLOG("Failed to start device %u: error %d\n",
187 : : cdev_id, rc);
188 : 0 : goto err;
189 : : }
190 : :
191 [ + - ]: 576 : if (device->cdev_info.capabilities->comp_feature_flags & RTE_COMP_FF_SHAREABLE_PRIV_XFORM) {
192 : 576 : rc = rte_compressdev_private_xform_create(cdev_id, &g_comp_xform,
193 : : &device->comp_xform);
194 [ - + ]: 576 : if (rc < 0) {
195 : 0 : SPDK_ERRLOG("Failed to create private comp xform device %u: error %d\n",
196 : : cdev_id, rc);
197 : 0 : goto err;
198 : : }
199 : :
200 : 576 : rc = rte_compressdev_private_xform_create(cdev_id, &g_decomp_xform,
201 : : &device->decomp_xform);
202 [ - + ]: 576 : if (rc) {
203 : 0 : SPDK_ERRLOG("Failed to create private decomp xform device %u: error %d\n",
204 : : cdev_id, rc);
205 : 0 : goto err;
206 : : }
207 : : } else {
208 : 0 : SPDK_ERRLOG("PMD does not support shared transforms\n");
209 : 0 : goto err;
210 : : }
211 : :
212 : : /* Build up list of device/qp combinations */
213 [ + + ]: 1728 : for (i = 0; i < q_pairs; i++) {
214 : 1152 : dev_qp = calloc(1, sizeof(struct comp_device_qp));
215 [ - + ]: 1152 : if (!dev_qp) {
216 : 0 : rc = -ENOMEM;
217 : 0 : goto err;
218 : : }
219 : 1152 : dev_qp->device = device;
220 : 1152 : dev_qp->qp = i;
221 : 1152 : dev_qp->chan = NULL;
222 : 1152 : TAILQ_INSERT_TAIL(&g_comp_device_qp, dev_qp, link);
223 : : }
224 : :
225 : 576 : TAILQ_INSERT_TAIL(&g_compress_devs, device, link);
226 : :
227 [ - + + - ]: 576 : if (strcmp(device->cdev_info.driver_name, QAT_PMD) == 0) {
228 : 576 : g_qat_available = true;
229 : : }
230 : :
231 [ - + - + ]: 576 : if (strcmp(device->cdev_info.driver_name, MLX5_PMD) == 0) {
232 : 0 : g_mlx5_pci_available = true;
233 : : }
234 : :
235 : 576 : return 0;
236 : :
237 : 0 : err:
238 [ # # ]: 0 : TAILQ_FOREACH_SAFE(dev_qp, &g_comp_device_qp, link, tmp_qp) {
239 [ # # ]: 0 : TAILQ_REMOVE(&g_comp_device_qp, dev_qp, link);
240 : 0 : free(dev_qp);
241 : : }
242 : 0 : free(device);
243 : 0 : return rc;
244 : : }
245 : :
246 : : /* Called from driver init entry point, accel_compress_init() */
247 : : static int
248 : 12 : accel_init_compress_drivers(void)
249 : : {
250 : : uint8_t cdev_count, i;
251 : : struct compress_dev *tmp_dev;
252 : : struct compress_dev *device;
253 : : int rc;
254 : :
255 : : /* If we have no compression devices, report error to fallback on other modules. */
256 : 12 : cdev_count = rte_compressdev_count();
257 [ - + ]: 12 : if (cdev_count == 0) {
258 : 0 : return -ENODEV;
259 : : }
260 [ - + ]: 12 : if (cdev_count > RTE_COMPRESS_MAX_DEVS) {
261 : 0 : SPDK_ERRLOG("invalid device count from rte_compressdev_count()\n");
262 : 0 : return -EINVAL;
263 : : }
264 : :
265 : 12 : g_mbuf_offset = rte_mbuf_dynfield_register(&rte_mbuf_dynfield_io_context);
266 [ - + ]: 12 : if (g_mbuf_offset < 0) {
267 : 0 : SPDK_ERRLOG("error registering dynamic field with DPDK\n");
268 : 0 : return -EINVAL;
269 : : }
270 : :
271 : 12 : g_mbuf_mp = rte_pktmbuf_pool_create("comp_mbuf_mp", NUM_MBUFS, POOL_CACHE_SIZE,
272 : 12 : sizeof(struct rte_mbuf), 0, rte_socket_id());
273 [ - + ]: 12 : if (g_mbuf_mp == NULL) {
274 : 0 : SPDK_ERRLOG("Cannot create mbuf pool\n");
275 : 0 : rc = -ENOMEM;
276 : 0 : goto error_create_mbuf;
277 : : }
278 : :
279 : 12 : g_comp_op_mp = rte_comp_op_pool_create("comp_op_pool", NUM_MBUFS, POOL_CACHE_SIZE,
280 : 12 : 0, rte_socket_id());
281 [ - + ]: 12 : if (g_comp_op_mp == NULL) {
282 : 0 : SPDK_ERRLOG("Cannot create comp op pool\n");
283 : 0 : rc = -ENOMEM;
284 : 0 : goto error_create_op;
285 : : }
286 : :
287 : : /* Init all devices */
288 [ + + ]: 588 : for (i = 0; i < cdev_count; i++) {
289 : 576 : rc = create_compress_dev(i);
290 [ - + ]: 576 : if (rc != 0) {
291 : 0 : goto error_create_compress_devs;
292 : : }
293 : : }
294 : :
295 [ - + + - ]: 12 : if (g_qat_available == true) {
296 : 12 : SPDK_NOTICELOG("initialized QAT PMD\n");
297 : : }
298 : :
299 : 12 : g_shinfo.free_cb = shinfo_free_cb;
300 : :
301 : 12 : return 0;
302 : :
303 : : /* Error cleanup paths. */
304 : 0 : error_create_compress_devs:
305 [ # # ]: 0 : TAILQ_FOREACH_SAFE(device, &g_compress_devs, link, tmp_dev) {
306 [ # # ]: 0 : TAILQ_REMOVE(&g_compress_devs, device, link);
307 : 0 : free(device);
308 : : }
309 : 0 : error_create_op:
310 : 0 : error_create_mbuf:
311 : 0 : rte_mempool_free(g_mbuf_mp);
312 : :
313 : 0 : return rc;
314 : : }
315 : :
316 : : int
317 : 12 : accel_compressdev_enable_probe(enum compress_pmd *opts)
318 : : {
319 : 12 : g_opts = *opts;
320 : 12 : g_compressdev_enable = true;
321 : :
322 : 12 : return 0;
323 : : }
324 : :
325 : : static int
326 : 2465908 : _setup_compress_mbuf(struct rte_mbuf **mbufs, int *mbuf_total, uint64_t *total_length,
327 : : struct iovec *iovs, int iovcnt, struct spdk_accel_task *task)
328 : : {
329 : : uint64_t iovec_length, updated_length, phys_addr;
330 : : uint64_t processed, mbuf_length, remainder;
331 : 2465908 : uint8_t *current_base = NULL;
332 : : int iov_index, mbuf_index;
333 : 2465908 : int rc = 0;
334 : :
335 : : /* Setup mbufs */
336 : 2465908 : iov_index = mbuf_index = 0;
337 [ + + ]: 4931816 : while (iov_index < iovcnt) {
338 : :
339 : 2465908 : processed = 0;
340 : 2465908 : iovec_length = iovs[iov_index].iov_len;
341 : :
342 : 2465908 : current_base = iovs[iov_index].iov_base;
343 [ + + ]: 2465908 : if (total_length) {
344 : 1232954 : *total_length += iovec_length;
345 : : }
346 : :
347 [ - + ]: 2465908 : assert(mbufs[mbuf_index] != NULL);
348 : 2465908 : *RTE_MBUF_DYNFIELD(mbufs[mbuf_index], g_mbuf_offset, uint64_t *) = (uint64_t)task;
349 : :
350 : : do {
351 : : /* new length is min of remaining left or max mbuf size of MBUF_SPLIT */
352 : 3173634 : mbuf_length = updated_length = spdk_min(MBUF_SPLIT, iovec_length - processed);
353 : :
354 : 3173634 : phys_addr = spdk_vtophys((void *)current_base, &updated_length);
355 : :
356 : 3173634 : rte_pktmbuf_attach_extbuf(mbufs[mbuf_index],
357 : : current_base,
358 : : phys_addr,
359 : : updated_length,
360 : : &g_shinfo);
361 : 3173634 : rte_pktmbuf_append(mbufs[mbuf_index], updated_length);
362 : 3173634 : remainder = mbuf_length - updated_length;
363 : :
364 : : /* although the mbufs were preallocated, we still need to chain them */
365 [ + + ]: 3173634 : if (mbuf_index > 0) {
366 : 707726 : rte_pktmbuf_chain(mbufs[0], mbufs[mbuf_index]);
367 : : }
368 : :
369 : : /* keep track of the total we've put into the mbuf chain */
370 : 3173634 : processed += updated_length;
371 : : /* bump the base by what was previously added */
372 : 3173634 : current_base += updated_length;
373 : :
374 : : /* If we crossed 2MB boundary we need another mbuf for the remainder */
375 [ - + ]: 3173634 : if (remainder > 0) {
376 : :
377 [ # # ]: 0 : assert(remainder <= MBUF_SPLIT);
378 : :
379 : : /* allocate an mbuf at the end of the array */
380 : 0 : rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp,
381 : 0 : (struct rte_mbuf **)&mbufs[*mbuf_total], 1);
382 [ # # ]: 0 : if (rc) {
383 : 0 : SPDK_ERRLOG("ERROR trying to get an extra mbuf!\n");
384 : 0 : return -1;
385 : : }
386 : 0 : (*mbuf_total)++;
387 : 0 : mbuf_index++;
388 : 0 : *RTE_MBUF_DYNFIELD(mbufs[mbuf_index], g_mbuf_offset, uint64_t *) = (uint64_t)task;
389 : :
390 : : /* bump the base by what was previously added */
391 : 0 : current_base += updated_length;
392 : :
393 : 0 : updated_length = remainder;
394 : 0 : phys_addr = spdk_vtophys((void *)current_base, &updated_length);
395 : :
396 : : /* assert we don't cross another */
397 [ # # ]: 0 : assert(remainder == updated_length);
398 : :
399 : 0 : rte_pktmbuf_attach_extbuf(mbufs[mbuf_index],
400 : : current_base,
401 : : phys_addr,
402 : : remainder,
403 : : &g_shinfo);
404 : 0 : rte_pktmbuf_append(mbufs[mbuf_index], remainder);
405 : 0 : rte_pktmbuf_chain(mbufs[0], mbufs[mbuf_index]);
406 : :
407 : : /* keep track of the total we've put into the mbuf chain */
408 : 0 : processed += remainder;
409 : : }
410 : :
411 : 3173634 : mbuf_index++;
412 : :
413 [ + + ]: 3173634 : } while (processed < iovec_length);
414 : :
415 [ - + ]: 2465908 : assert(processed == iovec_length);
416 : 2465908 : iov_index++;
417 : : }
418 : :
419 : 2465908 : return 0;
420 : : }
421 : :
422 : : static int
423 : 1232954 : _compress_operation(struct compress_io_channel *chan, struct spdk_accel_task *task)
424 : : {
425 : 1232954 : int dst_iovcnt = task->d.iovcnt;
426 : 1232954 : struct iovec *dst_iovs = task->d.iovs;
427 : 1232954 : int src_iovcnt = task->s.iovcnt;
428 : 1232954 : struct iovec *src_iovs = task->s.iovs;
429 : : struct rte_comp_op *comp_op;
430 : : uint8_t cdev_id;
431 : 1232954 : uint64_t total_length = 0;
432 : 1232954 : int rc = 0, i;
433 : 1232954 : int src_mbuf_total = 0;
434 : 1232954 : int dst_mbuf_total = 0;
435 : 1232954 : bool device_error = false;
436 : 1232954 : bool compress = (task->op_code == SPDK_ACCEL_OPC_COMPRESS);
437 : :
438 [ - + ]: 1232954 : assert(chan->device_qp->device != NULL);
439 : 1232954 : cdev_id = chan->device_qp->device->cdev_id;
440 : :
441 : : /* calc our mbuf totals based on max MBUF size allowed so we can pre-alloc mbufs in bulk */
442 [ + + ]: 2465908 : for (i = 0 ; i < src_iovcnt; i++) {
443 : 1232954 : src_mbuf_total += spdk_divide_round_up(src_iovs[i].iov_len, MBUF_SPLIT);
444 : : }
445 [ + + ]: 2465908 : for (i = 0 ; i < dst_iovcnt; i++) {
446 : 1232954 : dst_mbuf_total += spdk_divide_round_up(dst_iovs[i].iov_len, MBUF_SPLIT);
447 : : }
448 : :
449 : 1232954 : comp_op = rte_comp_op_alloc(g_comp_op_mp);
450 [ - + ]: 1232954 : if (!comp_op) {
451 : 0 : SPDK_ERRLOG("trying to get a comp op!\n");
452 : 0 : rc = -ENOMEM;
453 : 0 : goto error_get_op;
454 : : }
455 : :
456 : : /* get an mbuf per iov, src and dst */
457 : 1232954 : rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp, chan->src_mbufs, src_mbuf_total);
458 [ - + ]: 1232954 : if (rc) {
459 : 0 : SPDK_ERRLOG("ERROR trying to get src_mbufs!\n");
460 : 0 : rc = -ENOMEM;
461 : 0 : goto error_get_src;
462 : : }
463 [ - + ]: 1232954 : assert(chan->src_mbufs[0]);
464 : :
465 : 1232954 : rc = rte_pktmbuf_alloc_bulk(g_mbuf_mp, chan->dst_mbufs, dst_mbuf_total);
466 [ - + ]: 1232954 : if (rc) {
467 : 0 : SPDK_ERRLOG("ERROR trying to get dst_mbufs!\n");
468 : 0 : rc = -ENOMEM;
469 : 0 : goto error_get_dst;
470 : : }
471 [ - + ]: 1232954 : assert(chan->dst_mbufs[0]);
472 : :
473 : 1232954 : rc = _setup_compress_mbuf(chan->src_mbufs, &src_mbuf_total, &total_length,
474 : : src_iovs, src_iovcnt, task);
475 : :
476 [ - + ]: 1232954 : if (rc < 0) {
477 : 0 : goto error_src_dst;
478 : : }
479 [ - + - + : 1232954 : if (!chan->device_qp->device->sgl_in && src_mbuf_total > 1) {
- - ]
480 : 0 : SPDK_ERRLOG("Src buffer uses chained mbufs but driver %s doesn't support SGL input\n",
481 : : chan->drv_name);
482 : 0 : rc = -EINVAL;
483 : 0 : goto error_src_dst;
484 : : }
485 : :
486 : 1232954 : comp_op->m_src = chan->src_mbufs[0];
487 : 1232954 : comp_op->src.offset = 0;
488 : 1232954 : comp_op->src.length = total_length;
489 : :
490 : 1232954 : rc = _setup_compress_mbuf(chan->dst_mbufs, &dst_mbuf_total, NULL,
491 : : dst_iovs, dst_iovcnt, task);
492 [ - + ]: 1232954 : if (rc < 0) {
493 : 0 : goto error_src_dst;
494 : : }
495 [ - + - + : 1232954 : if (!chan->device_qp->device->sgl_out && dst_mbuf_total > 1) {
- - ]
496 : 0 : SPDK_ERRLOG("Dst buffer uses chained mbufs but driver %s doesn't support SGL output\n",
497 : : chan->drv_name);
498 : 0 : rc = -EINVAL;
499 : 0 : goto error_src_dst;
500 : : }
501 : :
502 : 1232954 : comp_op->m_dst = chan->dst_mbufs[0];
503 : 1232954 : comp_op->dst.offset = 0;
504 : :
505 [ + + ]: 1232954 : if (compress == true) {
506 : 274261 : comp_op->private_xform = chan->device_qp->device->comp_xform;
507 : : } else {
508 : 958693 : comp_op->private_xform = chan->device_qp->device->decomp_xform;
509 : : }
510 : :
511 : 1232954 : comp_op->op_type = RTE_COMP_OP_STATELESS;
512 : 1232954 : comp_op->flush_flag = RTE_COMP_FLUSH_FINAL;
513 : :
514 : 1232954 : rc = rte_compressdev_enqueue_burst(cdev_id, chan->device_qp->qp, &comp_op, 1);
515 [ - + ]: 1232954 : assert(rc <= 1);
516 : :
517 : : /* We always expect 1 got queued, if 0 then we need to queue it up. */
518 [ + + ]: 1232954 : if (rc == 1) {
519 : 1232953 : return 0;
520 [ + - ]: 1 : } else if (comp_op->status == RTE_COMP_OP_STATUS_NOT_PROCESSED) {
521 : 1 : rc = -EAGAIN;
522 : : } else {
523 : 0 : device_error = true;
524 : : }
525 : :
526 : : /* Error cleanup paths. */
527 : 1 : error_src_dst:
528 : 1 : rte_pktmbuf_free_bulk(chan->dst_mbufs, dst_iovcnt);
529 : 1 : error_get_dst:
530 : 1 : rte_pktmbuf_free_bulk(chan->src_mbufs, src_iovcnt);
531 : 1 : error_get_src:
532 : 1 : rte_comp_op_free(comp_op);
533 : 1 : error_get_op:
534 : :
535 [ - + ]: 1 : if (device_error == true) {
536 : : /* There was an error sending the op to the device, most
537 : : * likely with the parameters.
538 : : */
539 : 0 : SPDK_ERRLOG("Compression API returned 0x%x\n", comp_op->status);
540 : 0 : return -EINVAL;
541 : : }
542 [ + - - + ]: 1 : if (rc != -ENOMEM && rc != -EAGAIN) {
543 : 0 : return rc;
544 : : }
545 : :
546 : 1 : STAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
547 : 1 : return 0;
548 : : }
549 : :
550 : : /* Poller for the DPDK compression driver. */
551 : : static int
552 : 7086094 : comp_dev_poller(void *args)
553 : : {
554 : 7086094 : struct compress_io_channel *chan = args;
555 : : uint8_t cdev_id;
556 : : struct rte_comp_op *deq_ops[NUM_MAX_INFLIGHT_OPS];
557 : : uint16_t num_deq;
558 : : struct spdk_accel_task *task, *task_to_resubmit;
559 : : int rc, i, status;
560 : :
561 [ - + ]: 7086094 : assert(chan->device_qp->device != NULL);
562 : 7086094 : cdev_id = chan->device_qp->device->cdev_id;
563 : :
564 : 7086094 : num_deq = rte_compressdev_dequeue_burst(cdev_id, chan->device_qp->qp, deq_ops,
565 : : NUM_MAX_INFLIGHT_OPS);
566 [ + + ]: 8319047 : for (i = 0; i < num_deq; i++) {
567 : :
568 : : /* We store this off regardless of success/error so we know how to contruct the
569 : : * next task
570 : : */
571 : 1232953 : task = (struct spdk_accel_task *)*RTE_MBUF_DYNFIELD(deq_ops[i]->m_src, g_mbuf_offset,
572 : : uint64_t *);
573 : 1232953 : status = deq_ops[i]->status;
574 : :
575 [ + - ]: 1232953 : if (spdk_likely(status == RTE_COMP_OP_STATUS_SUCCESS)) {
576 [ + + ]: 1232953 : if (task->output_size != NULL) {
577 : 452332 : *task->output_size = deq_ops[i]->produced;
578 : : }
579 : : } else {
580 : 0 : SPDK_NOTICELOG("Deque status %u\n", status);
581 : : }
582 : :
583 : 1232953 : spdk_accel_task_complete(task, status);
584 : :
585 : : /* Now free both mbufs and the compress operation. The rte_pktmbuf_free()
586 : : * call takes care of freeing all of the mbufs in the chain back to their
587 : : * original pool.
588 : : */
589 : 1232953 : rte_pktmbuf_free(deq_ops[i]->m_src);
590 : 1232953 : rte_pktmbuf_free(deq_ops[i]->m_dst);
591 : :
592 : : /* There is no bulk free for com ops so we have to free them one at a time
593 : : * here however it would be rare that we'd ever have more than 1 at a time
594 : : * anyways.
595 : : */
596 : 1232953 : rte_comp_op_free(deq_ops[i]);
597 : :
598 : : /* Check if there are any pending comp ops to process, only pull one
599 : : * at a time off as _compress_operation() may re-queue the op.
600 : : */
601 [ + + ]: 1232953 : if (!STAILQ_EMPTY(&chan->queued_tasks)) {
602 : 1 : task_to_resubmit = STAILQ_FIRST(&chan->queued_tasks);
603 : 1 : rc = _compress_operation(chan, task_to_resubmit);
604 [ + - ]: 1 : if (rc == 0) {
605 [ + - ]: 1 : STAILQ_REMOVE_HEAD(&chan->queued_tasks, link);
606 : : }
607 : : }
608 : : }
609 : :
610 : 7086094 : return num_deq == 0 ? SPDK_POLLER_IDLE : SPDK_POLLER_BUSY;
611 : : }
612 : :
613 : : static int
614 : 1232953 : _process_single_task(struct spdk_io_channel *ch, struct spdk_accel_task *task)
615 : : {
616 : 1232953 : struct compress_io_channel *chan = spdk_io_channel_get_ctx(ch);
617 : : int rc;
618 : :
619 : 1232953 : rc = _compress_operation(chan, task);
620 [ - + ]: 1232953 : if (rc) {
621 : 0 : SPDK_ERRLOG("Error (%d) in comrpess operation\n", rc);
622 : 0 : assert(false);
623 : : }
624 : :
625 : 1232953 : return rc;
626 : : }
627 : :
628 : : static int
629 : 1232953 : compress_submit_tasks(struct spdk_io_channel *ch, struct spdk_accel_task *first_task)
630 : : {
631 : 1232953 : struct compress_io_channel *chan = spdk_io_channel_get_ctx(ch);
632 : : struct spdk_accel_task *task, *tmp;
633 : 1232953 : int rc = 0;
634 : :
635 : 1232953 : task = first_task;
636 : :
637 [ - + ]: 1232953 : if (!STAILQ_EMPTY(&chan->queued_tasks)) {
638 : 0 : goto queue_tasks;
639 : : }
640 : :
641 : : /* The caller will either submit a single task or a group of tasks that are
642 : : * linked together but they cannot be on a list. For example, see poller
643 : : * where a list of queued tasks is being resubmitted, the list they are on
644 : : * is initialized after saving off the first task from the list which is then
645 : : * passed in here. Similar thing is done in the accel framework.
646 : : */
647 [ + + ]: 2465906 : while (task) {
648 : 1232953 : tmp = STAILQ_NEXT(task, link);
649 : 1232953 : rc = _process_single_task(ch, task);
650 : :
651 [ - + ]: 1232953 : if (rc == -EBUSY) {
652 : 0 : goto queue_tasks;
653 [ - + ]: 1232953 : } else if (rc) {
654 : 0 : spdk_accel_task_complete(task, rc);
655 : : }
656 : 1232953 : task = tmp;
657 : : }
658 : :
659 : 1232953 : return 0;
660 : :
661 : 0 : queue_tasks:
662 [ # # ]: 0 : while (task != NULL) {
663 : 0 : tmp = STAILQ_NEXT(task, link);
664 : 0 : STAILQ_INSERT_TAIL(&chan->queued_tasks, task, link);
665 : 0 : task = tmp;
666 : : }
667 : 0 : return 0;
668 : : }
669 : :
670 : : static bool
671 : 37 : _set_pmd(struct compress_io_channel *chan)
672 : : {
673 : :
674 : : /* Note: the compress_isal PMD is not supported as accel_fw supports native ISAL
675 : : * using the accel_sw module */
676 [ + + ]: 37 : if (g_opts == COMPRESS_PMD_AUTO) {
677 [ - + + - ]: 22 : if (g_qat_available) {
678 : 22 : chan->drv_name = QAT_PMD;
679 [ # # # # ]: 0 : } else if (g_mlx5_pci_available) {
680 : 0 : chan->drv_name = MLX5_PMD;
681 : : }
682 [ + - - + : 15 : } else if (g_opts == COMPRESS_PMD_QAT_ONLY && g_qat_available) {
+ - ]
683 : 15 : chan->drv_name = QAT_PMD;
684 [ # # # # : 0 : } else if (g_opts == COMPRESS_PMD_MLX5_PCI_ONLY && g_mlx5_pci_available) {
# # ]
685 : 0 : chan->drv_name = MLX5_PMD;
686 : : } else {
687 : 0 : SPDK_ERRLOG("Requested PMD is not available.\n");
688 : 0 : return false;
689 : : }
690 : 37 : SPDK_NOTICELOG("Channel %p PMD being used: %s\n", chan, chan->drv_name);
691 : 37 : return true;
692 : : }
693 : :
694 : : static int compress_create_cb(void *io_device, void *ctx_buf);
695 : : static void compress_destroy_cb(void *io_device, void *ctx_buf);
696 : : static struct spdk_accel_module_if g_compress_module;
697 : : static int
698 : 12 : accel_compress_init(void)
699 : : {
700 : : int rc;
701 : :
702 [ - + - + ]: 12 : if (!g_compressdev_enable) {
703 : 0 : return -EINVAL;
704 : : }
705 : :
706 : 12 : rc = accel_init_compress_drivers();
707 [ - + ]: 12 : if (rc) {
708 [ # # ]: 0 : assert(TAILQ_EMPTY(&g_compress_devs));
709 : 0 : return rc;
710 : : }
711 : :
712 : 12 : g_compressdev_initialized = true;
713 : 12 : spdk_io_device_register(&g_compress_module, compress_create_cb, compress_destroy_cb,
714 : : sizeof(struct compress_io_channel), "compressdev_accel_module");
715 : 12 : return 0;
716 : : }
717 : :
718 : : static int
719 : 37 : compress_create_cb(void *io_device, void *ctx_buf)
720 : : {
721 : 37 : struct compress_io_channel *chan = ctx_buf;
722 : : const struct rte_compressdev_capabilities *capab;
723 : : struct comp_device_qp *device_qp;
724 : : size_t length;
725 : :
726 [ - + ]: 37 : if (_set_pmd(chan) == false) {
727 : 0 : assert(false);
728 : : return -ENODEV;
729 : : }
730 : :
731 : : /* The following variable length arrays of mbuf pointers are required to submit to compressdev */
732 : 37 : length = NUM_MBUFS * sizeof(void *);
733 : 37 : chan->src_mbufs = spdk_zmalloc(length, 0x40, NULL,
734 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
735 [ - + ]: 37 : if (chan->src_mbufs == NULL) {
736 : 0 : return -ENOMEM;
737 : : }
738 : 37 : chan->dst_mbufs = spdk_zmalloc(length, 0x40, NULL,
739 : : SPDK_ENV_LCORE_ID_ANY, SPDK_MALLOC_DMA);
740 [ - + ]: 37 : if (chan->dst_mbufs == NULL) {
741 : 0 : free(chan->src_mbufs);
742 : 0 : return -ENOMEM;
743 : : }
744 : :
745 : 37 : chan->poller = SPDK_POLLER_REGISTER(comp_dev_poller, chan, 0);
746 : 37 : STAILQ_INIT(&chan->queued_tasks);
747 : :
748 : 37 : pthread_mutex_lock(&g_comp_device_qp_lock);
749 [ + - ]: 76 : TAILQ_FOREACH(device_qp, &g_comp_device_qp, link) {
750 [ - + - + : 76 : if (strcmp(device_qp->device->cdev_info.driver_name, chan->drv_name) == 0) {
+ - ]
751 [ + + ]: 76 : if (device_qp->chan == NULL) {
752 : 37 : chan->device_qp = device_qp;
753 : 37 : device_qp->chan = chan;
754 : 37 : break;
755 : : }
756 : : }
757 : : }
758 : 37 : pthread_mutex_unlock(&g_comp_device_qp_lock);
759 : :
760 [ - + ]: 37 : if (chan->device_qp == NULL) {
761 : 0 : SPDK_ERRLOG("out of qpairs, cannot assign one\n");
762 : 0 : assert(false);
763 : : return -ENOMEM;
764 : : } else {
765 : 37 : capab = rte_compressdev_capability_get(0, RTE_COMP_ALGO_DEFLATE);
766 : :
767 [ + - ]: 37 : if (capab->comp_feature_flags & (RTE_COMP_FF_OOP_SGL_IN_SGL_OUT | RTE_COMP_FF_OOP_SGL_IN_LB_OUT)) {
768 : 37 : chan->device_qp->device->sgl_in = true;
769 : : }
770 : :
771 [ + - ]: 37 : if (capab->comp_feature_flags & (RTE_COMP_FF_OOP_SGL_IN_SGL_OUT | RTE_COMP_FF_OOP_LB_IN_SGL_OUT)) {
772 : 37 : chan->device_qp->device->sgl_out = true;
773 : : }
774 : : }
775 : :
776 : 37 : return 0;
777 : : }
778 : :
779 : : static void
780 : 1 : accel_compress_write_config_json(struct spdk_json_write_ctx *w)
781 : : {
782 [ - + + - ]: 1 : if (g_compressdev_enable) {
783 : 1 : spdk_json_write_object_begin(w);
784 : 1 : spdk_json_write_named_string(w, "method", "compressdev_scan_accel_module");
785 : 1 : spdk_json_write_named_object_begin(w, "params");
786 : 1 : spdk_json_write_named_uint32(w, "pmd", g_opts);
787 : 1 : spdk_json_write_object_end(w);
788 : 1 : spdk_json_write_object_end(w);
789 : : }
790 : 1 : }
791 : :
792 : : static void
793 : 37 : compress_destroy_cb(void *io_device, void *ctx_buf)
794 : : {
795 : 37 : struct compress_io_channel *chan = ctx_buf;
796 : 37 : struct comp_device_qp *device_qp = chan->device_qp;
797 : :
798 : 37 : spdk_free(chan->src_mbufs);
799 : 37 : spdk_free(chan->dst_mbufs);
800 : :
801 : 37 : spdk_poller_unregister(&chan->poller);
802 : :
803 [ - + ]: 37 : pthread_mutex_lock(&g_comp_device_qp_lock);
804 : 37 : chan->device_qp = NULL;
805 : 37 : device_qp->chan = NULL;
806 [ - + ]: 37 : pthread_mutex_unlock(&g_comp_device_qp_lock);
807 : 37 : }
808 : :
809 : : static size_t
810 : 12 : accel_compress_get_ctx_size(void)
811 : : {
812 : 12 : return 0;
813 : : }
814 : :
815 : : static bool
816 : 180 : compress_supports_opcode(enum spdk_accel_opcode opc)
817 : : {
818 [ - + + - : 180 : if (g_mlx5_pci_available || g_qat_available) {
- + + - ]
819 [ + + ]: 180 : switch (opc) {
820 : 24 : case SPDK_ACCEL_OPC_COMPRESS:
821 : : case SPDK_ACCEL_OPC_DECOMPRESS:
822 : 24 : return true;
823 : 156 : default:
824 : 156 : break;
825 : : }
826 : : }
827 : :
828 : 156 : return false;
829 : : }
830 : :
831 : : static struct spdk_io_channel *
832 : 74 : compress_get_io_channel(void)
833 : : {
834 : 74 : return spdk_get_io_channel(&g_compress_module);
835 : : }
836 : :
837 : : static void accel_compress_exit(void *ctx);
838 : : static struct spdk_accel_module_if g_compress_module = {
839 : : .module_init = accel_compress_init,
840 : : .module_fini = accel_compress_exit,
841 : : .write_config_json = accel_compress_write_config_json,
842 : : .get_ctx_size = accel_compress_get_ctx_size,
843 : : .name = "dpdk_compressdev",
844 : : .supports_opcode = compress_supports_opcode,
845 : : .get_io_channel = compress_get_io_channel,
846 : : .submit_tasks = compress_submit_tasks
847 : : };
848 : :
849 : : void
850 : 12 : accel_dpdk_compressdev_enable(void)
851 : : {
852 : 12 : spdk_accel_module_list_add(&g_compress_module);
853 : 12 : }
854 : :
855 : : /* Callback for unregistering the IO device. */
856 : : static void
857 : 12 : _device_unregister_cb(void *io_device)
858 : : {
859 : : struct comp_device_qp *dev_qp;
860 : : struct compress_dev *device;
861 : :
862 [ + + ]: 588 : while ((device = TAILQ_FIRST(&g_compress_devs))) {
863 [ + + ]: 576 : TAILQ_REMOVE(&g_compress_devs, device, link);
864 : 576 : free(device);
865 : : }
866 : :
867 [ + + ]: 1164 : while ((dev_qp = TAILQ_FIRST(&g_comp_device_qp))) {
868 [ + + ]: 1152 : TAILQ_REMOVE(&g_comp_device_qp, dev_qp, link);
869 : 1152 : free(dev_qp);
870 : : }
871 : :
872 [ - + ]: 12 : pthread_mutex_destroy(&g_comp_device_qp_lock);
873 : :
874 : 12 : rte_mempool_free(g_comp_op_mp);
875 : 12 : rte_mempool_free(g_mbuf_mp);
876 : :
877 : 12 : spdk_accel_module_finish();
878 : 12 : }
879 : :
880 : : static void
881 : 12 : accel_compress_exit(void *ctx)
882 : : {
883 [ - + + - ]: 12 : if (g_compressdev_initialized) {
884 : 12 : spdk_io_device_unregister(&g_compress_module, _device_unregister_cb);
885 : 12 : g_compressdev_initialized = false;
886 : : } else {
887 : 0 : spdk_accel_module_finish();
888 : : }
889 : 12 : }
|