crypto/cnxk: add asymmetric session
[dpdk.git] / drivers / crypto / cnxk / cn10k_cryptodev_ops.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <rte_cryptodev.h>
6 #include <rte_cryptodev_pmd.h>
7 #include <rte_ip.h>
8
9 #include "cn10k_cryptodev.h"
10 #include "cn10k_cryptodev_ops.h"
11 #include "cn10k_ipsec_la_ops.h"
12 #include "cn10k_ipsec.h"
13 #include "cnxk_cryptodev.h"
14 #include "cnxk_cryptodev_ops.h"
15 #include "cnxk_se.h"
16
17 static inline struct cnxk_se_sess *
18 cn10k_cpt_sym_temp_sess_create(struct cnxk_cpt_qp *qp, struct rte_crypto_op *op)
19 {
20         const int driver_id = cn10k_cryptodev_driver_id;
21         struct rte_crypto_sym_op *sym_op = op->sym;
22         struct rte_cryptodev_sym_session *sess;
23         struct cnxk_se_sess *priv;
24         int ret;
25
26         /* Create temporary session */
27         sess = rte_cryptodev_sym_session_create(qp->sess_mp);
28         if (sess == NULL)
29                 return NULL;
30
31         ret = sym_session_configure(qp->lf.roc_cpt, driver_id, sym_op->xform,
32                                     sess, qp->sess_mp_priv);
33         if (ret)
34                 goto sess_put;
35
36         priv = get_sym_session_private_data(sess, driver_id);
37
38         sym_op->session = sess;
39
40         return priv;
41
42 sess_put:
43         rte_mempool_put(qp->sess_mp, sess);
44         return NULL;
45 }
46
47 static __rte_always_inline int __rte_hot
48 cpt_sec_inst_fill(struct rte_crypto_op *op, struct cn10k_sec_session *sess,
49                   struct cpt_inflight_req *infl_req, struct cpt_inst_s *inst)
50 {
51         struct rte_crypto_sym_op *sym_op = op->sym;
52         union roc_ot_ipsec_sa_word2 *w2;
53         struct cn10k_ipsec_sa *sa;
54         int ret;
55
56         if (unlikely(sym_op->m_dst && sym_op->m_dst != sym_op->m_src)) {
57                 plt_dp_err("Out of place is not supported");
58                 return -ENOTSUP;
59         }
60
61         if (unlikely(!rte_pktmbuf_is_contiguous(sym_op->m_src))) {
62                 plt_dp_err("Scatter Gather mode is not supported");
63                 return -ENOTSUP;
64         }
65
66         sa = &sess->sa;
67         w2 = (union roc_ot_ipsec_sa_word2 *)&sa->in_sa.w2;
68
69         if (w2->s.dir == ROC_IE_OT_SA_DIR_OUTBOUND)
70                 ret = process_outb_sa(op, sa, inst);
71         else {
72                 infl_req->op_flags |= CPT_OP_FLAGS_IPSEC_DIR_INBOUND;
73                 ret = process_inb_sa(op, sa, inst);
74         }
75
76         return ret;
77 }
78
79 static __rte_always_inline int __rte_hot
80 cpt_sym_inst_fill(struct cnxk_cpt_qp *qp, struct rte_crypto_op *op,
81                   struct cnxk_se_sess *sess, struct cpt_inflight_req *infl_req,
82                   struct cpt_inst_s *inst)
83 {
84         uint64_t cpt_op;
85         int ret = -1;
86
87         cpt_op = sess->cpt_op;
88
89         if (cpt_op & ROC_SE_OP_CIPHER_MASK)
90                 ret = fill_fc_params(op, sess, &qp->meta_info, infl_req, inst);
91         else
92                 ret = fill_digest_params(op, sess, &qp->meta_info, infl_req,
93                                          inst);
94
95         return ret;
96 }
97
98 static inline int
99 cn10k_cpt_fill_inst(struct cnxk_cpt_qp *qp, struct rte_crypto_op *ops[],
100                     struct cpt_inst_s inst[], struct cpt_inflight_req *infl_req)
101 {
102         struct cn10k_sec_session *sec_sess;
103         struct rte_crypto_sym_op *sym_op;
104         struct cnxk_se_sess *sess;
105         struct rte_crypto_op *op;
106         uint64_t w7;
107         int ret;
108
109         op = ops[0];
110
111         inst[0].w0.u64 = 0;
112         inst[0].w2.u64 = 0;
113         inst[0].w3.u64 = 0;
114
115         sym_op = op->sym;
116
117         if (op->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
118                 if (op->sess_type == RTE_CRYPTO_OP_SECURITY_SESSION) {
119                         sec_sess = get_sec_session_private_data(
120                                 sym_op->sec_session);
121                         ret = cpt_sec_inst_fill(op, sec_sess, infl_req,
122                                                 &inst[0]);
123                         if (unlikely(ret))
124                                 return 0;
125                         w7 = sec_sess->sa.inst.w7;
126                 } else if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
127                         sess = get_sym_session_private_data(
128                                 sym_op->session, cn10k_cryptodev_driver_id);
129                         ret = cpt_sym_inst_fill(qp, op, sess, infl_req,
130                                                 &inst[0]);
131                         if (unlikely(ret))
132                                 return 0;
133                         w7 = sess->cpt_inst_w7;
134                 } else {
135                         sess = cn10k_cpt_sym_temp_sess_create(qp, op);
136                         if (unlikely(sess == NULL)) {
137                                 plt_dp_err("Could not create temp session");
138                                 return 0;
139                         }
140
141                         ret = cpt_sym_inst_fill(qp, op, sess, infl_req,
142                                                 &inst[0]);
143                         if (unlikely(ret)) {
144                                 sym_session_clear(cn10k_cryptodev_driver_id,
145                                                   op->sym->session);
146                                 rte_mempool_put(qp->sess_mp, op->sym->session);
147                                 return 0;
148                         }
149                         w7 = sess->cpt_inst_w7;
150                 }
151         } else {
152                 plt_dp_err("Unsupported op type");
153                 return 0;
154         }
155
156         inst[0].res_addr = (uint64_t)&infl_req->res;
157         infl_req->res.cn10k.compcode = CPT_COMP_NOT_DONE;
158         infl_req->cop = op;
159
160         inst[0].w7.u64 = w7;
161
162         return 1;
163 }
164
165 #define PKTS_PER_LOOP   32
166 #define PKTS_PER_STEORL 16
167
168 static uint16_t
169 cn10k_cpt_enqueue_burst(void *qptr, struct rte_crypto_op **ops, uint16_t nb_ops)
170 {
171         uint64_t lmt_base, lmt_arg, io_addr;
172         struct cpt_inflight_req *infl_req;
173         uint16_t nb_allowed, count = 0;
174         struct cnxk_cpt_qp *qp = qptr;
175         struct pending_queue *pend_q;
176         struct cpt_inst_s *inst;
177         uint16_t lmt_id;
178         int ret, i;
179
180         pend_q = &qp->pend_q;
181
182         nb_allowed = qp->lf.nb_desc - pend_q->pending_count;
183         nb_ops = RTE_MIN(nb_ops, nb_allowed);
184
185         if (unlikely(nb_ops == 0))
186                 return 0;
187
188         lmt_base = qp->lmtline.lmt_base;
189         io_addr = qp->lmtline.io_addr;
190
191         ROC_LMT_BASE_ID_GET(lmt_base, lmt_id);
192         inst = (struct cpt_inst_s *)lmt_base;
193
194 again:
195         for (i = 0; i < RTE_MIN(PKTS_PER_LOOP, nb_ops); i++) {
196                 infl_req = &pend_q->req_queue[pend_q->enq_tail];
197                 infl_req->op_flags = 0;
198
199                 ret = cn10k_cpt_fill_inst(qp, ops + i, &inst[2 * i], infl_req);
200                 if (unlikely(ret != 1)) {
201                         plt_dp_err("Could not process op: %p", ops + i);
202                         if (i == 0)
203                                 goto update_pending;
204                         break;
205                 }
206
207                 MOD_INC(pend_q->enq_tail, qp->lf.nb_desc);
208         }
209
210         if (i > PKTS_PER_STEORL) {
211                 lmt_arg = ROC_CN10K_CPT_LMT_ARG | (PKTS_PER_STEORL - 1) << 12 |
212                           (uint64_t)lmt_id;
213                 roc_lmt_submit_steorl(lmt_arg, io_addr);
214                 lmt_arg = ROC_CN10K_CPT_LMT_ARG |
215                           (i - PKTS_PER_STEORL - 1) << 12 |
216                           (uint64_t)(lmt_id + PKTS_PER_STEORL);
217                 roc_lmt_submit_steorl(lmt_arg, io_addr);
218         } else {
219                 lmt_arg = ROC_CN10K_CPT_LMT_ARG | (i - 1) << 12 |
220                           (uint64_t)lmt_id;
221                 roc_lmt_submit_steorl(lmt_arg, io_addr);
222         }
223
224         rte_io_wmb();
225
226         if (nb_ops - i > 0 && i == PKTS_PER_LOOP) {
227                 nb_ops -= i;
228                 ops += i;
229                 count += i;
230                 goto again;
231         }
232
233 update_pending:
234         pend_q->pending_count += count + i;
235
236         pend_q->time_out = rte_get_timer_cycles() +
237                            DEFAULT_COMMAND_TIMEOUT * rte_get_timer_hz();
238
239         return count + i;
240 }
241
242 static inline void
243 cn10k_cpt_sec_post_process(struct rte_crypto_op *cop,
244                            struct cpt_inflight_req *infl_req)
245 {
246         struct rte_crypto_sym_op *sym_op = cop->sym;
247         struct rte_mbuf *m = sym_op->m_src;
248         struct rte_ipv6_hdr *ip6;
249         struct rte_ipv4_hdr *ip;
250         uint16_t m_len;
251
252         if (infl_req->op_flags & CPT_OP_FLAGS_IPSEC_DIR_INBOUND) {
253                 ip = (struct rte_ipv4_hdr *)rte_pktmbuf_mtod(m, char *);
254
255                 if (((ip->version_ihl & 0xf0) >> RTE_IPV4_IHL_MULTIPLIER) ==
256                     IPVERSION) {
257                         m_len = rte_be_to_cpu_16(ip->total_length);
258                 } else {
259                         PLT_ASSERT(((ip->version_ihl & 0xf0) >>
260                                     RTE_IPV4_IHL_MULTIPLIER) == IPV6_VERSION);
261                         ip6 = (struct rte_ipv6_hdr *)ip;
262                         m_len = rte_be_to_cpu_16(ip6->payload_len) +
263                                 sizeof(struct rte_ipv6_hdr);
264                 }
265                 m->data_len = m_len;
266                 m->pkt_len = m_len;
267         }
268 }
269
270 static inline void
271 cn10k_cpt_dequeue_post_process(struct cnxk_cpt_qp *qp,
272                                struct rte_crypto_op *cop,
273                                struct cpt_inflight_req *infl_req)
274 {
275         struct cpt_cn10k_res_s *res = (struct cpt_cn10k_res_s *)&infl_req->res;
276         unsigned int sz;
277
278         if (likely(res->compcode == CPT_COMP_GOOD ||
279                    res->compcode == CPT_COMP_WARN)) {
280                 if (unlikely(res->uc_compcode)) {
281                         if (res->uc_compcode == ROC_SE_ERR_GC_ICV_MISCOMPARE)
282                                 cop->status = RTE_CRYPTO_OP_STATUS_AUTH_FAILED;
283                         else
284                                 cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
285
286                         plt_dp_info("Request failed with microcode error");
287                         plt_dp_info("MC completion code 0x%x",
288                                     res->uc_compcode);
289                         goto temp_sess_free;
290                 }
291
292                 cop->status = RTE_CRYPTO_OP_STATUS_SUCCESS;
293                 if (cop->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
294                         if (cop->sess_type == RTE_CRYPTO_OP_SECURITY_SESSION) {
295                                 cn10k_cpt_sec_post_process(cop, infl_req);
296                                 return;
297                         }
298
299                         /* Verify authentication data if required */
300                         if (unlikely(infl_req->op_flags &
301                                      CPT_OP_FLAGS_AUTH_VERIFY)) {
302                                 uintptr_t *rsp = infl_req->mdata;
303                                 compl_auth_verify(cop, (uint8_t *)rsp[0],
304                                                   rsp[1]);
305                         }
306                 }
307         } else {
308                 cop->status = RTE_CRYPTO_OP_STATUS_ERROR;
309                 plt_dp_info("HW completion code 0x%x", res->compcode);
310
311                 switch (res->compcode) {
312                 case CPT_COMP_INSTERR:
313                         plt_dp_err("Request failed with instruction error");
314                         break;
315                 case CPT_COMP_FAULT:
316                         plt_dp_err("Request failed with DMA fault");
317                         break;
318                 case CPT_COMP_HWERR:
319                         plt_dp_err("Request failed with hardware error");
320                         break;
321                 default:
322                         plt_dp_err(
323                                 "Request failed with unknown completion code");
324                 }
325         }
326
327 temp_sess_free:
328         if (unlikely(cop->sess_type == RTE_CRYPTO_OP_SESSIONLESS)) {
329                 if (cop->type == RTE_CRYPTO_OP_TYPE_SYMMETRIC) {
330                         sym_session_clear(cn10k_cryptodev_driver_id,
331                                           cop->sym->session);
332                         sz = rte_cryptodev_sym_get_existing_header_session_size(
333                                 cop->sym->session);
334                         memset(cop->sym->session, 0, sz);
335                         rte_mempool_put(qp->sess_mp, cop->sym->session);
336                         cop->sym->session = NULL;
337                 }
338         }
339 }
340
341 static uint16_t
342 cn10k_cpt_dequeue_burst(void *qptr, struct rte_crypto_op **ops, uint16_t nb_ops)
343 {
344         struct cpt_inflight_req *infl_req;
345         struct cnxk_cpt_qp *qp = qptr;
346         struct pending_queue *pend_q;
347         struct cpt_cn10k_res_s *res;
348         struct rte_crypto_op *cop;
349         int i, nb_pending;
350
351         pend_q = &qp->pend_q;
352
353         nb_pending = pend_q->pending_count;
354
355         if (nb_ops > nb_pending)
356                 nb_ops = nb_pending;
357
358         for (i = 0; i < nb_ops; i++) {
359                 infl_req = &pend_q->req_queue[pend_q->deq_head];
360
361                 res = (struct cpt_cn10k_res_s *)&infl_req->res;
362
363                 if (unlikely(res->compcode == CPT_COMP_NOT_DONE)) {
364                         if (unlikely(rte_get_timer_cycles() >
365                                      pend_q->time_out)) {
366                                 plt_err("Request timed out");
367                                 pend_q->time_out = rte_get_timer_cycles() +
368                                                    DEFAULT_COMMAND_TIMEOUT *
369                                                            rte_get_timer_hz();
370                         }
371                         break;
372                 }
373
374                 MOD_INC(pend_q->deq_head, qp->lf.nb_desc);
375
376                 cop = infl_req->cop;
377
378                 ops[i] = cop;
379
380                 cn10k_cpt_dequeue_post_process(qp, cop, infl_req);
381
382                 if (unlikely(infl_req->op_flags & CPT_OP_FLAGS_METABUF))
383                         rte_mempool_put(qp->meta_info.pool, infl_req->mdata);
384         }
385
386         pend_q->pending_count -= i;
387
388         return i;
389 }
390
391 void
392 cn10k_cpt_set_enqdeq_fns(struct rte_cryptodev *dev)
393 {
394         dev->enqueue_burst = cn10k_cpt_enqueue_burst;
395         dev->dequeue_burst = cn10k_cpt_dequeue_burst;
396
397         rte_mb();
398 }
399
400 static void
401 cn10k_cpt_dev_info_get(struct rte_cryptodev *dev,
402                        struct rte_cryptodev_info *info)
403 {
404         if (info != NULL) {
405                 cnxk_cpt_dev_info_get(dev, info);
406                 info->driver_id = cn10k_cryptodev_driver_id;
407         }
408 }
409
410 struct rte_cryptodev_ops cn10k_cpt_ops = {
411         /* Device control ops */
412         .dev_configure = cnxk_cpt_dev_config,
413         .dev_start = cnxk_cpt_dev_start,
414         .dev_stop = cnxk_cpt_dev_stop,
415         .dev_close = cnxk_cpt_dev_close,
416         .dev_infos_get = cn10k_cpt_dev_info_get,
417
418         .stats_get = NULL,
419         .stats_reset = NULL,
420         .queue_pair_setup = cnxk_cpt_queue_pair_setup,
421         .queue_pair_release = cnxk_cpt_queue_pair_release,
422
423         /* Symmetric crypto ops */
424         .sym_session_get_size = cnxk_cpt_sym_session_get_size,
425         .sym_session_configure = cnxk_cpt_sym_session_configure,
426         .sym_session_clear = cnxk_cpt_sym_session_clear,
427
428         /* Asymmetric crypto ops */
429         .asym_session_get_size = cnxk_ae_session_size_get,
430         .asym_session_configure = cnxk_ae_session_cfg,
431         .asym_session_clear = cnxk_ae_session_clear,
432
433 };