xref: /dpdk/drivers/raw/skeleton/skeleton_rawdev.c (revision 089e5ed727a15da2729cfee9b63533dd120bd04c)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2017 NXP
3  */
4 
5 #include <assert.h>
6 #include <stdio.h>
7 #include <stdbool.h>
8 #include <errno.h>
9 #include <stdint.h>
10 #include <inttypes.h>
11 #include <string.h>
12 
13 #include <rte_byteorder.h>
14 #include <rte_common.h>
15 #include <rte_debug.h>
16 #include <rte_dev.h>
17 #include <rte_eal.h>
18 #include <rte_kvargs.h>
19 #include <rte_log.h>
20 #include <rte_malloc.h>
21 #include <rte_memory.h>
22 #include <rte_memcpy.h>
23 #include <rte_lcore.h>
24 #include <rte_bus_vdev.h>
25 
26 #include <rte_rawdev.h>
27 #include <rte_rawdev_pmd.h>
28 
29 #include "skeleton_rawdev.h"
30 
31 /* Dynamic log type identifier */
32 int skeleton_pmd_logtype;
33 
34 /* Count of instances */
35 static uint16_t skeldev_init_once;
36 
37 /**< Rawdev Skeleton dummy driver name */
38 #define SKELETON_PMD_RAWDEV_NAME rawdev_skeleton
39 
40 struct queue_buffers {
41 	void *bufs[SKELETON_QUEUE_MAX_DEPTH];
42 };
43 
44 static struct queue_buffers queue_buf[SKELETON_MAX_QUEUES] = {};
45 static void clear_queue_bufs(int queue_id);
46 
47 static void skeleton_rawdev_info_get(struct rte_rawdev *dev,
48 				     rte_rawdev_obj_t dev_info)
49 {
50 	struct skeleton_rawdev *skeldev;
51 	struct skeleton_rawdev_conf *skeldev_conf;
52 
53 	SKELETON_PMD_FUNC_TRACE();
54 
55 	if (!dev_info) {
56 		SKELETON_PMD_ERR("Invalid request");
57 		return;
58 	}
59 
60 	skeldev = skeleton_rawdev_get_priv(dev);
61 
62 	skeldev_conf = dev_info;
63 
64 	skeldev_conf->num_queues = skeldev->num_queues;
65 	skeldev_conf->capabilities = skeldev->capabilities;
66 	skeldev_conf->device_state = skeldev->device_state;
67 	skeldev_conf->firmware_state = skeldev->fw.firmware_state;
68 }
69 
70 static int skeleton_rawdev_configure(const struct rte_rawdev *dev,
71 				     rte_rawdev_obj_t config)
72 {
73 	struct skeleton_rawdev *skeldev;
74 	struct skeleton_rawdev_conf *skeldev_conf;
75 
76 	SKELETON_PMD_FUNC_TRACE();
77 
78 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
79 
80 	if (!config) {
81 		SKELETON_PMD_ERR("Invalid configuration");
82 		return -EINVAL;
83 	}
84 
85 	skeldev_conf = config;
86 	skeldev = skeleton_rawdev_get_priv(dev);
87 
88 	if (skeldev_conf->num_queues <= SKELETON_MAX_QUEUES)
89 		skeldev->num_queues = skeldev_conf->num_queues;
90 	else
91 		return -EINVAL;
92 
93 	skeldev->capabilities = skeldev_conf->capabilities;
94 	skeldev->num_queues = skeldev_conf->num_queues;
95 
96 	return 0;
97 }
98 
99 static int skeleton_rawdev_start(struct rte_rawdev *dev)
100 {
101 	int ret = 0;
102 	struct skeleton_rawdev *skeldev;
103 	enum skeleton_firmware_state fw_state;
104 	enum skeleton_device_state device_state;
105 
106 	SKELETON_PMD_FUNC_TRACE();
107 
108 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
109 
110 	skeldev = skeleton_rawdev_get_priv(dev);
111 
112 	fw_state = skeldev->fw.firmware_state;
113 	device_state = skeldev->device_state;
114 
115 	if (fw_state == SKELETON_FW_LOADED &&
116 		device_state == SKELETON_DEV_STOPPED) {
117 		skeldev->device_state = SKELETON_DEV_RUNNING;
118 	} else {
119 		SKELETON_PMD_ERR("Device not ready for starting");
120 		ret = -EINVAL;
121 	}
122 
123 	return ret;
124 }
125 
126 static void skeleton_rawdev_stop(struct rte_rawdev *dev)
127 {
128 	struct skeleton_rawdev *skeldev;
129 
130 	SKELETON_PMD_FUNC_TRACE();
131 
132 	if (dev) {
133 		skeldev = skeleton_rawdev_get_priv(dev);
134 		skeldev->device_state = SKELETON_DEV_STOPPED;
135 	}
136 }
137 
138 static void
139 reset_queues(struct skeleton_rawdev *skeldev)
140 {
141 	int i;
142 
143 	for (i = 0; i < SKELETON_MAX_QUEUES; i++) {
144 		skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH;
145 		skeldev->queues[i].state = SKELETON_QUEUE_DETACH;
146 	}
147 }
148 
149 static void
150 reset_attribute_table(struct skeleton_rawdev *skeldev)
151 {
152 	int i;
153 
154 	for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) {
155 		if (skeldev->attr[i].name) {
156 			free(skeldev->attr[i].name);
157 			skeldev->attr[i].name = NULL;
158 		}
159 	}
160 }
161 
162 static int skeleton_rawdev_close(struct rte_rawdev *dev)
163 {
164 	int ret = 0, i;
165 	struct skeleton_rawdev *skeldev;
166 	enum skeleton_firmware_state fw_state;
167 	enum skeleton_device_state device_state;
168 
169 	SKELETON_PMD_FUNC_TRACE();
170 
171 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
172 
173 	skeldev = skeleton_rawdev_get_priv(dev);
174 
175 	fw_state = skeldev->fw.firmware_state;
176 	device_state = skeldev->device_state;
177 
178 	reset_queues(skeldev);
179 	reset_attribute_table(skeldev);
180 
181 	switch (fw_state) {
182 	case SKELETON_FW_LOADED:
183 		if (device_state == SKELETON_DEV_RUNNING) {
184 			SKELETON_PMD_ERR("Cannot close running device");
185 			ret = -EINVAL;
186 		} else {
187 			/* Probably call fw reset here */
188 			skeldev->fw.firmware_state = SKELETON_FW_READY;
189 		}
190 		break;
191 	case SKELETON_FW_READY:
192 	case SKELETON_FW_ERROR:
193 	default:
194 		SKELETON_PMD_DEBUG("Device already in stopped state");
195 		ret = -EINVAL;
196 		break;
197 	}
198 
199 	/* Clear all allocated queues */
200 	for (i = 0; i < SKELETON_MAX_QUEUES; i++)
201 		clear_queue_bufs(i);
202 
203 	return ret;
204 }
205 
206 static int skeleton_rawdev_reset(struct rte_rawdev *dev)
207 {
208 	struct skeleton_rawdev *skeldev;
209 
210 	SKELETON_PMD_FUNC_TRACE();
211 
212 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
213 
214 	skeldev = skeleton_rawdev_get_priv(dev);
215 
216 	SKELETON_PMD_DEBUG("Resetting device");
217 	skeldev->fw.firmware_state = SKELETON_FW_READY;
218 
219 	return 0;
220 }
221 
222 static void skeleton_rawdev_queue_def_conf(struct rte_rawdev *dev,
223 					   uint16_t queue_id,
224 					   rte_rawdev_obj_t queue_conf)
225 {
226 	struct skeleton_rawdev *skeldev;
227 	struct skeleton_rawdev_queue *skelq;
228 
229 	SKELETON_PMD_FUNC_TRACE();
230 
231 	if (!dev || !queue_conf)
232 		return;
233 
234 	skeldev = skeleton_rawdev_get_priv(dev);
235 	skelq = &skeldev->queues[queue_id];
236 
237 	if (queue_id < SKELETON_MAX_QUEUES)
238 		rte_memcpy(queue_conf, skelq,
239 			sizeof(struct skeleton_rawdev_queue));
240 }
241 
242 static void
243 clear_queue_bufs(int queue_id)
244 {
245 	int i;
246 
247 	/* Clear buffers for queue_id */
248 	for (i = 0; i < SKELETON_QUEUE_MAX_DEPTH; i++)
249 		queue_buf[queue_id].bufs[i] = NULL;
250 }
251 
252 static int skeleton_rawdev_queue_setup(struct rte_rawdev *dev,
253 				       uint16_t queue_id,
254 				       rte_rawdev_obj_t queue_conf)
255 {
256 	int ret = 0;
257 	struct skeleton_rawdev *skeldev;
258 	struct skeleton_rawdev_queue *q;
259 
260 	SKELETON_PMD_FUNC_TRACE();
261 
262 	if (!dev || !queue_conf)
263 		return -EINVAL;
264 
265 	skeldev = skeleton_rawdev_get_priv(dev);
266 	q = &skeldev->queues[queue_id];
267 
268 	if (skeldev->num_queues > queue_id &&
269 	    q->depth < SKELETON_QUEUE_MAX_DEPTH) {
270 		rte_memcpy(q, queue_conf,
271 			   sizeof(struct skeleton_rawdev_queue));
272 		clear_queue_bufs(queue_id);
273 	} else {
274 		SKELETON_PMD_ERR("Invalid queue configuration");
275 		ret = -EINVAL;
276 	}
277 
278 	return ret;
279 }
280 
281 static int skeleton_rawdev_queue_release(struct rte_rawdev *dev,
282 					 uint16_t queue_id)
283 {
284 	int ret = 0;
285 	struct skeleton_rawdev *skeldev;
286 
287 	SKELETON_PMD_FUNC_TRACE();
288 
289 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
290 
291 	skeldev = skeleton_rawdev_get_priv(dev);
292 
293 	if (skeldev->num_queues > queue_id) {
294 		skeldev->queues[queue_id].state = SKELETON_QUEUE_DETACH;
295 		skeldev->queues[queue_id].depth = SKELETON_QUEUE_DEF_DEPTH;
296 		clear_queue_bufs(queue_id);
297 	} else {
298 		SKELETON_PMD_ERR("Invalid queue configuration");
299 		ret = -EINVAL;
300 	}
301 
302 	return ret;
303 }
304 
305 static uint16_t skeleton_rawdev_queue_count(struct rte_rawdev *dev)
306 {
307 	struct skeleton_rawdev *skeldev;
308 
309 	SKELETON_PMD_FUNC_TRACE();
310 
311 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
312 
313 	skeldev = skeleton_rawdev_get_priv(dev);
314 	return skeldev->num_queues;
315 }
316 
317 static int skeleton_rawdev_get_attr(struct rte_rawdev *dev,
318 				    const char *attr_name,
319 				    uint64_t *attr_value)
320 {
321 	int i;
322 	uint8_t done = 0;
323 	struct skeleton_rawdev *skeldev;
324 
325 	SKELETON_PMD_FUNC_TRACE();
326 
327 	if (!dev || !attr_name || !attr_value) {
328 		SKELETON_PMD_ERR("Invalid arguments for getting attributes");
329 		return -EINVAL;
330 	}
331 
332 	skeldev = skeleton_rawdev_get_priv(dev);
333 
334 	for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) {
335 		if (!skeldev->attr[i].name)
336 			continue;
337 
338 		if (!strncmp(skeldev->attr[i].name, attr_name,
339 			    SKELETON_ATTRIBUTE_NAME_MAX)) {
340 			*attr_value = skeldev->attr[i].value;
341 			done = 1;
342 			SKELETON_PMD_DEBUG("Attribute (%s) Value (%" PRIu64 ")",
343 					   attr_name, *attr_value);
344 			break;
345 		}
346 	}
347 
348 	if (done)
349 		return 0;
350 
351 	/* Attribute not found */
352 	return -EINVAL;
353 }
354 
355 static int skeleton_rawdev_set_attr(struct rte_rawdev *dev,
356 				     const char *attr_name,
357 				     const uint64_t attr_value)
358 {
359 	int i;
360 	uint8_t done = 0;
361 	struct skeleton_rawdev *skeldev;
362 
363 	SKELETON_PMD_FUNC_TRACE();
364 
365 	if (!dev || !attr_name) {
366 		SKELETON_PMD_ERR("Invalid arguments for setting attributes");
367 		return -EINVAL;
368 	}
369 
370 	skeldev = skeleton_rawdev_get_priv(dev);
371 
372 	/* Check if attribute already exists */
373 	for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) {
374 		if (!skeldev->attr[i].name)
375 			break;
376 
377 		if (!strncmp(skeldev->attr[i].name, attr_name,
378 			     SKELETON_ATTRIBUTE_NAME_MAX)) {
379 			/* Update value */
380 			skeldev->attr[i].value = attr_value;
381 			done = 1;
382 			break;
383 		}
384 	}
385 
386 	if (!done) {
387 		if (i < (SKELETON_MAX_ATTRIBUTES - 1)) {
388 			/* There is still space to insert one more */
389 			skeldev->attr[i].name = strdup(attr_name);
390 			if (!skeldev->attr[i].name)
391 				return -ENOMEM;
392 
393 			skeldev->attr[i].value = attr_value;
394 			return 0;
395 		}
396 	}
397 
398 	return -EINVAL;
399 }
400 
401 static int skeleton_rawdev_enqueue_bufs(struct rte_rawdev *dev,
402 					struct rte_rawdev_buf **buffers,
403 					unsigned int count,
404 					rte_rawdev_obj_t context)
405 {
406 	unsigned int i;
407 	uint16_t q_id;
408 	RTE_SET_USED(dev);
409 
410 	/* context is essentially the queue_id which is
411 	 * transferred as opaque object through the library layer. This can
412 	 * help in complex implementation which require more information than
413 	 * just an integer - for example, a queue-pair.
414 	 */
415 	q_id = *((int *)context);
416 
417 	for (i = 0; i < count; i++)
418 		queue_buf[q_id].bufs[i] = buffers[i]->buf_addr;
419 
420 	return i;
421 }
422 
423 static int skeleton_rawdev_dequeue_bufs(struct rte_rawdev *dev,
424 					struct rte_rawdev_buf **buffers,
425 					unsigned int count,
426 					rte_rawdev_obj_t context)
427 {
428 	unsigned int i;
429 	uint16_t q_id;
430 	RTE_SET_USED(dev);
431 
432 	/* context is essentially the queue_id which is
433 	 * transferred as opaque object through the library layer. This can
434 	 * help in complex implementation which require more information than
435 	 * just an integer - for example, a queue-pair.
436 	 */
437 	q_id = *((int *)context);
438 
439 	for (i = 0; i < count; i++)
440 		buffers[i]->buf_addr = queue_buf[q_id].bufs[i];
441 
442 	return i;
443 }
444 
445 static int skeleton_rawdev_dump(struct rte_rawdev *dev, FILE *f)
446 {
447 	RTE_SET_USED(dev);
448 	RTE_SET_USED(f);
449 
450 	return 0;
451 }
452 
453 static int skeleton_rawdev_firmware_status_get(struct rte_rawdev *dev,
454 					       rte_rawdev_obj_t status_info)
455 {
456 	struct skeleton_rawdev *skeldev;
457 
458 	SKELETON_PMD_FUNC_TRACE();
459 
460 	skeldev = skeleton_rawdev_get_priv(dev);
461 
462 	RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
463 
464 	if (status_info)
465 		memcpy(status_info, &skeldev->fw.firmware_state,
466 			sizeof(enum skeleton_firmware_state));
467 
468 	return 0;
469 }
470 
471 
472 static int skeleton_rawdev_firmware_version_get(
473 					struct rte_rawdev *dev,
474 					rte_rawdev_obj_t version_info)
475 {
476 	struct skeleton_rawdev *skeldev;
477 	struct skeleton_firmware_version_info *vi;
478 
479 	SKELETON_PMD_FUNC_TRACE();
480 
481 	skeldev = skeleton_rawdev_get_priv(dev);
482 	vi = version_info;
483 
484 	vi->major = skeldev->fw.firmware_version.major;
485 	vi->minor = skeldev->fw.firmware_version.minor;
486 	vi->subrel = skeldev->fw.firmware_version.subrel;
487 
488 	return 0;
489 }
490 
491 static int skeleton_rawdev_firmware_load(struct rte_rawdev *dev,
492 					 rte_rawdev_obj_t firmware_buf)
493 {
494 	struct skeleton_rawdev *skeldev;
495 
496 	SKELETON_PMD_FUNC_TRACE();
497 
498 	skeldev = skeleton_rawdev_get_priv(dev);
499 
500 	/* firmware_buf is a mmaped, possibly DMA'able area, buffer. Being
501 	 * dummy, all this does is check if firmware_buf is not NULL and
502 	 * sets the state of the firmware.
503 	 */
504 	if (!firmware_buf)
505 		return -EINVAL;
506 
507 	skeldev->fw.firmware_state = SKELETON_FW_LOADED;
508 
509 	return 0;
510 }
511 
512 static int skeleton_rawdev_firmware_unload(struct rte_rawdev *dev)
513 {
514 	struct skeleton_rawdev *skeldev;
515 
516 	SKELETON_PMD_FUNC_TRACE();
517 
518 	skeldev = skeleton_rawdev_get_priv(dev);
519 
520 	skeldev->fw.firmware_state = SKELETON_FW_READY;
521 
522 	return 0;
523 }
524 
525 static const struct rte_rawdev_ops skeleton_rawdev_ops = {
526 	.dev_info_get = skeleton_rawdev_info_get,
527 	.dev_configure = skeleton_rawdev_configure,
528 	.dev_start = skeleton_rawdev_start,
529 	.dev_stop = skeleton_rawdev_stop,
530 	.dev_close = skeleton_rawdev_close,
531 	.dev_reset = skeleton_rawdev_reset,
532 
533 	.queue_def_conf = skeleton_rawdev_queue_def_conf,
534 	.queue_setup = skeleton_rawdev_queue_setup,
535 	.queue_release = skeleton_rawdev_queue_release,
536 	.queue_count = skeleton_rawdev_queue_count,
537 
538 	.attr_get = skeleton_rawdev_get_attr,
539 	.attr_set = skeleton_rawdev_set_attr,
540 
541 	.enqueue_bufs = skeleton_rawdev_enqueue_bufs,
542 	.dequeue_bufs = skeleton_rawdev_dequeue_bufs,
543 
544 	.dump = skeleton_rawdev_dump,
545 
546 	.xstats_get = NULL,
547 	.xstats_get_names = NULL,
548 	.xstats_get_by_name = NULL,
549 	.xstats_reset = NULL,
550 
551 	.firmware_status_get = skeleton_rawdev_firmware_status_get,
552 	.firmware_version_get = skeleton_rawdev_firmware_version_get,
553 	.firmware_load = skeleton_rawdev_firmware_load,
554 	.firmware_unload = skeleton_rawdev_firmware_unload,
555 
556 	.dev_selftest = test_rawdev_skeldev,
557 };
558 
559 static int
560 skeleton_rawdev_create(const char *name,
561 		       struct rte_vdev_device *vdev,
562 		       int socket_id)
563 {
564 	int ret = 0, i;
565 	struct rte_rawdev *rawdev = NULL;
566 	struct skeleton_rawdev *skeldev = NULL;
567 
568 	if (!name) {
569 		SKELETON_PMD_ERR("Invalid name of the device!");
570 		ret = -EINVAL;
571 		goto cleanup;
572 	}
573 
574 	/* Allocate device structure */
575 	rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct skeleton_rawdev),
576 					 socket_id);
577 	if (rawdev == NULL) {
578 		SKELETON_PMD_ERR("Unable to allocate rawdevice");
579 		ret = -EINVAL;
580 		goto cleanup;
581 	}
582 
583 	ret = rawdev->dev_id; /* return the rawdev id of new device */
584 
585 	rawdev->dev_ops = &skeleton_rawdev_ops;
586 	rawdev->device = &vdev->device;
587 
588 	skeldev = skeleton_rawdev_get_priv(rawdev);
589 
590 	skeldev->device_id = SKELETON_DEVICE_ID;
591 	skeldev->vendor_id = SKELETON_VENDOR_ID;
592 	skeldev->capabilities = SKELETON_DEFAULT_CAPA;
593 
594 	memset(&skeldev->fw, 0, sizeof(struct skeleton_firmware));
595 
596 	skeldev->fw.firmware_state = SKELETON_FW_READY;
597 	skeldev->fw.firmware_version.major = SKELETON_MAJOR_VER;
598 	skeldev->fw.firmware_version.minor = SKELETON_MINOR_VER;
599 	skeldev->fw.firmware_version.subrel = SKELETON_SUB_VER;
600 
601 	skeldev->device_state = SKELETON_DEV_STOPPED;
602 
603 	/* Reset/set to default queue configuration for this device */
604 	for (i = 0; i < SKELETON_MAX_QUEUES; i++) {
605 		skeldev->queues[i].state = SKELETON_QUEUE_DETACH;
606 		skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH;
607 	}
608 
609 	/* Clear all allocated queue buffers */
610 	for (i = 0; i < SKELETON_MAX_QUEUES; i++)
611 		clear_queue_bufs(i);
612 
613 	return ret;
614 
615 cleanup:
616 	if (rawdev)
617 		rte_rawdev_pmd_release(rawdev);
618 
619 	return ret;
620 }
621 
622 static int
623 skeleton_rawdev_destroy(const char *name)
624 {
625 	int ret;
626 	struct rte_rawdev *rdev;
627 
628 	if (!name) {
629 		SKELETON_PMD_ERR("Invalid device name");
630 		return -EINVAL;
631 	}
632 
633 	rdev = rte_rawdev_pmd_get_named_dev(name);
634 	if (!rdev) {
635 		SKELETON_PMD_ERR("Invalid device name (%s)", name);
636 		return -EINVAL;
637 	}
638 
639 	/* rte_rawdev_close is called by pmd_release */
640 	ret = rte_rawdev_pmd_release(rdev);
641 	if (ret)
642 		SKELETON_PMD_DEBUG("Device cleanup failed");
643 
644 	return 0;
645 }
646 
647 static int
648 skeldev_get_selftest(const char *key __rte_unused,
649 		     const char *value,
650 		     void *opaque)
651 {
652 	int *flag = opaque;
653 	*flag = atoi(value);
654 	return 0;
655 }
656 
657 static int
658 skeldev_parse_vdev_args(struct rte_vdev_device *vdev)
659 {
660 	int selftest = 0;
661 	const char *name;
662 	const char *params;
663 
664 	static const char *const args[] = {
665 		SKELETON_SELFTEST_ARG,
666 		NULL
667 	};
668 
669 	name = rte_vdev_device_name(vdev);
670 
671 	params = rte_vdev_device_args(vdev);
672 	if (params != NULL && params[0] != '\0') {
673 		struct rte_kvargs *kvlist = rte_kvargs_parse(params, args);
674 
675 		if (!kvlist) {
676 			SKELETON_PMD_INFO(
677 				"Ignoring unsupported params supplied '%s'",
678 				name);
679 		} else {
680 			int ret = rte_kvargs_process(kvlist,
681 					SKELETON_SELFTEST_ARG,
682 					skeldev_get_selftest, &selftest);
683 			if (ret != 0 || (selftest < 0 || selftest > 1)) {
684 				SKELETON_PMD_ERR("%s: Error in parsing args",
685 						 name);
686 				rte_kvargs_free(kvlist);
687 				ret = -1; /* enforce if selftest is invalid */
688 				return ret;
689 			}
690 		}
691 
692 		rte_kvargs_free(kvlist);
693 	}
694 
695 	return selftest;
696 }
697 
698 static int
699 skeleton_rawdev_probe(struct rte_vdev_device *vdev)
700 {
701 	const char *name;
702 	int selftest = 0, ret = 0;
703 
704 
705 	name = rte_vdev_device_name(vdev);
706 	if (name == NULL)
707 		return -EINVAL;
708 
709 	/* More than one instance is not supported */
710 	if (skeldev_init_once) {
711 		SKELETON_PMD_ERR("Multiple instance not supported for %s",
712 				 name);
713 		return -EINVAL;
714 	}
715 
716 	SKELETON_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id());
717 
718 	selftest = skeldev_parse_vdev_args(vdev);
719 	/* In case of invalid argument, selftest != 1; ignore other values */
720 
721 	ret = skeleton_rawdev_create(name, vdev, rte_socket_id());
722 	if (ret >= 0) {
723 		/* In case command line argument for 'selftest' was passed;
724 		 * if invalid arguments were passed, execution continues but
725 		 * without selftest.
726 		 */
727 		if (selftest == 1)
728 			test_rawdev_skeldev(ret);
729 	}
730 
731 	/* Device instance created; Second instance not possible */
732 	skeldev_init_once = 1;
733 
734 	return ret < 0 ? ret : 0;
735 }
736 
737 static int
738 skeleton_rawdev_remove(struct rte_vdev_device *vdev)
739 {
740 	const char *name;
741 	int ret;
742 
743 	name = rte_vdev_device_name(vdev);
744 	if (name == NULL)
745 		return -1;
746 
747 	SKELETON_PMD_INFO("Closing %s on NUMA node %d", name, rte_socket_id());
748 
749 	ret = skeleton_rawdev_destroy(name);
750 	if (!ret)
751 		skeldev_init_once = 0;
752 
753 	return ret;
754 }
755 
756 static struct rte_vdev_driver skeleton_pmd_drv = {
757 	.probe = skeleton_rawdev_probe,
758 	.remove = skeleton_rawdev_remove
759 };
760 
761 RTE_PMD_REGISTER_VDEV(SKELETON_PMD_RAWDEV_NAME, skeleton_pmd_drv);
762 
763 RTE_INIT(skeleton_pmd_init_log)
764 {
765 	skeleton_pmd_logtype = rte_log_register("rawdev.skeleton");
766 	if (skeleton_pmd_logtype >= 0)
767 		rte_log_set_level(skeleton_pmd_logtype, RTE_LOG_INFO);
768 }
769