8879a42d80df8444139825e86d4e1f5da7c23e9e
[dpdk.git] / drivers / compress / isal / isal_compress_pmd.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2018 Intel Corporation
3  */
4 #include <isa-l.h>
5
6 #include <rte_bus_vdev.h>
7 #include <rte_common.h>
8 #include <rte_malloc.h>
9 #include <rte_mbuf.h>
10 #include <rte_compressdev_pmd.h>
11
12 #include "isal_compress_pmd_private.h"
13
14 #define RTE_COMP_ISAL_WINDOW_SIZE 15
15 #define RTE_COMP_ISAL_LEVEL_ZERO 0 /* ISA-L Level 0 used for fixed Huffman */
16 #define RTE_COMP_ISAL_LEVEL_ONE 1
17 #define RTE_COMP_ISAL_LEVEL_TWO 2
18 #define RTE_COMP_ISAL_LEVEL_THREE 3 /* Optimised for AVX512 & AVX2 only */
19 #define CHKSUM_SZ_CRC 8
20 #define CHKSUM_SZ_ADLER 4
21
22 #define STRINGIFY(s) #s
23 #define ISAL_TOSTRING(maj, min, patch) \
24         STRINGIFY(maj)"."STRINGIFY(min)"."STRINGIFY(patch)
25 #define ISAL_VERSION_STRING \
26         ISAL_TOSTRING(ISAL_MAJOR_VERSION, ISAL_MINOR_VERSION, ISAL_PATCH_VERSION)
27
28 int isal_logtype_driver;
29
30 /* Verify and set private xform parameters */
31 int
32 isal_comp_set_priv_xform_parameters(struct isal_priv_xform *priv_xform,
33                 const struct rte_comp_xform *xform)
34 {
35         if (xform == NULL)
36                 return -EINVAL;
37
38         /* Set compression private xform variables */
39         if (xform->type == RTE_COMP_COMPRESS) {
40                 /* Set private xform type - COMPRESS/DECOMPRESS */
41                 priv_xform->type = RTE_COMP_COMPRESS;
42
43                 /* Set private xform algorithm */
44                 if (xform->compress.algo != RTE_COMP_ALGO_DEFLATE) {
45                         if (xform->compress.algo == RTE_COMP_ALGO_NULL) {
46                                 ISAL_PMD_LOG(ERR, "By-pass not supported\n");
47                                 return -ENOTSUP;
48                         }
49                         ISAL_PMD_LOG(ERR, "Algorithm not supported\n");
50                         return -ENOTSUP;
51                 }
52                 priv_xform->compress.algo = RTE_COMP_ALGO_DEFLATE;
53
54                 /* Set private xform window size, 32K supported */
55                 if (xform->compress.window_size == RTE_COMP_ISAL_WINDOW_SIZE)
56                         priv_xform->compress.window_size =
57                                         RTE_COMP_ISAL_WINDOW_SIZE;
58                 else {
59                         ISAL_PMD_LOG(ERR, "Window size not supported\n");
60                         return -ENOTSUP;
61                 }
62
63                 /* Set private xform huffman type */
64                 switch (xform->compress.deflate.huffman) {
65                 case(RTE_COMP_HUFFMAN_DEFAULT):
66                         priv_xform->compress.deflate.huffman =
67                                         RTE_COMP_HUFFMAN_DEFAULT;
68                         break;
69                 case(RTE_COMP_HUFFMAN_FIXED):
70                         priv_xform->compress.deflate.huffman =
71                                         RTE_COMP_HUFFMAN_FIXED;
72                         break;
73                 case(RTE_COMP_HUFFMAN_DYNAMIC):
74                         priv_xform->compress.deflate.huffman =
75                                         RTE_COMP_HUFFMAN_DYNAMIC;
76                         break;
77                 default:
78                         ISAL_PMD_LOG(ERR, "Huffman code not supported\n");
79                         return -ENOTSUP;
80                 }
81
82                 /* Set private xform checksum */
83                 switch (xform->compress.chksum) {
84                 /* Raw deflate by default */
85                 case(RTE_COMP_CHECKSUM_NONE):
86                         priv_xform->compress.chksum = IGZIP_DEFLATE;
87                         break;
88                 case(RTE_COMP_CHECKSUM_CRC32):
89                         priv_xform->compress.chksum = IGZIP_GZIP_NO_HDR;
90                         break;
91                 case(RTE_COMP_CHECKSUM_ADLER32):
92                         priv_xform->compress.chksum = IGZIP_ZLIB_NO_HDR;
93                         break;
94                 case(RTE_COMP_CHECKSUM_CRC32_ADLER32):
95                         ISAL_PMD_LOG(ERR, "Combined CRC and ADLER checksum not"
96                                         " supported\n");
97                         return -ENOTSUP;
98                 default:
99                         ISAL_PMD_LOG(ERR, "Checksum type not supported\n");
100                         priv_xform->compress.chksum = IGZIP_DEFLATE;
101                         break;
102                 }
103
104                 /* Set private xform level.
105                  * Checking compliance with compressdev API, -1 <= level => 9
106                  */
107                 if (xform->compress.level < RTE_COMP_LEVEL_PMD_DEFAULT ||
108                                 xform->compress.level > RTE_COMP_LEVEL_MAX) {
109                         ISAL_PMD_LOG(ERR, "Compression level out of range\n");
110                         return -EINVAL;
111                 }
112                 /* Check for Compressdev API level 0, No compression
113                  * not supported in ISA-L
114                  */
115                 else if (xform->compress.level == RTE_COMP_LEVEL_NONE) {
116                         ISAL_PMD_LOG(ERR, "No Compression not supported\n");
117                         return -ENOTSUP;
118                 }
119                 /* If using fixed huffman code, level must be 0 */
120                 else if (priv_xform->compress.deflate.huffman ==
121                                 RTE_COMP_HUFFMAN_FIXED) {
122                         ISAL_PMD_LOG(DEBUG, "ISA-L level 0 used due to a"
123                                         " fixed huffman code\n");
124                         priv_xform->compress.level = RTE_COMP_ISAL_LEVEL_ZERO;
125                         priv_xform->level_buffer_size =
126                                         ISAL_DEF_LVL0_DEFAULT;
127                 } else {
128                         /* Mapping API levels to ISA-L levels 1,2 & 3 */
129                         switch (xform->compress.level) {
130                         case RTE_COMP_LEVEL_PMD_DEFAULT:
131                                 /* Default is 1 if not using fixed huffman */
132                                 priv_xform->compress.level =
133                                                 RTE_COMP_ISAL_LEVEL_ONE;
134                                 priv_xform->level_buffer_size =
135                                                 ISAL_DEF_LVL1_DEFAULT;
136                                 break;
137                         case RTE_COMP_LEVEL_MIN:
138                                 priv_xform->compress.level =
139                                                 RTE_COMP_ISAL_LEVEL_ONE;
140                                 priv_xform->level_buffer_size =
141                                                 ISAL_DEF_LVL1_DEFAULT;
142                                 break;
143                         case RTE_COMP_ISAL_LEVEL_TWO:
144                                 priv_xform->compress.level =
145                                                 RTE_COMP_ISAL_LEVEL_TWO;
146                                 priv_xform->level_buffer_size =
147                                                 ISAL_DEF_LVL2_DEFAULT;
148                                 break;
149                         /* Level 3 or higher requested */
150                         default:
151                                 /* Check for AVX512, to use ISA-L level 3 */
152                                 if (rte_cpu_get_flag_enabled(
153                                                 RTE_CPUFLAG_AVX512F)) {
154                                         priv_xform->compress.level =
155                                                 RTE_COMP_ISAL_LEVEL_THREE;
156                                         priv_xform->level_buffer_size =
157                                                 ISAL_DEF_LVL3_DEFAULT;
158                                 }
159                                 /* Check for AVX2, to use ISA-L level 3 */
160                                 else if (rte_cpu_get_flag_enabled(
161                                                 RTE_CPUFLAG_AVX2)) {
162                                         priv_xform->compress.level =
163                                                 RTE_COMP_ISAL_LEVEL_THREE;
164                                         priv_xform->level_buffer_size =
165                                                 ISAL_DEF_LVL3_DEFAULT;
166                                 } else {
167                                         ISAL_PMD_LOG(DEBUG, "Requested ISA-L level"
168                                                 " 3 or above; Level 3 optimized"
169                                                 " for AVX512 & AVX2 only."
170                                                 " level changed to 2.\n");
171                                         priv_xform->compress.level =
172                                                 RTE_COMP_ISAL_LEVEL_TWO;
173                                         priv_xform->level_buffer_size =
174                                                 ISAL_DEF_LVL2_DEFAULT;
175                                 }
176                         }
177                 }
178         }
179
180         /* Set decompression private xform variables */
181         else if (xform->type == RTE_COMP_DECOMPRESS) {
182
183                 /* Set private xform type - COMPRESS/DECOMPRESS */
184                 priv_xform->type = RTE_COMP_DECOMPRESS;
185
186                 /* Set private xform algorithm */
187                 if (xform->decompress.algo != RTE_COMP_ALGO_DEFLATE) {
188                         if (xform->decompress.algo == RTE_COMP_ALGO_NULL) {
189                                 ISAL_PMD_LOG(ERR, "By pass not supported\n");
190                                 return -ENOTSUP;
191                         }
192                         ISAL_PMD_LOG(ERR, "Algorithm not supported\n");
193                         return -ENOTSUP;
194                 }
195                 priv_xform->decompress.algo = RTE_COMP_ALGO_DEFLATE;
196
197                 /* Set private xform checksum */
198                 switch (xform->decompress.chksum) {
199                 /* Raw deflate by default */
200                 case(RTE_COMP_CHECKSUM_NONE):
201                         priv_xform->decompress.chksum = ISAL_DEFLATE;
202                         break;
203                 case(RTE_COMP_CHECKSUM_CRC32):
204                         priv_xform->decompress.chksum = ISAL_GZIP_NO_HDR;
205                         break;
206                 case(RTE_COMP_CHECKSUM_ADLER32):
207                         priv_xform->decompress.chksum = ISAL_ZLIB_NO_HDR;
208                         break;
209                 case(RTE_COMP_CHECKSUM_CRC32_ADLER32):
210                         ISAL_PMD_LOG(ERR, "Combined CRC and ADLER checksum not"
211                                         " supported\n");
212                         return -ENOTSUP;
213                 default:
214                         ISAL_PMD_LOG(ERR, "Checksum type not supported\n");
215                         priv_xform->decompress.chksum = ISAL_DEFLATE;
216                         break;
217                 }
218
219                 /* Set private xform window size, 32K supported */
220                 if (xform->decompress.window_size == RTE_COMP_ISAL_WINDOW_SIZE)
221                         priv_xform->decompress.window_size =
222                                         RTE_COMP_ISAL_WINDOW_SIZE;
223                 else {
224                         ISAL_PMD_LOG(ERR, "Window size not supported\n");
225                         return -ENOTSUP;
226                 }
227         }
228         return 0;
229 }
230
231 /* Compression using chained mbufs for input/output data */
232 static int
233 chained_mbuf_compression(struct rte_comp_op *op, struct isal_comp_qp *qp)
234 {
235         int ret;
236         uint32_t remaining_offset;
237         uint32_t remaining_data = op->src.length;
238         struct rte_mbuf *src = op->m_src;
239         struct rte_mbuf *dst = op->m_dst;
240
241         /* check for source/destination offset passing multiple segments
242          * and point compression stream to input/output buffer.
243          */
244         remaining_offset = op->src.offset;
245         while (remaining_offset >= src->data_len) {
246                 remaining_offset -= src->data_len;
247                 src = src->next;
248         }
249         qp->stream->avail_in = RTE_MIN(src->data_len - remaining_offset,
250                         op->src.length);
251         qp->stream->next_in = rte_pktmbuf_mtod_offset(src, uint8_t *,
252                         remaining_offset);
253
254         remaining_offset = op->dst.offset;
255         while (remaining_offset >= dst->data_len) {
256                 remaining_offset -= dst->data_len;
257                 dst = dst->next;
258         }
259         qp->stream->avail_out = dst->data_len - remaining_offset;
260         qp->stream->next_out = rte_pktmbuf_mtod_offset(dst, uint8_t *,
261                         remaining_offset);
262
263         if (unlikely(!qp->stream->next_in || !qp->stream->next_out)) {
264                 ISAL_PMD_LOG(ERR, "Invalid source or destination buffer\n");
265                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
266                 return -1;
267         }
268
269         while (qp->stream->internal_state.state != ZSTATE_END) {
270                 /* Last segment of data */
271                 if (remaining_data <= src->data_len)
272                         qp->stream->end_of_stream = 1;
273
274                 /* Execute compression operation */
275                 ret = isal_deflate(qp->stream);
276
277                 remaining_data = op->src.length - qp->stream->total_in;
278
279                 if (ret != COMP_OK) {
280                         ISAL_PMD_LOG(ERR, "Compression operation failed\n");
281                         op->status = RTE_COMP_OP_STATUS_ERROR;
282                         return ret;
283                 }
284
285                 if (qp->stream->avail_in == 0 &&
286                                 qp->stream->total_in != op->src.length) {
287                         if (src->next != NULL) {
288                                 src = src->next;
289                                 qp->stream->next_in =
290                                                 rte_pktmbuf_mtod(src, uint8_t *);
291                                 qp->stream->avail_in =
292                                         RTE_MIN(remaining_data, src->data_len);
293                         } else {
294                                 ISAL_PMD_LOG(ERR,
295                                 "Not enough input buffer segments\n");
296                                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
297                                 return -1;
298                         }
299                 }
300
301                 if (qp->stream->avail_out == 0 &&
302                                 qp->stream->internal_state.state != ZSTATE_END) {
303                         if (dst->next != NULL) {
304                                 dst = dst->next;
305                                 qp->stream->next_out =
306                                                 rte_pktmbuf_mtod(dst, uint8_t *);
307                                 qp->stream->avail_out = dst->data_len;
308                         } else {
309                                 ISAL_PMD_LOG(ERR,
310                                 "Not enough output buffer segments\n");
311                                 op->status =
312                                 RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
313                                 return -1;
314                         }
315                 }
316         }
317
318         return 0;
319 }
320
321 /* Decompression using chained mbufs for input/output data */
322 static int
323 chained_mbuf_decompression(struct rte_comp_op *op, struct isal_comp_qp *qp)
324 {
325         int ret;
326         uint32_t consumed_data, src_remaining_offset, dst_remaining_offset;
327         uint32_t remaining_data = op->src.length;
328         struct rte_mbuf *src = op->m_src;
329         struct rte_mbuf *dst = op->m_dst;
330
331         /* check for offset passing multiple segments
332          * and point decompression state to input/output buffer
333          */
334         src_remaining_offset = op->src.offset;
335         while (src_remaining_offset >= src->data_len) {
336                 src_remaining_offset -= src->data_len;
337                 src = src->next;
338         }
339         qp->state->avail_in = RTE_MIN(src->data_len - src_remaining_offset,
340                         op->src.length);
341         qp->state->next_in = rte_pktmbuf_mtod_offset(src, uint8_t *,
342                         src_remaining_offset);
343
344         dst_remaining_offset = op->dst.offset;
345         while (dst_remaining_offset >= dst->data_len) {
346                 dst_remaining_offset -= dst->data_len;
347                 dst = dst->next;
348         }
349         qp->state->avail_out = dst->data_len - dst_remaining_offset;
350         qp->state->next_out = rte_pktmbuf_mtod_offset(dst, uint8_t *,
351                         dst_remaining_offset);
352
353         while (qp->state->block_state != ISAL_BLOCK_FINISH) {
354
355                 ret = isal_inflate(qp->state);
356
357                 if (ret != ISAL_DECOMP_OK) {
358                         ISAL_PMD_LOG(ERR, "Decompression operation failed\n");
359                         op->status = RTE_COMP_OP_STATUS_ERROR;
360                         return ret;
361                 }
362
363                 /* Check for first segment, offset needs to be accounted for */
364                 if (remaining_data == op->src.length) {
365                         consumed_data = src->data_len - src_remaining_offset;
366                 } else
367                         consumed_data = src->data_len;
368
369                 if (qp->state->avail_in == 0
370                                 && op->consumed != op->src.length) {
371                         op->consumed += consumed_data;
372                         remaining_data -= consumed_data;
373
374                         if (src->next != NULL) {
375                                 src = src->next;
376                                 qp->state->next_in =
377                                                 rte_pktmbuf_mtod(src, uint8_t *);
378                                 qp->state->avail_in =
379                                         RTE_MIN(remaining_data, src->data_len);
380                         }
381                 }
382
383                 if (qp->state->avail_out == 0 &&
384                                 qp->state->block_state != ISAL_BLOCK_FINISH) {
385                         if (dst->next != NULL) {
386                                 dst = dst->next;
387                                 qp->state->next_out =
388                                                 rte_pktmbuf_mtod(dst, uint8_t *);
389                                 qp->state->avail_out = dst->data_len;
390                         } else {
391                                 ISAL_PMD_LOG(ERR,
392                                 "Not enough output buffer segments\n");
393                                 op->status =
394                                 RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
395                                 return -1;
396                         }
397                 }
398         }
399
400         return 0;
401 }
402
403 /* Stateless Compression Function */
404 static int
405 process_isal_deflate(struct rte_comp_op *op, struct isal_comp_qp *qp,
406                 struct isal_priv_xform *priv_xform)
407 {
408         int ret = 0;
409         op->status = RTE_COMP_OP_STATUS_SUCCESS;
410
411         /* Required due to init clearing level_buf */
412         uint8_t *temp_level_buf = qp->stream->level_buf;
413
414         /* Initialize compression stream */
415         isal_deflate_stateless_init(qp->stream);
416
417         qp->stream->level_buf = temp_level_buf;
418
419         /* Set Checksum flag */
420         qp->stream->gzip_flag = priv_xform->compress.chksum;
421
422         /* Stateless operation, input will be consumed in one go */
423         qp->stream->flush = NO_FLUSH;
424
425         /* set compression level & intermediate level buffer size */
426         qp->stream->level = priv_xform->compress.level;
427         qp->stream->level_buf_size = priv_xform->level_buffer_size;
428
429         /* Set op huffman code */
430         if (priv_xform->compress.deflate.huffman == RTE_COMP_HUFFMAN_FIXED)
431                 isal_deflate_set_hufftables(qp->stream, NULL,
432                                 IGZIP_HUFFTABLE_STATIC);
433         else if (priv_xform->compress.deflate.huffman ==
434                         RTE_COMP_HUFFMAN_DEFAULT)
435                 isal_deflate_set_hufftables(qp->stream, NULL,
436                         IGZIP_HUFFTABLE_DEFAULT);
437         /* Dynamically change the huffman code to suit the input data */
438         else if (priv_xform->compress.deflate.huffman ==
439                         RTE_COMP_HUFFMAN_DYNAMIC)
440                 isal_deflate_set_hufftables(qp->stream, NULL,
441                                 IGZIP_HUFFTABLE_DEFAULT);
442
443         if (op->m_src->pkt_len < (op->src.length + op->src.offset)) {
444                 ISAL_PMD_LOG(ERR, "Input mbuf(s) not big enough.\n");
445                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
446                 return -1;
447         }
448
449         if (op->dst.offset >= op->m_dst->pkt_len) {
450                 ISAL_PMD_LOG(ERR, "Output mbuf(s) not big enough"
451                                 " for offset provided.\n");
452                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
453                 return -1;
454         }
455
456         /* Chained mbufs */
457         if (op->m_src->nb_segs > 1 || op->m_dst->nb_segs > 1) {
458                 ret = chained_mbuf_compression(op, qp);
459                 if (ret < 0)
460                         return ret;
461         } else {
462                 /* Linear buffer */
463                 qp->stream->end_of_stream = 1; /* All input consumed in one */
464                 /* Point compression stream to input buffer */
465                 qp->stream->avail_in = op->src.length;
466                 qp->stream->next_in = rte_pktmbuf_mtod_offset(op->m_src,
467                                 uint8_t *, op->src.offset);
468
469                 /*  Point compression stream to output buffer */
470                 qp->stream->avail_out = op->m_dst->data_len - op->dst.offset;
471                 qp->stream->next_out  = rte_pktmbuf_mtod_offset(op->m_dst,
472                                 uint8_t *, op->dst.offset);
473
474                 if (unlikely(!qp->stream->next_in || !qp->stream->next_out)) {
475                         ISAL_PMD_LOG(ERR, "Invalid source or destination"
476                                         " buffers\n");
477                         op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
478                         return -1;
479                 }
480
481                 /* Execute compression operation */
482                 ret =  isal_deflate_stateless(qp->stream);
483
484                 /* Check that output buffer did not run out of space */
485                 if (ret == STATELESS_OVERFLOW) {
486                         ISAL_PMD_LOG(ERR, "Output buffer not big enough\n");
487                         op->status = RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
488                         return ret;
489                 }
490
491                 /* Check that input buffer has been fully consumed */
492                 if (qp->stream->avail_in != (uint32_t)0) {
493                         ISAL_PMD_LOG(ERR, "Input buffer could not be read"
494                                         " entirely\n");
495                         op->status = RTE_COMP_OP_STATUS_ERROR;
496                         return -1;
497                 }
498
499                 if (ret != COMP_OK) {
500                         ISAL_PMD_LOG(ERR, "Compression operation failed\n");
501                         op->status = RTE_COMP_OP_STATUS_ERROR;
502                         return ret;
503                 }
504         }
505
506         op->consumed = qp->stream->total_in;
507         if (qp->stream->gzip_flag == IGZIP_DEFLATE) {
508                 op->produced = qp->stream->total_out;
509         } else if (qp->stream->gzip_flag == IGZIP_ZLIB_NO_HDR) {
510                 op->produced = qp->stream->total_out - CHKSUM_SZ_ADLER;
511                 op->output_chksum = qp->stream->internal_state.crc + 1;
512         } else {
513                 op->produced = qp->stream->total_out - CHKSUM_SZ_CRC;
514                 op->output_chksum = qp->stream->internal_state.crc;
515         }
516
517         isal_deflate_reset(qp->stream);
518
519         return ret;
520 }
521
522 /* Stateless Decompression Function */
523 static int
524 process_isal_inflate(struct rte_comp_op *op, struct isal_comp_qp *qp,
525                 struct isal_priv_xform *priv_xform)
526 {
527         int ret = 0;
528
529         op->status = RTE_COMP_OP_STATUS_SUCCESS;
530
531         /* Initialize decompression state */
532         isal_inflate_init(qp->state);
533
534         /* Set Checksum flag */
535         qp->state->crc_flag = priv_xform->decompress.chksum;
536
537         if (op->m_src->pkt_len < (op->src.length + op->src.offset)) {
538                 ISAL_PMD_LOG(ERR, "Input mbuf(s) not big enough.\n");
539                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
540                 return -1;
541         }
542
543         if (op->dst.offset >= op->m_dst->pkt_len) {
544                 ISAL_PMD_LOG(ERR, "Output mbuf not big enough for "
545                                 "offset provided.\n");
546                 op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
547                 return -1;
548         }
549
550         /* Chained mbufs */
551         if (op->m_src->nb_segs > 1 || op->m_dst->nb_segs > 1) {
552                 ret = chained_mbuf_decompression(op, qp);
553                 if (ret !=  0)
554                         return ret;
555         } else {
556                 /* Linear buffer */
557                 /* Point decompression state to input buffer */
558                 qp->state->avail_in = op->src.length;
559                 qp->state->next_in = rte_pktmbuf_mtod_offset(op->m_src,
560                                 uint8_t *, op->src.offset);
561
562                 /* Point decompression state to output buffer */
563                 qp->state->avail_out = op->m_dst->data_len - op->dst.offset;
564                 qp->state->next_out  = rte_pktmbuf_mtod_offset(op->m_dst,
565                                 uint8_t *, op->dst.offset);
566
567                 if (unlikely(!qp->state->next_in || !qp->state->next_out)) {
568                         ISAL_PMD_LOG(ERR, "Invalid source or destination"
569                                         " buffers\n");
570                         op->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
571                         return -1;
572                 }
573
574                 /* Execute decompression operation */
575                 ret = isal_inflate_stateless(qp->state);
576
577                 if (ret == ISAL_OUT_OVERFLOW) {
578                         ISAL_PMD_LOG(ERR, "Output buffer not big enough\n");
579                         op->status = RTE_COMP_OP_STATUS_OUT_OF_SPACE_TERMINATED;
580                         return ret;
581                 }
582
583                 /* Check that input buffer has been fully consumed */
584                 if (qp->state->avail_in != (uint32_t)0) {
585                         ISAL_PMD_LOG(ERR, "Input buffer could not be read"
586                                         " entirely\n");
587                         op->status = RTE_COMP_OP_STATUS_ERROR;
588                         return -1;
589                 }
590
591                 if (ret != ISAL_DECOMP_OK && ret != ISAL_END_INPUT) {
592                         ISAL_PMD_LOG(ERR, "Decompression operation failed\n");
593                         op->status = RTE_COMP_OP_STATUS_ERROR;
594                         return ret;
595                 }
596                 op->consumed = op->src.length - qp->state->avail_in;
597         }
598         op->produced = qp->state->total_out;
599         op->output_chksum = qp->state->crc;
600
601         isal_inflate_reset(qp->state);
602
603         return ret;
604 }
605
606 /* Process compression/decompression operation */
607 static int
608 process_op(struct isal_comp_qp *qp, struct rte_comp_op *op,
609                 struct isal_priv_xform *priv_xform)
610 {
611         switch (priv_xform->type) {
612         case RTE_COMP_COMPRESS:
613                 process_isal_deflate(op, qp, priv_xform);
614                 break;
615         case RTE_COMP_DECOMPRESS:
616                 process_isal_inflate(op, qp, priv_xform);
617                 break;
618         default:
619                 ISAL_PMD_LOG(ERR, "Operation Not Supported\n");
620                 return -ENOTSUP;
621         }
622         return 0;
623 }
624
625 /* Enqueue burst */
626 static uint16_t
627 isal_comp_pmd_enqueue_burst(void *queue_pair, struct rte_comp_op **ops,
628                         uint16_t nb_ops)
629 {
630         struct isal_comp_qp *qp = queue_pair;
631         uint16_t i;
632         int retval;
633         int16_t num_enq = RTE_MIN(qp->num_free_elements, nb_ops);
634
635         for (i = 0; i < num_enq; i++) {
636                 if (unlikely(ops[i]->op_type != RTE_COMP_OP_STATELESS)) {
637                         ops[i]->status = RTE_COMP_OP_STATUS_INVALID_ARGS;
638                         ISAL_PMD_LOG(ERR, "Stateful operation not Supported\n");
639                         qp->qp_stats.enqueue_err_count++;
640                         continue;
641                 }
642                 retval = process_op(qp, ops[i], ops[i]->private_xform);
643                 if (unlikely(retval < 0) ||
644                                 ops[i]->status != RTE_COMP_OP_STATUS_SUCCESS) {
645                         qp->qp_stats.enqueue_err_count++;
646                 }
647         }
648
649         retval = rte_ring_enqueue_burst(qp->processed_pkts, (void *)ops,
650                         num_enq, NULL);
651         qp->num_free_elements -= retval;
652         qp->qp_stats.enqueued_count += retval;
653
654         return retval;
655 }
656
657 /* Dequeue burst */
658 static uint16_t
659 isal_comp_pmd_dequeue_burst(void *queue_pair, struct rte_comp_op **ops,
660                 uint16_t nb_ops)
661 {
662         struct isal_comp_qp *qp = queue_pair;
663         uint16_t nb_dequeued;
664
665         nb_dequeued = rte_ring_dequeue_burst(qp->processed_pkts, (void **)ops,
666                         nb_ops, NULL);
667         qp->num_free_elements += nb_dequeued;
668         qp->qp_stats.dequeued_count += nb_dequeued;
669
670         return nb_dequeued;
671 }
672
673 /* Create ISA-L compression device */
674 static int
675 compdev_isal_create(const char *name, struct rte_vdev_device *vdev,
676                 struct rte_compressdev_pmd_init_params *init_params)
677 {
678         struct rte_compressdev *dev;
679
680         dev = rte_compressdev_pmd_create(name, &vdev->device,
681                         sizeof(struct isal_comp_private), init_params);
682         if (dev == NULL) {
683                 ISAL_PMD_LOG(ERR, "failed to create compressdev vdev");
684                 return -EFAULT;
685         }
686
687         dev->dev_ops = isal_compress_pmd_ops;
688
689         /* register rx/tx burst functions for data path */
690         dev->dequeue_burst = isal_comp_pmd_dequeue_burst;
691         dev->enqueue_burst = isal_comp_pmd_enqueue_burst;
692
693         ISAL_PMD_LOG(INFO, "\nISA-L library version used: "ISAL_VERSION_STRING);
694
695         return 0;
696 }
697
698 /** Remove compression device */
699 static int
700 compdev_isal_remove_dev(struct rte_vdev_device *vdev)
701 {
702         struct rte_compressdev *compdev;
703         const char *name;
704
705         name = rte_vdev_device_name(vdev);
706         if (name == NULL)
707                 return -EINVAL;
708
709         compdev = rte_compressdev_pmd_get_named_dev(name);
710         if (compdev == NULL)
711                 return -ENODEV;
712
713         return rte_compressdev_pmd_destroy(compdev);
714 }
715
716 /** Initialise ISA-L compression device */
717 static int
718 compdev_isal_probe(struct rte_vdev_device *dev)
719 {
720         struct rte_compressdev_pmd_init_params init_params = {
721                 "",
722                 rte_socket_id(),
723         };
724         const char *name, *args;
725         int retval;
726
727         name = rte_vdev_device_name(dev);
728         if (name == NULL)
729                 return -EINVAL;
730
731         args = rte_vdev_device_args(dev);
732
733         retval = rte_compressdev_pmd_parse_input_args(&init_params, args);
734         if (retval) {
735                 ISAL_PMD_LOG(ERR,
736                         "Failed to parse initialisation arguments[%s]\n", args);
737                 return -EINVAL;
738         }
739
740         return compdev_isal_create(name, dev, &init_params);
741 }
742
743 static struct rte_vdev_driver compdev_isal_pmd_drv = {
744         .probe = compdev_isal_probe,
745         .remove = compdev_isal_remove_dev,
746 };
747
748 RTE_PMD_REGISTER_VDEV(COMPDEV_NAME_ISAL_PMD, compdev_isal_pmd_drv);
749 RTE_PMD_REGISTER_PARAM_STRING(COMPDEV_NAME_ISAL_PMD,
750         "socket_id=<int>");
751
752 RTE_INIT(isal_init_log)
753 {
754         isal_logtype_driver = rte_log_register("pmd.compress.isal");
755         if (isal_logtype_driver >= 0)
756                 rte_log_set_level(isal_logtype_driver, RTE_LOG_INFO);
757 }