2061f465e82110d33c74697d9157ac91c11b2690
[dpdk.git] / drivers / crypto / ccp / rte_ccp_pmd.c
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright(c) 2018 Advanced Micro Devices, Inc. All rights reserved.
3  */
4
5 #include <rte_bus_pci.h>
6 #include <rte_bus_vdev.h>
7 #include <rte_common.h>
8 #include <rte_config.h>
9 #include <rte_cryptodev.h>
10 #include <rte_cryptodev_pmd.h>
11 #include <rte_pci.h>
12 #include <rte_dev.h>
13 #include <rte_malloc.h>
14
15 #include "ccp_crypto.h"
16 #include "ccp_dev.h"
17 #include "ccp_pmd_private.h"
18
19 /**
20  * Global static parameter used to find if CCP device is already initialized.
21  */
22 static unsigned int ccp_pmd_init_done;
23 uint8_t ccp_cryptodev_driver_id;
24
25 struct ccp_pmd_init_params {
26         struct rte_cryptodev_pmd_init_params def_p;
27         bool auth_opt;
28 };
29
30 #define CCP_CRYPTODEV_PARAM_NAME                ("name")
31 #define CCP_CRYPTODEV_PARAM_SOCKET_ID           ("socket_id")
32 #define CCP_CRYPTODEV_PARAM_MAX_NB_QP           ("max_nb_queue_pairs")
33 #define CCP_CRYPTODEV_PARAM_MAX_NB_SESS         ("max_nb_sessions")
34 #define CCP_CRYPTODEV_PARAM_AUTH_OPT            ("ccp_auth_opt")
35
36 const char *ccp_pmd_valid_params[] = {
37         CCP_CRYPTODEV_PARAM_NAME,
38         CCP_CRYPTODEV_PARAM_SOCKET_ID,
39         CCP_CRYPTODEV_PARAM_MAX_NB_QP,
40         CCP_CRYPTODEV_PARAM_MAX_NB_SESS,
41         CCP_CRYPTODEV_PARAM_AUTH_OPT,
42 };
43
44 /** ccp pmd auth option */
45 enum ccp_pmd_auth_opt {
46         CCP_PMD_AUTH_OPT_CCP = 0,
47         CCP_PMD_AUTH_OPT_CPU,
48 };
49
50 /** parse integer from integer argument */
51 static int
52 parse_integer_arg(const char *key __rte_unused,
53                   const char *value, void *extra_args)
54 {
55         int *i = (int *) extra_args;
56
57         *i = atoi(value);
58         if (*i < 0) {
59                 CCP_LOG_ERR("Argument has to be positive.\n");
60                 return -EINVAL;
61         }
62
63         return 0;
64 }
65
66 /** parse name argument */
67 static int
68 parse_name_arg(const char *key __rte_unused,
69                const char *value, void *extra_args)
70 {
71         struct rte_cryptodev_pmd_init_params *params = extra_args;
72
73         if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
74                 CCP_LOG_ERR("Invalid name %s, should be less than "
75                             "%u bytes.\n", value,
76                             RTE_CRYPTODEV_NAME_MAX_LEN - 1);
77                 return -EINVAL;
78         }
79
80         strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
81
82         return 0;
83 }
84
85 /** parse authentication operation option */
86 static int
87 parse_auth_opt_arg(const char *key __rte_unused,
88                    const char *value, void *extra_args)
89 {
90         struct ccp_pmd_init_params *params = extra_args;
91         int i;
92
93         i = atoi(value);
94         if (i < CCP_PMD_AUTH_OPT_CCP || i > CCP_PMD_AUTH_OPT_CPU) {
95                 CCP_LOG_ERR("Invalid ccp pmd auth option. "
96                             "0->auth on CCP(default), "
97                             "1->auth on CPU\n");
98                 return -EINVAL;
99         }
100         params->auth_opt = i;
101         return 0;
102 }
103
104 static int
105 ccp_pmd_parse_input_args(struct ccp_pmd_init_params *params,
106                          const char *input_args)
107 {
108         struct rte_kvargs *kvlist = NULL;
109         int ret = 0;
110
111         if (params == NULL)
112                 return -EINVAL;
113
114         if (input_args) {
115                 kvlist = rte_kvargs_parse(input_args,
116                                           ccp_pmd_valid_params);
117                 if (kvlist == NULL)
118                         return -1;
119
120                 ret = rte_kvargs_process(kvlist,
121                                          CCP_CRYPTODEV_PARAM_MAX_NB_QP,
122                                          &parse_integer_arg,
123                                          &params->def_p.max_nb_queue_pairs);
124                 if (ret < 0)
125                         goto free_kvlist;
126
127                 ret = rte_kvargs_process(kvlist,
128                                          CCP_CRYPTODEV_PARAM_MAX_NB_SESS,
129                                          &parse_integer_arg,
130                                          &params->def_p.max_nb_sessions);
131                 if (ret < 0)
132                         goto free_kvlist;
133
134                 ret = rte_kvargs_process(kvlist,
135                                          CCP_CRYPTODEV_PARAM_SOCKET_ID,
136                                          &parse_integer_arg,
137                                          &params->def_p.socket_id);
138                 if (ret < 0)
139                         goto free_kvlist;
140
141                 ret = rte_kvargs_process(kvlist,
142                                          CCP_CRYPTODEV_PARAM_NAME,
143                                          &parse_name_arg,
144                                          &params->def_p);
145                 if (ret < 0)
146                         goto free_kvlist;
147
148                 ret = rte_kvargs_process(kvlist,
149                                          CCP_CRYPTODEV_PARAM_AUTH_OPT,
150                                          &parse_auth_opt_arg,
151                                          params);
152                 if (ret < 0)
153                         goto free_kvlist;
154
155         }
156
157 free_kvlist:
158         rte_kvargs_free(kvlist);
159         return ret;
160 }
161
162 static struct ccp_session *
163 get_ccp_session(struct ccp_qp *qp, struct rte_crypto_op *op)
164 {
165         struct ccp_session *sess = NULL;
166
167         if (op->sess_type == RTE_CRYPTO_OP_WITH_SESSION) {
168                 if (unlikely(op->sym->session == NULL))
169                         return NULL;
170
171                 sess = (struct ccp_session *)
172                         get_session_private_data(
173                                 op->sym->session,
174                                 ccp_cryptodev_driver_id);
175         } else if (op->sess_type == RTE_CRYPTO_OP_SESSIONLESS) {
176                 void *_sess;
177                 void *_sess_private_data = NULL;
178                 struct ccp_private *internals;
179
180                 if (rte_mempool_get(qp->sess_mp, &_sess))
181                         return NULL;
182                 if (rte_mempool_get(qp->sess_mp, (void **)&_sess_private_data))
183                         return NULL;
184
185                 sess = (struct ccp_session *)_sess_private_data;
186
187                 internals = (struct ccp_private *)qp->dev->data->dev_private;
188                 if (unlikely(ccp_set_session_parameters(sess, op->sym->xform,
189                                                         internals) != 0)) {
190                         rte_mempool_put(qp->sess_mp, _sess);
191                         rte_mempool_put(qp->sess_mp, _sess_private_data);
192                         sess = NULL;
193                 }
194                 op->sym->session = (struct rte_cryptodev_sym_session *)_sess;
195                 set_session_private_data(op->sym->session,
196                                          ccp_cryptodev_driver_id,
197                                          _sess_private_data);
198         }
199
200         return sess;
201 }
202
203 static uint16_t
204 ccp_pmd_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops,
205                       uint16_t nb_ops)
206 {
207         struct ccp_session *sess = NULL;
208         struct ccp_qp *qp = queue_pair;
209         struct ccp_queue *cmd_q;
210         struct rte_cryptodev *dev = qp->dev;
211         uint16_t i, enq_cnt = 0, slots_req = 0;
212
213         if (nb_ops == 0)
214                 return 0;
215
216         if (unlikely(rte_ring_full(qp->processed_pkts) != 0))
217                 return 0;
218
219         for (i = 0; i < nb_ops; i++) {
220                 sess = get_ccp_session(qp, ops[i]);
221                 if (unlikely(sess == NULL) && (i == 0)) {
222                         qp->qp_stats.enqueue_err_count++;
223                         return 0;
224                 } else if (sess == NULL) {
225                         nb_ops = i;
226                         break;
227                 }
228                 slots_req += ccp_compute_slot_count(sess);
229         }
230
231         cmd_q = ccp_allot_queue(dev, slots_req);
232         if (unlikely(cmd_q == NULL))
233                 return 0;
234
235         enq_cnt = process_ops_to_enqueue(qp, ops, cmd_q, nb_ops, slots_req);
236         qp->qp_stats.enqueued_count += enq_cnt;
237         return enq_cnt;
238 }
239
240 static uint16_t
241 ccp_pmd_dequeue_burst(void *queue_pair, struct rte_crypto_op **ops,
242                 uint16_t nb_ops)
243 {
244         struct ccp_qp *qp = queue_pair;
245         uint16_t nb_dequeued = 0, i;
246
247         nb_dequeued = process_ops_to_dequeue(qp, ops, nb_ops);
248
249         /* Free session if a session-less crypto op */
250         for (i = 0; i < nb_dequeued; i++)
251                 if (unlikely(ops[i]->sess_type ==
252                              RTE_CRYPTO_OP_SESSIONLESS)) {
253                         rte_mempool_put(qp->sess_mp,
254                                         ops[i]->sym->session);
255                         ops[i]->sym->session = NULL;
256                 }
257         qp->qp_stats.dequeued_count += nb_dequeued;
258
259         return nb_dequeued;
260 }
261
262 /*
263  * The set of PCI devices this driver supports
264  */
265 static struct rte_pci_id ccp_pci_id[] = {
266         {
267                 RTE_PCI_DEVICE(0x1022, 0x1456), /* AMD CCP-5a */
268         },
269         {
270                 RTE_PCI_DEVICE(0x1022, 0x1468), /* AMD CCP-5b */
271         },
272         {.device_id = 0},
273 };
274
275 /** Remove ccp pmd */
276 static int
277 cryptodev_ccp_remove(struct rte_vdev_device *dev)
278 {
279         const char *name;
280
281         ccp_pmd_init_done = 0;
282         name = rte_vdev_device_name(dev);
283         if (name == NULL)
284                 return -EINVAL;
285
286         RTE_LOG(INFO, PMD, "Closing ccp device %s on numa socket %u\n",
287                         name, rte_socket_id());
288
289         return 0;
290 }
291
292 /** Create crypto device */
293 static int
294 cryptodev_ccp_create(const char *name,
295                      struct rte_vdev_device *vdev,
296                      struct ccp_pmd_init_params *init_params)
297 {
298         struct rte_cryptodev *dev;
299         struct ccp_private *internals;
300         uint8_t cryptodev_cnt = 0;
301
302         if (init_params->def_p.name[0] == '\0')
303                 snprintf(init_params->def_p.name,
304                          sizeof(init_params->def_p.name),
305                          "%s", name);
306
307         dev = rte_cryptodev_pmd_create(init_params->def_p.name,
308                                        &vdev->device,
309                                        &init_params->def_p);
310         if (dev == NULL) {
311                 CCP_LOG_ERR("failed to create cryptodev vdev");
312                 goto init_error;
313         }
314
315         cryptodev_cnt = ccp_probe_devices(ccp_pci_id);
316
317         if (cryptodev_cnt == 0) {
318                 CCP_LOG_ERR("failed to detect CCP crypto device");
319                 goto init_error;
320         }
321
322         printf("CCP : Crypto device count = %d\n", cryptodev_cnt);
323         dev->driver_id = ccp_cryptodev_driver_id;
324
325         /* register rx/tx burst functions for data path */
326         dev->dev_ops = ccp_pmd_ops;
327         dev->enqueue_burst = ccp_pmd_enqueue_burst;
328         dev->dequeue_burst = ccp_pmd_dequeue_burst;
329
330         dev->feature_flags = RTE_CRYPTODEV_FF_SYMMETRIC_CRYPTO |
331                         RTE_CRYPTODEV_FF_HW_ACCELERATED |
332                         RTE_CRYPTODEV_FF_SYM_OPERATION_CHAINING;
333
334         internals = dev->data->dev_private;
335
336         internals->max_nb_qpairs = init_params->def_p.max_nb_queue_pairs;
337         internals->max_nb_sessions = init_params->def_p.max_nb_sessions;
338         internals->auth_opt = init_params->auth_opt;
339         internals->crypto_num_dev = cryptodev_cnt;
340
341         return 0;
342
343 init_error:
344         CCP_LOG_ERR("driver %s: %s() failed",
345                     init_params->def_p.name, __func__);
346         cryptodev_ccp_remove(vdev);
347
348         return -EFAULT;
349 }
350
351 /** Probe ccp pmd */
352 static int
353 cryptodev_ccp_probe(struct rte_vdev_device *vdev)
354 {
355         int rc = 0;
356         const char *name;
357         struct ccp_pmd_init_params init_params = {
358                 .def_p = {
359                         "",
360                         sizeof(struct ccp_private),
361                         rte_socket_id(),
362                         CCP_PMD_MAX_QUEUE_PAIRS,
363                         RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_SESSIONS
364                 },
365                 .auth_opt = CCP_PMD_AUTH_OPT_CCP,
366         };
367         const char *input_args;
368
369         if (ccp_pmd_init_done) {
370                 RTE_LOG(INFO, PMD, "CCP PMD already initialized\n");
371                 return -EFAULT;
372         }
373         name = rte_vdev_device_name(vdev);
374         if (name == NULL)
375                 return -EINVAL;
376
377         input_args = rte_vdev_device_args(vdev);
378         ccp_pmd_parse_input_args(&init_params, input_args);
379         init_params.def_p.max_nb_queue_pairs = CCP_PMD_MAX_QUEUE_PAIRS;
380
381         RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name,
382                 init_params.def_p.socket_id);
383         RTE_LOG(INFO, PMD, "Max number of queue pairs = %d\n",
384                 init_params.def_p.max_nb_queue_pairs);
385         RTE_LOG(INFO, PMD, "Max number of sessions = %d\n",
386                 init_params.def_p.max_nb_sessions);
387         RTE_LOG(INFO, PMD, "Authentication offload to %s\n",
388                 ((init_params.auth_opt == 0) ? "CCP" : "CPU"));
389
390         rc = cryptodev_ccp_create(name, vdev, &init_params);
391         if (rc)
392                 return rc;
393         ccp_pmd_init_done = 1;
394         return 0;
395 }
396
397 static struct rte_vdev_driver cryptodev_ccp_pmd_drv = {
398         .probe = cryptodev_ccp_probe,
399         .remove = cryptodev_ccp_remove
400 };
401
402 static struct cryptodev_driver ccp_crypto_drv;
403
404 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_CCP_PMD, cryptodev_ccp_pmd_drv);
405 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_CCP_PMD,
406         "max_nb_queue_pairs=<int> "
407         "max_nb_sessions=<int> "
408         "socket_id=<int> "
409         "ccp_auth_opt=<int>");
410 RTE_PMD_REGISTER_CRYPTO_DRIVER(ccp_crypto_drv, cryptodev_ccp_pmd_drv.driver,
411                                ccp_cryptodev_driver_id);