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