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