crypto/cnxk: write CPT CTX through microcode op
[dpdk.git] / drivers / crypto / cnxk / cn10k_ipsec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <cryptodev_pmd.h>
6 #include <rte_esp.h>
7 #include <rte_ip.h>
8 #include <rte_malloc.h>
9 #include <rte_security.h>
10 #include <rte_security_driver.h>
11 #include <rte_udp.h>
12
13 #include "cn10k_ipsec.h"
14 #include "cnxk_cryptodev.h"
15 #include "cnxk_cryptodev_ops.h"
16 #include "cnxk_ipsec.h"
17 #include "cnxk_security.h"
18
19 #include "roc_api.h"
20
21 static uint64_t
22 ipsec_cpt_inst_w7_get(struct roc_cpt *roc_cpt, void *sa)
23 {
24         union cpt_inst_w7 w7;
25
26         w7.u64 = 0;
27         w7.s.egrp = roc_cpt->eng_grp[CPT_ENG_TYPE_IE];
28         w7.s.ctx_val = 1;
29         w7.s.cptr = (uint64_t)sa;
30         rte_mb();
31
32         return w7.u64;
33 }
34
35 static int
36 cn10k_ipsec_outb_sa_create(struct roc_cpt *roc_cpt, struct roc_cpt_lf *lf,
37                            struct rte_security_ipsec_xform *ipsec_xfrm,
38                            struct rte_crypto_sym_xform *crypto_xfrm,
39                            struct rte_security_session *sec_sess)
40 {
41         union roc_ot_ipsec_outb_param1 param1;
42         struct roc_ot_ipsec_outb_sa *sa_dptr;
43         struct cnxk_ipsec_outb_rlens rlens;
44         struct cn10k_sec_session *sess;
45         struct cn10k_ipsec_sa *sa;
46         union cpt_inst_w4 inst_w4;
47         void *out_sa;
48         int ret = 0;
49
50         sess = get_sec_session_private_data(sec_sess);
51         sa = &sess->sa;
52         out_sa = &sa->out_sa;
53
54         /* Allocate memory to be used as dptr for CPT ucode WRITE_SA op */
55         sa_dptr = plt_zmalloc(ROC_NIX_INL_OT_IPSEC_OUTB_HW_SZ, 0);
56         if (sa_dptr == NULL) {
57                 plt_err("Couldn't allocate memory for SA dptr");
58                 return -ENOMEM;
59         }
60
61         memset(sa_dptr, 0, sizeof(struct roc_ot_ipsec_outb_sa));
62
63         /* Translate security parameters to SA */
64         ret = cnxk_ot_ipsec_outb_sa_fill(sa_dptr, ipsec_xfrm, crypto_xfrm);
65         if (ret) {
66                 plt_err("Could not fill outbound session parameters");
67                 goto sa_dptr_free;
68         }
69
70         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
71
72 #ifdef LA_IPSEC_DEBUG
73         /* Use IV from application in debug mode */
74         if (ipsec_xfrm->options.iv_gen_disable == 1) {
75                 sa_dptr->w2.s.iv_src = ROC_IE_OT_SA_IV_SRC_FROM_SA;
76                 if (crypto_xfrm->type == RTE_CRYPTO_SYM_XFORM_AEAD) {
77                         sa->iv_offset = crypto_xfrm->aead.iv.offset;
78                         sa->iv_length = crypto_xfrm->aead.iv.length;
79                 } else {
80                         sa->iv_offset = crypto_xfrm->cipher.iv.offset;
81                         sa->iv_length = crypto_xfrm->cipher.iv.length;
82                 }
83         }
84 #else
85         if (ipsec_xfrm->options.iv_gen_disable != 0) {
86                 plt_err("Application provided IV not supported");
87                 ret = -ENOTSUP;
88                 goto sa_dptr_free;
89         }
90 #endif
91
92         /* Get Rlen calculation data */
93         ret = cnxk_ipsec_outb_rlens_get(&rlens, ipsec_xfrm, crypto_xfrm);
94         if (ret)
95                 goto sa_dptr_free;
96
97         sa->max_extended_len = rlens.max_extended_len;
98
99         /* pre-populate CPT INST word 4 */
100         inst_w4.u64 = 0;
101         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_OUTBOUND_IPSEC;
102
103         param1.u16 = 0;
104
105         /* Disable IP checksum computation by default */
106         param1.s.ip_csum_disable = ROC_IE_OT_SA_INNER_PKT_IP_CSUM_DISABLE;
107
108         if (ipsec_xfrm->options.ip_csum_enable) {
109                 param1.s.ip_csum_disable =
110                         ROC_IE_OT_SA_INNER_PKT_IP_CSUM_ENABLE;
111         }
112
113         /* Disable L4 checksum computation by default */
114         param1.s.l4_csum_disable = ROC_IE_OT_SA_INNER_PKT_L4_CSUM_DISABLE;
115
116         if (ipsec_xfrm->options.l4_csum_enable) {
117                 param1.s.l4_csum_disable =
118                         ROC_IE_OT_SA_INNER_PKT_L4_CSUM_ENABLE;
119         }
120
121         inst_w4.s.param1 = param1.u16;
122
123         sa->inst.w4 = inst_w4.u64;
124
125         memset(out_sa, 0, sizeof(struct roc_ot_ipsec_outb_sa));
126
127         /* Copy word0 from sa_dptr to populate ctx_push_sz ctx_size fields */
128         memcpy(out_sa, sa_dptr, 8);
129
130         /* Write session using microcode opcode */
131         ret = roc_cpt_ctx_write(lf, sa_dptr, out_sa,
132                                 ROC_NIX_INL_OT_IPSEC_OUTB_HW_SZ);
133         if (ret) {
134                 plt_err("Could not write outbound session to hardware");
135                 goto sa_dptr_free;
136         }
137
138         /* Trigger CTX flush to write dirty data back to DRAM */
139         roc_cpt_lf_ctx_flush(lf, out_sa, false);
140
141 sa_dptr_free:
142         plt_free(sa_dptr);
143
144         return ret;
145 }
146
147 static int
148 cn10k_ipsec_inb_sa_create(struct roc_cpt *roc_cpt, struct roc_cpt_lf *lf,
149                           struct rte_security_ipsec_xform *ipsec_xfrm,
150                           struct rte_crypto_sym_xform *crypto_xfrm,
151                           struct rte_security_session *sec_sess)
152 {
153         union roc_ot_ipsec_inb_param1 param1;
154         struct roc_ot_ipsec_inb_sa *sa_dptr;
155         struct cn10k_sec_session *sess;
156         struct cn10k_ipsec_sa *sa;
157         union cpt_inst_w4 inst_w4;
158         void *in_sa;
159         int ret = 0;
160
161         sess = get_sec_session_private_data(sec_sess);
162         sa = &sess->sa;
163         in_sa = &sa->in_sa;
164
165         /* Allocate memory to be used as dptr for CPT ucode WRITE_SA op */
166         sa_dptr = plt_zmalloc(ROC_NIX_INL_OT_IPSEC_INB_HW_SZ, 0);
167         if (sa_dptr == NULL) {
168                 plt_err("Couldn't allocate memory for SA dptr");
169                 return -ENOMEM;
170         }
171
172         memset(sa_dptr, 0, sizeof(struct roc_ot_ipsec_inb_sa));
173
174         /* Translate security parameters to SA */
175         ret = cnxk_ot_ipsec_inb_sa_fill(sa_dptr, ipsec_xfrm, crypto_xfrm);
176         if (ret) {
177                 plt_err("Could not fill inbound session parameters");
178                 goto sa_dptr_free;
179         }
180
181         sa->inst.w7 = ipsec_cpt_inst_w7_get(roc_cpt, sa);
182
183         /* pre-populate CPT INST word 4 */
184         inst_w4.u64 = 0;
185         inst_w4.s.opcode_major = ROC_IE_OT_MAJOR_OP_PROCESS_INBOUND_IPSEC;
186
187         param1.u16 = 0;
188
189         /* Disable IP checksum verification by default */
190         param1.s.ip_csum_disable = ROC_IE_OT_SA_INNER_PKT_IP_CSUM_DISABLE;
191
192         if (ipsec_xfrm->options.ip_csum_enable) {
193                 param1.s.ip_csum_disable =
194                         ROC_IE_OT_SA_INNER_PKT_IP_CSUM_ENABLE;
195                 sa->ip_csum_enable = true;
196         }
197
198         /* Disable L4 checksum verification by default */
199         param1.s.l4_csum_disable = ROC_IE_OT_SA_INNER_PKT_L4_CSUM_DISABLE;
200
201         if (ipsec_xfrm->options.l4_csum_enable) {
202                 param1.s.l4_csum_disable =
203                         ROC_IE_OT_SA_INNER_PKT_L4_CSUM_ENABLE;
204         }
205
206         param1.s.esp_trailer_disable = 1;
207
208         inst_w4.s.param1 = param1.u16;
209
210         sa->inst.w4 = inst_w4.u64;
211
212         memset(in_sa, 0, sizeof(struct roc_ot_ipsec_inb_sa));
213
214         /* Copy word0 from sa_dptr to populate ctx_push_sz ctx_size fields */
215         memcpy(in_sa, sa_dptr, 8);
216
217         /* Write session using microcode opcode */
218         ret = roc_cpt_ctx_write(lf, sa_dptr, in_sa,
219                                 ROC_NIX_INL_OT_IPSEC_INB_HW_SZ);
220         if (ret) {
221                 plt_err("Could not write inbound session to hardware");
222                 goto sa_dptr_free;
223         }
224
225         /* Trigger CTX flush to write dirty data back to DRAM */
226         roc_cpt_lf_ctx_flush(lf, in_sa, false);
227
228 sa_dptr_free:
229         plt_free(sa_dptr);
230
231         return ret;
232 }
233
234 static int
235 cn10k_ipsec_session_create(void *dev,
236                            struct rte_security_ipsec_xform *ipsec_xfrm,
237                            struct rte_crypto_sym_xform *crypto_xfrm,
238                            struct rte_security_session *sess)
239 {
240         struct rte_cryptodev *crypto_dev = dev;
241         struct roc_cpt *roc_cpt;
242         struct cnxk_cpt_vf *vf;
243         struct cnxk_cpt_qp *qp;
244         int ret;
245
246         qp = crypto_dev->data->queue_pairs[0];
247         if (qp == NULL) {
248                 plt_err("Setup cpt queue pair before creating security session");
249                 return -EPERM;
250         }
251
252         ret = cnxk_ipsec_xform_verify(ipsec_xfrm, crypto_xfrm);
253         if (ret)
254                 return ret;
255
256         vf = crypto_dev->data->dev_private;
257         roc_cpt = &vf->cpt;
258
259         if (ipsec_xfrm->direction == RTE_SECURITY_IPSEC_SA_DIR_INGRESS)
260                 return cn10k_ipsec_inb_sa_create(roc_cpt, &qp->lf, ipsec_xfrm,
261                                                  crypto_xfrm, sess);
262         else
263                 return cn10k_ipsec_outb_sa_create(roc_cpt, &qp->lf, ipsec_xfrm,
264                                                   crypto_xfrm, sess);
265 }
266
267 static int
268 cn10k_sec_session_create(void *device, struct rte_security_session_conf *conf,
269                          struct rte_security_session *sess,
270                          struct rte_mempool *mempool)
271 {
272         struct cn10k_sec_session *priv;
273         int ret;
274
275         if (conf->action_type != RTE_SECURITY_ACTION_TYPE_LOOKASIDE_PROTOCOL)
276                 return -EINVAL;
277
278         if (rte_mempool_get(mempool, (void **)&priv)) {
279                 plt_err("Could not allocate security session private data");
280                 return -ENOMEM;
281         }
282
283         set_sec_session_private_data(sess, priv);
284
285         if (conf->protocol != RTE_SECURITY_PROTOCOL_IPSEC) {
286                 ret = -ENOTSUP;
287                 goto mempool_put;
288         }
289         ret = cn10k_ipsec_session_create(device, &conf->ipsec,
290                                          conf->crypto_xform, sess);
291         if (ret)
292                 goto mempool_put;
293
294         return 0;
295
296 mempool_put:
297         rte_mempool_put(mempool, priv);
298         set_sec_session_private_data(sess, NULL);
299         return ret;
300 }
301
302 static int
303 cn10k_sec_session_destroy(void *device __rte_unused,
304                           struct rte_security_session *sess)
305 {
306         struct cn10k_sec_session *priv;
307         struct rte_mempool *sess_mp;
308
309         priv = get_sec_session_private_data(sess);
310
311         if (priv == NULL)
312                 return 0;
313
314         sess_mp = rte_mempool_from_obj(priv);
315
316         set_sec_session_private_data(sess, NULL);
317         rte_mempool_put(sess_mp, priv);
318
319         return 0;
320 }
321
322 static unsigned int
323 cn10k_sec_session_get_size(void *device __rte_unused)
324 {
325         return sizeof(struct cn10k_sec_session);
326 }
327
328 /* Update platform specific security ops */
329 void
330 cn10k_sec_ops_override(void)
331 {
332         /* Update platform specific ops */
333         cnxk_sec_ops.session_create = cn10k_sec_session_create;
334         cnxk_sec_ops.session_destroy = cn10k_sec_session_destroy;
335         cnxk_sec_ops.session_get_size = cn10k_sec_session_get_size;
336 }