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