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