xref: /dpdk/drivers/regex/mlx5/mlx5_regex_fastpath.c (revision 4d4e245ad637c0befbd6da9976c28174a1d74b88)
15f41b66dSYuval Avnery /* SPDX-License-Identifier: BSD-3-Clause
25f41b66dSYuval Avnery  * Copyright 2020 Mellanox Technologies, Ltd
35f41b66dSYuval Avnery  */
45f41b66dSYuval Avnery 
55f41b66dSYuval Avnery #include <unistd.h>
65f41b66dSYuval Avnery #include <sys/mman.h>
75f41b66dSYuval Avnery 
85f41b66dSYuval Avnery #include <rte_malloc.h>
95f41b66dSYuval Avnery #include <rte_log.h>
105f41b66dSYuval Avnery #include <rte_errno.h>
115f41b66dSYuval Avnery #include <rte_bus_pci.h>
125f41b66dSYuval Avnery #include <rte_pci.h>
135f41b66dSYuval Avnery #include <rte_regexdev_driver.h>
145f41b66dSYuval Avnery #include <rte_mbuf.h>
155f41b66dSYuval Avnery 
165f41b66dSYuval Avnery #include <infiniband/mlx5dv.h>
175f41b66dSYuval Avnery #include <mlx5_glue.h>
185f41b66dSYuval Avnery #include <mlx5_common.h>
195f41b66dSYuval Avnery #include <mlx5_prm.h>
205f41b66dSYuval Avnery #include <strings.h>
215f41b66dSYuval Avnery 
225f41b66dSYuval Avnery #include "mlx5_regex_utils.h"
235f41b66dSYuval Avnery #include "mlx5_rxp.h"
245f41b66dSYuval Avnery #include "mlx5_regex.h"
255f41b66dSYuval Avnery 
26*4d4e245aSYuval Avnery #define MLX5_REGEX_MAX_WQE_INDEX 0xffff
275f41b66dSYuval Avnery #define MLX5_REGEX_METADATA_SIZE 64
285f41b66dSYuval Avnery #define MLX5_REGEX_MAX_INPUT (1 << 14)
295f41b66dSYuval Avnery #define MLX5_REGEX_MAX_OUTPUT (1 << 11)
30*4d4e245aSYuval Avnery #define MLX5_REGEX_WQE_CTRL_OFFSET 12
315f41b66dSYuval Avnery #define MLX5_REGEX_WQE_METADATA_OFFSET 16
325f41b66dSYuval Avnery #define MLX5_REGEX_WQE_GATHER_OFFSET 32
335f41b66dSYuval Avnery #define MLX5_REGEX_WQE_SCATTER_OFFSET 48
345f41b66dSYuval Avnery 
355f41b66dSYuval Avnery static inline uint32_t
365f41b66dSYuval Avnery sq_size_get(struct mlx5_regex_sq *sq)
375f41b66dSYuval Avnery {
385f41b66dSYuval Avnery 	return (1U << sq->log_nb_desc);
395f41b66dSYuval Avnery }
405f41b66dSYuval Avnery 
415f41b66dSYuval Avnery struct mlx5_regex_job {
425f41b66dSYuval Avnery 	uint64_t user_id;
435f41b66dSYuval Avnery 	uint8_t *input;
445f41b66dSYuval Avnery 	volatile uint8_t *output;
455f41b66dSYuval Avnery 	volatile uint8_t *metadata;
465f41b66dSYuval Avnery } __rte_cached_aligned;
475f41b66dSYuval Avnery 
485f41b66dSYuval Avnery static inline void
495f41b66dSYuval Avnery set_data_seg(struct mlx5_wqe_data_seg *seg,
505f41b66dSYuval Avnery 	     uint32_t length, uint32_t lkey,
515f41b66dSYuval Avnery 	     uintptr_t address)
525f41b66dSYuval Avnery {
535f41b66dSYuval Avnery 	seg->byte_count = rte_cpu_to_be_32(length);
545f41b66dSYuval Avnery 	seg->lkey = rte_cpu_to_be_32(lkey);
555f41b66dSYuval Avnery 	seg->addr = rte_cpu_to_be_64(address);
565f41b66dSYuval Avnery }
575f41b66dSYuval Avnery 
585f41b66dSYuval Avnery static inline void
595f41b66dSYuval Avnery set_metadata_seg(struct mlx5_wqe_metadata_seg *seg,
605f41b66dSYuval Avnery 		 uint32_t mmo_control_31_0, uint32_t lkey,
615f41b66dSYuval Avnery 		 uintptr_t address)
625f41b66dSYuval Avnery {
635f41b66dSYuval Avnery 	seg->mmo_control_31_0 = htobe32(mmo_control_31_0);
645f41b66dSYuval Avnery 	seg->lkey = rte_cpu_to_be_32(lkey);
655f41b66dSYuval Avnery 	seg->addr = rte_cpu_to_be_64(address);
665f41b66dSYuval Avnery }
675f41b66dSYuval Avnery 
68*4d4e245aSYuval Avnery static inline void
69*4d4e245aSYuval Avnery set_regex_ctrl_seg(void *seg, uint8_t le, uint16_t subset_id0,
70*4d4e245aSYuval Avnery 		   uint16_t subset_id1, uint16_t subset_id2,
71*4d4e245aSYuval Avnery 		   uint16_t subset_id3, uint8_t ctrl)
72*4d4e245aSYuval Avnery {
73*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, le, le);
74*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, ctrl, ctrl);
75*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, subset_id_0, subset_id0);
76*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, subset_id_1, subset_id1);
77*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, subset_id_2, subset_id2);
78*4d4e245aSYuval Avnery 	MLX5_SET(regexp_mmo_control, seg, subset_id_3, subset_id3);
79*4d4e245aSYuval Avnery }
80*4d4e245aSYuval Avnery 
81*4d4e245aSYuval Avnery static inline void
82*4d4e245aSYuval Avnery set_wqe_ctrl_seg(struct mlx5_wqe_ctrl_seg *seg, uint16_t pi, uint8_t opcode,
83*4d4e245aSYuval Avnery 		 uint8_t opmod, uint32_t qp_num, uint8_t fm_ce_se, uint8_t ds,
84*4d4e245aSYuval Avnery 		 uint8_t signature, uint32_t imm)
85*4d4e245aSYuval Avnery {
86*4d4e245aSYuval Avnery 	seg->opmod_idx_opcode = rte_cpu_to_be_32(((uint32_t)opmod << 24) |
87*4d4e245aSYuval Avnery 						 ((uint32_t)pi << 8) |
88*4d4e245aSYuval Avnery 						 opcode);
89*4d4e245aSYuval Avnery 	seg->qpn_ds = rte_cpu_to_be_32((qp_num << 8) | ds);
90*4d4e245aSYuval Avnery 	seg->fm_ce_se = fm_ce_se;
91*4d4e245aSYuval Avnery 	seg->signature = signature;
92*4d4e245aSYuval Avnery 	seg->imm = imm;
93*4d4e245aSYuval Avnery }
94*4d4e245aSYuval Avnery 
95*4d4e245aSYuval Avnery static inline void
96*4d4e245aSYuval Avnery prep_one(struct mlx5_regex_sq *sq, struct rte_regex_ops *op,
97*4d4e245aSYuval Avnery 	 struct mlx5_regex_job *job)
98*4d4e245aSYuval Avnery {
99*4d4e245aSYuval Avnery 	size_t wqe_offset = (sq->pi & (sq_size_get(sq) - 1)) * MLX5_SEND_WQE_BB;
100*4d4e245aSYuval Avnery 	uint8_t *wqe = (uint8_t *)sq->wqe + wqe_offset;
101*4d4e245aSYuval Avnery 	int ds = 4; /*  ctrl + meta + input + output */
102*4d4e245aSYuval Avnery 
103*4d4e245aSYuval Avnery 	memcpy(job->input,
104*4d4e245aSYuval Avnery 		rte_pktmbuf_mtod(op->mbuf, void *),
105*4d4e245aSYuval Avnery 		rte_pktmbuf_data_len(op->mbuf));
106*4d4e245aSYuval Avnery 	set_wqe_ctrl_seg((struct mlx5_wqe_ctrl_seg *)wqe, sq->pi,
107*4d4e245aSYuval Avnery 			 MLX5_OPCODE_MMO, MLX5_OPC_MOD_MMO_REGEX, sq->obj->id,
108*4d4e245aSYuval Avnery 			 0, ds, 0, 0);
109*4d4e245aSYuval Avnery 	set_regex_ctrl_seg(wqe + 12, 0, op->group_id0, op->group_id1,
110*4d4e245aSYuval Avnery 			   op->group_id2,
111*4d4e245aSYuval Avnery 			   op->group_id3, 0);
112*4d4e245aSYuval Avnery 	struct mlx5_wqe_data_seg *input_seg =
113*4d4e245aSYuval Avnery 		(struct mlx5_wqe_data_seg *)(wqe +
114*4d4e245aSYuval Avnery 					     MLX5_REGEX_WQE_GATHER_OFFSET);
115*4d4e245aSYuval Avnery 	input_seg->byte_count =
116*4d4e245aSYuval Avnery 		rte_cpu_to_be_32(rte_pktmbuf_data_len(op->mbuf));
117*4d4e245aSYuval Avnery 	job->user_id = op->user_id;
118*4d4e245aSYuval Avnery 	sq->db_pi = sq->pi;
119*4d4e245aSYuval Avnery 	sq->pi = (sq->pi + 1) & MLX5_REGEX_MAX_WQE_INDEX;
120*4d4e245aSYuval Avnery }
121*4d4e245aSYuval Avnery 
122*4d4e245aSYuval Avnery static inline void
123*4d4e245aSYuval Avnery send_doorbell(struct mlx5dv_devx_uar *uar, struct mlx5_regex_sq *sq)
124*4d4e245aSYuval Avnery {
125*4d4e245aSYuval Avnery 	size_t wqe_offset = (sq->db_pi & (sq_size_get(sq) - 1)) *
126*4d4e245aSYuval Avnery 		MLX5_SEND_WQE_BB;
127*4d4e245aSYuval Avnery 	uint8_t *wqe = (uint8_t *)sq->wqe + wqe_offset;
128*4d4e245aSYuval Avnery 	((struct mlx5_wqe_ctrl_seg *)wqe)->fm_ce_se = MLX5_WQE_CTRL_CQ_UPDATE;
129*4d4e245aSYuval Avnery 	uint64_t *doorbell_addr =
130*4d4e245aSYuval Avnery 		(uint64_t *)((uint8_t *)uar->base_addr + 0x800);
131*4d4e245aSYuval Avnery 	rte_cio_wmb();
132*4d4e245aSYuval Avnery 	sq->dbr[MLX5_SND_DBR] = rte_cpu_to_be_32((sq->db_pi + 1) &
133*4d4e245aSYuval Avnery 						 MLX5_REGEX_MAX_WQE_INDEX);
134*4d4e245aSYuval Avnery 	rte_wmb();
135*4d4e245aSYuval Avnery 	*doorbell_addr = *(volatile uint64_t *)wqe;
136*4d4e245aSYuval Avnery 	rte_wmb();
137*4d4e245aSYuval Avnery }
138*4d4e245aSYuval Avnery 
139*4d4e245aSYuval Avnery static inline int
140*4d4e245aSYuval Avnery can_send(struct mlx5_regex_sq *sq) {
141*4d4e245aSYuval Avnery 	return unlikely(sq->ci > sq->pi) ?
142*4d4e245aSYuval Avnery 			MLX5_REGEX_MAX_WQE_INDEX + sq->pi - sq->ci <
143*4d4e245aSYuval Avnery 			sq_size_get(sq) :
144*4d4e245aSYuval Avnery 			sq->pi - sq->ci < sq_size_get(sq);
145*4d4e245aSYuval Avnery }
146*4d4e245aSYuval Avnery 
147*4d4e245aSYuval Avnery static inline uint32_t
148*4d4e245aSYuval Avnery job_id_get(uint32_t qid, size_t sq_size, size_t index) {
149*4d4e245aSYuval Avnery 	return qid * sq_size + index % sq_size;
150*4d4e245aSYuval Avnery }
151*4d4e245aSYuval Avnery 
152*4d4e245aSYuval Avnery uint16_t
153*4d4e245aSYuval Avnery mlx5_regexdev_enqueue(struct rte_regexdev *dev, uint16_t qp_id,
154*4d4e245aSYuval Avnery 		      struct rte_regex_ops **ops, uint16_t nb_ops)
155*4d4e245aSYuval Avnery {
156*4d4e245aSYuval Avnery 	struct mlx5_regex_priv *priv = dev->data->dev_private;
157*4d4e245aSYuval Avnery 	struct mlx5_regex_qp *queue = &priv->qps[qp_id];
158*4d4e245aSYuval Avnery 	struct mlx5_regex_sq *sq;
159*4d4e245aSYuval Avnery 	size_t sqid, job_id, i = 0;
160*4d4e245aSYuval Avnery 
161*4d4e245aSYuval Avnery 	while ((sqid = ffs(queue->free_sqs))) {
162*4d4e245aSYuval Avnery 		sqid--; /* ffs returns 1 for bit 0 */
163*4d4e245aSYuval Avnery 		sq = &queue->sqs[sqid];
164*4d4e245aSYuval Avnery 		while (can_send(sq)) {
165*4d4e245aSYuval Avnery 			job_id = job_id_get(sqid, sq_size_get(sq), sq->pi);
166*4d4e245aSYuval Avnery 			prep_one(sq, ops[i], &queue->jobs[job_id]);
167*4d4e245aSYuval Avnery 			i++;
168*4d4e245aSYuval Avnery 			if (unlikely(i == nb_ops)) {
169*4d4e245aSYuval Avnery 				send_doorbell(priv->uar, sq);
170*4d4e245aSYuval Avnery 				goto out;
171*4d4e245aSYuval Avnery 			}
172*4d4e245aSYuval Avnery 		}
173*4d4e245aSYuval Avnery 		queue->free_sqs &= ~(1 << sqid);
174*4d4e245aSYuval Avnery 		send_doorbell(priv->uar, sq);
175*4d4e245aSYuval Avnery 	}
176*4d4e245aSYuval Avnery 
177*4d4e245aSYuval Avnery out:
178*4d4e245aSYuval Avnery 	queue->pi += i;
179*4d4e245aSYuval Avnery 	return i;
180*4d4e245aSYuval Avnery }
181*4d4e245aSYuval Avnery 
1825f41b66dSYuval Avnery static void
1835f41b66dSYuval Avnery setup_sqs(struct mlx5_regex_qp *queue)
1845f41b66dSYuval Avnery {
1855f41b66dSYuval Avnery 	size_t sqid, entry;
1865f41b66dSYuval Avnery 	uint32_t job_id;
1875f41b66dSYuval Avnery 	for (sqid = 0; sqid < queue->nb_obj; sqid++) {
1885f41b66dSYuval Avnery 		struct mlx5_regex_sq *sq = &queue->sqs[sqid];
1895f41b66dSYuval Avnery 		uint8_t *wqe = (uint8_t *)sq->wqe;
1905f41b66dSYuval Avnery 		for (entry = 0 ; entry < sq_size_get(sq); entry++) {
1915f41b66dSYuval Avnery 			job_id = sqid * sq_size_get(sq) + entry;
1925f41b66dSYuval Avnery 			struct mlx5_regex_job *job = &queue->jobs[job_id];
1935f41b66dSYuval Avnery 
1945f41b66dSYuval Avnery 			set_metadata_seg((struct mlx5_wqe_metadata_seg *)
1955f41b66dSYuval Avnery 					 (wqe + MLX5_REGEX_WQE_METADATA_OFFSET),
1965f41b66dSYuval Avnery 					 0, queue->metadata->lkey,
1975f41b66dSYuval Avnery 					 (uintptr_t)job->metadata);
1985f41b66dSYuval Avnery 			set_data_seg((struct mlx5_wqe_data_seg *)
1995f41b66dSYuval Avnery 				     (wqe + MLX5_REGEX_WQE_GATHER_OFFSET),
2005f41b66dSYuval Avnery 				     0, queue->inputs->lkey,
2015f41b66dSYuval Avnery 				     (uintptr_t)job->input);
2025f41b66dSYuval Avnery 			set_data_seg((struct mlx5_wqe_data_seg *)
2035f41b66dSYuval Avnery 				     (wqe + MLX5_REGEX_WQE_SCATTER_OFFSET),
2045f41b66dSYuval Avnery 				     MLX5_REGEX_MAX_OUTPUT,
2055f41b66dSYuval Avnery 				     queue->outputs->lkey,
2065f41b66dSYuval Avnery 				     (uintptr_t)job->output);
2075f41b66dSYuval Avnery 			wqe += 64;
2085f41b66dSYuval Avnery 		}
2095f41b66dSYuval Avnery 		queue->free_sqs |= 1 << sqid;
2105f41b66dSYuval Avnery 	}
2115f41b66dSYuval Avnery }
2125f41b66dSYuval Avnery 
2135f41b66dSYuval Avnery static int
2145f41b66dSYuval Avnery setup_buffers(struct mlx5_regex_qp *qp, struct ibv_pd *pd)
2155f41b66dSYuval Avnery {
2165f41b66dSYuval Avnery 	uint32_t i;
2175f41b66dSYuval Avnery 	int err;
2185f41b66dSYuval Avnery 
2195f41b66dSYuval Avnery 	void *ptr = rte_calloc(__func__, qp->nb_desc,
2205f41b66dSYuval Avnery 			       MLX5_REGEX_METADATA_SIZE,
2215f41b66dSYuval Avnery 			       MLX5_REGEX_METADATA_SIZE);
2225f41b66dSYuval Avnery 	if (!ptr)
2235f41b66dSYuval Avnery 		return -ENOMEM;
2245f41b66dSYuval Avnery 
2255f41b66dSYuval Avnery 	qp->metadata = mlx5_glue->reg_mr(pd, ptr,
2265f41b66dSYuval Avnery 					 MLX5_REGEX_METADATA_SIZE*qp->nb_desc,
2275f41b66dSYuval Avnery 					 IBV_ACCESS_LOCAL_WRITE);
2285f41b66dSYuval Avnery 	if (!qp->metadata) {
2295f41b66dSYuval Avnery 		rte_free(ptr);
2305f41b66dSYuval Avnery 		return -EINVAL;
2315f41b66dSYuval Avnery 	}
2325f41b66dSYuval Avnery 	ptr = rte_calloc(__func__, qp->nb_desc,
2335f41b66dSYuval Avnery 			 MLX5_REGEX_MAX_INPUT,
2345f41b66dSYuval Avnery 			 MLX5_REGEX_MAX_INPUT);
2355f41b66dSYuval Avnery 
2365f41b66dSYuval Avnery 	if (!ptr) {
2375f41b66dSYuval Avnery 		err = -ENOMEM;
2385f41b66dSYuval Avnery 		goto err_input;
2395f41b66dSYuval Avnery 	}
2405f41b66dSYuval Avnery 	qp->inputs = mlx5_glue->reg_mr(pd, ptr,
2415f41b66dSYuval Avnery 				       MLX5_REGEX_MAX_INPUT*qp->nb_desc,
2425f41b66dSYuval Avnery 				       IBV_ACCESS_LOCAL_WRITE);
2435f41b66dSYuval Avnery 	if (!qp->inputs) {
2445f41b66dSYuval Avnery 		rte_free(ptr);
2455f41b66dSYuval Avnery 		err = -EINVAL;
2465f41b66dSYuval Avnery 		goto err_input;
2475f41b66dSYuval Avnery 	}
2485f41b66dSYuval Avnery 
2495f41b66dSYuval Avnery 	ptr = rte_calloc(__func__, qp->nb_desc,
2505f41b66dSYuval Avnery 			 MLX5_REGEX_MAX_OUTPUT,
2515f41b66dSYuval Avnery 			 MLX5_REGEX_MAX_OUTPUT);
2525f41b66dSYuval Avnery 	if (!ptr) {
2535f41b66dSYuval Avnery 		err = -ENOMEM;
2545f41b66dSYuval Avnery 		goto err_output;
2555f41b66dSYuval Avnery 	}
2565f41b66dSYuval Avnery 	qp->outputs = mlx5_glue->reg_mr(pd, ptr,
2575f41b66dSYuval Avnery 					MLX5_REGEX_MAX_OUTPUT * qp->nb_desc,
2585f41b66dSYuval Avnery 					IBV_ACCESS_LOCAL_WRITE);
2595f41b66dSYuval Avnery 	if (!qp->outputs) {
2605f41b66dSYuval Avnery 		rte_free(ptr);
2615f41b66dSYuval Avnery 		err = -EINVAL;
2625f41b66dSYuval Avnery 		goto err_output;
2635f41b66dSYuval Avnery 	}
2645f41b66dSYuval Avnery 
2655f41b66dSYuval Avnery 	/* distribute buffers to jobs */
2665f41b66dSYuval Avnery 	for (i = 0; i < qp->nb_desc; i++) {
2675f41b66dSYuval Avnery 		qp->jobs[i].input =
2685f41b66dSYuval Avnery 			(uint8_t *)qp->inputs->addr +
2695f41b66dSYuval Avnery 			(i % qp->nb_desc) * MLX5_REGEX_MAX_INPUT;
2705f41b66dSYuval Avnery 		qp->jobs[i].output =
2715f41b66dSYuval Avnery 			(uint8_t *)qp->outputs->addr +
2725f41b66dSYuval Avnery 			(i % qp->nb_desc) * MLX5_REGEX_MAX_OUTPUT;
2735f41b66dSYuval Avnery 		qp->jobs[i].metadata =
2745f41b66dSYuval Avnery 			(uint8_t *)qp->metadata->addr +
2755f41b66dSYuval Avnery 			(i % qp->nb_desc) * MLX5_REGEX_METADATA_SIZE;
2765f41b66dSYuval Avnery 	}
2775f41b66dSYuval Avnery 	return 0;
2785f41b66dSYuval Avnery 
2795f41b66dSYuval Avnery err_output:
2805f41b66dSYuval Avnery 	ptr = qp->inputs->addr;
2815f41b66dSYuval Avnery 	rte_free(ptr);
2825f41b66dSYuval Avnery 	mlx5_glue->dereg_mr(qp->inputs);
2835f41b66dSYuval Avnery err_input:
2845f41b66dSYuval Avnery 	ptr = qp->metadata->addr;
2855f41b66dSYuval Avnery 	rte_free(ptr);
2865f41b66dSYuval Avnery 	mlx5_glue->dereg_mr(qp->metadata);
2875f41b66dSYuval Avnery 	return err;
2885f41b66dSYuval Avnery }
2895f41b66dSYuval Avnery 
2905f41b66dSYuval Avnery int
2915f41b66dSYuval Avnery mlx5_regexdev_setup_fastpath(struct mlx5_regex_priv *priv, uint32_t qp_id)
2925f41b66dSYuval Avnery {
2935f41b66dSYuval Avnery 	struct mlx5_regex_qp *qp = &priv->qps[qp_id];
2945f41b66dSYuval Avnery 	int err;
2955f41b66dSYuval Avnery 
2965f41b66dSYuval Avnery 	qp->jobs = rte_calloc(__func__, qp->nb_desc, sizeof(*qp->jobs),
2975f41b66dSYuval Avnery 			      sizeof(*qp->jobs));
2985f41b66dSYuval Avnery 	if (!qp->jobs)
2995f41b66dSYuval Avnery 		return -ENOMEM;
3005f41b66dSYuval Avnery 	err = setup_buffers(qp, priv->pd);
3015f41b66dSYuval Avnery 	if (err)
3025f41b66dSYuval Avnery 		return err;
3035f41b66dSYuval Avnery 	setup_sqs(qp);
3045f41b66dSYuval Avnery 	return 0;
3055f41b66dSYuval Avnery }
306