Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright (c) 2023 NVIDIA Corporation & Affiliates
3 : : */
4 : :
5 : : #include <rte_malloc.h>
6 : : #include <rte_mempool.h>
7 : : #include <rte_eal_paging.h>
8 : : #include <rte_errno.h>
9 : : #include <rte_log.h>
10 : : #include <bus_pci_driver.h>
11 : : #include <rte_memory.h>
12 : : #include <rte_io.h>
13 : :
14 : : #include <mlx5_glue.h>
15 : : #include <mlx5_common.h>
16 : : #include <mlx5_devx_cmds.h>
17 : : #include <mlx5_common_os.h>
18 : :
19 : : #include "mlx5_crypto_utils.h"
20 : : #include "mlx5_crypto.h"
21 : :
22 : : /*
23 : : * AES-GCM uses indirect KLM mode. The UMR WQE comprises of WQE control +
24 : : * UMR control + mkey context + indirect KLM. The WQE size is aligned to
25 : : * be 3 WQEBBS.
26 : : */
27 : : #define MLX5_UMR_GCM_WQE_SIZE \
28 : : (RTE_ALIGN(sizeof(struct mlx5_umr_wqe) + sizeof(struct mlx5_wqe_dseg), \
29 : : MLX5_SEND_WQE_BB))
30 : :
31 : : #define MLX5_UMR_GCM_WQE_SET_SIZE \
32 : : (MLX5_UMR_GCM_WQE_SIZE + \
33 : : RTE_ALIGN(sizeof(struct mlx5_wqe_send_en_wqe), \
34 : : MLX5_SEND_WQE_BB))
35 : :
36 : : #define MLX5_UMR_GCM_WQE_STRIDE \
37 : : (MLX5_UMR_GCM_WQE_SIZE / MLX5_SEND_WQE_BB)
38 : :
39 : : #define MLX5_MMO_CRYPTO_OPC (MLX5_OPCODE_MMO | \
40 : : (MLX5_OPC_MOD_MMO_CRYPTO << WQE_CSEG_OPC_MOD_OFFSET))
41 : :
42 : : /*
43 : : * The status default value is RTE_CRYPTO_OP_STATUS_SUCCESS.
44 : : * Copy tag should fill different value to status.
45 : : */
46 : : #define MLX5_CRYPTO_OP_STATUS_GCM_TAG_COPY (RTE_CRYPTO_OP_STATUS_SUCCESS + 1)
47 : :
48 : : struct mlx5_crypto_gcm_op_info {
49 : : bool need_umr;
50 : : bool is_oop;
51 : : bool is_enc;
52 : : void *digest;
53 : : void *src_addr;
54 : : };
55 : :
56 : : struct mlx5_crypto_gcm_data {
57 : : void *src_addr;
58 : : uint32_t src_bytes;
59 : : void *dst_addr;
60 : : uint32_t dst_bytes;
61 : : uint32_t src_mkey;
62 : : uint32_t dst_mkey;
63 : : };
64 : :
65 : : struct __rte_packed_begin mlx5_crypto_gcm_tag_cpy_info {
66 : : void *digest;
67 : : uint8_t tag_len;
68 : : } __rte_packed_end;
69 : :
70 : : static struct rte_cryptodev_capabilities mlx5_crypto_gcm_caps[] = {
71 : : {
72 : : .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
73 : : },
74 : : {
75 : : .op = RTE_CRYPTO_OP_TYPE_UNDEFINED,
76 : : }
77 : : };
78 : :
79 : : int
80 : 0 : mlx5_crypto_dek_fill_gcm_attr(struct mlx5_crypto_dek *dek,
81 : : struct mlx5_devx_dek_attr *dek_attr,
82 : : void *cb_ctx)
83 : : {
84 : : uint32_t offset = 0;
85 : : struct mlx5_crypto_dek_ctx *ctx = cb_ctx;
86 : 0 : struct rte_crypto_aead_xform *aead_ctx = &ctx->xform->aead;
87 : :
88 [ # # ]: 0 : if (aead_ctx->algo != RTE_CRYPTO_AEAD_AES_GCM) {
89 : 0 : DRV_LOG(ERR, "Only AES-GCM algo supported.");
90 : 0 : return -EINVAL;
91 : : }
92 : 0 : dek_attr->key_purpose = MLX5_CRYPTO_KEY_PURPOSE_GCM;
93 [ # # # ]: 0 : switch (aead_ctx->key.length) {
94 : 0 : case 16:
95 : : offset = 16;
96 : 0 : dek->size = 16;
97 : 0 : dek_attr->key_size = MLX5_CRYPTO_KEY_SIZE_128b;
98 : 0 : break;
99 : 0 : case 32:
100 : 0 : dek->size = 32;
101 : 0 : dek_attr->key_size = MLX5_CRYPTO_KEY_SIZE_256b;
102 : 0 : break;
103 : 0 : default:
104 : 0 : DRV_LOG(ERR, "Wrapped key size not supported.");
105 : 0 : return -EINVAL;
106 : : }
107 : 0 : memcpy(&dek_attr->key[offset], aead_ctx->key.data, aead_ctx->key.length);
108 : 0 : memcpy(&dek->data, aead_ctx->key.data, aead_ctx->key.length);
109 : 0 : return 0;
110 : : }
111 : :
112 : : static int
113 : 0 : mlx5_crypto_generate_gcm_cap(struct mlx5_hca_crypto_mmo_attr *mmo_attr,
114 : : struct rte_cryptodev_capabilities *cap)
115 : : {
116 : : /* Init key size. */
117 : 0 : if (mmo_attr->gcm_128_encrypt && mmo_attr->gcm_128_decrypt &&
118 [ # # ]: 0 : mmo_attr->gcm_256_encrypt && mmo_attr->gcm_256_decrypt) {
119 : 0 : cap->sym.aead.key_size.min = 16;
120 : 0 : cap->sym.aead.key_size.max = 32;
121 : 0 : cap->sym.aead.key_size.increment = 16;
122 [ # # ]: 0 : } else if (mmo_attr->gcm_256_encrypt && mmo_attr->gcm_256_decrypt) {
123 : 0 : cap->sym.aead.key_size.min = 32;
124 : 0 : cap->sym.aead.key_size.max = 32;
125 : 0 : cap->sym.aead.key_size.increment = 0;
126 [ # # ]: 0 : } else if (mmo_attr->gcm_128_encrypt && mmo_attr->gcm_128_decrypt) {
127 : 0 : cap->sym.aead.key_size.min = 16;
128 : 0 : cap->sym.aead.key_size.max = 16;
129 : 0 : cap->sym.aead.key_size.increment = 0;
130 : : } else {
131 : 0 : DRV_LOG(ERR, "No available AES-GCM encryption/decryption supported.");
132 : 0 : return -1;
133 : : }
134 : : /* Init tag size. */
135 [ # # ]: 0 : if (mmo_attr->gcm_auth_tag_128 && mmo_attr->gcm_auth_tag_96) {
136 : 0 : cap->sym.aead.digest_size.min = 12;
137 : 0 : cap->sym.aead.digest_size.max = 16;
138 : 0 : cap->sym.aead.digest_size.increment = 4;
139 [ # # ]: 0 : } else if (mmo_attr->gcm_auth_tag_96) {
140 : 0 : cap->sym.aead.digest_size.min = 12;
141 : 0 : cap->sym.aead.digest_size.max = 12;
142 : 0 : cap->sym.aead.digest_size.increment = 0;
143 [ # # ]: 0 : } else if (mmo_attr->gcm_auth_tag_128) {
144 : 0 : cap->sym.aead.digest_size.min = 16;
145 : 0 : cap->sym.aead.digest_size.max = 16;
146 : 0 : cap->sym.aead.digest_size.increment = 0;
147 : : } else {
148 : 0 : DRV_LOG(ERR, "No available AES-GCM tag size supported.");
149 : 0 : return -1;
150 : : }
151 : : /* Init AAD size. */
152 : 0 : cap->sym.aead.aad_size.min = 0;
153 : 0 : cap->sym.aead.aad_size.max = UINT16_MAX;
154 : 0 : cap->sym.aead.aad_size.increment = 1;
155 : : /* Init IV size. */
156 : 0 : cap->sym.aead.iv_size.min = 12;
157 : 0 : cap->sym.aead.iv_size.max = 12;
158 : 0 : cap->sym.aead.iv_size.increment = 0;
159 : : /* Init left items. */
160 : 0 : cap->op = RTE_CRYPTO_OP_TYPE_SYMMETRIC;
161 : 0 : cap->sym.xform_type = RTE_CRYPTO_SYM_XFORM_AEAD;
162 : 0 : cap->sym.aead.algo = RTE_CRYPTO_AEAD_AES_GCM;
163 : 0 : return 0;
164 : : }
165 : :
166 : : static int
167 : 0 : mlx5_crypto_sym_gcm_session_configure(struct rte_cryptodev *dev,
168 : : struct rte_crypto_sym_xform *xform,
169 : : struct rte_cryptodev_sym_session *session)
170 : : {
171 : 0 : struct mlx5_crypto_priv *priv = dev->data->dev_private;
172 : 0 : struct mlx5_crypto_session *sess_private_data = CRYPTODEV_GET_SYM_SESS_PRIV(session);
173 : : struct rte_crypto_aead_xform *aead = &xform->aead;
174 : : uint32_t op_type;
175 : :
176 [ # # ]: 0 : if (unlikely(xform->next != NULL)) {
177 : 0 : DRV_LOG(ERR, "Xform next is not supported.");
178 : 0 : return -ENOTSUP;
179 : : }
180 [ # # ]: 0 : if (aead->algo != RTE_CRYPTO_AEAD_AES_GCM) {
181 : 0 : DRV_LOG(ERR, "Only AES-GCM algorithm is supported.");
182 : 0 : return -ENOTSUP;
183 : : }
184 : :
185 [ # # ]: 0 : if (aead->op == RTE_CRYPTO_AEAD_OP_ENCRYPT)
186 : : op_type = MLX5_CRYPTO_OP_TYPE_ENCRYPTION;
187 : : else
188 : : op_type = MLX5_CRYPTO_OP_TYPE_DECRYPTION;
189 : 0 : sess_private_data->op_type = op_type;
190 [ # # ]: 0 : sess_private_data->mmo_ctrl = rte_cpu_to_be_32
191 : : (op_type << MLX5_CRYPTO_MMO_OP_OFFSET |
192 : : MLX5_ENCRYPTION_TYPE_AES_GCM << MLX5_CRYPTO_MMO_TYPE_OFFSET);
193 [ # # ]: 0 : sess_private_data->wqe_aad_len = rte_cpu_to_be_32((uint32_t)aead->aad_length);
194 [ # # ]: 0 : sess_private_data->wqe_tag_len = rte_cpu_to_be_32((uint32_t)aead->digest_length);
195 : 0 : sess_private_data->aad_len = aead->aad_length;
196 : 0 : sess_private_data->tag_len = aead->digest_length;
197 : 0 : sess_private_data->iv_offset = aead->iv.offset;
198 : 0 : sess_private_data->iv_len = aead->iv.length;
199 : 0 : sess_private_data->dek = mlx5_crypto_dek_prepare(priv, xform);
200 [ # # ]: 0 : if (sess_private_data->dek == NULL) {
201 : 0 : DRV_LOG(ERR, "Failed to prepare dek.");
202 : 0 : return -ENOMEM;
203 : : }
204 : 0 : sess_private_data->dek_id =
205 [ # # ]: 0 : rte_cpu_to_be_32(sess_private_data->dek->obj->id &
206 : : 0xffffff);
207 : 0 : DRV_LOG(DEBUG, "Session %p was configured.", sess_private_data);
208 : 0 : return 0;
209 : : }
210 : :
211 : : static void *
212 : 0 : mlx5_crypto_gcm_mkey_klm_update(struct mlx5_crypto_priv *priv,
213 : : struct mlx5_crypto_qp *qp __rte_unused,
214 : : uint32_t idx)
215 : : {
216 : 0 : return &qp->klm_array[idx * priv->max_klm_num];
217 : : }
218 : :
219 : : static int
220 : 0 : mlx5_crypto_gcm_qp_release(struct rte_cryptodev *dev, uint16_t qp_id)
221 : : {
222 : 0 : struct mlx5_crypto_qp *qp = dev->data->queue_pairs[qp_id];
223 : :
224 [ # # ]: 0 : if (qp->umr_qp_obj.qp != NULL)
225 : 0 : mlx5_devx_qp_destroy(&qp->umr_qp_obj);
226 [ # # ]: 0 : if (qp->qp_obj.qp != NULL)
227 : 0 : mlx5_devx_qp_destroy(&qp->qp_obj);
228 [ # # ]: 0 : if (qp->cq_obj.cq != NULL)
229 : 0 : mlx5_devx_cq_destroy(&qp->cq_obj);
230 [ # # ]: 0 : if (qp->mr.obj != NULL) {
231 : 0 : void *opaq = qp->mr.addr;
232 : :
233 : 0 : mlx5_os_dereg_mr(&qp->mr);
234 : 0 : rte_free(opaq);
235 : : }
236 : 0 : mlx5_crypto_indirect_mkeys_release(qp, qp->entries_n);
237 : 0 : mlx5_mr_btree_free(&qp->mr_ctrl.cache_bh);
238 : 0 : rte_free(qp->ipsec_mem);
239 : 0 : rte_free(qp);
240 : 0 : dev->data->queue_pairs[qp_id] = NULL;
241 : 0 : return 0;
242 : : }
243 : :
244 : : static void
245 : 0 : mlx5_crypto_gcm_init_qp(struct mlx5_crypto_qp *qp)
246 : : {
247 : 0 : volatile struct mlx5_gga_wqe *restrict wqe =
248 : : (volatile struct mlx5_gga_wqe *)qp->qp_obj.wqes;
249 : 0 : volatile union mlx5_gga_crypto_opaque *opaq = qp->opaque_addr;
250 [ # # ]: 0 : const uint32_t sq_ds = rte_cpu_to_be_32((qp->qp_obj.qp->id << 8) | 4u);
251 : : const uint32_t flags = RTE_BE32(MLX5_COMP_ALWAYS <<
252 : : MLX5_COMP_MODE_OFFSET);
253 [ # # ]: 0 : const uint32_t opaq_lkey = rte_cpu_to_be_32(qp->mr.lkey);
254 : : int i;
255 : :
256 : : /* All the next fields state should stay constant. */
257 [ # # ]: 0 : for (i = 0; i < qp->entries_n; ++i, ++wqe) {
258 : 0 : wqe->sq_ds = sq_ds;
259 : 0 : wqe->flags = flags;
260 : 0 : wqe->opaque_lkey = opaq_lkey;
261 : 0 : wqe->opaque_vaddr = rte_cpu_to_be_64((uint64_t)(uintptr_t)&opaq[i]);
262 : : }
263 : 0 : }
264 : :
265 : : static inline int
266 : 0 : mlx5_crypto_gcm_umr_qp_setup(struct rte_cryptodev *dev, struct mlx5_crypto_qp *qp,
267 : : int socket_id)
268 : : {
269 : 0 : struct mlx5_crypto_priv *priv = dev->data->dev_private;
270 : 0 : struct mlx5_devx_qp_attr attr = {0};
271 : : uint32_t ret;
272 : : uint32_t log_wqbb_n;
273 : :
274 : : /* Set UMR + SEND_EN WQE as maximum same with crypto. */
275 [ # # ]: 0 : log_wqbb_n = rte_log2_u32(qp->entries_n *
276 : : (MLX5_UMR_GCM_WQE_SET_SIZE / MLX5_SEND_WQE_BB));
277 : 0 : attr.pd = priv->cdev->pdn;
278 [ # # ]: 0 : attr.uar_index = mlx5_os_get_devx_uar_page_id(priv->uar.obj);
279 : 0 : attr.cqn = qp->cq_obj.cq->id;
280 : : attr.num_of_receive_wqes = 0;
281 : 0 : attr.num_of_send_wqbbs = RTE_BIT32(log_wqbb_n);
282 : 0 : attr.ts_format =
283 : 0 : mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
284 : 0 : attr.cd_master = 1;
285 : 0 : ret = mlx5_devx_qp_create(priv->cdev->ctx, &qp->umr_qp_obj,
286 : 0 : attr.num_of_send_wqbbs * MLX5_SEND_WQE_BB,
287 : : &attr, socket_id);
288 [ # # ]: 0 : if (ret) {
289 : 0 : DRV_LOG(ERR, "Failed to create UMR QP.");
290 : 0 : return -1;
291 : : }
292 [ # # ]: 0 : if (mlx5_devx_qp2rts(&qp->umr_qp_obj, qp->umr_qp_obj.qp->id)) {
293 : 0 : DRV_LOG(ERR, "Failed to change UMR QP state to RTS.");
294 : 0 : return -1;
295 : : }
296 : : /* Save the UMR WQEBBS for checking the WQE boundary. */
297 : 0 : qp->umr_wqbbs = attr.num_of_send_wqbbs;
298 : 0 : return 0;
299 : : }
300 : :
301 : : static int
302 : 0 : mlx5_crypto_gcm_qp_setup(struct rte_cryptodev *dev, uint16_t qp_id,
303 : : const struct rte_cryptodev_qp_conf *qp_conf,
304 : : int socket_id)
305 : : {
306 : 0 : struct mlx5_crypto_priv *priv = dev->data->dev_private;
307 : 0 : struct mlx5_hca_attr *attr = &priv->cdev->config.hca_attr;
308 : : struct mlx5_crypto_qp *qp;
309 : 0 : struct mlx5_devx_cq_attr cq_attr = {
310 [ # # ]: 0 : .uar_page_id = mlx5_os_get_devx_uar_page_id(priv->uar.obj),
311 : : };
312 : 0 : struct mlx5_devx_qp_attr qp_attr = {
313 : 0 : .pd = priv->cdev->pdn,
314 : 0 : .uar_index = mlx5_os_get_devx_uar_page_id(priv->uar.obj),
315 : : .user_index = qp_id,
316 : : };
317 : 0 : struct mlx5_devx_mkey_attr mkey_attr = {
318 : : .pd = priv->cdev->pdn,
319 : : .umr_en = 1,
320 : 0 : .klm_num = priv->max_klm_num,
321 : : };
322 [ # # ]: 0 : uint32_t log_ops_n = rte_log2_u32(qp_conf->nb_descriptors);
323 [ # # ]: 0 : uint32_t entries = RTE_BIT32(log_ops_n);
324 : : uint32_t alloc_size = sizeof(*qp);
325 : : uint32_t extra_obj_size = 0;
326 : : size_t mr_size, opaq_size;
327 : : void *mr_buf;
328 : : int ret;
329 : :
330 [ # # ]: 0 : if (!mlx5_crypto_is_ipsec_opt(priv))
331 : : extra_obj_size = sizeof(struct mlx5_devx_obj *);
332 : : alloc_size = RTE_ALIGN(alloc_size, RTE_CACHE_LINE_SIZE);
333 : 0 : alloc_size += (sizeof(struct rte_crypto_op *) +
334 : : extra_obj_size) * entries;
335 : 0 : qp = rte_zmalloc_socket(__func__, alloc_size, RTE_CACHE_LINE_SIZE,
336 : : socket_id);
337 [ # # ]: 0 : if (qp == NULL) {
338 : 0 : DRV_LOG(ERR, "Failed to allocate qp memory.");
339 : 0 : rte_errno = ENOMEM;
340 : 0 : return -rte_errno;
341 : : }
342 : 0 : qp->priv = priv;
343 : 0 : qp->entries_n = entries;
344 [ # # ]: 0 : if (mlx5_mr_ctrl_init(&qp->mr_ctrl, &priv->cdev->mr_scache.dev_gen,
345 : : priv->dev_config.socket_id)) {
346 : 0 : DRV_LOG(ERR, "Cannot allocate MR Btree for qp %u.",
347 : : (uint32_t)qp_id);
348 : 0 : rte_errno = ENOMEM;
349 : 0 : goto err;
350 : : }
351 : : /*
352 : : * The following KLM pointer must be aligned with
353 : : * MLX5_UMR_KLM_PTR_ALIGN. Aligned opaq_size here
354 : : * to make the KLM pointer with offset be aligned.
355 : : */
356 : 0 : opaq_size = RTE_ALIGN(sizeof(union mlx5_gga_crypto_opaque) * entries,
357 : : MLX5_UMR_KLM_PTR_ALIGN);
358 : 0 : mr_size = (priv->max_klm_num * sizeof(struct mlx5_klm) * entries) + opaq_size;
359 : 0 : mr_buf = rte_calloc(__func__, (size_t)1, mr_size, MLX5_UMR_KLM_PTR_ALIGN);
360 [ # # ]: 0 : if (mr_buf == NULL) {
361 : 0 : DRV_LOG(ERR, "Failed to allocate mr memory.");
362 : 0 : rte_errno = ENOMEM;
363 : 0 : goto err;
364 : : }
365 [ # # ]: 0 : if (mlx5_os_reg_mr(priv->cdev->pd, mr_buf, mr_size, &qp->mr) != 0) {
366 : 0 : rte_free(mr_buf);
367 : 0 : DRV_LOG(ERR, "Failed to register opaque MR.");
368 : 0 : rte_errno = ENOMEM;
369 : 0 : goto err;
370 : : }
371 : 0 : qp->opaque_addr = qp->mr.addr;
372 [ # # ]: 0 : qp->klm_array = RTE_PTR_ADD(qp->opaque_addr, opaq_size);
373 : : /*
374 : : * Triple the CQ size as UMR QP which contains UMR and SEND_EN WQE
375 : : * will share this CQ .
376 : : */
377 [ # # # # ]: 0 : qp->cq_entries_n = rte_align32pow2(entries * (mlx5_crypto_is_ipsec_opt(priv) ? 1 : 3));
378 : 0 : ret = mlx5_devx_cq_create(priv->cdev->ctx, &qp->cq_obj,
379 [ # # ]: 0 : rte_log2_u32(qp->cq_entries_n),
380 : : &cq_attr, socket_id);
381 [ # # ]: 0 : if (ret != 0) {
382 : 0 : DRV_LOG(ERR, "Failed to create CQ.");
383 : 0 : goto err;
384 : : }
385 : 0 : qp_attr.cqn = qp->cq_obj.cq->id;
386 : 0 : qp_attr.ts_format = mlx5_ts_format_conv(attr->qp_ts_format);
387 : 0 : qp_attr.num_of_receive_wqes = 0;
388 : 0 : qp_attr.num_of_send_wqbbs = entries;
389 : 0 : qp_attr.mmo = attr->crypto_mmo.crypto_mmo_qp;
390 : : /* Set MMO QP as follower as the input data may depend on UMR. */
391 : 0 : qp_attr.cd_slave_send = !mlx5_crypto_is_ipsec_opt(priv);
392 : 0 : ret = mlx5_devx_qp_create(priv->cdev->ctx, &qp->qp_obj,
393 : 0 : qp_attr.num_of_send_wqbbs * MLX5_WQE_SIZE,
394 : : &qp_attr, socket_id);
395 [ # # ]: 0 : if (ret != 0) {
396 : 0 : DRV_LOG(ERR, "Failed to create QP.");
397 : 0 : goto err;
398 : : }
399 : 0 : mlx5_crypto_gcm_init_qp(qp);
400 : 0 : ret = mlx5_devx_qp2rts(&qp->qp_obj, 0);
401 [ # # ]: 0 : if (ret)
402 : 0 : goto err;
403 [ # # ]: 0 : qp->ops = (struct rte_crypto_op **)(qp + 1);
404 [ # # ]: 0 : if (!mlx5_crypto_is_ipsec_opt(priv)) {
405 : 0 : qp->mkey = (struct mlx5_devx_obj **)(qp->ops + entries);
406 [ # # ]: 0 : if (mlx5_crypto_gcm_umr_qp_setup(dev, qp, socket_id)) {
407 : 0 : DRV_LOG(ERR, "Failed to setup UMR QP.");
408 : 0 : goto err;
409 : : }
410 : 0 : DRV_LOG(INFO, "QP %u: SQN=0x%X CQN=0x%X entries num = %u",
411 : : (uint32_t)qp_id, qp->qp_obj.qp->id, qp->cq_obj.cq->id, entries);
412 [ # # ]: 0 : if (mlx5_crypto_indirect_mkeys_prepare(priv, qp, &mkey_attr,
413 : : mlx5_crypto_gcm_mkey_klm_update)) {
414 : 0 : DRV_LOG(ERR, "Cannot allocate indirect memory regions.");
415 : 0 : rte_errno = ENOMEM;
416 : 0 : goto err;
417 : : }
418 : : } else {
419 : 0 : extra_obj_size = sizeof(struct mlx5_crypto_ipsec_mem) * entries;
420 : 0 : qp->ipsec_mem = rte_calloc(__func__, (size_t)1, extra_obj_size,
421 : : RTE_CACHE_LINE_SIZE);
422 [ # # ]: 0 : if (!qp->ipsec_mem) {
423 : 0 : DRV_LOG(ERR, "Failed to allocate ipsec_mem.");
424 : 0 : goto err;
425 : : }
426 : : }
427 : 0 : dev->data->queue_pairs[qp_id] = qp;
428 : 0 : return 0;
429 : 0 : err:
430 : 0 : mlx5_crypto_gcm_qp_release(dev, qp_id);
431 : 0 : return -1;
432 : : }
433 : :
434 : : static __rte_always_inline void
435 : : mlx5_crypto_gcm_get_op_info(struct mlx5_crypto_qp *qp,
436 : : struct rte_crypto_op *op,
437 : : struct mlx5_crypto_gcm_op_info *op_info)
438 : : {
439 : : struct mlx5_crypto_session *sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
440 : 0 : struct rte_mbuf *m_src = op->sym->m_src;
441 : 0 : void *aad_addr = op->sym->aead.aad.data;
442 : 0 : void *tag_addr = op->sym->aead.digest.data;
443 : 0 : void *src_addr = rte_pktmbuf_mtod_offset(m_src, void *, op->sym->aead.data.offset);
444 : : struct rte_mbuf *m_dst = m_src;
445 : : void *dst_addr = src_addr;
446 : : void *expected_aad = NULL;
447 : : void *expected_tag = NULL;
448 : 0 : bool is_enc = sess->op_type == MLX5_CRYPTO_OP_TYPE_ENCRYPTION;
449 : : bool cp_aad = false;
450 : : bool cp_tag = false;
451 : :
452 : : op_info->is_oop = false;
453 : : op_info->need_umr = false;
454 : : op_info->is_enc = is_enc;
455 : : op_info->digest = NULL;
456 : : op_info->src_addr = aad_addr;
457 [ # # ]: 0 : if (op->sym->m_dst && op->sym->m_dst != m_src) {
458 : : /* Add 2 for AAD and digest. */
459 : : MLX5_ASSERT((uint32_t)(m_dst->nb_segs + m_src->nb_segs + 2) <
460 : : qp->priv->max_klm_num);
461 : : op_info->is_oop = true;
462 : : m_dst = op->sym->m_dst;
463 : 0 : dst_addr = rte_pktmbuf_mtod_offset(m_dst, void *, op->sym->aead.data.offset);
464 [ # # ]: 0 : if (m_dst->nb_segs > 1) {
465 : : op_info->need_umr = true;
466 : : return;
467 : : }
468 : : /*
469 : : * If the op's mbuf has extra data offset, don't copy AAD to
470 : : * this area.
471 : : */
472 [ # # # # ]: 0 : if (rte_pktmbuf_headroom(m_dst) < sess->aad_len ||
473 : : op->sym->aead.data.offset) {
474 : : op_info->need_umr = true;
475 : : return;
476 : : }
477 : : } else {
478 : : /* Add 2 for AAD and digest. */
479 : : MLX5_ASSERT((uint32_t)(m_src->nb_segs) + 2 < qp->priv->max_klm_num);
480 : : }
481 [ # # ]: 0 : if (m_src->nb_segs > 1) {
482 : : op_info->need_umr = true;
483 : : return;
484 : : }
485 : 0 : expected_aad = RTE_PTR_SUB(src_addr, sess->aad_len);
486 [ # # ]: 0 : if (expected_aad != aad_addr) {
487 : : /*
488 : : * If the op's mbuf has extra data offset, don't copy AAD to
489 : : * this area.
490 : : */
491 [ # # # # ]: 0 : if (sess->aad_len > MLX5_CRYPTO_GCM_MAX_AAD ||
492 [ # # ]: 0 : sess->aad_len > rte_pktmbuf_headroom(m_src) ||
493 : : op->sym->aead.data.offset) {
494 : : op_info->need_umr = true;
495 : : return;
496 : : }
497 : : cp_aad = true;
498 : : op_info->src_addr = expected_aad;
499 : : }
500 [ # # ]: 0 : expected_tag = RTE_PTR_ADD(is_enc ? dst_addr : src_addr, op->sym->aead.data.length);
501 [ # # ]: 0 : if (expected_tag != tag_addr) {
502 [ # # ]: 0 : struct rte_mbuf *mbuf = is_enc ? m_dst : m_src;
503 : :
504 : : /*
505 : : * If op's mbuf is not fully set as payload, don't copy digest to
506 : : * the left area.
507 : : */
508 [ # # ]: 0 : if (rte_pktmbuf_tailroom(mbuf) < sess->tag_len ||
509 [ # # ]: 0 : rte_pktmbuf_data_len(mbuf) != op->sym->aead.data.length) {
510 : : op_info->need_umr = true;
511 : : return;
512 : : }
513 [ # # ]: 0 : if (is_enc) {
514 : : op_info->digest = expected_tag;
515 : 0 : qp->cpy_tag_op++;
516 : : } else {
517 : : cp_tag = true;
518 : : }
519 : : }
520 [ # # ]: 0 : if (cp_aad)
521 : : memcpy(expected_aad, aad_addr, sess->aad_len);
522 [ # # ]: 0 : if (cp_tag)
523 : 0 : memcpy(expected_tag, tag_addr, sess->tag_len);
524 : : }
525 : :
526 : : static __rte_always_inline uint32_t
527 : : _mlx5_crypto_gcm_umr_build_mbuf_klm(struct mlx5_crypto_qp *qp,
528 : : struct rte_mbuf *mbuf,
529 : : struct mlx5_klm *klm,
530 : : uint32_t offset,
531 : : uint32_t *remain)
532 : : {
533 : 0 : uint32_t data_len = (rte_pktmbuf_data_len(mbuf) - offset);
534 : 0 : uintptr_t addr = rte_pktmbuf_mtod_offset(mbuf, uintptr_t, offset);
535 : :
536 : : if (data_len > *remain)
537 : : data_len = *remain;
538 : 0 : *remain -= data_len;
539 : 0 : klm->byte_count = rte_cpu_to_be_32(data_len);
540 [ # # # # : 0 : klm->address = rte_cpu_to_be_64(addr);
# # # # #
# # # # #
# # ]
541 : 0 : klm->mkey = mlx5_mr_mb2mr(&qp->mr_ctrl, mbuf);
542 : : return klm->mkey;
543 : : }
544 : :
545 : : static __rte_always_inline int
546 : : mlx5_crypto_gcm_build_mbuf_chain_klms(struct mlx5_crypto_qp *qp,
547 : : struct rte_crypto_op *op,
548 : : struct rte_mbuf *mbuf,
549 : : struct mlx5_klm *klm)
550 : : {
551 : 0 : uint32_t remain_len = op->sym->aead.data.length;
552 : : __rte_unused uint32_t nb_segs = mbuf->nb_segs;
553 : : uint32_t klm_n = 0;
554 : :
555 : : /* mbuf seg num should be less than max_segs_num. */
556 : : MLX5_ASSERT(nb_segs <= qp->priv->max_segs_num);
557 : : /* First mbuf needs to take the data offset. */
558 [ # # # # ]: 0 : if (unlikely(_mlx5_crypto_gcm_umr_build_mbuf_klm(qp, mbuf, klm,
559 : : op->sym->aead.data.offset, &remain_len) == UINT32_MAX)) {
560 : 0 : op->status = RTE_CRYPTO_OP_STATUS_ERROR;
561 : 0 : return 0;
562 : : }
563 : 0 : klm++;
564 : : klm_n++;
565 [ # # # # ]: 0 : while (remain_len) {
566 : : nb_segs--;
567 [ # # # # ]: 0 : mbuf = mbuf->next;
568 : : MLX5_ASSERT(mbuf && nb_segs);
569 [ # # # # ]: 0 : if (unlikely(_mlx5_crypto_gcm_umr_build_mbuf_klm(qp, mbuf, klm,
570 : : 0, &remain_len) == UINT32_MAX)) {
571 : 0 : op->status = RTE_CRYPTO_OP_STATUS_ERROR;
572 : 0 : return 0;
573 : : }
574 : 0 : klm++;
575 : 0 : klm_n++;
576 : : }
577 : 0 : return klm_n;
578 : : }
579 : :
580 : : static __rte_always_inline int
581 : : mlx5_crypto_gcm_build_klm_by_addr(struct mlx5_crypto_qp *qp,
582 : : struct mlx5_klm *klm,
583 : : void *addr,
584 : : uint32_t len)
585 : : {
586 : 0 : klm->byte_count = rte_cpu_to_be_32(len);
587 : 0 : klm->address = rte_cpu_to_be_64((uintptr_t)addr);
588 : 0 : klm->mkey = mlx5_mr_addr2mr_bh(&qp->mr_ctrl, (uintptr_t)addr);
589 [ # # # # ]: 0 : if (klm->mkey == UINT32_MAX)
590 : : return 0;
591 : : return 1;
592 : : }
593 : :
594 : : static __rte_always_inline int
595 : : mlx5_crypto_gcm_build_op_klm(struct mlx5_crypto_qp *qp,
596 : : struct rte_crypto_op *op,
597 : : struct mlx5_crypto_gcm_op_info *op_info,
598 : : struct mlx5_klm *klm,
599 : : uint32_t *len)
600 : : {
601 : : struct mlx5_crypto_session *sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
602 : : struct mlx5_klm *digest = NULL, *aad = NULL;
603 : 0 : uint32_t total_len = op->sym->aead.data.length + sess->aad_len + sess->tag_len;
604 : : uint32_t klm_n = 0, klm_src = 0, klm_dst = 0;
605 : :
606 : : /* Build AAD KLM. */
607 : : aad = klm;
608 : 0 : if (!mlx5_crypto_gcm_build_klm_by_addr(qp, aad, op->sym->aead.aad.data, sess->aad_len))
609 : : return 0;
610 : : klm_n++;
611 : : /* Build src mubf KLM. */
612 [ # # ]: 0 : klm_src = mlx5_crypto_gcm_build_mbuf_chain_klms(qp, op, op->sym->m_src, &klm[klm_n]);
613 [ # # ]: 0 : if (!klm_src)
614 : : return 0;
615 : 0 : klm_n += klm_src;
616 : : /* Reserve digest KLM if needed. */
617 [ # # ]: 0 : if (!op_info->is_oop ||
618 [ # # ]: 0 : sess->op_type == MLX5_CRYPTO_OP_TYPE_DECRYPTION) {
619 : 0 : digest = &klm[klm_n];
620 : 0 : klm_n++;
621 : : }
622 : : /* Build dst mbuf KLM. */
623 [ # # ]: 0 : if (op_info->is_oop) {
624 : 0 : klm[klm_n] = *aad;
625 : 0 : klm_n++;
626 : 0 : klm_dst = mlx5_crypto_gcm_build_mbuf_chain_klms(qp, op, op->sym->m_dst,
627 [ # # ]: 0 : &klm[klm_n]);
628 [ # # ]: 0 : if (!klm_dst)
629 : : return 0;
630 : 0 : klm_n += klm_dst;
631 : 0 : total_len += (op->sym->aead.data.length + sess->aad_len);
632 : : }
633 : : /* Update digest at the end if it is not set. */
634 [ # # ]: 0 : if (!digest) {
635 : 0 : digest = &klm[klm_n];
636 : 0 : klm_n++;
637 : : }
638 : : /* Build digest KLM. */
639 : 0 : if (!mlx5_crypto_gcm_build_klm_by_addr(qp, digest, op->sym->aead.digest.data,
640 [ # # ]: 0 : sess->tag_len))
641 : : return 0;
642 : : *len = total_len;
643 : 0 : return klm_n;
644 : : }
645 : :
646 : : static __rte_always_inline struct mlx5_wqe_cseg *
647 : : mlx5_crypto_gcm_get_umr_wqe(struct mlx5_crypto_qp *qp)
648 : : {
649 : 0 : uint32_t wqe_offset = qp->umr_pi & (qp->umr_wqbbs - 1);
650 : 0 : uint32_t left_wqbbs = qp->umr_wqbbs - wqe_offset;
651 : : struct mlx5_wqe_cseg *wqe;
652 : :
653 : : /* If UMR WQE is near the boundary. */
654 : 0 : if (left_wqbbs < MLX5_UMR_GCM_WQE_STRIDE) {
655 : : /* Append NOP WQE as the left WQEBBS is not enough for UMR. */
656 : 0 : wqe = RTE_PTR_ADD(qp->umr_qp_obj.umem_buf, wqe_offset * MLX5_SEND_WQE_BB);
657 [ # # ]: 0 : wqe->opcode = rte_cpu_to_be_32(MLX5_OPCODE_NOP | ((uint32_t)qp->umr_pi << 8));
658 [ # # ]: 0 : wqe->sq_ds = rte_cpu_to_be_32((qp->umr_qp_obj.qp->id << 8) | (left_wqbbs << 2));
659 : 0 : wqe->flags = RTE_BE32(0);
660 : 0 : wqe->misc = RTE_BE32(0);
661 : 0 : qp->umr_pi += left_wqbbs;
662 : 0 : wqe_offset = qp->umr_pi & (qp->umr_wqbbs - 1);
663 : : }
664 : 0 : wqe_offset *= MLX5_SEND_WQE_BB;
665 [ # # ]: 0 : return RTE_PTR_ADD(qp->umr_qp_obj.umem_buf, wqe_offset);
666 : : }
667 : :
668 : : static __rte_always_inline int
669 : : mlx5_crypto_gcm_build_umr(struct mlx5_crypto_qp *qp,
670 : : struct rte_crypto_op *op,
671 : : uint32_t idx,
672 : : struct mlx5_crypto_gcm_op_info *op_info,
673 : : struct mlx5_crypto_gcm_data *data)
674 : : {
675 : 0 : struct mlx5_crypto_priv *priv = qp->priv;
676 : 0 : struct mlx5_crypto_session *sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
677 : : struct mlx5_wqe_cseg *wqe;
678 : : struct mlx5_wqe_umr_cseg *ucseg;
679 : : struct mlx5_wqe_mkey_cseg *mkc;
680 : : struct mlx5_klm *iklm;
681 [ # # ]: 0 : struct mlx5_klm *klm = &qp->klm_array[idx * priv->max_klm_num];
682 : : uint16_t klm_size, klm_align;
683 : : uint32_t total_len;
684 : :
685 : : /* Build KLM base on the op. */
686 : 0 : klm_size = mlx5_crypto_gcm_build_op_klm(qp, op, op_info, klm, &total_len);
687 [ # # ]: 0 : if (!klm_size)
688 : : return -EINVAL;
689 [ # # ]: 0 : klm_align = RTE_ALIGN(klm_size, 4);
690 : : /* Get UMR WQE memory. */
691 : : wqe = mlx5_crypto_gcm_get_umr_wqe(qp);
692 : : memset(wqe, 0, MLX5_UMR_GCM_WQE_SIZE);
693 : : /* Set WQE control seg. Non-inline KLM UMR WQE size must be 9 WQE_DS. */
694 [ # # ]: 0 : wqe->opcode = rte_cpu_to_be_32(MLX5_OPCODE_UMR | ((uint32_t)qp->umr_pi << 8));
695 [ # # ]: 0 : wqe->sq_ds = rte_cpu_to_be_32((qp->umr_qp_obj.qp->id << 8) | 9);
696 : 0 : wqe->flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR << MLX5_COMP_MODE_OFFSET);
697 [ # # ]: 0 : wqe->misc = rte_cpu_to_be_32(qp->mkey[idx]->id);
698 : : /* Set UMR WQE control seg. */
699 : : ucseg = (struct mlx5_wqe_umr_cseg *)(wqe + 1);
700 : 0 : ucseg->mkey_mask |= RTE_BE64(1u << 0);
701 [ # # ]: 0 : ucseg->ko_to_bs = rte_cpu_to_be_32(klm_align << MLX5_UMRC_KO_OFFSET);
702 : : /* Set mkey context seg. */
703 : : mkc = (struct mlx5_wqe_mkey_cseg *)(ucseg + 1);
704 [ # # ]: 0 : mkc->len = rte_cpu_to_be_64(total_len);
705 [ # # ]: 0 : mkc->qpn_mkey = rte_cpu_to_be_32(0xffffff00 | (qp->mkey[idx]->id & 0xff));
706 : : /* Set UMR pointer to data seg. */
707 : : iklm = (struct mlx5_klm *)(mkc + 1);
708 : 0 : iklm->address = rte_cpu_to_be_64((uintptr_t)((char *)klm));
709 [ # # ]: 0 : iklm->mkey = rte_cpu_to_be_32(qp->mr.lkey);
710 [ # # ]: 0 : data->src_mkey = rte_cpu_to_be_32(qp->mkey[idx]->id);
711 : : data->dst_mkey = data->src_mkey;
712 : : data->src_addr = 0;
713 : 0 : data->src_bytes = sess->aad_len + op->sym->aead.data.length;
714 : : data->dst_bytes = data->src_bytes;
715 [ # # ]: 0 : if (op_info->is_enc)
716 : 0 : data->dst_bytes += sess->tag_len;
717 : : else
718 : 0 : data->src_bytes += sess->tag_len;
719 [ # # ]: 0 : if (op_info->is_oop)
720 : 0 : data->dst_addr = (void *)(uintptr_t)(data->src_bytes);
721 : : else
722 : : data->dst_addr = 0;
723 : : /* Clear the padding memory. */
724 : 0 : memset(&klm[klm_size], 0, sizeof(struct mlx5_klm) * (klm_align - klm_size));
725 : : /* Update PI and WQE */
726 : 0 : qp->umr_pi += MLX5_UMR_GCM_WQE_STRIDE;
727 : 0 : qp->umr_wqe = (uint8_t *)wqe;
728 : 0 : return 0;
729 : : }
730 : :
731 : : static __rte_always_inline void
732 : : mlx5_crypto_gcm_build_send_en(struct mlx5_crypto_qp *qp)
733 : : {
734 : 0 : uint32_t wqe_offset = (qp->umr_pi & (qp->umr_wqbbs - 1)) * MLX5_SEND_WQE_BB;
735 : 0 : struct mlx5_wqe_cseg *cs = RTE_PTR_ADD(qp->umr_qp_obj.wqes, wqe_offset);
736 : 0 : struct mlx5_wqe_qseg *qs = RTE_PTR_ADD(cs, sizeof(struct mlx5_wqe_cseg));
737 : :
738 [ # # ]: 0 : cs->opcode = rte_cpu_to_be_32(MLX5_OPCODE_SEND_EN | ((uint32_t)qp->umr_pi << 8));
739 [ # # ]: 0 : cs->sq_ds = rte_cpu_to_be_32((qp->umr_qp_obj.qp->id << 8) | 2);
740 : : /*
741 : : * No need to generate the SEND_EN CQE as we want only GGA CQE
742 : : * in the CQ normally. We can compare qp->last_send_gga_pi with
743 : : * qp->pi to know if all SEND_EN be consumed.
744 : : */
745 : 0 : cs->flags = RTE_BE32((MLX5_COMP_ONLY_FIRST_ERR << MLX5_COMP_MODE_OFFSET) |
746 : : MLX5_WQE_CTRL_INITIATOR_SMALL_FENCE);
747 : 0 : cs->misc = RTE_BE32(0);
748 [ # # ]: 0 : qs->max_index = rte_cpu_to_be_32(qp->pi);
749 [ # # ]: 0 : qs->qpn_cqn = rte_cpu_to_be_32(qp->qp_obj.qp->id);
750 : 0 : qp->umr_wqe = (uint8_t *)cs;
751 : 0 : qp->umr_pi += 1;
752 : : }
753 : :
754 : : static __rte_always_inline void
755 : : mlx5_crypto_gcm_wqe_set(struct mlx5_crypto_qp *qp,
756 : : struct rte_crypto_op *op,
757 : : uint32_t idx,
758 : : struct mlx5_crypto_gcm_data *data)
759 : : {
760 : 0 : struct mlx5_crypto_session *sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
761 : 0 : struct mlx5_gga_wqe *wqe = &((struct mlx5_gga_wqe *)qp->qp_obj.wqes)[idx];
762 : 0 : union mlx5_gga_crypto_opaque *opaq = qp->opaque_addr;
763 : :
764 : 0 : memcpy(opaq[idx].cp.iv,
765 [ # # # # ]: 0 : rte_crypto_op_ctod_offset(op, uint8_t *, sess->iv_offset), sess->iv_len);
766 : 0 : opaq[idx].cp.tag_size = sess->wqe_tag_len;
767 : 0 : opaq[idx].cp.aad_size = sess->wqe_aad_len;
768 : : /* Update control seg. */
769 [ # # # # ]: 0 : wqe->opcode = rte_cpu_to_be_32(MLX5_MMO_CRYPTO_OPC + (qp->pi << 8));
770 : 0 : wqe->gga_ctrl1 = sess->mmo_ctrl;
771 : 0 : wqe->gga_ctrl2 = sess->dek_id;
772 : 0 : wqe->flags = RTE_BE32(MLX5_COMP_ONLY_FIRST_ERR << MLX5_COMP_MODE_OFFSET);
773 : : /* Update op_info seg. */
774 [ # # # # ]: 0 : wqe->gather.bcount = rte_cpu_to_be_32(data->src_bytes);
775 : 0 : wqe->gather.lkey = data->src_mkey;
776 : 0 : wqe->gather.pbuf = rte_cpu_to_be_64((uintptr_t)data->src_addr);
777 : : /* Update output seg. */
778 [ # # # # ]: 0 : wqe->scatter.bcount = rte_cpu_to_be_32(data->dst_bytes);
779 : 0 : wqe->scatter.lkey = data->dst_mkey;
780 : 0 : wqe->scatter.pbuf = rte_cpu_to_be_64((uintptr_t)data->dst_addr);
781 : 0 : qp->wqe = (uint8_t *)wqe;
782 : : }
783 : :
784 : : static uint16_t
785 : 0 : mlx5_crypto_gcm_enqueue_burst(void *queue_pair,
786 : : struct rte_crypto_op **ops,
787 : : uint16_t nb_ops)
788 : : {
789 : : struct mlx5_crypto_qp *qp = queue_pair;
790 : : struct mlx5_crypto_session *sess;
791 : 0 : struct mlx5_crypto_priv *priv = qp->priv;
792 : : struct mlx5_crypto_gcm_tag_cpy_info *tag;
793 : : struct mlx5_crypto_gcm_data gcm_data;
794 : : struct rte_crypto_op *op;
795 : : struct mlx5_crypto_gcm_op_info op_info;
796 : 0 : uint16_t mask = qp->entries_n - 1;
797 : 0 : uint16_t remain = qp->entries_n - (qp->pi - qp->qp_ci);
798 : : uint32_t idx;
799 : : uint16_t umr_cnt = 0;
800 : :
801 : : if (remain < nb_ops)
802 : : nb_ops = remain;
803 : : else
804 : : remain = nb_ops;
805 [ # # ]: 0 : if (unlikely(remain == 0))
806 : : return 0;
807 : : do {
808 : 0 : op = *ops++;
809 : 0 : sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
810 [ # # ]: 0 : idx = qp->pi & mask;
811 : : mlx5_crypto_gcm_get_op_info(qp, op, &op_info);
812 [ # # ]: 0 : if (!op_info.need_umr) {
813 : : gcm_data.src_addr = op_info.src_addr;
814 : 0 : gcm_data.src_bytes = op->sym->aead.data.length + sess->aad_len;
815 [ # # ]: 0 : gcm_data.src_mkey = mlx5_mr_mb2mr(&qp->mr_ctrl, op->sym->m_src);
816 [ # # ]: 0 : if (op_info.is_oop) {
817 [ # # ]: 0 : gcm_data.dst_addr = RTE_PTR_SUB
818 : : (rte_pktmbuf_mtod_offset(op->sym->m_dst,
819 : : void *, op->sym->aead.data.offset), sess->aad_len);
820 : : gcm_data.dst_mkey = mlx5_mr_mb2mr(&qp->mr_ctrl, op->sym->m_dst);
821 : : } else {
822 : : gcm_data.dst_addr = gcm_data.src_addr;
823 : : gcm_data.dst_mkey = gcm_data.src_mkey;
824 : : }
825 : : gcm_data.dst_bytes = gcm_data.src_bytes;
826 [ # # ]: 0 : if (op_info.is_enc)
827 : 0 : gcm_data.dst_bytes += sess->tag_len;
828 : : else
829 : 0 : gcm_data.src_bytes += sess->tag_len;
830 : : } else {
831 [ # # ]: 0 : if (unlikely(mlx5_crypto_gcm_build_umr(qp, op, idx,
832 : : &op_info, &gcm_data))) {
833 : 0 : qp->stats.enqueue_err_count++;
834 [ # # ]: 0 : if (remain != nb_ops) {
835 : 0 : qp->stats.enqueued_count -= remain;
836 : 0 : break;
837 : : }
838 : : return 0;
839 : : }
840 : 0 : umr_cnt++;
841 : : }
842 : : mlx5_crypto_gcm_wqe_set(qp, op, idx, &gcm_data);
843 [ # # ]: 0 : if (op_info.digest) {
844 : 0 : tag = (struct mlx5_crypto_gcm_tag_cpy_info *)op->sym->aead.digest.data;
845 : 0 : tag->digest = op_info.digest;
846 : 0 : tag->tag_len = sess->tag_len;
847 : 0 : op->status = MLX5_CRYPTO_OP_STATUS_GCM_TAG_COPY;
848 : : } else {
849 : 0 : op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
850 : : }
851 : 0 : qp->ops[idx] = op;
852 : 0 : qp->pi++;
853 [ # # ]: 0 : } while (--remain);
854 : 0 : qp->stats.enqueued_count += nb_ops;
855 : : /* Update the last GGA cseg with COMP. */
856 : 0 : ((struct mlx5_wqe_cseg *)qp->wqe)->flags =
857 : : RTE_BE32(MLX5_COMP_ALWAYS << MLX5_COMP_MODE_OFFSET);
858 : : /* Only when there are no pending SEND_EN WQEs in background. */
859 [ # # # # ]: 0 : if (!umr_cnt && !qp->has_umr) {
860 : 0 : mlx5_doorbell_ring(&priv->uar.bf_db, *(volatile uint64_t *)qp->wqe,
861 : 0 : qp->pi, &qp->qp_obj.db_rec[MLX5_SND_DBR],
862 : 0 : !priv->uar.dbnc);
863 : : } else {
864 : : mlx5_crypto_gcm_build_send_en(qp);
865 : 0 : mlx5_doorbell_ring(&priv->uar.bf_db, *(volatile uint64_t *)qp->umr_wqe,
866 : 0 : qp->umr_pi, &qp->umr_qp_obj.db_rec[MLX5_SND_DBR],
867 : 0 : !priv->uar.dbnc);
868 : 0 : qp->last_gga_pi = qp->pi;
869 : 0 : qp->has_umr = true;
870 : : }
871 : : return nb_ops;
872 : : }
873 : :
874 : : static __rte_noinline void
875 : 0 : mlx5_crypto_gcm_cqe_err_handle(struct mlx5_crypto_qp *qp, struct rte_crypto_op *op)
876 : : {
877 : : uint8_t op_code;
878 : 0 : const uint32_t idx = qp->cq_ci & (qp->entries_n - 1);
879 : 0 : volatile struct mlx5_error_cqe *cqe = (volatile struct mlx5_error_cqe *)
880 : 0 : &qp->cq_obj.cqes[idx];
881 : :
882 : 0 : op_code = rte_be_to_cpu_32(cqe->s_wqe_opcode_qpn) >> MLX5_CQ_INDEX_WIDTH;
883 : 0 : DRV_LOG(ERR, "CQE ERR:0x%x, Vendor_ERR:0x%x, OP:0x%x, QPN:0x%x, WQE_CNT:0x%x",
884 : : cqe->syndrome, cqe->vendor_err_synd, op_code,
885 : : (rte_be_to_cpu_32(cqe->s_wqe_opcode_qpn) & 0xffffff),
886 : : rte_be_to_cpu_16(cqe->wqe_counter));
887 [ # # ]: 0 : if (op && op_code == MLX5_OPCODE_MMO) {
888 : 0 : op->status = RTE_CRYPTO_OP_STATUS_ERROR;
889 : 0 : qp->stats.dequeue_err_count++;
890 : : }
891 : 0 : }
892 : :
893 : : static __rte_always_inline void
894 : : mlx5_crypto_gcm_fill_op(struct mlx5_crypto_qp *qp,
895 : : struct rte_crypto_op **ops,
896 : : uint16_t orci,
897 : : uint16_t rci,
898 : : uint16_t op_mask)
899 : : {
900 : : uint16_t n;
901 : :
902 : 0 : orci &= op_mask;
903 : 0 : rci &= op_mask;
904 : 0 : if (unlikely(orci > rci)) {
905 : 0 : n = op_mask - orci + 1;
906 : 0 : memcpy(ops, &qp->ops[orci], n * sizeof(*ops));
907 : : orci = 0;
908 : : } else {
909 : : n = 0;
910 : : }
911 : : /* rci can be 0 here, memcpy will skip that. */
912 : 0 : memcpy(&ops[n], &qp->ops[orci], (rci - orci) * sizeof(*ops));
913 : : }
914 : :
915 : : static __rte_always_inline void
916 : : mlx5_crypto_gcm_cpy_tag(struct mlx5_crypto_qp *qp,
917 : : uint16_t orci,
918 : : uint16_t rci,
919 : : uint16_t op_mask)
920 : : {
921 : : struct rte_crypto_op *op;
922 : : struct mlx5_crypto_gcm_tag_cpy_info *tag;
923 : :
924 [ # # # # ]: 0 : while (qp->cpy_tag_op && orci != rci) {
925 : 0 : op = qp->ops[orci & op_mask];
926 [ # # ]: 0 : if (op->status == MLX5_CRYPTO_OP_STATUS_GCM_TAG_COPY) {
927 : 0 : tag = (struct mlx5_crypto_gcm_tag_cpy_info *)op->sym->aead.digest.data;
928 : 0 : memcpy(op->sym->aead.digest.data, tag->digest, tag->tag_len);
929 : 0 : op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
930 : 0 : qp->cpy_tag_op--;
931 : : }
932 : 0 : orci++;
933 : : }
934 : : }
935 : :
936 : : static uint16_t
937 : 0 : mlx5_crypto_gcm_dequeue_burst(void *queue_pair,
938 : : struct rte_crypto_op **ops,
939 : : uint16_t nb_ops)
940 : : {
941 : : struct mlx5_crypto_qp *qp = queue_pair;
942 : : volatile struct mlx5_cqe *restrict cqe;
943 : 0 : const unsigned int cq_size = qp->cq_entries_n;
944 : 0 : const unsigned int mask = cq_size - 1;
945 : 0 : const unsigned int op_mask = qp->entries_n - 1;
946 : : uint32_t idx;
947 : 0 : uint32_t next_idx = qp->cq_ci & mask;
948 : 0 : uint16_t reported_ci = qp->reported_ci;
949 : 0 : uint16_t qp_ci = qp->qp_ci;
950 : 0 : const uint16_t max = RTE_MIN((uint16_t)(qp->pi - reported_ci), nb_ops);
951 : : uint16_t op_num = 0;
952 : : int ret;
953 : :
954 [ # # ]: 0 : if (unlikely(max == 0))
955 : : return 0;
956 [ # # ]: 0 : while (qp_ci - reported_ci < max) {
957 : : idx = next_idx;
958 : 0 : next_idx = (qp->cq_ci + 1) & mask;
959 [ # # ]: 0 : cqe = &qp->cq_obj.cqes[idx];
960 : : ret = check_cqe(cqe, cq_size, qp->cq_ci);
961 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
962 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_HW_OWN))
963 : 0 : mlx5_crypto_gcm_cqe_err_handle(qp,
964 : 0 : qp->ops[reported_ci & op_mask]);
965 : : break;
966 : : }
967 : 0 : qp_ci = rte_be_to_cpu_16(cqe->wqe_counter) + 1;
968 [ # # ]: 0 : if (qp->has_umr &&
969 [ # # ]: 0 : (qp->last_gga_pi + 1) == qp_ci)
970 : 0 : qp->has_umr = false;
971 : 0 : qp->cq_ci++;
972 : : }
973 : : /* If wqe_counter changed, means CQE handled. */
974 [ # # ]: 0 : if (likely(qp->qp_ci != qp_ci)) {
975 : 0 : qp->qp_ci = qp_ci;
976 : 0 : rte_io_wmb();
977 [ # # ]: 0 : qp->cq_obj.db_rec[0] = rte_cpu_to_be_32(qp->cq_ci);
978 : : }
979 : : /* If reported_ci is not same with qp_ci, means op retrieved. */
980 [ # # ]: 0 : if (qp_ci != reported_ci) {
981 : 0 : op_num = RTE_MIN((uint16_t)(qp_ci - reported_ci), max);
982 : 0 : reported_ci += op_num;
983 : 0 : mlx5_crypto_gcm_cpy_tag(qp, qp->reported_ci, reported_ci, op_mask);
984 [ # # ]: 0 : mlx5_crypto_gcm_fill_op(qp, ops, qp->reported_ci, reported_ci, op_mask);
985 : 0 : qp->stats.dequeued_count += op_num;
986 : 0 : qp->reported_ci = reported_ci;
987 : : }
988 : : return op_num;
989 : : }
990 : :
991 : : static uint16_t
992 : 0 : mlx5_crypto_gcm_ipsec_enqueue_burst(void *queue_pair,
993 : : struct rte_crypto_op **ops,
994 : : uint16_t nb_ops)
995 : : {
996 : : struct mlx5_crypto_qp *qp = queue_pair;
997 : : struct mlx5_crypto_session *sess;
998 : 0 : struct mlx5_crypto_priv *priv = qp->priv;
999 : : struct mlx5_crypto_gcm_data gcm_data;
1000 : : struct rte_crypto_op *op;
1001 : : struct rte_mbuf *m_src;
1002 : : struct rte_mbuf *m_dst;
1003 : 0 : uint16_t mask = qp->entries_n - 1;
1004 : 0 : uint16_t remain = qp->entries_n - (qp->pi - qp->qp_ci);
1005 : : uint32_t idx;
1006 : : uint32_t pkt_iv_len;
1007 : : uint8_t *payload;
1008 : :
1009 : : if (remain < nb_ops)
1010 : : nb_ops = remain;
1011 : : else
1012 : : remain = nb_ops;
1013 [ # # ]: 0 : if (unlikely(remain == 0))
1014 : : return 0;
1015 : : do {
1016 : 0 : op = *ops++;
1017 : 0 : sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
1018 : 0 : idx = qp->pi & mask;
1019 : 0 : m_src = op->sym->m_src;
1020 : : MLX5_ASSERT(m_src->nb_segs == 1);
1021 : 0 : payload = rte_pktmbuf_mtod_offset(m_src, void *, op->sym->aead.data.offset);
1022 : 0 : gcm_data.src_addr = RTE_PTR_SUB(payload, sess->aad_len);
1023 : : /*
1024 : : * IPsec IV between payload and AAD should be equal or less than
1025 : : * MLX5_CRYPTO_GCM_IPSEC_IV_SIZE.
1026 : : */
1027 : 0 : pkt_iv_len = RTE_PTR_DIFF(payload,
1028 : : RTE_PTR_ADD(op->sym->aead.aad.data, sess->aad_len));
1029 : : MLX5_ASSERT(pkt_iv_len <= MLX5_CRYPTO_GCM_IPSEC_IV_SIZE);
1030 : 0 : gcm_data.src_bytes = op->sym->aead.data.length + sess->aad_len;
1031 [ # # ]: 0 : gcm_data.src_mkey = mlx5_mr_mb2mr(&qp->mr_ctrl, op->sym->m_src);
1032 : 0 : m_dst = op->sym->m_dst;
1033 [ # # ]: 0 : if (m_dst && m_dst != m_src) {
1034 : : MLX5_ASSERT(m_dst->nb_segs == 1 &&
1035 : : (rte_pktmbuf_headroom(m_dst) + op->sym->aead.data.offset)
1036 : : >= sess->aad_len + pkt_iv_len);
1037 [ # # ]: 0 : gcm_data.dst_addr = RTE_PTR_SUB
1038 : : (rte_pktmbuf_mtod_offset(m_dst,
1039 : : void *, op->sym->aead.data.offset), sess->aad_len);
1040 : : gcm_data.dst_mkey = mlx5_mr_mb2mr(&qp->mr_ctrl, m_dst);
1041 : : } else {
1042 : : gcm_data.dst_addr = gcm_data.src_addr;
1043 : : gcm_data.dst_mkey = gcm_data.src_mkey;
1044 : : }
1045 : : gcm_data.dst_bytes = gcm_data.src_bytes;
1046 : : /* Digest should follow payload. */
1047 [ # # ]: 0 : if (sess->op_type == MLX5_CRYPTO_OP_TYPE_ENCRYPTION) {
1048 : : MLX5_ASSERT(RTE_PTR_ADD(gcm_data.dst_addr,
1049 : : sess->aad_len + op->sym->aead.data.length) ==
1050 : : op->sym->aead.digest.data);
1051 : 0 : gcm_data.dst_bytes += sess->tag_len;
1052 : : } else {
1053 : : MLX5_ASSERT(RTE_PTR_ADD(gcm_data.src_addr,
1054 : : sess->aad_len + op->sym->aead.data.length) ==
1055 : : op->sym->aead.digest.data);
1056 : 0 : gcm_data.src_bytes += sess->tag_len;
1057 : : }
1058 : : mlx5_crypto_gcm_wqe_set(qp, op, idx, &gcm_data);
1059 : : /*
1060 : : * All the data such as IV have been copied above,
1061 : : * shrink AAD before payload. First backup the mem,
1062 : : * then do shrink.
1063 : : */
1064 : 0 : rte_memcpy(&qp->ipsec_mem[idx],
1065 [ # # ]: 0 : RTE_PTR_SUB(payload, MLX5_CRYPTO_GCM_IPSEC_IV_SIZE),
1066 : : MLX5_CRYPTO_GCM_IPSEC_IV_SIZE);
1067 : : /* If no memory overlap, do copy directly, otherwise memmove. */
1068 [ # # ]: 0 : if (likely(pkt_iv_len >= sess->aad_len))
1069 [ # # ]: 0 : rte_memcpy(gcm_data.src_addr, op->sym->aead.aad.data, sess->aad_len);
1070 : : else
1071 : 0 : memmove(gcm_data.src_addr, op->sym->aead.aad.data, sess->aad_len);
1072 : 0 : op->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
1073 : 0 : qp->ops[idx] = op;
1074 : 0 : qp->pi++;
1075 [ # # ]: 0 : } while (--remain);
1076 : 0 : qp->stats.enqueued_count += nb_ops;
1077 : : /* Update the last GGA cseg with COMP. */
1078 : 0 : ((struct mlx5_wqe_cseg *)qp->wqe)->flags =
1079 : : RTE_BE32(MLX5_COMP_ALWAYS << MLX5_COMP_MODE_OFFSET);
1080 : 0 : mlx5_doorbell_ring(&priv->uar.bf_db, *(volatile uint64_t *)qp->wqe,
1081 : 0 : qp->pi, &qp->qp_obj.db_rec[MLX5_SND_DBR],
1082 : 0 : !priv->uar.dbnc);
1083 : : return nb_ops;
1084 : : }
1085 : :
1086 : : static __rte_always_inline void
1087 : : mlx5_crypto_gcm_restore_ipsec_mem(struct mlx5_crypto_qp *qp,
1088 : : uint16_t orci,
1089 : : uint16_t rci,
1090 : : uint16_t op_mask)
1091 : : {
1092 : : uint32_t idx;
1093 : : struct mlx5_crypto_session *sess;
1094 : : struct rte_crypto_op *op;
1095 : : struct rte_mbuf *m_src;
1096 : : struct rte_mbuf *m_dst;
1097 : : uint8_t *payload;
1098 : :
1099 [ # # ]: 0 : while (orci != rci) {
1100 : 0 : idx = orci & op_mask;
1101 : 0 : op = qp->ops[idx];
1102 : 0 : sess = CRYPTODEV_GET_SYM_SESS_PRIV(op->sym->session);
1103 : 0 : m_src = op->sym->m_src;
1104 : 0 : payload = rte_pktmbuf_mtod_offset(m_src, void *,
1105 : : op->sym->aead.data.offset);
1106 : : /* Restore the IPsec memory. */
1107 [ # # ]: 0 : if (unlikely(sess->aad_len > MLX5_CRYPTO_GCM_IPSEC_IV_SIZE))
1108 : 0 : memmove(op->sym->aead.aad.data,
1109 : 0 : RTE_PTR_SUB(payload, sess->aad_len), sess->aad_len);
1110 : 0 : rte_memcpy(RTE_PTR_SUB(payload, MLX5_CRYPTO_GCM_IPSEC_IV_SIZE),
1111 [ # # ]: 0 : &qp->ipsec_mem[idx], MLX5_CRYPTO_GCM_IPSEC_IV_SIZE);
1112 : 0 : m_dst = op->sym->m_dst;
1113 [ # # ]: 0 : if (m_dst && m_dst != m_src) {
1114 : : uint32_t bytes_to_copy;
1115 : :
1116 : 0 : bytes_to_copy = RTE_PTR_DIFF(payload, op->sym->aead.aad.data);
1117 [ # # ]: 0 : rte_memcpy(RTE_PTR_SUB(rte_pktmbuf_mtod_offset(m_dst, void *,
1118 : : op->sym->aead.data.offset), bytes_to_copy),
1119 : : op->sym->aead.aad.data,
1120 : : bytes_to_copy);
1121 : : }
1122 : 0 : orci++;
1123 : : }
1124 : : }
1125 : :
1126 : : static uint16_t
1127 : 0 : mlx5_crypto_gcm_ipsec_dequeue_burst(void *queue_pair,
1128 : : struct rte_crypto_op **ops,
1129 : : uint16_t nb_ops)
1130 : : {
1131 : : struct mlx5_crypto_qp *qp = queue_pair;
1132 : : volatile struct mlx5_cqe *restrict cqe;
1133 : 0 : const unsigned int cq_size = qp->cq_entries_n;
1134 : 0 : const unsigned int mask = cq_size - 1;
1135 : 0 : const unsigned int op_mask = qp->entries_n - 1;
1136 : : uint32_t idx;
1137 : 0 : uint32_t next_idx = qp->cq_ci & mask;
1138 : 0 : uint16_t reported_ci = qp->reported_ci;
1139 : 0 : uint16_t qp_ci = qp->qp_ci;
1140 : 0 : const uint16_t max = RTE_MIN((uint16_t)(qp->pi - reported_ci), nb_ops);
1141 : : uint16_t op_num = 0;
1142 : : int ret;
1143 : :
1144 [ # # ]: 0 : if (unlikely(max == 0))
1145 : : return 0;
1146 [ # # ]: 0 : while (qp_ci - reported_ci < max) {
1147 : : idx = next_idx;
1148 : 0 : next_idx = (qp->cq_ci + 1) & mask;
1149 [ # # ]: 0 : cqe = &qp->cq_obj.cqes[idx];
1150 : : ret = check_cqe(cqe, cq_size, qp->cq_ci);
1151 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_SW_OWN)) {
1152 [ # # ]: 0 : if (unlikely(ret != MLX5_CQE_STATUS_HW_OWN))
1153 : 0 : mlx5_crypto_gcm_cqe_err_handle(qp,
1154 : 0 : qp->ops[reported_ci & op_mask]);
1155 : : break;
1156 : : }
1157 : 0 : qp_ci = rte_be_to_cpu_16(cqe->wqe_counter) + 1;
1158 : 0 : qp->cq_ci++;
1159 : : }
1160 : : /* If wqe_counter changed, means CQE handled. */
1161 [ # # ]: 0 : if (likely(qp->qp_ci != qp_ci)) {
1162 : 0 : qp->qp_ci = qp_ci;
1163 : 0 : rte_io_wmb();
1164 [ # # ]: 0 : qp->cq_obj.db_rec[0] = rte_cpu_to_be_32(qp->cq_ci);
1165 : : }
1166 : : /* If reported_ci is not same with qp_ci, means op retrieved. */
1167 [ # # ]: 0 : if (qp_ci != reported_ci) {
1168 : 0 : op_num = RTE_MIN((uint16_t)(qp_ci - reported_ci), max);
1169 : 0 : reported_ci += op_num;
1170 : 0 : mlx5_crypto_gcm_restore_ipsec_mem(qp, qp->reported_ci, reported_ci, op_mask);
1171 [ # # ]: 0 : mlx5_crypto_gcm_fill_op(qp, ops, qp->reported_ci, reported_ci, op_mask);
1172 : 0 : qp->stats.dequeued_count += op_num;
1173 : 0 : qp->reported_ci = reported_ci;
1174 : : }
1175 : : return op_num;
1176 : : }
1177 : :
1178 : : int
1179 : 0 : mlx5_crypto_gcm_init(struct mlx5_crypto_priv *priv)
1180 : : {
1181 : 0 : struct mlx5_common_device *cdev = priv->cdev;
1182 : 0 : struct rte_cryptodev *crypto_dev = priv->crypto_dev;
1183 : 0 : struct rte_cryptodev_ops *dev_ops = crypto_dev->dev_ops;
1184 : : int ret;
1185 : :
1186 : : /* Override AES-GCM specified ops. */
1187 : 0 : dev_ops->sym_session_configure = mlx5_crypto_sym_gcm_session_configure;
1188 : 0 : dev_ops->queue_pair_setup = mlx5_crypto_gcm_qp_setup;
1189 [ # # ]: 0 : dev_ops->queue_pair_release = mlx5_crypto_gcm_qp_release;
1190 [ # # ]: 0 : if (mlx5_crypto_is_ipsec_opt(priv)) {
1191 : 0 : crypto_dev->dequeue_burst = mlx5_crypto_gcm_ipsec_dequeue_burst;
1192 : 0 : crypto_dev->enqueue_burst = mlx5_crypto_gcm_ipsec_enqueue_burst;
1193 : 0 : priv->max_klm_num = 0;
1194 : : } else {
1195 : 0 : crypto_dev->dequeue_burst = mlx5_crypto_gcm_dequeue_burst;
1196 : 0 : crypto_dev->enqueue_burst = mlx5_crypto_gcm_enqueue_burst;
1197 : 0 : priv->max_klm_num = RTE_ALIGN((priv->max_segs_num + 1) * 2 + 1,
1198 : : MLX5_UMR_KLM_NUM_ALIGN);
1199 : : }
1200 : : /* Generate GCM capability. */
1201 : 0 : ret = mlx5_crypto_generate_gcm_cap(&cdev->config.hca_attr.crypto_mmo,
1202 : : mlx5_crypto_gcm_caps);
1203 [ # # ]: 0 : if (ret) {
1204 : 0 : DRV_LOG(ERR, "No enough AES-GCM cap.");
1205 : 0 : return -1;
1206 : : }
1207 : 0 : priv->caps = mlx5_crypto_gcm_caps;
1208 : 0 : return 0;
1209 : : }
|