1
2
3
4
5#include <unistd.h>
6#include <strings.h>
7#include <stdint.h>
8#include <sys/mman.h>
9
10#include <rte_malloc.h>
11#include <rte_log.h>
12#include <rte_errno.h>
13#include <rte_bus_pci.h>
14#include <rte_pci.h>
15#include <rte_regexdev_driver.h>
16#include <rte_mbuf.h>
17
18#include <infiniband/mlx5dv.h>
19#include <mlx5_glue.h>
20#include <mlx5_common.h>
21#include <mlx5_prm.h>
22
23#include "mlx5_regex_utils.h"
24#include "mlx5_rxp.h"
25#include "mlx5_regex.h"
26
27#define MLX5_REGEX_MAX_WQE_INDEX 0xffff
28#define MLX5_REGEX_METADATA_SIZE ((size_t)64)
29#define MLX5_REGEX_MAX_OUTPUT (((size_t)1) << 11)
30#define MLX5_REGEX_WQE_CTRL_OFFSET 12
31#define MLX5_REGEX_WQE_METADATA_OFFSET 16
32#define MLX5_REGEX_WQE_GATHER_OFFSET 32
33#define MLX5_REGEX_WQE_SCATTER_OFFSET 48
34#define MLX5_REGEX_METADATA_OFF 32
35#define MLX5_REGEX_UMR_WQE_SIZE 192
36
37#define MLX5_REGEX_MAX_KLM_NUM 128
38
39#define MLX5_REGEX_KLMS_SIZE \
40 ((MLX5_REGEX_MAX_KLM_NUM) * sizeof(struct mlx5_klm))
41
42#define MLX5_REGEX_UMR_SQ_PI_IDX(pi, ops) \
43 (((pi) + (ops)) & (MLX5_REGEX_MAX_WQE_INDEX >> 2))
44
45static inline uint32_t
46sq_size_get(struct mlx5_regex_sq *sq)
47{
48 return (1U << sq->log_nb_desc);
49}
50
51static inline uint32_t
52cq_size_get(struct mlx5_regex_cq *cq)
53{
54 return (1U << cq->log_nb_desc);
55}
56
57struct mlx5_regex_job {
58 uint64_t user_id;
59 volatile uint8_t *output;
60 volatile uint8_t *metadata;
61 struct mlx5_klm *imkey_array;
62 struct mlx5_devx_obj *imkey;
63} __rte_cached_aligned;
64
65static inline void
66set_data_seg(struct mlx5_wqe_data_seg *seg,
67 uint32_t length, uint32_t lkey,
68 uintptr_t address)
69{
70 seg->byte_count = rte_cpu_to_be_32(length);
71 seg->lkey = rte_cpu_to_be_32(lkey);
72 seg->addr = rte_cpu_to_be_64(address);
73}
74
75static inline void
76set_metadata_seg(struct mlx5_wqe_metadata_seg *seg,
77 uint32_t mmo_control_31_0, uint32_t lkey,
78 uintptr_t address)
79{
80 seg->mmo_control_31_0 = htobe32(mmo_control_31_0);
81 seg->lkey = rte_cpu_to_be_32(lkey);
82 seg->addr = rte_cpu_to_be_64(address);
83}
84
85static inline void
86set_regex_ctrl_seg(void *seg, uint8_t le, uint16_t subset_id0,
87 uint16_t subset_id1, uint16_t subset_id2,
88 uint16_t subset_id3, uint8_t ctrl)
89{
90 MLX5_SET(regexp_mmo_control, seg, le, le);
91 MLX5_SET(regexp_mmo_control, seg, ctrl, ctrl);
92 MLX5_SET(regexp_mmo_control, seg, subset_id_0, subset_id0);
93 MLX5_SET(regexp_mmo_control, seg, subset_id_1, subset_id1);
94 MLX5_SET(regexp_mmo_control, seg, subset_id_2, subset_id2);
95 MLX5_SET(regexp_mmo_control, seg, subset_id_3, subset_id3);
96}
97
98static inline void
99set_wqe_ctrl_seg(struct mlx5_wqe_ctrl_seg *seg, uint16_t pi, uint8_t opcode,
100 uint8_t opmod, uint32_t qp_num, uint8_t fm_ce_se, uint8_t ds,
101 uint8_t signature, uint32_t imm)
102{
103 seg->opmod_idx_opcode = rte_cpu_to_be_32(((uint32_t)opmod << 24) |
104 ((uint32_t)pi << 8) |
105 opcode);
106 seg->qpn_ds = rte_cpu_to_be_32((qp_num << 8) | ds);
107 seg->fm_ce_se = fm_ce_se;
108 seg->signature = signature;
109 seg->imm = imm;
110}
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125static inline uint32_t
126mlx5_regex_addr2mr(struct mlx5_regex_priv *priv, struct mlx5_mr_ctrl *mr_ctrl,
127 struct rte_mbuf *mbuf)
128{
129 uintptr_t addr = rte_pktmbuf_mtod(mbuf, uintptr_t);
130 uint32_t lkey;
131
132
133 if (unlikely(*mr_ctrl->dev_gen_ptr != mr_ctrl->cur_gen))
134 mlx5_mr_flush_local_cache(mr_ctrl);
135
136 lkey = mlx5_mr_lookup_lkey(mr_ctrl->cache, &mr_ctrl->mru,
137 MLX5_MR_CACHE_N, addr);
138 if (likely(lkey != UINT32_MAX))
139 return lkey;
140
141 return mlx5_mr_addr2mr_bh(priv->pd, 0, &priv->mr_scache, mr_ctrl, addr,
142 !!(mbuf->ol_flags & EXT_ATTACHED_MBUF));
143}
144
145
146static inline void
147__prep_one(struct mlx5_regex_priv *priv, struct mlx5_regex_sq *sq,
148 struct rte_regex_ops *op, struct mlx5_regex_job *job,
149 size_t pi, struct mlx5_klm *klm)
150{
151 size_t wqe_offset = (pi & (sq_size_get(sq) - 1)) *
152 (MLX5_SEND_WQE_BB << (priv->has_umr ? 2 : 0)) +
153 (priv->has_umr ? MLX5_REGEX_UMR_WQE_SIZE : 0);
154 uint16_t group0 = op->req_flags & RTE_REGEX_OPS_REQ_GROUP_ID0_VALID_F ?
155 op->group_id0 : 0;
156 uint16_t group1 = op->req_flags & RTE_REGEX_OPS_REQ_GROUP_ID1_VALID_F ?
157 op->group_id1 : 0;
158 uint16_t group2 = op->req_flags & RTE_REGEX_OPS_REQ_GROUP_ID2_VALID_F ?
159 op->group_id2 : 0;
160 uint16_t group3 = op->req_flags & RTE_REGEX_OPS_REQ_GROUP_ID3_VALID_F ?
161 op->group_id3 : 0;
162 uint8_t control = op->req_flags &
163 RTE_REGEX_OPS_REQ_MATCH_HIGH_PRIORITY_F ? 1 : 0;
164
165
166 if (!(op->req_flags & (RTE_REGEX_OPS_REQ_GROUP_ID0_VALID_F |
167 RTE_REGEX_OPS_REQ_GROUP_ID1_VALID_F |
168 RTE_REGEX_OPS_REQ_GROUP_ID2_VALID_F |
169 RTE_REGEX_OPS_REQ_GROUP_ID3_VALID_F)))
170 group0 = op->group_id0;
171 uint8_t *wqe = (uint8_t *)(uintptr_t)sq->sq_obj.wqes + wqe_offset;
172 int ds = 4;
173
174 set_wqe_ctrl_seg((struct mlx5_wqe_ctrl_seg *)wqe,
175 (priv->has_umr ? (pi * 4 + 3) : pi),
176 MLX5_OPCODE_MMO, MLX5_OPC_MOD_MMO_REGEX,
177 sq->sq_obj.sq->id, 0, ds, 0, 0);
178 set_regex_ctrl_seg(wqe + 12, 0, group0, group1, group2, group3,
179 control);
180 struct mlx5_wqe_data_seg *input_seg =
181 (struct mlx5_wqe_data_seg *)(wqe +
182 MLX5_REGEX_WQE_GATHER_OFFSET);
183 input_seg->byte_count = rte_cpu_to_be_32(klm->byte_count);
184 input_seg->addr = rte_cpu_to_be_64(klm->address);
185 input_seg->lkey = klm->mkey;
186 job->user_id = op->user_id;
187}
188
189static inline void
190prep_one(struct mlx5_regex_priv *priv, struct mlx5_regex_qp *qp,
191 struct mlx5_regex_sq *sq, struct rte_regex_ops *op,
192 struct mlx5_regex_job *job)
193{
194 struct mlx5_klm klm;
195
196 klm.byte_count = rte_pktmbuf_data_len(op->mbuf);
197 klm.mkey = mlx5_regex_addr2mr(priv, &qp->mr_ctrl, op->mbuf);
198 klm.address = rte_pktmbuf_mtod(op->mbuf, uintptr_t);
199 __prep_one(priv, sq, op, job, sq->pi, &klm);
200 sq->db_pi = sq->pi;
201 sq->pi = (sq->pi + 1) & MLX5_REGEX_MAX_WQE_INDEX;
202}
203
204static inline void
205send_doorbell(struct mlx5_regex_priv *priv, struct mlx5_regex_sq *sq)
206{
207 struct mlx5dv_devx_uar *uar = priv->uar;
208 size_t wqe_offset = (sq->db_pi & (sq_size_get(sq) - 1)) *
209 (MLX5_SEND_WQE_BB << (priv->has_umr ? 2 : 0)) +
210 (priv->has_umr ? MLX5_REGEX_UMR_WQE_SIZE : 0);
211 uint8_t *wqe = (uint8_t *)(uintptr_t)sq->sq_obj.wqes + wqe_offset;
212
213 ((struct mlx5_wqe_ctrl_seg *)wqe)->fm_ce_se |= MLX5_WQE_CTRL_CQ_UPDATE;
214 uint64_t *doorbell_addr =
215 (uint64_t *)((uint8_t *)uar->base_addr + 0x800);
216 rte_io_wmb();
217 sq->sq_obj.db_rec[MLX5_SND_DBR] = rte_cpu_to_be_32((priv->has_umr ?
218 (sq->db_pi * 4 + 3) : sq->db_pi) &
219 MLX5_REGEX_MAX_WQE_INDEX);
220 rte_wmb();
221 *doorbell_addr = *(volatile uint64_t *)wqe;
222 rte_wmb();
223}
224
225static inline int
226get_free(struct mlx5_regex_sq *sq, uint8_t has_umr) {
227 return (sq_size_get(sq) - ((sq->pi - sq->ci) &
228 (has_umr ? (MLX5_REGEX_MAX_WQE_INDEX >> 2) :
229 MLX5_REGEX_MAX_WQE_INDEX)));
230}
231
232static inline uint32_t
233job_id_get(uint32_t qid, size_t sq_size, size_t index) {
234 return qid * sq_size + (index & (sq_size - 1));
235}
236
237#ifdef HAVE_MLX5_UMR_IMKEY
238static inline int
239mkey_klm_available(struct mlx5_klm *klm, uint32_t pos, uint32_t new)
240{
241 return (klm && ((pos + new) <= MLX5_REGEX_MAX_KLM_NUM));
242}
243
244static inline void
245complete_umr_wqe(struct mlx5_regex_qp *qp, struct mlx5_regex_sq *sq,
246 struct mlx5_regex_job *mkey_job,
247 size_t umr_index, uint32_t klm_size, uint32_t total_len)
248{
249 size_t wqe_offset = (umr_index & (sq_size_get(sq) - 1)) *
250 (MLX5_SEND_WQE_BB * 4);
251 struct mlx5_wqe_ctrl_seg *wqe = (struct mlx5_wqe_ctrl_seg *)((uint8_t *)
252 (uintptr_t)sq->sq_obj.wqes + wqe_offset);
253 struct mlx5_wqe_umr_ctrl_seg *ucseg =
254 (struct mlx5_wqe_umr_ctrl_seg *)(wqe + 1);
255 struct mlx5_wqe_mkey_context_seg *mkc =
256 (struct mlx5_wqe_mkey_context_seg *)(ucseg + 1);
257 struct mlx5_klm *iklm = (struct mlx5_klm *)(mkc + 1);
258 uint16_t klm_align = RTE_ALIGN(klm_size, 4);
259
260 memset(wqe, 0, MLX5_REGEX_UMR_WQE_SIZE);
261
262 set_wqe_ctrl_seg(wqe, (umr_index * 4), MLX5_OPCODE_UMR,
263 0, sq->sq_obj.sq->id, 0, 9, 0,
264 rte_cpu_to_be_32(mkey_job->imkey->id));
265
266 ucseg->mkey_mask |= rte_cpu_to_be_64(MLX5_WQE_UMR_CTRL_MKEY_MASK_LEN |
267 MLX5_WQE_UMR_CTRL_FLAG_TRNSLATION_OFFSET |
268 MLX5_WQE_UMR_CTRL_MKEY_MASK_ACCESS_LOCAL_WRITE);
269 ucseg->klm_octowords = rte_cpu_to_be_16(klm_align);
270
271 mkc->len = rte_cpu_to_be_64(total_len);
272 mkc->qpn_mkey = rte_cpu_to_be_32(0xffffff00 |
273 (mkey_job->imkey->id & 0xff));
274
275 iklm->address = rte_cpu_to_be_64
276 ((uintptr_t)((char *)mkey_job->imkey_array));
277 iklm->mkey = rte_cpu_to_be_32(qp->imkey_addr->lkey);
278 iklm->byte_count = rte_cpu_to_be_32(klm_align);
279
280 memset((uint8_t *)&mkey_job->imkey_array[klm_size], 0,
281 sizeof(struct mlx5_klm) * (klm_align - klm_size));
282
283
284 wqe = (struct mlx5_wqe_ctrl_seg *)
285 (((uint8_t *)wqe) + MLX5_REGEX_UMR_WQE_SIZE);
286 wqe->fm_ce_se |= MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE;
287}
288
289static inline void
290prep_nop_regex_wqe_set(struct mlx5_regex_priv *priv, struct mlx5_regex_sq *sq,
291 struct rte_regex_ops *op, struct mlx5_regex_job *job,
292 size_t pi, struct mlx5_klm *klm)
293{
294 size_t wqe_offset = (pi & (sq_size_get(sq) - 1)) *
295 (MLX5_SEND_WQE_BB << 2);
296 struct mlx5_wqe_ctrl_seg *wqe = (struct mlx5_wqe_ctrl_seg *)((uint8_t *)
297 (uintptr_t)sq->sq_obj.wqes + wqe_offset);
298
299
300 if ((rte_be_to_cpu_32(wqe->opmod_idx_opcode) & 0xff) != MLX5_OPCODE_NOP)
301 memset(wqe, 0, MLX5_REGEX_UMR_WQE_SIZE);
302
303 set_wqe_ctrl_seg(wqe, pi * 4, MLX5_OPCODE_NOP, 0, sq->sq_obj.sq->id,
304 0, 12, 0, 0);
305 __prep_one(priv, sq, op, job, pi, klm);
306}
307
308static inline void
309prep_regex_umr_wqe_set(struct mlx5_regex_priv *priv, struct mlx5_regex_qp *qp,
310 struct mlx5_regex_sq *sq, struct rte_regex_ops **op, size_t nb_ops)
311{
312 struct mlx5_regex_job *job = NULL;
313 size_t sqid = sq->sqn, mkey_job_id = 0;
314 size_t left_ops = nb_ops;
315 uint32_t klm_num = 0, len;
316 struct mlx5_klm *mkey_klm = NULL;
317 struct mlx5_klm klm;
318
319 sqid = sq->sqn;
320 while (left_ops--)
321 rte_prefetch0(op[left_ops]);
322 left_ops = nb_ops;
323
324
325
326
327
328
329 while (left_ops--) {
330 struct rte_mbuf *mbuf = op[left_ops]->mbuf;
331 size_t pi = MLX5_REGEX_UMR_SQ_PI_IDX(sq->pi, left_ops);
332
333 if (mbuf->nb_segs > 1) {
334 size_t scatter_size = 0;
335
336 if (!mkey_klm_available(mkey_klm, klm_num,
337 mbuf->nb_segs)) {
338
339
340
341
342 if (mkey_klm)
343 complete_umr_wqe(qp, sq,
344 &qp->jobs[mkey_job_id],
345 MLX5_REGEX_UMR_SQ_PI_IDX(pi, 1),
346 klm_num, len);
347
348
349
350
351 mkey_job_id = job_id_get(sqid,
352 sq_size_get(sq), pi);
353 mkey_klm = qp->jobs[mkey_job_id].imkey_array;
354 klm_num = 0;
355 len = 0;
356 }
357
358 klm.address = len;
359 klm.mkey = rte_cpu_to_be_32
360 (qp->jobs[mkey_job_id].imkey->id);
361 while (mbuf) {
362
363 mkey_klm->mkey = mlx5_regex_addr2mr
364 (priv, &qp->mr_ctrl, mbuf);
365 mkey_klm->address = rte_cpu_to_be_64
366 (rte_pktmbuf_mtod(mbuf, uintptr_t));
367 mkey_klm->byte_count = rte_cpu_to_be_32
368 (rte_pktmbuf_data_len(mbuf));
369
370
371
372
373 scatter_size += rte_pktmbuf_data_len(mbuf);
374 mkey_klm++;
375 klm_num++;
376 mbuf = mbuf->next;
377 }
378 len += scatter_size;
379 klm.byte_count = scatter_size;
380 } else {
381
382 klm.mkey = mlx5_regex_addr2mr(priv, &qp->mr_ctrl, mbuf);
383 klm.address = rte_pktmbuf_mtod(mbuf, uintptr_t);
384 klm.byte_count = rte_pktmbuf_data_len(mbuf);
385 }
386 job = &qp->jobs[job_id_get(sqid, sq_size_get(sq), pi)];
387
388
389
390
391 prep_nop_regex_wqe_set(priv, sq, op[left_ops], job, pi, &klm);
392 }
393
394
395
396
397 if (mkey_klm)
398 complete_umr_wqe(qp, sq, &qp->jobs[mkey_job_id], sq->pi,
399 klm_num, len);
400 sq->db_pi = MLX5_REGEX_UMR_SQ_PI_IDX(sq->pi, nb_ops - 1);
401 sq->pi = MLX5_REGEX_UMR_SQ_PI_IDX(sq->pi, nb_ops);
402}
403
404uint16_t
405mlx5_regexdev_enqueue_gga(struct rte_regexdev *dev, uint16_t qp_id,
406 struct rte_regex_ops **ops, uint16_t nb_ops)
407{
408 struct mlx5_regex_priv *priv = dev->data->dev_private;
409 struct mlx5_regex_qp *queue = &priv->qps[qp_id];
410 struct mlx5_regex_sq *sq;
411 size_t sqid, nb_left = nb_ops, nb_desc;
412
413 while ((sqid = ffs(queue->free_sqs))) {
414 sqid--;
415 sq = &queue->sqs[sqid];
416 nb_desc = get_free(sq, priv->has_umr);
417 if (nb_desc) {
418
419 if (nb_desc > nb_left)
420 nb_desc = nb_left;
421 else
422 queue->free_sqs &= ~(1 << sqid);
423 prep_regex_umr_wqe_set(priv, queue, sq, ops, nb_desc);
424 send_doorbell(priv, sq);
425 nb_left -= nb_desc;
426 }
427 if (!nb_left)
428 break;
429 ops += nb_desc;
430 }
431 nb_ops -= nb_left;
432 queue->pi += nb_ops;
433 return nb_ops;
434}
435#endif
436
437uint16_t
438mlx5_regexdev_enqueue(struct rte_regexdev *dev, uint16_t qp_id,
439 struct rte_regex_ops **ops, uint16_t nb_ops)
440{
441 struct mlx5_regex_priv *priv = dev->data->dev_private;
442 struct mlx5_regex_qp *queue = &priv->qps[qp_id];
443 struct mlx5_regex_sq *sq;
444 size_t sqid, job_id, i = 0;
445
446 while ((sqid = ffs(queue->free_sqs))) {
447 sqid--;
448 sq = &queue->sqs[sqid];
449 while (get_free(sq, priv->has_umr)) {
450 job_id = job_id_get(sqid, sq_size_get(sq), sq->pi);
451 prep_one(priv, queue, sq, ops[i], &queue->jobs[job_id]);
452 i++;
453 if (unlikely(i == nb_ops)) {
454 send_doorbell(priv, sq);
455 goto out;
456 }
457 }
458 queue->free_sqs &= ~(1 << sqid);
459 send_doorbell(priv, sq);
460 }
461
462out:
463 queue->pi += i;
464 return i;
465}
466
467#define MLX5_REGEX_RESP_SZ 8
468
469static inline void
470extract_result(struct rte_regex_ops *op, struct mlx5_regex_job *job)
471{
472 size_t j;
473 size_t offset;
474 uint16_t status;
475
476 op->user_id = job->user_id;
477 op->nb_matches = MLX5_GET_VOLATILE(regexp_metadata, job->metadata +
478 MLX5_REGEX_METADATA_OFF,
479 match_count);
480 op->nb_actual_matches = MLX5_GET_VOLATILE(regexp_metadata,
481 job->metadata +
482 MLX5_REGEX_METADATA_OFF,
483 detected_match_count);
484 for (j = 0; j < op->nb_matches; j++) {
485 offset = MLX5_REGEX_RESP_SZ * j;
486 op->matches[j].rule_id =
487 MLX5_GET_VOLATILE(regexp_match_tuple,
488 (job->output + offset), rule_id);
489 op->matches[j].start_offset =
490 MLX5_GET_VOLATILE(regexp_match_tuple,
491 (job->output + offset), start_ptr);
492 op->matches[j].len =
493 MLX5_GET_VOLATILE(regexp_match_tuple,
494 (job->output + offset), length);
495 }
496 status = MLX5_GET_VOLATILE(regexp_metadata, job->metadata +
497 MLX5_REGEX_METADATA_OFF,
498 status);
499 op->rsp_flags = 0;
500 if (status & MLX5_RXP_RESP_STATUS_PMI_SOJ)
501 op->rsp_flags |= RTE_REGEX_OPS_RSP_PMI_SOJ_F;
502 if (status & MLX5_RXP_RESP_STATUS_PMI_EOJ)
503 op->rsp_flags |= RTE_REGEX_OPS_RSP_PMI_EOJ_F;
504 if (status & MLX5_RXP_RESP_STATUS_MAX_LATENCY)
505 op->rsp_flags |= RTE_REGEX_OPS_RSP_MAX_SCAN_TIMEOUT_F;
506 if (status & MLX5_RXP_RESP_STATUS_MAX_MATCH)
507 op->rsp_flags |= RTE_REGEX_OPS_RSP_MAX_MATCH_F;
508 if (status & MLX5_RXP_RESP_STATUS_MAX_PREFIX)
509 op->rsp_flags |= RTE_REGEX_OPS_RSP_MAX_PREFIX_F;
510 if (status & MLX5_RXP_RESP_STATUS_MAX_PRI_THREADS)
511 op->rsp_flags |= RTE_REGEX_OPS_RSP_RESOURCE_LIMIT_REACHED_F;
512 if (status & MLX5_RXP_RESP_STATUS_MAX_SEC_THREADS)
513 op->rsp_flags |= RTE_REGEX_OPS_RSP_RESOURCE_LIMIT_REACHED_F;
514}
515
516static inline volatile struct mlx5_cqe *
517poll_one(struct mlx5_regex_cq *cq)
518{
519 volatile struct mlx5_cqe *cqe;
520 size_t next_cqe_offset;
521
522 next_cqe_offset = (cq->ci & (cq_size_get(cq) - 1));
523 cqe = (volatile struct mlx5_cqe *)(cq->cq_obj.cqes + next_cqe_offset);
524 rte_io_wmb();
525
526 int ret = check_cqe(cqe, cq_size_get(cq), cq->ci);
527
528 if (unlikely(ret == MLX5_CQE_STATUS_ERR)) {
529 DRV_LOG(ERR, "Completion with error on qp 0x%x", 0);
530 return NULL;
531 }
532
533 if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN))
534 return NULL;
535
536 return cqe;
537}
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555uint16_t
556mlx5_regexdev_dequeue(struct rte_regexdev *dev, uint16_t qp_id,
557 struct rte_regex_ops **ops, uint16_t nb_ops)
558{
559 struct mlx5_regex_priv *priv = dev->data->dev_private;
560 struct mlx5_regex_qp *queue = &priv->qps[qp_id];
561 struct mlx5_regex_cq *cq = &queue->cq;
562 volatile struct mlx5_cqe *cqe;
563 size_t i = 0;
564
565 while ((cqe = poll_one(cq))) {
566 uint16_t wq_counter
567 = (rte_be_to_cpu_16(cqe->wqe_counter) + 1) &
568 MLX5_REGEX_MAX_WQE_INDEX;
569 size_t sqid = cqe->rsvd3[2];
570 struct mlx5_regex_sq *sq = &queue->sqs[sqid];
571
572
573 if (priv->has_umr)
574 wq_counter >>= 2;
575 while (sq->ci != wq_counter) {
576 if (unlikely(i == nb_ops)) {
577
578 goto out;
579 }
580 uint32_t job_id = job_id_get(sqid, sq_size_get(sq),
581 sq->ci);
582 extract_result(ops[i], &queue->jobs[job_id]);
583 sq->ci = (sq->ci + 1) & (priv->has_umr ?
584 (MLX5_REGEX_MAX_WQE_INDEX >> 2) :
585 MLX5_REGEX_MAX_WQE_INDEX);
586 i++;
587 }
588 cq->ci = (cq->ci + 1) & 0xffffff;
589 rte_wmb();
590 cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->ci);
591 queue->free_sqs |= (1 << sqid);
592 }
593
594out:
595 queue->ci += i;
596 return i;
597}
598
599static void
600setup_sqs(struct mlx5_regex_priv *priv, struct mlx5_regex_qp *queue)
601{
602 size_t sqid, entry;
603 uint32_t job_id;
604 for (sqid = 0; sqid < queue->nb_obj; sqid++) {
605 struct mlx5_regex_sq *sq = &queue->sqs[sqid];
606 uint8_t *wqe = (uint8_t *)(uintptr_t)sq->sq_obj.wqes;
607 for (entry = 0 ; entry < sq_size_get(sq); entry++) {
608 job_id = sqid * sq_size_get(sq) + entry;
609 struct mlx5_regex_job *job = &queue->jobs[job_id];
610
611
612 if (priv->has_umr) {
613 set_wqe_ctrl_seg
614 ((struct mlx5_wqe_ctrl_seg *)wqe,
615 entry * 2, MLX5_OPCODE_NOP, 0,
616 sq->sq_obj.sq->id, 0, 12, 0, 0);
617 wqe += MLX5_REGEX_UMR_WQE_SIZE;
618 }
619 set_metadata_seg((struct mlx5_wqe_metadata_seg *)
620 (wqe + MLX5_REGEX_WQE_METADATA_OFFSET),
621 0, queue->metadata->lkey,
622 (uintptr_t)job->metadata);
623 set_data_seg((struct mlx5_wqe_data_seg *)
624 (wqe + MLX5_REGEX_WQE_SCATTER_OFFSET),
625 MLX5_REGEX_MAX_OUTPUT,
626 queue->outputs->lkey,
627 (uintptr_t)job->output);
628 wqe += 64;
629 }
630 queue->free_sqs |= 1 << sqid;
631 }
632}
633
634static int
635setup_buffers(struct mlx5_regex_priv *priv, struct mlx5_regex_qp *qp)
636{
637 struct ibv_pd *pd = priv->pd;
638 uint32_t i;
639 int err;
640
641 void *ptr = rte_calloc(__func__, qp->nb_desc,
642 MLX5_REGEX_METADATA_SIZE,
643 MLX5_REGEX_METADATA_SIZE);
644 if (!ptr)
645 return -ENOMEM;
646
647 qp->metadata = mlx5_glue->reg_mr(pd, ptr,
648 MLX5_REGEX_METADATA_SIZE * qp->nb_desc,
649 IBV_ACCESS_LOCAL_WRITE);
650 if (!qp->metadata) {
651 DRV_LOG(ERR, "Failed to register metadata");
652 rte_free(ptr);
653 return -EINVAL;
654 }
655
656 ptr = rte_calloc(__func__, qp->nb_desc,
657 MLX5_REGEX_MAX_OUTPUT,
658 MLX5_REGEX_MAX_OUTPUT);
659 if (!ptr) {
660 err = -ENOMEM;
661 goto err_output;
662 }
663 qp->outputs = mlx5_glue->reg_mr(pd, ptr,
664 MLX5_REGEX_MAX_OUTPUT * qp->nb_desc,
665 IBV_ACCESS_LOCAL_WRITE);
666 if (!qp->outputs) {
667 rte_free(ptr);
668 DRV_LOG(ERR, "Failed to register output");
669 err = -EINVAL;
670 goto err_output;
671 }
672
673 if (priv->has_umr) {
674 ptr = rte_calloc(__func__, qp->nb_desc, MLX5_REGEX_KLMS_SIZE,
675 MLX5_REGEX_KLMS_SIZE);
676 if (!ptr) {
677 err = -ENOMEM;
678 goto err_imkey;
679 }
680 qp->imkey_addr = mlx5_glue->reg_mr(pd, ptr,
681 MLX5_REGEX_KLMS_SIZE * qp->nb_desc,
682 IBV_ACCESS_LOCAL_WRITE);
683 if (!qp->imkey_addr) {
684 rte_free(ptr);
685 DRV_LOG(ERR, "Failed to register output");
686 err = -EINVAL;
687 goto err_imkey;
688 }
689 }
690
691
692 for (i = 0; i < qp->nb_desc; i++) {
693 qp->jobs[i].output =
694 (uint8_t *)qp->outputs->addr +
695 (i % qp->nb_desc) * MLX5_REGEX_MAX_OUTPUT;
696 qp->jobs[i].metadata =
697 (uint8_t *)qp->metadata->addr +
698 (i % qp->nb_desc) * MLX5_REGEX_METADATA_SIZE;
699 if (qp->imkey_addr)
700 qp->jobs[i].imkey_array = (struct mlx5_klm *)
701 qp->imkey_addr->addr +
702 (i % qp->nb_desc) * MLX5_REGEX_MAX_KLM_NUM;
703 }
704
705 return 0;
706
707err_imkey:
708 ptr = qp->outputs->addr;
709 rte_free(ptr);
710 mlx5_glue->dereg_mr(qp->outputs);
711err_output:
712 ptr = qp->metadata->addr;
713 rte_free(ptr);
714 mlx5_glue->dereg_mr(qp->metadata);
715 return err;
716}
717
718int
719mlx5_regexdev_setup_fastpath(struct mlx5_regex_priv *priv, uint32_t qp_id)
720{
721 struct mlx5_regex_qp *qp = &priv->qps[qp_id];
722 struct mlx5_klm klm = { 0 };
723 struct mlx5_devx_mkey_attr attr = {
724 .klm_array = &klm,
725 .klm_num = 1,
726 .umr_en = 1,
727 };
728 uint32_t i;
729 int err = 0;
730
731 qp->jobs = rte_calloc(__func__, qp->nb_desc, sizeof(*qp->jobs), 64);
732 if (!qp->jobs)
733 return -ENOMEM;
734 err = setup_buffers(priv, qp);
735 if (err) {
736 rte_free(qp->jobs);
737 return err;
738 }
739
740 setup_sqs(priv, qp);
741
742 if (priv->has_umr) {
743#ifdef HAVE_IBV_FLOW_DV_SUPPORT
744 if (regex_get_pdn(priv->pd, &attr.pd)) {
745 err = -rte_errno;
746 DRV_LOG(ERR, "Failed to get pdn.");
747 mlx5_regexdev_teardown_fastpath(priv, qp_id);
748 return err;
749 }
750#endif
751 for (i = 0; i < qp->nb_desc; i++) {
752 attr.klm_num = MLX5_REGEX_MAX_KLM_NUM;
753 attr.klm_array = qp->jobs[i].imkey_array;
754 qp->jobs[i].imkey = mlx5_devx_cmd_mkey_create(priv->ctx,
755 &attr);
756 if (!qp->jobs[i].imkey) {
757 err = -rte_errno;
758 DRV_LOG(ERR, "Failed to allocate imkey.");
759 mlx5_regexdev_teardown_fastpath(priv, qp_id);
760 }
761 }
762 }
763 return err;
764}
765
766static void
767free_buffers(struct mlx5_regex_qp *qp)
768{
769 if (qp->imkey_addr) {
770 mlx5_glue->dereg_mr(qp->imkey_addr);
771 rte_free(qp->imkey_addr->addr);
772 }
773 if (qp->metadata) {
774 mlx5_glue->dereg_mr(qp->metadata);
775 rte_free(qp->metadata->addr);
776 }
777 if (qp->outputs) {
778 mlx5_glue->dereg_mr(qp->outputs);
779 rte_free(qp->outputs->addr);
780 }
781}
782
783void
784mlx5_regexdev_teardown_fastpath(struct mlx5_regex_priv *priv, uint32_t qp_id)
785{
786 struct mlx5_regex_qp *qp = &priv->qps[qp_id];
787 uint32_t i;
788
789 if (qp) {
790 for (i = 0; i < qp->nb_desc; i++) {
791 if (qp->jobs[i].imkey)
792 claim_zero(mlx5_devx_cmd_destroy
793 (qp->jobs[i].imkey));
794 }
795 free_buffers(qp);
796 if (qp->jobs)
797 rte_free(qp->jobs);
798 }
799}
800