1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2017 Intel Corporation. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * * Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * * Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in 14 * the documentation and/or other materials provided with the 15 * distribution. 16 * * Neither the name of Intel Corporation nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 #include <rte_common.h> 33 #include <rte_hexdump.h> 34 #include <rte_cryptodev.h> 35 #include <rte_cryptodev_pmd.h> 36 #include <rte_vdev.h> 37 #include <rte_malloc.h> 38 #include <rte_cpuflags.h> 39 #include <rte_reorder.h> 40 #include <rte_cryptodev_scheduler.h> 41 42 #include "scheduler_pmd_private.h" 43 44 struct scheduler_init_params { 45 struct rte_crypto_vdev_init_params def_p; 46 uint32_t nb_slaves; 47 uint8_t slaves[MAX_SLAVES_NUM]; 48 }; 49 50 #define RTE_CRYPTODEV_VDEV_NAME ("name") 51 #define RTE_CRYPTODEV_VDEV_SLAVE ("slave") 52 #define RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG ("max_nb_queue_pairs") 53 #define RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG ("max_nb_sessions") 54 #define RTE_CRYPTODEV_VDEV_SOCKET_ID ("socket_id") 55 56 const char *scheduler_valid_params[] = { 57 RTE_CRYPTODEV_VDEV_NAME, 58 RTE_CRYPTODEV_VDEV_SLAVE, 59 RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG, 60 RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG, 61 RTE_CRYPTODEV_VDEV_SOCKET_ID 62 }; 63 64 static uint16_t 65 scheduler_enqueue_burst(void *queue_pair, struct rte_crypto_op **ops, 66 uint16_t nb_ops) 67 { 68 struct scheduler_qp_ctx *qp_ctx = queue_pair; 69 uint16_t processed_ops; 70 71 processed_ops = (*qp_ctx->schedule_enqueue)(qp_ctx, ops, 72 nb_ops); 73 74 return processed_ops; 75 } 76 77 static uint16_t 78 scheduler_dequeue_burst(void *queue_pair, struct rte_crypto_op **ops, 79 uint16_t nb_ops) 80 { 81 struct scheduler_qp_ctx *qp_ctx = queue_pair; 82 uint16_t processed_ops; 83 84 processed_ops = (*qp_ctx->schedule_dequeue)(qp_ctx, ops, 85 nb_ops); 86 87 return processed_ops; 88 } 89 90 static int 91 attach_init_slaves(uint8_t scheduler_id, 92 const uint8_t *slaves, const uint8_t nb_slaves) 93 { 94 uint8_t i; 95 96 for (i = 0; i < nb_slaves; i++) { 97 struct rte_cryptodev *dev = 98 rte_cryptodev_pmd_get_dev(slaves[i]); 99 int status = rte_cryptodev_scheduler_slave_attach( 100 scheduler_id, slaves[i]); 101 102 if (status < 0 || !dev) { 103 CS_LOG_ERR("Failed to attach slave cryptodev " 104 "%u.\n", slaves[i]); 105 return status; 106 } 107 108 RTE_LOG(INFO, PMD, " Attached slave cryptodev %s\n", 109 dev->data->name); 110 } 111 112 return 0; 113 } 114 115 static int 116 cryptodev_scheduler_create(const char *name, 117 struct scheduler_init_params *init_params) 118 { 119 char crypto_dev_name[RTE_CRYPTODEV_NAME_MAX_LEN] = {0}; 120 struct rte_cryptodev *dev; 121 struct scheduler_ctx *sched_ctx; 122 123 if (init_params->def_p.name[0] == '\0') { 124 int ret = rte_cryptodev_pmd_create_dev_name( 125 crypto_dev_name, 126 RTE_STR(CRYPTODEV_NAME_SCHEDULER_PMD)); 127 128 if (ret < 0) { 129 CS_LOG_ERR("failed to create unique name"); 130 return ret; 131 } 132 } else { 133 strncpy(crypto_dev_name, init_params->def_p.name, 134 RTE_CRYPTODEV_NAME_MAX_LEN - 1); 135 } 136 137 dev = rte_cryptodev_pmd_virtual_dev_init(crypto_dev_name, 138 sizeof(struct scheduler_ctx), 139 init_params->def_p.socket_id); 140 if (dev == NULL) { 141 CS_LOG_ERR("driver %s: failed to create cryptodev vdev", 142 name); 143 return -EFAULT; 144 } 145 146 dev->dev_type = RTE_CRYPTODEV_SCHEDULER_PMD; 147 dev->dev_ops = rte_crypto_scheduler_pmd_ops; 148 149 dev->enqueue_burst = scheduler_enqueue_burst; 150 dev->dequeue_burst = scheduler_dequeue_burst; 151 152 sched_ctx = dev->data->dev_private; 153 sched_ctx->max_nb_queue_pairs = 154 init_params->def_p.max_nb_queue_pairs; 155 156 return attach_init_slaves(dev->data->dev_id, init_params->slaves, 157 init_params->nb_slaves); 158 } 159 160 static int 161 cryptodev_scheduler_remove(const char *name) 162 { 163 struct rte_cryptodev *dev; 164 struct scheduler_ctx *sched_ctx; 165 166 if (name == NULL) 167 return -EINVAL; 168 169 dev = rte_cryptodev_pmd_get_named_dev(name); 170 if (dev == NULL) 171 return -EINVAL; 172 173 sched_ctx = dev->data->dev_private; 174 175 if (sched_ctx->nb_slaves) { 176 uint32_t i; 177 178 for (i = 0; i < sched_ctx->nb_slaves; i++) 179 rte_cryptodev_scheduler_slave_detach(dev->data->dev_id, 180 sched_ctx->slaves[i].dev_id); 181 } 182 183 RTE_LOG(INFO, PMD, "Closing Crypto Scheduler device %s on numa " 184 "socket %u\n", name, rte_socket_id()); 185 186 return 0; 187 } 188 189 static uint8_t 190 number_of_sockets(void) 191 { 192 int sockets = 0; 193 int i; 194 const struct rte_memseg *ms = rte_eal_get_physmem_layout(); 195 196 for (i = 0; ((i < RTE_MAX_MEMSEG) && (ms[i].addr != NULL)); i++) { 197 if (sockets < ms[i].socket_id) 198 sockets = ms[i].socket_id; 199 } 200 201 /* Number of sockets = maximum socket_id + 1 */ 202 return ++sockets; 203 } 204 205 /** Parse integer from integer argument */ 206 static int 207 parse_integer_arg(const char *key __rte_unused, 208 const char *value, void *extra_args) 209 { 210 int *i = (int *) extra_args; 211 212 *i = atoi(value); 213 if (*i < 0) { 214 CS_LOG_ERR("Argument has to be positive.\n"); 215 return -1; 216 } 217 218 return 0; 219 } 220 221 /** Parse name */ 222 static int 223 parse_name_arg(const char *key __rte_unused, 224 const char *value, void *extra_args) 225 { 226 struct rte_crypto_vdev_init_params *params = extra_args; 227 228 if (strlen(value) >= RTE_CRYPTODEV_NAME_MAX_LEN - 1) { 229 CS_LOG_ERR("Invalid name %s, should be less than " 230 "%u bytes.\n", value, 231 RTE_CRYPTODEV_NAME_MAX_LEN - 1); 232 return -1; 233 } 234 235 strncpy(params->name, value, RTE_CRYPTODEV_NAME_MAX_LEN); 236 237 return 0; 238 } 239 240 /** Parse slave */ 241 static int 242 parse_slave_arg(const char *key __rte_unused, 243 const char *value, void *extra_args) 244 { 245 struct scheduler_init_params *param = extra_args; 246 struct rte_cryptodev *dev = 247 rte_cryptodev_pmd_get_named_dev(value); 248 249 if (!dev) { 250 RTE_LOG(ERR, PMD, "Invalid slave name %s.\n", value); 251 return -1; 252 } 253 254 if (param->nb_slaves >= MAX_SLAVES_NUM - 1) { 255 CS_LOG_ERR("Too many slaves.\n"); 256 return -1; 257 } 258 259 param->slaves[param->nb_slaves] = dev->data->dev_id; 260 param->nb_slaves++; 261 262 return 0; 263 } 264 265 static int 266 scheduler_parse_init_params(struct scheduler_init_params *params, 267 const char *input_args) 268 { 269 struct rte_kvargs *kvlist = NULL; 270 int ret = 0; 271 272 if (params == NULL) 273 return -EINVAL; 274 275 if (input_args) { 276 kvlist = rte_kvargs_parse(input_args, 277 scheduler_valid_params); 278 if (kvlist == NULL) 279 return -1; 280 281 ret = rte_kvargs_process(kvlist, 282 RTE_CRYPTODEV_VDEV_MAX_NB_QP_ARG, 283 &parse_integer_arg, 284 ¶ms->def_p.max_nb_queue_pairs); 285 if (ret < 0) 286 goto free_kvlist; 287 288 ret = rte_kvargs_process(kvlist, 289 RTE_CRYPTODEV_VDEV_MAX_NB_SESS_ARG, 290 &parse_integer_arg, 291 ¶ms->def_p.max_nb_sessions); 292 if (ret < 0) 293 goto free_kvlist; 294 295 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SOCKET_ID, 296 &parse_integer_arg, 297 ¶ms->def_p.socket_id); 298 if (ret < 0) 299 goto free_kvlist; 300 301 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_NAME, 302 &parse_name_arg, 303 ¶ms->def_p); 304 if (ret < 0) 305 goto free_kvlist; 306 307 ret = rte_kvargs_process(kvlist, RTE_CRYPTODEV_VDEV_SLAVE, 308 &parse_slave_arg, params); 309 if (ret < 0) 310 goto free_kvlist; 311 312 if (params->def_p.socket_id >= number_of_sockets()) { 313 CDEV_LOG_ERR("Invalid socket id specified to create " 314 "the virtual crypto device on"); 315 goto free_kvlist; 316 } 317 } 318 319 free_kvlist: 320 rte_kvargs_free(kvlist); 321 return ret; 322 } 323 324 static int 325 cryptodev_scheduler_probe(const char *name, const char *input_args) 326 { 327 struct scheduler_init_params init_params = { 328 .def_p = { 329 RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_QUEUE_PAIRS, 330 RTE_CRYPTODEV_VDEV_DEFAULT_MAX_NB_SESSIONS, 331 rte_socket_id(), 332 "" 333 }, 334 .nb_slaves = 0, 335 .slaves = {0} 336 }; 337 338 scheduler_parse_init_params(&init_params, input_args); 339 340 RTE_LOG(INFO, PMD, "Initialising %s on NUMA node %d\n", name, 341 init_params.def_p.socket_id); 342 RTE_LOG(INFO, PMD, " Max number of queue pairs = %d\n", 343 init_params.def_p.max_nb_queue_pairs); 344 RTE_LOG(INFO, PMD, " Max number of sessions = %d\n", 345 init_params.def_p.max_nb_sessions); 346 if (init_params.def_p.name[0] != '\0') 347 RTE_LOG(INFO, PMD, " User defined name = %s\n", 348 init_params.def_p.name); 349 350 return cryptodev_scheduler_create(name, &init_params); 351 } 352 353 static struct rte_vdev_driver cryptodev_scheduler_pmd_drv = { 354 .probe = cryptodev_scheduler_probe, 355 .remove = cryptodev_scheduler_remove 356 }; 357 358 RTE_PMD_REGISTER_VDEV(CRYPTODEV_NAME_SCHEDULER_PMD, 359 cryptodev_scheduler_pmd_drv); 360 RTE_PMD_REGISTER_PARAM_STRING(CRYPTODEV_NAME_SCHEDULER_PMD, 361 "max_nb_queue_pairs=<int> " 362 "max_nb_sessions=<int> " 363 "socket_id=<int> " 364 "slave=<name>"); 365