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