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