rawdev: allow queue config query to return error
[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 int 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 -EINVAL;
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         return 0;
245 }
246
247 static void
248 clear_queue_bufs(int queue_id)
249 {
250         int i;
251
252         /* Clear buffers for queue_id */
253         for (i = 0; i < SKELETON_QUEUE_MAX_DEPTH; i++)
254                 queue_buf[queue_id].bufs[i] = NULL;
255 }
256
257 static int skeleton_rawdev_queue_setup(struct rte_rawdev *dev,
258                                        uint16_t queue_id,
259                                        rte_rawdev_obj_t queue_conf,
260                                        size_t conf_size)
261 {
262         int ret = 0;
263         struct skeleton_rawdev *skeldev;
264         struct skeleton_rawdev_queue *q;
265
266         SKELETON_PMD_FUNC_TRACE();
267
268         if (!dev || !queue_conf ||
269                         conf_size != sizeof(struct skeleton_rawdev_queue))
270                 return -EINVAL;
271
272         skeldev = skeleton_rawdev_get_priv(dev);
273         q = &skeldev->queues[queue_id];
274
275         if (skeldev->num_queues > queue_id &&
276             q->depth < SKELETON_QUEUE_MAX_DEPTH) {
277                 rte_memcpy(q, queue_conf,
278                            sizeof(struct skeleton_rawdev_queue));
279                 clear_queue_bufs(queue_id);
280         } else {
281                 SKELETON_PMD_ERR("Invalid queue configuration");
282                 ret = -EINVAL;
283         }
284
285         return ret;
286 }
287
288 static int skeleton_rawdev_queue_release(struct rte_rawdev *dev,
289                                          uint16_t queue_id)
290 {
291         int ret = 0;
292         struct skeleton_rawdev *skeldev;
293
294         SKELETON_PMD_FUNC_TRACE();
295
296         RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
297
298         skeldev = skeleton_rawdev_get_priv(dev);
299
300         if (skeldev->num_queues > queue_id) {
301                 skeldev->queues[queue_id].state = SKELETON_QUEUE_DETACH;
302                 skeldev->queues[queue_id].depth = SKELETON_QUEUE_DEF_DEPTH;
303                 clear_queue_bufs(queue_id);
304         } else {
305                 SKELETON_PMD_ERR("Invalid queue configuration");
306                 ret = -EINVAL;
307         }
308
309         return ret;
310 }
311
312 static uint16_t skeleton_rawdev_queue_count(struct rte_rawdev *dev)
313 {
314         struct skeleton_rawdev *skeldev;
315
316         SKELETON_PMD_FUNC_TRACE();
317
318         RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
319
320         skeldev = skeleton_rawdev_get_priv(dev);
321         return skeldev->num_queues;
322 }
323
324 static int skeleton_rawdev_get_attr(struct rte_rawdev *dev,
325                                     const char *attr_name,
326                                     uint64_t *attr_value)
327 {
328         int i;
329         uint8_t done = 0;
330         struct skeleton_rawdev *skeldev;
331
332         SKELETON_PMD_FUNC_TRACE();
333
334         if (!dev || !attr_name || !attr_value) {
335                 SKELETON_PMD_ERR("Invalid arguments for getting attributes");
336                 return -EINVAL;
337         }
338
339         skeldev = skeleton_rawdev_get_priv(dev);
340
341         for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) {
342                 if (!skeldev->attr[i].name)
343                         continue;
344
345                 if (!strncmp(skeldev->attr[i].name, attr_name,
346                             SKELETON_ATTRIBUTE_NAME_MAX)) {
347                         *attr_value = skeldev->attr[i].value;
348                         done = 1;
349                         SKELETON_PMD_DEBUG("Attribute (%s) Value (%" PRIu64 ")",
350                                            attr_name, *attr_value);
351                         break;
352                 }
353         }
354
355         if (done)
356                 return 0;
357
358         /* Attribute not found */
359         return -EINVAL;
360 }
361
362 static int skeleton_rawdev_set_attr(struct rte_rawdev *dev,
363                                      const char *attr_name,
364                                      const uint64_t attr_value)
365 {
366         int i;
367         uint8_t done = 0;
368         struct skeleton_rawdev *skeldev;
369
370         SKELETON_PMD_FUNC_TRACE();
371
372         if (!dev || !attr_name) {
373                 SKELETON_PMD_ERR("Invalid arguments for setting attributes");
374                 return -EINVAL;
375         }
376
377         skeldev = skeleton_rawdev_get_priv(dev);
378
379         /* Check if attribute already exists */
380         for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) {
381                 if (!skeldev->attr[i].name)
382                         break;
383
384                 if (!strncmp(skeldev->attr[i].name, attr_name,
385                              SKELETON_ATTRIBUTE_NAME_MAX)) {
386                         /* Update value */
387                         skeldev->attr[i].value = attr_value;
388                         done = 1;
389                         break;
390                 }
391         }
392
393         if (!done) {
394                 if (i < (SKELETON_MAX_ATTRIBUTES - 1)) {
395                         /* There is still space to insert one more */
396                         skeldev->attr[i].name = strdup(attr_name);
397                         if (!skeldev->attr[i].name)
398                                 return -ENOMEM;
399
400                         skeldev->attr[i].value = attr_value;
401                         return 0;
402                 }
403         }
404
405         return -EINVAL;
406 }
407
408 static int skeleton_rawdev_enqueue_bufs(struct rte_rawdev *dev,
409                                         struct rte_rawdev_buf **buffers,
410                                         unsigned int count,
411                                         rte_rawdev_obj_t context)
412 {
413         unsigned int i;
414         uint16_t q_id;
415         RTE_SET_USED(dev);
416
417         /* context is essentially the queue_id which is
418          * transferred as opaque object through the library layer. This can
419          * help in complex implementation which require more information than
420          * just an integer - for example, a queue-pair.
421          */
422         q_id = *((int *)context);
423
424         for (i = 0; i < count; i++)
425                 queue_buf[q_id].bufs[i] = buffers[i]->buf_addr;
426
427         return i;
428 }
429
430 static int skeleton_rawdev_dequeue_bufs(struct rte_rawdev *dev,
431                                         struct rte_rawdev_buf **buffers,
432                                         unsigned int count,
433                                         rte_rawdev_obj_t context)
434 {
435         unsigned int i;
436         uint16_t q_id;
437         RTE_SET_USED(dev);
438
439         /* context is essentially the queue_id which is
440          * transferred as opaque object through the library layer. This can
441          * help in complex implementation which require more information than
442          * just an integer - for example, a queue-pair.
443          */
444         q_id = *((int *)context);
445
446         for (i = 0; i < count; i++)
447                 buffers[i]->buf_addr = queue_buf[q_id].bufs[i];
448
449         return i;
450 }
451
452 static int skeleton_rawdev_dump(struct rte_rawdev *dev, FILE *f)
453 {
454         RTE_SET_USED(dev);
455         RTE_SET_USED(f);
456
457         return 0;
458 }
459
460 static int skeleton_rawdev_firmware_status_get(struct rte_rawdev *dev,
461                                                rte_rawdev_obj_t status_info)
462 {
463         struct skeleton_rawdev *skeldev;
464
465         SKELETON_PMD_FUNC_TRACE();
466
467         skeldev = skeleton_rawdev_get_priv(dev);
468
469         RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL);
470
471         if (status_info)
472                 memcpy(status_info, &skeldev->fw.firmware_state,
473                         sizeof(enum skeleton_firmware_state));
474
475         return 0;
476 }
477
478
479 static int skeleton_rawdev_firmware_version_get(
480                                         struct rte_rawdev *dev,
481                                         rte_rawdev_obj_t version_info)
482 {
483         struct skeleton_rawdev *skeldev;
484         struct skeleton_firmware_version_info *vi;
485
486         SKELETON_PMD_FUNC_TRACE();
487
488         skeldev = skeleton_rawdev_get_priv(dev);
489         vi = version_info;
490
491         vi->major = skeldev->fw.firmware_version.major;
492         vi->minor = skeldev->fw.firmware_version.minor;
493         vi->subrel = skeldev->fw.firmware_version.subrel;
494
495         return 0;
496 }
497
498 static int skeleton_rawdev_firmware_load(struct rte_rawdev *dev,
499                                          rte_rawdev_obj_t firmware_buf)
500 {
501         struct skeleton_rawdev *skeldev;
502
503         SKELETON_PMD_FUNC_TRACE();
504
505         skeldev = skeleton_rawdev_get_priv(dev);
506
507         /* firmware_buf is a mmaped, possibly DMA'able area, buffer. Being
508          * dummy, all this does is check if firmware_buf is not NULL and
509          * sets the state of the firmware.
510          */
511         if (!firmware_buf)
512                 return -EINVAL;
513
514         skeldev->fw.firmware_state = SKELETON_FW_LOADED;
515
516         return 0;
517 }
518
519 static int skeleton_rawdev_firmware_unload(struct rte_rawdev *dev)
520 {
521         struct skeleton_rawdev *skeldev;
522
523         SKELETON_PMD_FUNC_TRACE();
524
525         skeldev = skeleton_rawdev_get_priv(dev);
526
527         skeldev->fw.firmware_state = SKELETON_FW_READY;
528
529         return 0;
530 }
531
532 static const struct rte_rawdev_ops skeleton_rawdev_ops = {
533         .dev_info_get = skeleton_rawdev_info_get,
534         .dev_configure = skeleton_rawdev_configure,
535         .dev_start = skeleton_rawdev_start,
536         .dev_stop = skeleton_rawdev_stop,
537         .dev_close = skeleton_rawdev_close,
538         .dev_reset = skeleton_rawdev_reset,
539
540         .queue_def_conf = skeleton_rawdev_queue_def_conf,
541         .queue_setup = skeleton_rawdev_queue_setup,
542         .queue_release = skeleton_rawdev_queue_release,
543         .queue_count = skeleton_rawdev_queue_count,
544
545         .attr_get = skeleton_rawdev_get_attr,
546         .attr_set = skeleton_rawdev_set_attr,
547
548         .enqueue_bufs = skeleton_rawdev_enqueue_bufs,
549         .dequeue_bufs = skeleton_rawdev_dequeue_bufs,
550
551         .dump = skeleton_rawdev_dump,
552
553         .xstats_get = NULL,
554         .xstats_get_names = NULL,
555         .xstats_get_by_name = NULL,
556         .xstats_reset = NULL,
557
558         .firmware_status_get = skeleton_rawdev_firmware_status_get,
559         .firmware_version_get = skeleton_rawdev_firmware_version_get,
560         .firmware_load = skeleton_rawdev_firmware_load,
561         .firmware_unload = skeleton_rawdev_firmware_unload,
562
563         .dev_selftest = test_rawdev_skeldev,
564 };
565
566 static int
567 skeleton_rawdev_create(const char *name,
568                        struct rte_vdev_device *vdev,
569                        int socket_id)
570 {
571         int ret = 0, i;
572         struct rte_rawdev *rawdev = NULL;
573         struct skeleton_rawdev *skeldev = NULL;
574
575         if (!name) {
576                 SKELETON_PMD_ERR("Invalid name of the device!");
577                 ret = -EINVAL;
578                 goto cleanup;
579         }
580
581         /* Allocate device structure */
582         rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct skeleton_rawdev),
583                                          socket_id);
584         if (rawdev == NULL) {
585                 SKELETON_PMD_ERR("Unable to allocate rawdevice");
586                 ret = -EINVAL;
587                 goto cleanup;
588         }
589
590         ret = rawdev->dev_id; /* return the rawdev id of new device */
591
592         rawdev->dev_ops = &skeleton_rawdev_ops;
593         rawdev->device = &vdev->device;
594
595         skeldev = skeleton_rawdev_get_priv(rawdev);
596
597         skeldev->device_id = SKELETON_DEVICE_ID;
598         skeldev->vendor_id = SKELETON_VENDOR_ID;
599         skeldev->capabilities = SKELETON_DEFAULT_CAPA;
600
601         memset(&skeldev->fw, 0, sizeof(struct skeleton_firmware));
602
603         skeldev->fw.firmware_state = SKELETON_FW_READY;
604         skeldev->fw.firmware_version.major = SKELETON_MAJOR_VER;
605         skeldev->fw.firmware_version.minor = SKELETON_MINOR_VER;
606         skeldev->fw.firmware_version.subrel = SKELETON_SUB_VER;
607
608         skeldev->device_state = SKELETON_DEV_STOPPED;
609
610         /* Reset/set to default queue configuration for this device */
611         for (i = 0; i < SKELETON_MAX_QUEUES; i++) {
612                 skeldev->queues[i].state = SKELETON_QUEUE_DETACH;
613                 skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH;
614         }
615
616         /* Clear all allocated queue buffers */
617         for (i = 0; i < SKELETON_MAX_QUEUES; i++)
618                 clear_queue_bufs(i);
619
620         return ret;
621
622 cleanup:
623         if (rawdev)
624                 rte_rawdev_pmd_release(rawdev);
625
626         return ret;
627 }
628
629 static int
630 skeleton_rawdev_destroy(const char *name)
631 {
632         int ret;
633         struct rte_rawdev *rdev;
634
635         if (!name) {
636                 SKELETON_PMD_ERR("Invalid device name");
637                 return -EINVAL;
638         }
639
640         rdev = rte_rawdev_pmd_get_named_dev(name);
641         if (!rdev) {
642                 SKELETON_PMD_ERR("Invalid device name (%s)", name);
643                 return -EINVAL;
644         }
645
646         /* rte_rawdev_close is called by pmd_release */
647         ret = rte_rawdev_pmd_release(rdev);
648         if (ret)
649                 SKELETON_PMD_DEBUG("Device cleanup failed");
650
651         return 0;
652 }
653
654 static int
655 skeldev_get_selftest(const char *key __rte_unused,
656                      const char *value,
657                      void *opaque)
658 {
659         int *flag = opaque;
660         *flag = atoi(value);
661         return 0;
662 }
663
664 static int
665 skeldev_parse_vdev_args(struct rte_vdev_device *vdev)
666 {
667         int selftest = 0;
668         const char *name;
669         const char *params;
670
671         static const char *const args[] = {
672                 SKELETON_SELFTEST_ARG,
673                 NULL
674         };
675
676         name = rte_vdev_device_name(vdev);
677
678         params = rte_vdev_device_args(vdev);
679         if (params != NULL && params[0] != '\0') {
680                 struct rte_kvargs *kvlist = rte_kvargs_parse(params, args);
681
682                 if (!kvlist) {
683                         SKELETON_PMD_INFO(
684                                 "Ignoring unsupported params supplied '%s'",
685                                 name);
686                 } else {
687                         int ret = rte_kvargs_process(kvlist,
688                                         SKELETON_SELFTEST_ARG,
689                                         skeldev_get_selftest, &selftest);
690                         if (ret != 0 || (selftest < 0 || selftest > 1)) {
691                                 SKELETON_PMD_ERR("%s: Error in parsing args",
692                                                  name);
693                                 rte_kvargs_free(kvlist);
694                                 ret = -1; /* enforce if selftest is invalid */
695                                 return ret;
696                         }
697                 }
698
699                 rte_kvargs_free(kvlist);
700         }
701
702         return selftest;
703 }
704
705 static int
706 skeleton_rawdev_probe(struct rte_vdev_device *vdev)
707 {
708         const char *name;
709         int selftest = 0, ret = 0;
710
711
712         name = rte_vdev_device_name(vdev);
713         if (name == NULL)
714                 return -EINVAL;
715
716         /* More than one instance is not supported */
717         if (skeldev_init_once) {
718                 SKELETON_PMD_ERR("Multiple instance not supported for %s",
719                                  name);
720                 return -EINVAL;
721         }
722
723         SKELETON_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id());
724
725         selftest = skeldev_parse_vdev_args(vdev);
726         /* In case of invalid argument, selftest != 1; ignore other values */
727
728         ret = skeleton_rawdev_create(name, vdev, rte_socket_id());
729         if (ret >= 0) {
730                 /* In case command line argument for 'selftest' was passed;
731                  * if invalid arguments were passed, execution continues but
732                  * without selftest.
733                  */
734                 if (selftest == 1)
735                         test_rawdev_skeldev(ret);
736         }
737
738         /* Device instance created; Second instance not possible */
739         skeldev_init_once = 1;
740
741         return ret < 0 ? ret : 0;
742 }
743
744 static int
745 skeleton_rawdev_remove(struct rte_vdev_device *vdev)
746 {
747         const char *name;
748         int ret;
749
750         name = rte_vdev_device_name(vdev);
751         if (name == NULL)
752                 return -1;
753
754         SKELETON_PMD_INFO("Closing %s on NUMA node %d", name, rte_socket_id());
755
756         ret = skeleton_rawdev_destroy(name);
757         if (!ret)
758                 skeldev_init_once = 0;
759
760         return ret;
761 }
762
763 static struct rte_vdev_driver skeleton_pmd_drv = {
764         .probe = skeleton_rawdev_probe,
765         .remove = skeleton_rawdev_remove
766 };
767
768 RTE_PMD_REGISTER_VDEV(SKELETON_PMD_RAWDEV_NAME, skeleton_pmd_drv);
769 RTE_LOG_REGISTER(skeleton_pmd_logtype, rawdev.skeleton, INFO);