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