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