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