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