raw/cnxk_gpio: add option to select subset of GPIOs
[dpdk.git] / drivers / raw / cnxk_gpio / cnxk_gpio.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4
5 #include <dirent.h>
6 #include <string.h>
7
8 #include <rte_bus_vdev.h>
9 #include <rte_eal.h>
10 #include <rte_kvargs.h>
11 #include <rte_lcore.h>
12 #include <rte_rawdev_pmd.h>
13
14 #include <roc_api.h>
15
16 #include "cnxk_gpio.h"
17 #include "rte_pmd_cnxk_gpio.h"
18
19 #define CNXK_GPIO_BUFSZ 128
20 #define CNXK_GPIO_CLASS_PATH "/sys/class/gpio"
21
22 static const char *const cnxk_gpio_args[] = {
23 #define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
24         CNXK_GPIO_ARG_GPIOCHIP,
25 #define CNXK_GPIO_ARG_ALLOWLIST "allowlist"
26         CNXK_GPIO_ARG_ALLOWLIST,
27         NULL
28 };
29
30 static char *allowlist;
31
32 static void
33 cnxk_gpio_format_name(char *name, size_t len)
34 {
35         snprintf(name, len, "cnxk_gpio");
36 }
37
38 static int
39 cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
40 {
41         const char *pattern = "gpiochip";
42
43         return !strncmp(dirent->d_name, pattern, strlen(pattern));
44 }
45
46 static void
47 cnxk_gpio_set_defaults(struct cnxk_gpiochip *gpiochip)
48 {
49         struct dirent **namelist;
50         int n;
51
52         n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
53                     alphasort);
54         if (n < 0 || n == 0)
55                 return;
56
57         sscanf(namelist[0]->d_name, "gpiochip%d", &gpiochip->num);
58         while (n--)
59                 free(namelist[n]);
60         free(namelist);
61 }
62
63 static int
64 cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
65                              void *extra_args)
66 {
67         long val;
68
69         errno = 0;
70         val = strtol(value, NULL, 10);
71         if (errno)
72                 return -errno;
73
74         *(int *)extra_args = (int)val;
75
76         return 0;
77 }
78
79 static int
80 cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value,
81                               void *extra_args __rte_unused)
82 {
83         allowlist = strdup(value);
84         if (!allowlist)
85                 return -ENOMEM;
86
87         return 0;
88 }
89
90 static int
91 cnxk_gpio_parse_args(struct cnxk_gpiochip *gpiochip, const char *args)
92 {
93         struct rte_kvargs *kvlist;
94         int ret;
95
96         kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
97         if (!kvlist)
98                 return 0;
99
100         ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_GPIOCHIP);
101         if (ret == 1) {
102                 ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_GPIOCHIP,
103                                          cnxk_gpio_parse_arg_gpiochip,
104                                          &gpiochip->num);
105                 if (ret)
106                         goto out;
107         }
108
109         ret = rte_kvargs_count(kvlist, CNXK_GPIO_ARG_ALLOWLIST);
110         if (ret == 1) {
111                 ret = rte_kvargs_process(kvlist, CNXK_GPIO_ARG_ALLOWLIST,
112                                          cnxk_gpio_parse_arg_allowlist, NULL);
113                 if (ret)
114                         goto out;
115         }
116
117         ret = 0;
118 out:
119         rte_kvargs_free(kvlist);
120
121         return ret;
122 }
123
124 static int
125 cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip)
126 {
127         int i, ret, val, queue = 0;
128         char *token;
129         int *list;
130
131         list = rte_calloc(NULL, gpiochip->num_gpios, sizeof(*list), 0);
132         if (!list)
133                 return -ENOMEM;
134
135         /* replace brackets with something meaningless for strtol() */
136         allowlist[0] = ' ';
137         allowlist[strlen(allowlist) - 1] = ' ';
138
139         /* quiesce -Wcast-qual */
140         token = strtok((char *)(uintptr_t)allowlist, ",");
141         do {
142                 errno = 0;
143                 val = strtol(token, NULL, 10);
144                 if (errno) {
145                         RTE_LOG(ERR, PMD, "failed to parse %s\n", token);
146                         ret = -errno;
147                         goto out;
148                 }
149
150                 if (val < 0 || val >= gpiochip->num_gpios) {
151                         RTE_LOG(ERR, PMD, "gpio%d out of 0-%d range\n", val,
152                                 gpiochip->num_gpios - 1);
153                         ret = -EINVAL;
154                         goto out;
155                 }
156
157                 for (i = 0; i < queue; i++) {
158                         if (list[i] != val)
159                                 continue;
160
161                         RTE_LOG(WARNING, PMD, "gpio%d already allowed\n", val);
162                         break;
163                 }
164                 if (i == queue)
165                         list[queue++] = val;
166         } while ((token = strtok(NULL, ",")));
167
168         gpiochip->allowlist = list;
169         gpiochip->num_queues = queue;
170
171         return 0;
172 out:
173         rte_free(list);
174
175         return ret;
176 }
177
178 static int
179 cnxk_gpio_read_attr(char *attr, char *val)
180 {
181         FILE *fp;
182         int ret;
183
184         fp = fopen(attr, "r");
185         if (!fp)
186                 return -errno;
187
188         ret = fscanf(fp, "%s", val);
189         if (ret < 0)
190                 return -errno;
191         if (ret != 1)
192                 return -EIO;
193
194         ret = fclose(fp);
195         if (ret)
196                 return -errno;
197
198         return 0;
199 }
200
201 static int
202 cnxk_gpio_read_attr_int(char *attr, int *val)
203 {
204         char buf[CNXK_GPIO_BUFSZ];
205         int ret;
206
207         ret = cnxk_gpio_read_attr(attr, buf);
208         if (ret)
209                 return ret;
210
211         ret = sscanf(buf, "%d", val);
212         if (ret < 0)
213                 return -errno;
214
215         return 0;
216 }
217
218 static int
219 cnxk_gpio_write_attr(const char *attr, const char *val)
220 {
221         FILE *fp;
222         int ret;
223
224         if (!val)
225                 return -EINVAL;
226
227         fp = fopen(attr, "w");
228         if (!fp)
229                 return -errno;
230
231         ret = fprintf(fp, "%s", val);
232         if (ret < 0) {
233                 fclose(fp);
234                 return ret;
235         }
236
237         ret = fclose(fp);
238         if (ret)
239                 return -errno;
240
241         return 0;
242 }
243
244 static int
245 cnxk_gpio_write_attr_int(const char *attr, int val)
246 {
247         char buf[CNXK_GPIO_BUFSZ];
248
249         snprintf(buf, sizeof(buf), "%d", val);
250
251         return cnxk_gpio_write_attr(attr, buf);
252 }
253
254 static bool
255 cnxk_gpio_queue_valid(struct cnxk_gpiochip *gpiochip, uint16_t queue)
256 {
257         return queue < gpiochip->num_queues;
258 }
259
260 static int
261 cnxk_queue_to_gpio(struct cnxk_gpiochip *gpiochip, uint16_t queue)
262 {
263         return gpiochip->allowlist ? gpiochip->allowlist[queue] : queue;
264 }
265
266 static struct cnxk_gpio *
267 cnxk_gpio_lookup(struct cnxk_gpiochip *gpiochip, uint16_t queue)
268 {
269         int gpio = cnxk_queue_to_gpio(gpiochip, queue);
270
271         return gpiochip->gpios[gpio];
272 }
273
274 static int
275 cnxk_gpio_queue_setup(struct rte_rawdev *dev, uint16_t queue_id,
276                       rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
277 {
278         struct cnxk_gpiochip *gpiochip = dev->dev_private;
279         char buf[CNXK_GPIO_BUFSZ];
280         struct cnxk_gpio *gpio;
281         int num, ret;
282
283         RTE_SET_USED(queue_conf);
284         RTE_SET_USED(queue_conf_size);
285
286         if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
287                 return -EINVAL;
288
289         gpio = cnxk_gpio_lookup(gpiochip, queue_id);
290         if (gpio)
291                 return -EEXIST;
292
293         gpio = rte_zmalloc(NULL, sizeof(*gpio), 0);
294         if (!gpio)
295                 return -ENOMEM;
296
297         num = cnxk_queue_to_gpio(gpiochip, queue_id);
298         gpio->num = num + gpiochip->base;
299         gpio->gpiochip = gpiochip;
300
301         snprintf(buf, sizeof(buf), "%s/export", CNXK_GPIO_CLASS_PATH);
302         ret = cnxk_gpio_write_attr_int(buf, gpio->num);
303         if (ret) {
304                 rte_free(gpio);
305                 return ret;
306         }
307
308         gpiochip->gpios[num] = gpio;
309
310         return 0;
311 }
312
313 static int
314 cnxk_gpio_queue_release(struct rte_rawdev *dev, uint16_t queue_id)
315 {
316         struct cnxk_gpiochip *gpiochip = dev->dev_private;
317         char buf[CNXK_GPIO_BUFSZ];
318         struct cnxk_gpio *gpio;
319         int num, ret;
320
321         if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
322                 return -EINVAL;
323
324         gpio = cnxk_gpio_lookup(gpiochip, queue_id);
325         if (!gpio)
326                 return -ENODEV;
327
328         snprintf(buf, sizeof(buf), "%s/unexport", CNXK_GPIO_CLASS_PATH);
329         ret = cnxk_gpio_write_attr_int(buf, gpio->num);
330         if (ret)
331                 return ret;
332
333         num = cnxk_queue_to_gpio(gpiochip, queue_id);
334         gpiochip->gpios[num] = NULL;
335         rte_free(gpio);
336
337         return 0;
338 }
339
340 static int
341 cnxk_gpio_queue_def_conf(struct rte_rawdev *dev, uint16_t queue_id,
342                          rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
343 {
344         struct cnxk_gpiochip *gpiochip = dev->dev_private;
345         struct cnxk_gpio_queue_conf *conf = queue_conf;
346
347         if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
348                 return -EINVAL;
349
350         if (queue_conf_size != sizeof(*conf))
351                 return -EINVAL;
352
353         conf->size = 1;
354         conf->gpio = cnxk_queue_to_gpio(gpiochip, queue_id);
355
356         return 0;
357 }
358
359 static uint16_t
360 cnxk_gpio_queue_count(struct rte_rawdev *dev)
361 {
362         struct cnxk_gpiochip *gpiochip = dev->dev_private;
363
364         return gpiochip->num_queues;
365 }
366
367 static const struct {
368         enum cnxk_gpio_pin_edge edge;
369         const char *name;
370 } cnxk_gpio_edge_name[] = {
371         { CNXK_GPIO_PIN_EDGE_NONE, "none" },
372         { CNXK_GPIO_PIN_EDGE_FALLING, "falling" },
373         { CNXK_GPIO_PIN_EDGE_RISING, "rising" },
374         { CNXK_GPIO_PIN_EDGE_BOTH, "both" },
375 };
376
377 static const char *
378 cnxk_gpio_edge_to_name(enum cnxk_gpio_pin_edge edge)
379 {
380         unsigned int i;
381
382         for (i = 0; i < RTE_DIM(cnxk_gpio_edge_name); i++) {
383                 if (cnxk_gpio_edge_name[i].edge == edge)
384                         return cnxk_gpio_edge_name[i].name;
385         }
386
387         return NULL;
388 }
389
390 static enum cnxk_gpio_pin_edge
391 cnxk_gpio_name_to_edge(const char *name)
392 {
393         unsigned int i;
394
395         for (i = 0; i < RTE_DIM(cnxk_gpio_edge_name); i++) {
396                 if (!strcmp(cnxk_gpio_edge_name[i].name, name))
397                         break;
398         }
399
400         return cnxk_gpio_edge_name[i].edge;
401 }
402
403 static const struct {
404         enum cnxk_gpio_pin_dir dir;
405         const char *name;
406 } cnxk_gpio_dir_name[] = {
407         { CNXK_GPIO_PIN_DIR_IN, "in" },
408         { CNXK_GPIO_PIN_DIR_OUT, "out" },
409         { CNXK_GPIO_PIN_DIR_HIGH, "high" },
410         { CNXK_GPIO_PIN_DIR_LOW, "low" },
411 };
412
413 static const char *
414 cnxk_gpio_dir_to_name(enum cnxk_gpio_pin_dir dir)
415 {
416         unsigned int i;
417
418         for (i = 0; i < RTE_DIM(cnxk_gpio_dir_name); i++) {
419                 if (cnxk_gpio_dir_name[i].dir == dir)
420                         return cnxk_gpio_dir_name[i].name;
421         }
422
423         return NULL;
424 }
425
426 static enum cnxk_gpio_pin_dir
427 cnxk_gpio_name_to_dir(const char *name)
428 {
429         unsigned int i;
430
431         for (i = 0; i < RTE_DIM(cnxk_gpio_dir_name); i++) {
432                 if (!strcmp(cnxk_gpio_dir_name[i].name, name))
433                         break;
434         }
435
436         return cnxk_gpio_dir_name[i].dir;
437 }
438
439 static int
440 cnxk_gpio_register_irq(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq)
441 {
442         int ret;
443
444         ret = cnxk_gpio_irq_request(gpio->num - gpio->gpiochip->base, irq->cpu);
445         if (ret)
446                 return ret;
447
448         gpio->handler = irq->handler;
449         gpio->data = irq->data;
450         gpio->cpu = irq->cpu;
451
452         return 0;
453 }
454
455 static int
456 cnxk_gpio_unregister_irq(struct cnxk_gpio *gpio)
457 {
458         return cnxk_gpio_irq_free(gpio->num - gpio->gpiochip->base);
459 }
460
461 static int
462 cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf)
463 {
464         struct cnxk_gpio_msg *msg = rbuf->buf_addr;
465         enum cnxk_gpio_pin_edge edge;
466         enum cnxk_gpio_pin_dir dir;
467         char buf[CNXK_GPIO_BUFSZ];
468         void *rsp = NULL;
469         int ret, val, n;
470
471         n = snprintf(buf, sizeof(buf), "%s/gpio%d", CNXK_GPIO_CLASS_PATH,
472                      gpio->num);
473
474         switch (msg->type) {
475         case CNXK_GPIO_MSG_TYPE_SET_PIN_VALUE:
476                 snprintf(buf + n, sizeof(buf) - n, "/value");
477                 ret = cnxk_gpio_write_attr_int(buf, !!*(int *)msg->data);
478                 break;
479         case CNXK_GPIO_MSG_TYPE_SET_PIN_EDGE:
480                 snprintf(buf + n, sizeof(buf) - n, "/edge");
481                 edge = *(enum cnxk_gpio_pin_edge *)msg->data;
482                 ret = cnxk_gpio_write_attr(buf, cnxk_gpio_edge_to_name(edge));
483                 break;
484         case CNXK_GPIO_MSG_TYPE_SET_PIN_DIR:
485                 snprintf(buf + n, sizeof(buf) - n, "/direction");
486                 dir = *(enum cnxk_gpio_pin_dir *)msg->data;
487                 ret = cnxk_gpio_write_attr(buf, cnxk_gpio_dir_to_name(dir));
488                 break;
489         case CNXK_GPIO_MSG_TYPE_SET_PIN_ACTIVE_LOW:
490                 snprintf(buf + n, sizeof(buf) - n, "/active_low");
491                 val = *(int *)msg->data;
492                 ret = cnxk_gpio_write_attr_int(buf, val);
493                 break;
494         case CNXK_GPIO_MSG_TYPE_GET_PIN_VALUE:
495                 snprintf(buf + n, sizeof(buf) - n, "/value");
496                 ret = cnxk_gpio_read_attr_int(buf, &val);
497                 if (ret)
498                         break;
499
500                 rsp = rte_zmalloc(NULL, sizeof(int), 0);
501                 if (!rsp)
502                         return -ENOMEM;
503
504                 *(int *)rsp = val;
505                 break;
506         case CNXK_GPIO_MSG_TYPE_GET_PIN_EDGE:
507                 snprintf(buf + n, sizeof(buf) - n, "/edge");
508                 ret = cnxk_gpio_read_attr(buf, buf);
509                 if (ret)
510                         break;
511
512                 rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_edge), 0);
513                 if (!rsp)
514                         return -ENOMEM;
515
516                 *(enum cnxk_gpio_pin_edge *)rsp = cnxk_gpio_name_to_edge(buf);
517                 break;
518         case CNXK_GPIO_MSG_TYPE_GET_PIN_DIR:
519                 snprintf(buf + n, sizeof(buf) - n, "/direction");
520                 ret = cnxk_gpio_read_attr(buf, buf);
521                 if (ret)
522                         break;
523
524                 rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_dir), 0);
525                 if (!rsp)
526                         return -ENOMEM;
527
528                 *(enum cnxk_gpio_pin_dir *)rsp = cnxk_gpio_name_to_dir(buf);
529                 break;
530         case CNXK_GPIO_MSG_TYPE_GET_PIN_ACTIVE_LOW:
531                 snprintf(buf + n, sizeof(buf) - n, "/active_low");
532                 ret = cnxk_gpio_read_attr_int(buf, &val);
533                 if (ret)
534                         break;
535
536                 rsp = rte_zmalloc(NULL, sizeof(int), 0);
537                 if (!rsp)
538                         return -ENOMEM;
539
540                 *(int *)rsp = val;
541                 break;
542         case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ:
543                 ret = cnxk_gpio_register_irq(gpio,
544                                              (struct cnxk_gpio_irq *)msg->data);
545                 break;
546         case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ:
547                 ret = cnxk_gpio_unregister_irq(gpio);
548                 break;
549         default:
550                 return -EINVAL;
551         }
552
553         /* get rid of last response if any */
554         if (gpio->rsp) {
555                 RTE_LOG(WARNING, PMD, "previous response got overwritten\n");
556                 rte_free(gpio->rsp);
557         }
558         gpio->rsp = rsp;
559
560         return ret;
561 }
562
563 static bool
564 cnxk_gpio_valid(struct cnxk_gpiochip *gpiochip, int gpio)
565 {
566         return gpio < gpiochip->num_gpios && gpiochip->gpios[gpio];
567 }
568
569 static int
570 cnxk_gpio_enqueue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
571                        unsigned int count, rte_rawdev_obj_t context)
572 {
573         struct cnxk_gpiochip *gpiochip = dev->dev_private;
574         unsigned int gpio_num = (size_t)context;
575         struct cnxk_gpio *gpio;
576         int ret;
577
578         if (count == 0)
579                 return 0;
580
581         if (!cnxk_gpio_valid(gpiochip, gpio_num))
582                 return -EINVAL;
583         gpio = gpiochip->gpios[gpio_num];
584
585         ret = cnxk_gpio_process_buf(gpio, buffers[0]);
586         if (ret)
587                 return ret;
588
589         return 1;
590 }
591
592 static int
593 cnxk_gpio_dequeue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
594                        unsigned int count, rte_rawdev_obj_t context)
595 {
596         struct cnxk_gpiochip *gpiochip = dev->dev_private;
597         unsigned int gpio_num = (size_t)context;
598         struct cnxk_gpio *gpio;
599
600         if (count == 0)
601                 return 0;
602
603         if (!cnxk_gpio_valid(gpiochip, gpio_num))
604                 return -EINVAL;
605         gpio = gpiochip->gpios[gpio_num];
606
607         if (gpio->rsp) {
608                 buffers[0]->buf_addr = gpio->rsp;
609                 gpio->rsp = NULL;
610
611                 return 1;
612         }
613
614         return 0;
615 }
616
617 static int
618 cnxk_gpio_dev_close(struct rte_rawdev *dev)
619 {
620         RTE_SET_USED(dev);
621
622         return 0;
623 }
624
625 static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
626         .dev_close = cnxk_gpio_dev_close,
627         .enqueue_bufs = cnxk_gpio_enqueue_bufs,
628         .dequeue_bufs = cnxk_gpio_dequeue_bufs,
629         .queue_def_conf = cnxk_gpio_queue_def_conf,
630         .queue_count = cnxk_gpio_queue_count,
631         .queue_setup = cnxk_gpio_queue_setup,
632         .queue_release = cnxk_gpio_queue_release,
633         .dev_selftest = cnxk_gpio_selftest,
634 };
635
636 static int
637 cnxk_gpio_probe(struct rte_vdev_device *dev)
638 {
639         char name[RTE_RAWDEV_NAME_MAX_LEN];
640         struct cnxk_gpiochip *gpiochip;
641         struct rte_rawdev *rawdev;
642         char buf[CNXK_GPIO_BUFSZ];
643         int ret;
644
645         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
646                 return 0;
647
648         cnxk_gpio_format_name(name, sizeof(name));
649         rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip),
650                                          rte_socket_id());
651         if (!rawdev) {
652                 RTE_LOG(ERR, PMD, "failed to allocate %s rawdev", name);
653                 return -ENOMEM;
654         }
655
656         rawdev->dev_ops = &cnxk_gpio_rawdev_ops;
657         rawdev->device = &dev->device;
658         rawdev->driver_name = dev->device.name;
659
660         gpiochip = rawdev->dev_private;
661         cnxk_gpio_set_defaults(gpiochip);
662
663         /* defaults may be overwritten by this call */
664         ret = cnxk_gpio_parse_args(gpiochip, rte_vdev_device_args(dev));
665         if (ret)
666                 goto out;
667
668         ret = cnxk_gpio_irq_init(gpiochip);
669         if (ret)
670                 goto out;
671
672         /* read gpio base */
673         snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH,
674                  gpiochip->num);
675         ret = cnxk_gpio_read_attr_int(buf, &gpiochip->base);
676         if (ret) {
677                 RTE_LOG(ERR, PMD, "failed to read %s", buf);
678                 goto out;
679         }
680
681         /* read number of available gpios */
682         snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH,
683                  gpiochip->num);
684         ret = cnxk_gpio_read_attr_int(buf, &gpiochip->num_gpios);
685         if (ret) {
686                 RTE_LOG(ERR, PMD, "failed to read %s", buf);
687                 goto out;
688         }
689         gpiochip->num_queues = gpiochip->num_gpios;
690
691         if (allowlist) {
692                 ret = cnxk_gpio_parse_allowlist(gpiochip);
693                 free(allowlist);
694                 allowlist = NULL;
695                 if (ret)
696                         goto out;
697         }
698
699         gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios,
700                                      sizeof(struct cnxk_gpio *), 0);
701         if (!gpiochip->gpios) {
702                 RTE_LOG(ERR, PMD, "failed to allocate gpios memory");
703                 ret = -ENOMEM;
704                 goto out;
705         }
706
707         return 0;
708 out:
709         free(allowlist);
710         rte_free(gpiochip->allowlist);
711         rte_rawdev_pmd_release(rawdev);
712
713         return ret;
714 }
715
716 static int
717 cnxk_gpio_remove(struct rte_vdev_device *dev)
718 {
719         char name[RTE_RAWDEV_NAME_MAX_LEN];
720         struct cnxk_gpiochip *gpiochip;
721         struct rte_rawdev *rawdev;
722         struct cnxk_gpio *gpio;
723         int i;
724
725         RTE_SET_USED(dev);
726
727         if (rte_eal_process_type() != RTE_PROC_PRIMARY)
728                 return 0;
729
730         cnxk_gpio_format_name(name, sizeof(name));
731         rawdev = rte_rawdev_pmd_get_named_dev(name);
732         if (!rawdev)
733                 return -ENODEV;
734
735         gpiochip = rawdev->dev_private;
736         for (i = 0; i < gpiochip->num_gpios; i++) {
737                 gpio = gpiochip->gpios[i];
738                 if (!gpio)
739                         continue;
740
741                 if (gpio->handler)
742                         cnxk_gpio_unregister_irq(gpio);
743
744                 cnxk_gpio_queue_release(rawdev, gpio->num);
745         }
746
747         rte_free(gpiochip->allowlist);
748         rte_free(gpiochip->gpios);
749         cnxk_gpio_irq_fini();
750         rte_rawdev_pmd_release(rawdev);
751
752         return 0;
753 }
754
755 static struct rte_vdev_driver cnxk_gpio_drv = {
756         .probe = cnxk_gpio_probe,
757         .remove = cnxk_gpio_remove,
758 };
759
760 RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
761 RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio,
762                 "gpiochip=<int> "
763                 "allowlist=<list>");