New upstream version 18.11-rc1
[deb_dpdk.git] / drivers / crypto / scheduler / scheduler_pmd.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2017 Intel Corporation
3  */
4 #include <rte_common.h>
5 #include <rte_hexdump.h>
6 #include <rte_cryptodev.h>
7 #include <rte_cryptodev_pmd.h>
8 #include <rte_bus_vdev.h>
9 #include <rte_malloc.h>
10 #include <rte_cpuflags.h>
11 #include <rte_reorder.h>
12 #include <rte_string_fns.h>
13
14 #include "rte_cryptodev_scheduler.h"
15 #include "scheduler_pmd_private.h"
16
17 uint8_t cryptodev_scheduler_driver_id;
18
19 struct scheduler_init_params {
20         struct rte_cryptodev_pmd_init_params def_p;
21         uint32_t nb_slaves;
22         enum rte_cryptodev_scheduler_mode mode;
23         char mode_param_str[RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN];
24         uint32_t enable_ordering;
25         uint16_t wc_pool[RTE_MAX_LCORE];
26         uint16_t nb_wc;
27         char slave_names[RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES]
28                         [RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN];
29 };
30
31 #define RTE_CRYPTODEV_VDEV_NAME                 ("name")
32 #define RTE_CRYPTODEV_VDEV_SLAVE                ("slave")
33 #define RTE_CRYPTODEV_VDEV_MODE                 ("mode")
34 #define RTE_CRYPTODEV_VDEV_MODE_PARAM           ("mode_param")
35 #define RTE_CRYPTODEV_VDEV_ORDERING             ("ordering")
36 #define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG        ("max_nb_queue_pairs")
37 #define RTE_CRYPTODEV_VDEV_SOCKET_ID            ("socket_id")
38 #define RTE_CRYPTODEV_VDEV_COREMASK             ("coremask")
39 #define RTE_CRYPTODEV_VDEV_CORELIST             ("corelist")
40
41 static const char * const scheduler_valid_params[] = {
42         RTE_CRYPTODEV_VDEV_NAME,
43         RTE_CRYPTODEV_VDEV_SLAVE,
44         RTE_CRYPTODEV_VDEV_MODE,
45         RTE_CRYPTODEV_VDEV_MODE_PARAM,
46         RTE_CRYPTODEV_VDEV_ORDERING,
47         RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
48         RTE_CRYPTODEV_VDEV_SOCKET_ID,
49         RTE_CRYPTODEV_VDEV_COREMASK,
50         RTE_CRYPTODEV_VDEV_CORELIST
51 };
52
53 struct scheduler_parse_map {
54         const char *name;
55         uint32_t val;
56 };
57
58 const struct scheduler_parse_map scheduler_mode_map[] = {
59         {RTE_STR(SCHEDULER_MODE_NAME_ROUND_ROBIN),
60                         CDEV_SCHED_MODE_ROUNDROBIN},
61         {RTE_STR(SCHEDULER_MODE_NAME_PKT_SIZE_DISTR),
62                         CDEV_SCHED_MODE_PKT_SIZE_DISTR},
63         {RTE_STR(SCHEDULER_MODE_NAME_FAIL_OVER),
64                         CDEV_SCHED_MODE_FAILOVER},
65         {RTE_STR(SCHEDULER_MODE_NAME_MULTI_CORE),
66                         CDEV_SCHED_MODE_MULTICORE}
67 };
68
69 const struct scheduler_parse_map scheduler_ordering_map[] = {
70                 {"enable", 1},
71                 {"disable", 0}
72 };
73
74 #define CDEV_SCHED_MODE_PARAM_SEP_CHAR          ':'
75
76 static int
77 cryptodev_scheduler_create(const char *name,
78                 struct rte_vdev_device *vdev,
79                 struct scheduler_init_params *init_params)
80 {
81         struct rte_cryptodev *dev;
82         struct scheduler_ctx *sched_ctx;
83         uint32_t i;
84         int ret;
85
86         dev = rte_cryptodev_pmd_create(name, &vdev->device,
87                         &init_params->def_p);
88         if (dev == NULL) {
89                 CR_SCHED_LOG(ERR, "driver %s: failed to create cryptodev vdev",
90                         name);
91                 return -EFAULT;
92         }
93
94         dev->driver_id = cryptodev_scheduler_driver_id;
95         dev->dev_ops = rte_crypto_scheduler_pmd_ops;
96
97         sched_ctx = dev->data->dev_private;
98         sched_ctx->max_nb_queue_pairs =
99                         init_params->def_p.max_nb_queue_pairs;
100
101         if (init_params->mode == CDEV_SCHED_MODE_MULTICORE) {
102                 uint16_t i;
103
104                 sched_ctx->nb_wc = init_params->nb_wc;
105
106                 for (i = 0; i < sched_ctx->nb_wc; i++) {
107                         sched_ctx->wc_pool[i] = init_params->wc_pool[i];
108                         CR_SCHED_LOG(INFO, "  Worker core[%u]=%u added",
109                                 i, sched_ctx->wc_pool[i]);
110                 }
111         }
112
113         if (init_params->mode > CDEV_SCHED_MODE_USERDEFINED &&
114                         init_params->mode < CDEV_SCHED_MODE_COUNT) {
115                 union {
116                         struct rte_cryptodev_scheduler_threshold_option
117                                         threshold_option;
118                 } option;
119                 enum rte_cryptodev_schedule_option_type option_type;
120                 char param_name[RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN] = {0};
121                 char param_val[RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN] = {0};
122                 char *s, *end;
123
124                 ret = rte_cryptodev_scheduler_mode_set(dev->data->dev_id,
125                         init_params->mode);
126                 if (ret < 0) {
127                         rte_cryptodev_pmd_release_device(dev);
128                         return ret;
129                 }
130
131                 for (i = 0; i < RTE_DIM(scheduler_mode_map); i++) {
132                         if (scheduler_mode_map[i].val != sched_ctx->mode)
133                                 continue;
134
135                         CR_SCHED_LOG(INFO, "  Scheduling mode = %s",
136                                         scheduler_mode_map[i].name);
137                         break;
138                 }
139
140                 if (strlen(init_params->mode_param_str) > 0) {
141                         s = strchr(init_params->mode_param_str,
142                                         CDEV_SCHED_MODE_PARAM_SEP_CHAR);
143                         if (s == NULL) {
144                                 CR_SCHED_LOG(ERR, "Invalid mode param");
145                                 return -EINVAL;
146                         }
147
148                         strlcpy(param_name, init_params->mode_param_str,
149                                         s - init_params->mode_param_str + 1);
150                         s++;
151                         strlcpy(param_val, s,
152                                         RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN);
153
154                         switch (init_params->mode) {
155                         case CDEV_SCHED_MODE_PKT_SIZE_DISTR:
156                                 if (strcmp(param_name,
157                                         RTE_CRYPTODEV_SCHEDULER_PARAM_THRES)
158                                                 != 0) {
159                                         CR_SCHED_LOG(ERR, "Invalid mode param");
160                                         return -EINVAL;
161                                 }
162                                 option_type = CDEV_SCHED_OPTION_THRESHOLD;
163
164                                 option.threshold_option.threshold =
165                                                 strtoul(param_val, &end, 0);
166                                 break;
167                         default:
168                                 CR_SCHED_LOG(ERR, "Invalid mode param");
169                                 return -EINVAL;
170                         }
171
172                         if (sched_ctx->ops.option_set(dev, option_type,
173                                         (void *)&option) < 0) {
174                                 CR_SCHED_LOG(ERR, "Invalid mode param");
175                                 return -EINVAL;
176                         }
177
178                         RTE_LOG(INFO, PMD, "  Sched mode param (%s = %s)\n",
179                                         param_name, param_val);
180                 }
181         }
182
183         sched_ctx->reordering_enabled = init_params->enable_ordering;
184
185         for (i = 0; i < RTE_DIM(scheduler_ordering_map); i++) {
186                 if (scheduler_ordering_map[i].val !=
187                                 sched_ctx->reordering_enabled)
188                         continue;
189
190                 CR_SCHED_LOG(INFO, "  Packet ordering = %s",
191                                 scheduler_ordering_map[i].name);
192
193                 break;
194         }
195
196         for (i = 0; i < init_params->nb_slaves; i++) {
197                 sched_ctx->init_slave_names[sched_ctx->nb_init_slaves] =
198                         rte_zmalloc_socket(
199                                 NULL,
200                                 RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN, 0,
201                                 SOCKET_ID_ANY);
202
203                 if (!sched_ctx->init_slave_names[
204                                 sched_ctx->nb_init_slaves]) {
205                         CR_SCHED_LOG(ERR, "driver %s: Insufficient memory",
206                                         name);
207                         return -ENOMEM;
208                 }
209
210                 strncpy(sched_ctx->init_slave_names[
211                                         sched_ctx->nb_init_slaves],
212                                 init_params->slave_names[i],
213                                 RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN - 1);
214
215                 sched_ctx->nb_init_slaves++;
216         }
217
218         /*
219          * Initialize capabilities structure as an empty structure,
220          * in case device information is requested when no slaves are attached
221          */
222         sched_ctx->capabilities = rte_zmalloc_socket(NULL,
223                         sizeof(struct rte_cryptodev_capabilities),
224                         0, SOCKET_ID_ANY);
225
226         if (!sched_ctx->capabilities) {
227                 CR_SCHED_LOG(ERR, "Not enough memory for capability "
228                                 "information");
229                 return -ENOMEM;
230         }
231
232         return 0;
233 }
234
235 static int
236 cryptodev_scheduler_remove(struct rte_vdev_device *vdev)
237 {
238         const char *name;
239         struct rte_cryptodev *dev;
240         struct scheduler_ctx *sched_ctx;
241
242         if (vdev == NULL)
243                 return -EINVAL;
244
245         name = rte_vdev_device_name(vdev);
246         dev = rte_cryptodev_pmd_get_named_dev(name);
247         if (dev == NULL)
248                 return -EINVAL;
249
250         sched_ctx = dev->data->dev_private;
251
252         if (sched_ctx->nb_slaves) {
253                 uint32_t i;
254
255                 for (i = 0; i < sched_ctx->nb_slaves; i++)
256                         rte_cryptodev_scheduler_slave_detach(dev->data->dev_id,
257                                         sched_ctx->slaves[i].dev_id);
258         }
259
260         return rte_cryptodev_pmd_destroy(dev);
261 }
262
263 /** Parse integer from integer argument */
264 static int
265 parse_integer_arg(const char *key __rte_unused,
266                 const char *value, void *extra_args)
267 {
268         int *i = (int *) extra_args;
269
270         *i = atoi(value);
271         if (*i < 0) {
272                 CR_SCHED_LOG(ERR, "Argument has to be positive.");
273                 return -EINVAL;
274         }
275
276         return 0;
277 }
278
279 /** Parse integer from hexadecimal integer argument */
280 static int
281 parse_coremask_arg(const char *key __rte_unused,
282                 const char *value, void *extra_args)
283 {
284         int i, j, val;
285         uint16_t idx = 0;
286         char c;
287         struct scheduler_init_params *params = extra_args;
288
289         params->nb_wc = 0;
290
291         if (value == NULL)
292                 return -1;
293         /* Remove all blank characters ahead and after .
294          * Remove 0x/0X if exists.
295          */
296         while (isblank(*value))
297                 value++;
298         if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X')))
299                 value += 2;
300         i = strlen(value);
301         while ((i > 0) && isblank(value[i - 1]))
302                 i--;
303
304         if (i == 0)
305                 return -1;
306
307         for (i = i - 1; i >= 0 && idx < RTE_MAX_LCORE; i--) {
308                 c = value[i];
309                 if (isxdigit(c) == 0) {
310                         /* invalid characters */
311                         return -1;
312                 }
313                 if (isdigit(c))
314                         val = c - '0';
315                 else if (isupper(c))
316                         val = c - 'A' + 10;
317                 else
318                         val = c - 'a' + 10;
319
320                 for (j = 0; j < 4 && idx < RTE_MAX_LCORE; j++, idx++) {
321                         if ((1 << j) & val)
322                                 params->wc_pool[params->nb_wc++] = idx;
323                 }
324         }
325
326         return 0;
327 }
328
329 /** Parse integer from list of integers argument */
330 static int
331 parse_corelist_arg(const char *key __rte_unused,
332                 const char *value, void *extra_args)
333 {
334         struct scheduler_init_params *params = extra_args;
335
336         params->nb_wc = 0;
337
338         const char *token = value;
339
340         while (isdigit(token[0])) {
341                 char *rval;
342                 unsigned int core = strtoul(token, &rval, 10);
343
344                 if (core >= RTE_MAX_LCORE) {
345                         CR_SCHED_LOG(ERR, "Invalid worker core %u, should be smaller "
346                                    "than %u.", core, RTE_MAX_LCORE);
347                 }
348                 params->wc_pool[params->nb_wc++] = (uint16_t)core;
349                 token = (const char *)rval;
350                 if (token[0] == '\0')
351                         break;
352                 token++;
353         }
354
355         return 0;
356 }
357
358 /** Parse name */
359 static int
360 parse_name_arg(const char *key __rte_unused,
361                 const char *value, void *extra_args)
362 {
363         struct rte_cryptodev_pmd_init_params *params = extra_args;
364
365         if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) {
366                 CR_SCHED_LOG(ERR, "Invalid name %s, should be less than "
367                                 "%u bytes.", value,
368                                 RTE_CRYPTODEV_NAME_MAX_LEN - 1);
369                 return -EINVAL;
370         }
371
372         strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN);
373
374         return 0;
375 }
376
377 /** Parse slave */
378 static int
379 parse_slave_arg(const char *key __rte_unused,
380                 const char *value, void *extra_args)
381 {
382         struct scheduler_init_params *param = extra_args;
383
384         if (param->nb_slaves >= RTE_CRYPTODEV_SCHEDULER_MAX_NB_SLAVES) {
385                 CR_SCHED_LOG(ERR, "Too many slaves.");
386                 return -ENOMEM;
387         }
388
389         strncpy(param->slave_names[param->nb_slaves++], value,
390                         RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN - 1);
391
392         return 0;
393 }
394
395 static int
396 parse_mode_arg(const char *key __rte_unused,
397                 const char *value, void *extra_args)
398 {
399         struct scheduler_init_params *param = extra_args;
400         uint32_t i;
401
402         for (i = 0; i < RTE_DIM(scheduler_mode_map); i++) {
403                 if (strcmp(value, scheduler_mode_map[i].name) == 0) {
404                         param->mode = (enum rte_cryptodev_scheduler_mode)
405                                         scheduler_mode_map[i].val;
406
407                         break;
408                 }
409         }
410
411         if (i == RTE_DIM(scheduler_mode_map)) {
412                 CR_SCHED_LOG(ERR, "Unrecognized input.");
413                 return -EINVAL;
414         }
415
416         return 0;
417 }
418
419 static int
420 parse_mode_param_arg(const char *key __rte_unused,
421                 const char *value, void *extra_args)
422 {
423         struct scheduler_init_params *param = extra_args;
424
425         strlcpy(param->mode_param_str, value,
426                         RTE_CRYPTODEV_SCHEDULER_NAME_MAX_LEN);
427
428         return 0;
429 }
430
431 static int
432 parse_ordering_arg(const char *key __rte_unused,
433                 const char *value, void *extra_args)
434 {
435         struct scheduler_init_params *param = extra_args;
436         uint32_t i;
437
438         for (i = 0; i < RTE_DIM(scheduler_ordering_map); i++) {
439                 if (strcmp(value, scheduler_ordering_map[i].name) == 0) {
440                         param->enable_ordering =
441                                         scheduler_ordering_map[i].val;
442                         break;
443                 }
444         }
445
446         if (i == RTE_DIM(scheduler_ordering_map)) {
447                 CR_SCHED_LOG(ERR, "Unrecognized input.");
448                 return -EINVAL;
449         }
450
451         return 0;
452 }
453
454 static int
455 scheduler_parse_init_params(struct scheduler_init_params *params,
456                 const char *input_args)
457 {
458         struct rte_kvargs *kvlist = NULL;
459         int ret = 0;
460
461         if (params == NULL)
462                 return -EINVAL;
463
464         if (input_args) {
465                 kvlist = rte_kvargs_parse(input_args,
466                                 scheduler_valid_params);
467                 if (kvlist == NULL)
468                         return -1;
469
470                 ret = rte_kvargs_process(kvlist,
471                                 RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG,
472                                 &parse_integer_arg,
473                                 &params->def_p.max_nb_queue_pairs);
474                 if (ret < 0)
475                         goto free_kvlist;
476
477                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID,
478                                 &parse_integer_arg,
479                                 &params->def_p.socket_id);
480                 if (ret < 0)
481                         goto free_kvlist;
482
483                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_COREMASK,
484                                 &parse_coremask_arg,
485                                 params);
486                 if (ret < 0)
487                         goto free_kvlist;
488
489                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_CORELIST,
490                                 &parse_corelist_arg,
491                                 params);
492                 if (ret < 0)
493                         goto free_kvlist;
494
495                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME,
496                                 &parse_name_arg,
497                                 &params->def_p);
498                 if (ret < 0)
499                         goto free_kvlist;
500
501                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SLAVE,
502                                 &parse_slave_arg, params);
503                 if (ret < 0)
504                         goto free_kvlist;
505
506                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_MODE,
507                                 &parse_mode_arg, params);
508                 if (ret < 0)
509                         goto free_kvlist;
510
511                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_MODE_PARAM,
512                                 &parse_mode_param_arg, params);
513                 if (ret < 0)
514                         goto free_kvlist;
515
516                 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_ORDERING,
517                                 &parse_ordering_arg, params);
518                 if (ret < 0)
519                         goto free_kvlist;
520         }
521
522 free_kvlist:
523         rte_kvargs_free(kvlist);
524         return ret;
525 }
526
527 static int
528 cryptodev_scheduler_probe(struct rte_vdev_device *vdev)
529 {
530         struct scheduler_init_params init_params = {
531                 .def_p = {
532                         "",
533                         sizeof(struct scheduler_ctx),
534                         rte_socket_id(),
535                         RTE_CRYPTODEV_PMD_DEFAULT_MAX_NB_QUEUE_PAIRS
536                 },
537                 .nb_slaves = 0,
538                 .mode = CDEV_SCHED_MODE_NOT_SET,
539                 .enable_ordering = 0,
540                 .slave_names = { {0} }
541         };
542         const char *name;
543
544         name = rte_vdev_device_name(vdev);
545         if (name == NULL)
546                 return -EINVAL;
547
548         scheduler_parse_init_params(&init_params,
549                                     rte_vdev_device_args(vdev));
550
551
552         return cryptodev_scheduler_create(name,
553                                         vdev,
554                                         &init_params);
555 }
556
557 static struct rte_vdev_driver cryptodev_scheduler_pmd_drv = {
558         .probe = cryptodev_scheduler_probe,
559         .remove = cryptodev_scheduler_remove
560 };
561
562 static struct cryptodev_driver scheduler_crypto_drv;
563
564 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_SCHEDULER_PMD,
565         cryptodev_scheduler_pmd_drv);
566 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SCHEDULER_PMD,
567         "max_nb_queue_pairs=<int> "
568         "socket_id=<int> "
569         "slave=<name>");
570 RTE_PMD_REGISTER_CRYPTO_DRIVER(scheduler_crypto_drv,
571                 cryptodev_scheduler_pmd_drv.driver,
572                 cryptodev_scheduler_driver_id);