Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2021 Marvell.
3 : : */
4 : :
5 : : #include <dirent.h>
6 : : #include <errno.h>
7 : : #include <fcntl.h>
8 : : #include <linux/gpio.h>
9 : : #include <regex.h>
10 : : #include <string.h>
11 : : #include <sys/ioctl.h>
12 : : #include <sys/stat.h>
13 : : #include <sys/types.h>
14 : :
15 : : #include <bus_vdev_driver.h>
16 : : #include <rte_eal.h>
17 : : #include <rte_errno.h>
18 : : #include <rte_interrupts.h>
19 : : #include <rte_kvargs.h>
20 : : #include <rte_lcore.h>
21 : : #include <rte_rawdev_pmd.h>
22 : :
23 : : #include <roc_api.h>
24 : :
25 : : #include "cnxk_gpio.h"
26 : : #include "rte_pmd_cnxk_gpio.h"
27 : :
28 : : #define CNXK_GPIO_PARAMS_MZ_NAME "cnxk_gpio_params_mz"
29 : : #define CNXK_GPIO_INVALID_FD (-1)
30 : :
31 [ - + ]: 253 : RTE_LOG_REGISTER_SUFFIX(cnxk_logtype_gpio, gpio, INFO);
32 : :
33 : : #ifdef CNXK_GPIO_V2_PRESENT
34 : :
35 : : struct cnxk_gpio_params {
36 : : unsigned int num;
37 : : char allowlist[];
38 : : };
39 : :
40 : : static const char *const cnxk_gpio_args[] = {
41 : : #define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
42 : : CNXK_GPIO_ARG_GPIOCHIP,
43 : : #define CNXK_GPIO_ARG_ALLOWLIST "allowlist"
44 : : CNXK_GPIO_ARG_ALLOWLIST,
45 : : NULL
46 : : };
47 : :
48 : : static void
49 : : cnxk_gpio_format_name(char *name, size_t len)
50 : : {
51 : : snprintf(name, len, "cnxk_gpio");
52 : : }
53 : :
54 : : static int
55 : 0 : cnxk_gpio_ioctl(struct cnxk_gpio *gpio, unsigned long cmd, void *arg)
56 : : {
57 [ # # ]: 0 : return ioctl(gpio->fd, cmd, arg) ? -errno : 0;
58 : : }
59 : :
60 : : static int
61 : 0 : cnxk_gpio_gpiochip_ioctl(struct cnxk_gpiochip *gpiochip, unsigned long cmd, void *arg)
62 : : {
63 : : char path[PATH_MAX];
64 : : int ret = 0, fd;
65 : :
66 : 0 : snprintf(path, sizeof(path), "/dev/gpiochip%d", gpiochip->num);
67 : : fd = open(path, O_RDONLY);
68 [ # # ]: 0 : if (fd == -1)
69 : 0 : return -errno;
70 : :
71 [ # # ]: 0 : if (ioctl(fd, cmd, arg))
72 : 0 : ret = -errno;
73 : :
74 : 0 : close(fd);
75 : :
76 : 0 : return ret;
77 : : }
78 : :
79 : : static int
80 : 0 : cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
81 : : {
82 : : const char *pattern = "gpiochip";
83 : :
84 : 0 : return !strncmp(dirent->d_name, pattern, strlen(pattern));
85 : : }
86 : :
87 : : static int
88 : 0 : cnxk_gpio_set_defaults(struct cnxk_gpio_params *params)
89 : : {
90 : : struct dirent **namelist;
91 : : int ret = 0, n;
92 : :
93 : 0 : n = scandir("/dev", &namelist, cnxk_gpio_filter_gpiochip, alphasort);
94 [ # # ]: 0 : if (n < 0 || n == 0)
95 : : return -ENODEV;
96 : :
97 [ # # ]: 0 : if (sscanf(namelist[0]->d_name, "gpiochip%d", ¶ms->num) != 1)
98 : : ret = -EINVAL;
99 : :
100 [ # # ]: 0 : while (n--)
101 : 0 : free(namelist[n]);
102 : 0 : free(namelist);
103 : :
104 : 0 : return ret;
105 : : }
106 : :
107 : : static int
108 : 0 : cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
109 : : void *extra_args)
110 : : {
111 : : unsigned long val;
112 : :
113 : 0 : errno = 0;
114 : 0 : val = strtoul(value, NULL, 10);
115 [ # # ]: 0 : if (errno)
116 : 0 : return -errno;
117 : :
118 : 0 : *(unsigned int *)extra_args = val;
119 : :
120 : 0 : return 0;
121 : : }
122 : :
123 : : static int
124 : 0 : cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value, void *extra_args)
125 : : {
126 : 0 : *(const char **)extra_args = value;
127 : :
128 : 0 : return 0;
129 : : }
130 : :
131 : : static int
132 : : cnxk_gpio_params_restore(struct cnxk_gpio_params **params)
133 : : {
134 : : const struct rte_memzone *mz;
135 : :
136 : 0 : mz = rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME);
137 [ # # ]: 0 : if (!mz)
138 : : return -ENODEV;
139 : :
140 : 0 : *params = mz->addr;
141 : :
142 : : return 0;
143 : : }
144 : :
145 : : static struct cnxk_gpio_params *
146 : 0 : cnxk_gpio_params_reserve(size_t len)
147 : : {
148 : : const struct rte_memzone *mz;
149 : :
150 : 0 : mz = rte_memzone_reserve(CNXK_GPIO_PARAMS_MZ_NAME, len, rte_socket_id(), 0);
151 [ # # ]: 0 : if (!mz)
152 : : return NULL;
153 : :
154 : 0 : return mz->addr;
155 : : }
156 : :
157 : : static void
158 : 0 : cnxk_gpio_params_release(void)
159 : : {
160 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY)
161 : 0 : rte_memzone_free(rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME));
162 : 0 : }
163 : :
164 : : static int
165 : 0 : cnxk_gpio_parse_arg(struct rte_kvargs *kvlist, const char *arg, arg_handler_t handler, void *data)
166 : : {
167 : : int ret;
168 : :
169 : 0 : ret = rte_kvargs_count(kvlist, arg);
170 [ # # ]: 0 : if (ret == 0)
171 : : return 0;
172 [ # # ]: 0 : if (ret > 1)
173 : : return -EINVAL;
174 : :
175 [ # # ]: 0 : return rte_kvargs_process(kvlist, arg, handler, data) ? -EIO : 1;
176 : : }
177 : :
178 : : static int
179 : 0 : cnxk_gpio_parse_store_args(struct cnxk_gpio_params **params, const char *args)
180 : : {
181 : : size_t len = sizeof(**params) + 1;
182 : 0 : const char *allowlist = NULL;
183 : : struct rte_kvargs *kvlist;
184 : : int ret;
185 : :
186 : 0 : kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
187 [ # # ]: 0 : if (!kvlist) {
188 : 0 : *params = cnxk_gpio_params_reserve(len);
189 [ # # ]: 0 : if (!*params)
190 : : return -ENOMEM;
191 : :
192 : 0 : ret = cnxk_gpio_set_defaults(*params);
193 [ # # ]: 0 : if (ret)
194 : 0 : goto out;
195 : :
196 : : return 0;
197 : : }
198 : :
199 : 0 : ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_ALLOWLIST, cnxk_gpio_parse_arg_allowlist,
200 : : &allowlist);
201 [ # # ]: 0 : if (ret < 0) {
202 : : ret = -EINVAL;
203 : 0 : goto out;
204 : : }
205 : :
206 [ # # ]: 0 : if (allowlist)
207 : 0 : len += strlen(allowlist);
208 : :
209 : 0 : *params = cnxk_gpio_params_reserve(len);
210 [ # # ]: 0 : if (!(*params)) {
211 : : ret = -ENOMEM;
212 : 0 : goto out;
213 : : }
214 : :
215 [ # # ]: 0 : if (allowlist)
216 : 0 : strlcpy((*params)->allowlist, allowlist, strlen(allowlist) + 1);
217 : :
218 : 0 : ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_GPIOCHIP, cnxk_gpio_parse_arg_gpiochip,
219 : 0 : &(*params)->num);
220 [ # # ]: 0 : if (ret == 0)
221 : 0 : ret = cnxk_gpio_set_defaults(*params);
222 : :
223 : 0 : out:
224 : 0 : rte_kvargs_free(kvlist);
225 : :
226 : 0 : return ret;
227 : : }
228 : :
229 : : static bool
230 : 0 : cnxk_gpio_allowlist_valid(const char *allowlist)
231 : : {
232 : : bool ret = false;
233 : : regex_t regex;
234 : :
235 : : /* [gpio0<,gpio1,...,gpioN>], where '<...>' is optional part */
236 [ # # ]: 0 : if (regcomp(®ex, "^\\[[0-9]+(,[0-9]+)*\\]$", REG_EXTENDED))
237 : : return ret;
238 : :
239 [ # # ]: 0 : if (!regexec(®ex, allowlist, 0, NULL, 0))
240 : : ret = true;
241 : :
242 : 0 : regfree(®ex);
243 : :
244 : 0 : return ret;
245 : : }
246 : :
247 : : static int
248 : 0 : cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip, char *allowlist)
249 : : {
250 : : int i, ret, val, queue = 0;
251 : : char *token;
252 : : int *list;
253 : :
254 : 0 : list = rte_calloc(NULL, gpiochip->num_gpios, sizeof(*list), 0);
255 [ # # ]: 0 : if (!list)
256 : : return -ENOMEM;
257 : :
258 : : /* no gpios provided so allow all */
259 [ # # ]: 0 : if (!*allowlist) {
260 [ # # ]: 0 : for (i = 0; i < gpiochip->num_gpios; i++)
261 : 0 : list[queue++] = i;
262 : :
263 : 0 : goto out_done;
264 : : }
265 : :
266 [ # # ]: 0 : if (!cnxk_gpio_allowlist_valid(allowlist))
267 : : return -EINVAL;
268 : :
269 : 0 : allowlist = strdup(allowlist);
270 [ # # ]: 0 : if (!allowlist) {
271 : : ret = -ENOMEM;
272 : 0 : goto out;
273 : : }
274 : :
275 : : /* replace brackets with something meaningless for strtol() */
276 : 0 : allowlist[0] = ' ';
277 : 0 : allowlist[strlen(allowlist) - 1] = ' ';
278 : :
279 : : /* quiesce -Wcast-qual */
280 : 0 : token = strtok((char *)(uintptr_t)allowlist, ",");
281 : : do {
282 : 0 : errno = 0;
283 : 0 : val = strtol(token, NULL, 10);
284 [ # # ]: 0 : if (errno) {
285 : 0 : CNXK_GPIO_LOG(ERR, "failed to parse %s", token);
286 : 0 : ret = -errno;
287 : 0 : goto out;
288 : : }
289 : :
290 [ # # # # ]: 0 : if (val < 0 || val >= gpiochip->num_gpios) {
291 : 0 : CNXK_GPIO_LOG(ERR, "gpio%d out of 0-%d range", val,
292 : : gpiochip->num_gpios - 1);
293 : : ret = -EINVAL;
294 : 0 : goto out;
295 : : }
296 : :
297 [ # # ]: 0 : for (i = 0; i < queue; i++) {
298 [ # # ]: 0 : if (list[i] != val)
299 : : continue;
300 : :
301 : 0 : CNXK_GPIO_LOG(WARNING, "gpio%d already allowed", val);
302 : 0 : break;
303 : : }
304 [ # # ]: 0 : if (i == queue)
305 : 0 : list[queue++] = val;
306 [ # # ]: 0 : } while ((token = strtok(NULL, ",")));
307 : :
308 : 0 : free(allowlist);
309 : 0 : out_done:
310 : 0 : gpiochip->allowlist = list;
311 : 0 : gpiochip->num_queues = queue;
312 : :
313 : 0 : return 0;
314 : 0 : out:
315 : 0 : free(allowlist);
316 : 0 : rte_free(list);
317 : :
318 : 0 : return ret;
319 : : }
320 : :
321 : : static bool
322 : : cnxk_gpio_queue_valid(struct cnxk_gpiochip *gpiochip, uint16_t queue)
323 : : {
324 : 0 : return queue < gpiochip->num_queues;
325 : : }
326 : :
327 : : static int
328 : : cnxk_queue_to_gpio(struct cnxk_gpiochip *gpiochip, uint16_t queue)
329 : : {
330 [ # # # # : 0 : return gpiochip->allowlist ? gpiochip->allowlist[queue] : queue;
# # # # ]
331 : : }
332 : :
333 : : static struct cnxk_gpio *
334 : : cnxk_gpio_lookup(struct cnxk_gpiochip *gpiochip, uint16_t queue)
335 : : {
336 : : int gpio = cnxk_queue_to_gpio(gpiochip, queue);
337 : :
338 : 0 : return gpiochip->gpios[gpio];
339 : : }
340 : :
341 : : static bool
342 : 0 : cnxk_gpio_available(struct cnxk_gpio *gpio)
343 : : {
344 : 0 : struct gpio_v2_line_info info = { .offset = gpio->num };
345 : : int ret;
346 : :
347 : 0 : ret = cnxk_gpio_gpiochip_ioctl(gpio->gpiochip, GPIO_V2_GET_LINEINFO_IOCTL, &info);
348 [ # # ]: 0 : if (ret)
349 : : return false;
350 : :
351 : 0 : return !(info.flags & GPIO_V2_LINE_FLAG_USED);
352 : : }
353 : :
354 : : static int
355 : 0 : cnxk_gpio_queue_setup(struct rte_rawdev *dev, uint16_t queue_id,
356 : : rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
357 : : {
358 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
359 : 0 : struct gpio_v2_line_request req = {0};
360 : : struct cnxk_gpio *gpio;
361 : : int ret;
362 : :
363 : : RTE_SET_USED(queue_conf);
364 : : RTE_SET_USED(queue_conf_size);
365 : :
366 [ # # ]: 0 : if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
367 : : return -EINVAL;
368 : :
369 : : gpio = cnxk_gpio_lookup(gpiochip, queue_id);
370 [ # # ]: 0 : if (gpio)
371 : : return -EEXIST;
372 : :
373 : 0 : gpio = rte_zmalloc(NULL, sizeof(*gpio), 0);
374 [ # # ]: 0 : if (!gpio)
375 : : return -ENOMEM;
376 : :
377 : 0 : gpio->num = cnxk_queue_to_gpio(gpiochip, queue_id);
378 : 0 : gpio->fd = CNXK_GPIO_INVALID_FD;
379 : 0 : gpio->gpiochip = gpiochip;
380 : :
381 [ # # ]: 0 : if (!cnxk_gpio_available(gpio)) {
382 : 0 : rte_free(gpio);
383 : 0 : return -EBUSY;
384 : : }
385 : :
386 : : cnxk_gpio_format_name(req.consumer, sizeof(req.consumer));
387 : 0 : req.offsets[req.num_lines] = gpio->num;
388 : 0 : req.num_lines = 1;
389 : :
390 : 0 : ret = cnxk_gpio_gpiochip_ioctl(gpio->gpiochip, GPIO_V2_GET_LINE_IOCTL, &req);
391 [ # # ]: 0 : if (ret) {
392 : 0 : rte_free(gpio);
393 : 0 : return ret;
394 : : }
395 : :
396 : 0 : gpio->fd = req.fd;
397 : 0 : gpiochip->gpios[gpio->num] = gpio;
398 : :
399 : 0 : return 0;
400 : : }
401 : :
402 : : static void
403 : 0 : cnxk_gpio_intr_handler(void *data)
404 : : {
405 : : struct gpio_v2_line_event event;
406 : : struct cnxk_gpio *gpio = data;
407 : : int ret;
408 : :
409 : 0 : ret = read(gpio->fd, &event, sizeof(event));
410 [ # # ]: 0 : if (ret != sizeof(event)) {
411 : 0 : CNXK_GPIO_LOG(ERR, "failed to read gpio%d event data", gpio->num);
412 : 0 : goto out;
413 : : }
414 [ # # ]: 0 : if ((unsigned int)gpio->num != event.offset) {
415 : 0 : CNXK_GPIO_LOG(ERR, "expected event from gpio%d, received from gpio%d",
416 : : gpio->num, event.offset);
417 : 0 : goto out;
418 : : }
419 : :
420 [ # # ]: 0 : if (gpio->intr.handler2)
421 : 0 : (gpio->intr.handler2)(&event, gpio->intr.data);
422 [ # # ]: 0 : else if (gpio->intr.handler)
423 : 0 : (gpio->intr.handler)(gpio->num, gpio->intr.data);
424 : 0 : out:
425 : 0 : rte_intr_ack(gpio->intr.intr_handle);
426 : 0 : }
427 : :
428 : : static int
429 : 0 : cnxk_gpio_unregister_irq(struct cnxk_gpio *gpio)
430 : : {
431 : : int ret;
432 : :
433 [ # # ]: 0 : if (!gpio->intr.intr_handle)
434 : : return 0;
435 : :
436 : 0 : ret = rte_intr_disable(gpio->intr.intr_handle);
437 [ # # ]: 0 : if (ret)
438 : : return ret;
439 : :
440 : 0 : ret = rte_intr_callback_unregister_sync(gpio->intr.intr_handle, cnxk_gpio_intr_handler,
441 : : (void *)-1);
442 [ # # ]: 0 : if (ret)
443 : : return ret;
444 : :
445 : 0 : rte_intr_instance_free(gpio->intr.intr_handle);
446 : 0 : gpio->intr.intr_handle = NULL;
447 : :
448 : 0 : return 0;
449 : : }
450 : :
451 : :
452 : : static int
453 : 0 : cnxk_gpio_queue_release(struct rte_rawdev *dev, uint16_t queue_id)
454 : : {
455 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
456 : : struct cnxk_gpio *gpio;
457 : : int num;
458 : :
459 [ # # ]: 0 : if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
460 : : return -EINVAL;
461 : :
462 : : gpio = cnxk_gpio_lookup(gpiochip, queue_id);
463 [ # # ]: 0 : if (!gpio)
464 : : return -ENODEV;
465 : :
466 [ # # ]: 0 : if (gpio->intr.intr_handle)
467 : 0 : cnxk_gpio_unregister_irq(gpio);
468 : :
469 [ # # ]: 0 : if (gpio->fd != CNXK_GPIO_INVALID_FD)
470 : 0 : close(gpio->fd);
471 : :
472 : : num = cnxk_queue_to_gpio(gpiochip, queue_id);
473 : 0 : gpiochip->gpios[num] = NULL;
474 : 0 : rte_free(gpio);
475 : :
476 : 0 : return 0;
477 : : }
478 : :
479 : : static int
480 : 0 : cnxk_gpio_queue_def_conf(struct rte_rawdev *dev, uint16_t queue_id,
481 : : rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
482 : : {
483 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
484 : : struct cnxk_gpio_queue_conf *conf = queue_conf;
485 : :
486 [ # # ]: 0 : if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
487 : : return -EINVAL;
488 : :
489 [ # # ]: 0 : if (queue_conf_size != sizeof(*conf))
490 : : return -EINVAL;
491 : :
492 [ # # ]: 0 : conf->size = 1;
493 : 0 : conf->gpio = cnxk_queue_to_gpio(gpiochip, queue_id);
494 : :
495 : 0 : return 0;
496 : : }
497 : :
498 : : static uint16_t
499 : 0 : cnxk_gpio_queue_count(struct rte_rawdev *dev)
500 : : {
501 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
502 : :
503 : 0 : return gpiochip->num_queues;
504 : : }
505 : :
506 : : static const struct {
507 : : enum cnxk_gpio_pin_edge edge;
508 : : enum gpio_v2_line_flag flag;
509 : : } cnxk_gpio_edge_flag[] = {
510 : : { CNXK_GPIO_PIN_EDGE_NONE, 0 },
511 : : { CNXK_GPIO_PIN_EDGE_FALLING, GPIO_V2_LINE_FLAG_EDGE_FALLING },
512 : : { CNXK_GPIO_PIN_EDGE_RISING, GPIO_V2_LINE_FLAG_EDGE_RISING },
513 : : { CNXK_GPIO_PIN_EDGE_BOTH, GPIO_V2_LINE_FLAG_EDGE_FALLING | GPIO_V2_LINE_FLAG_EDGE_RISING },
514 : : };
515 : :
516 : : static int
517 : : cnxk_gpio_edge_to_flag(enum cnxk_gpio_pin_edge edge)
518 : : {
519 : : unsigned int i;
520 : :
521 [ # # ]: 0 : for (i = 0; i < RTE_DIM(cnxk_gpio_edge_flag); i++) {
522 [ # # ]: 0 : if (cnxk_gpio_edge_flag[i].edge == edge)
523 : : break;
524 : : }
525 [ # # ]: 0 : if (i == RTE_DIM(cnxk_gpio_edge_flag))
526 : : return -EINVAL;
527 : :
528 : 0 : return cnxk_gpio_edge_flag[i].flag;
529 : : }
530 : :
531 : : static int
532 : : cnxk_gpio_flag_to_edge(enum gpio_v2_line_flag flag)
533 : : {
534 : : unsigned int i;
535 : :
536 : : for (i = 0; i < RTE_DIM(cnxk_gpio_edge_flag); i++) {
537 : : if ((cnxk_gpio_edge_flag[i].flag & flag) == cnxk_gpio_edge_flag[i].flag)
538 : : break;
539 : : }
540 : : if (i == RTE_DIM(cnxk_gpio_edge_flag))
541 : : return -EINVAL;
542 : :
543 : : return cnxk_gpio_edge_flag[i].edge;
544 : : }
545 : :
546 : : static const struct {
547 : : enum cnxk_gpio_pin_dir dir;
548 : : enum gpio_v2_line_flag flag;
549 : : } cnxk_gpio_dir_flag[] = {
550 : : { CNXK_GPIO_PIN_DIR_IN, GPIO_V2_LINE_FLAG_INPUT },
551 : : { CNXK_GPIO_PIN_DIR_OUT, GPIO_V2_LINE_FLAG_OUTPUT },
552 : : { CNXK_GPIO_PIN_DIR_HIGH, GPIO_V2_LINE_FLAG_OUTPUT },
553 : : { CNXK_GPIO_PIN_DIR_LOW, GPIO_V2_LINE_FLAG_OUTPUT },
554 : : };
555 : :
556 : : static int
557 : : cnxk_gpio_dir_to_flag(enum cnxk_gpio_pin_dir dir)
558 : : {
559 : : unsigned int i;
560 : :
561 [ # # ]: 0 : for (i = 0; i < RTE_DIM(cnxk_gpio_dir_flag); i++) {
562 [ # # ]: 0 : if (cnxk_gpio_dir_flag[i].dir == dir)
563 : : break;
564 : : }
565 [ # # ]: 0 : if (i == RTE_DIM(cnxk_gpio_dir_flag))
566 : : return -EINVAL;
567 : :
568 : 0 : return cnxk_gpio_dir_flag[i].flag;
569 : : }
570 : :
571 : : static int
572 : : cnxk_gpio_flag_to_dir(enum gpio_v2_line_flag flag)
573 : : {
574 : : unsigned int i;
575 : :
576 [ # # ]: 0 : for (i = 0; i < RTE_DIM(cnxk_gpio_dir_flag); i++) {
577 [ # # ]: 0 : if ((cnxk_gpio_dir_flag[i].flag & flag) == cnxk_gpio_dir_flag[i].flag)
578 : : break;
579 : : }
580 [ # # ]: 0 : if (i == RTE_DIM(cnxk_gpio_dir_flag))
581 : : return -EINVAL;
582 : :
583 : 0 : return cnxk_gpio_dir_flag[i].dir;
584 : : }
585 : :
586 : : static int
587 : 0 : cnxk_gpio_register_irq_compat(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq,
588 : : struct cnxk_gpio_irq2 *irq2)
589 : : {
590 : : struct rte_intr_handle *intr_handle;
591 : : int ret;
592 : :
593 [ # # ]: 0 : if (!irq && !irq2)
594 : : return -EINVAL;
595 : :
596 [ # # # # : 0 : if ((irq && !irq->handler) || (irq2 && !irq2->handler))
# # # # ]
597 : : return -EINVAL;
598 : :
599 [ # # ]: 0 : if (gpio->intr.intr_handle)
600 : : return -EEXIST;
601 : :
602 : 0 : intr_handle = rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
603 [ # # ]: 0 : if (!intr_handle)
604 : : return -ENOMEM;
605 : :
606 [ # # ]: 0 : if (rte_intr_type_set(intr_handle, RTE_INTR_HANDLE_VDEV)) {
607 : 0 : ret = -rte_errno;
608 : 0 : goto out;
609 : : }
610 : :
611 [ # # ]: 0 : if (rte_intr_fd_set(intr_handle, gpio->fd)) {
612 : 0 : ret = -rte_errno;
613 : 0 : goto out;
614 : : }
615 : :
616 [ # # ]: 0 : if (rte_intr_callback_register(intr_handle, cnxk_gpio_intr_handler, gpio)) {
617 : 0 : ret = -rte_errno;
618 : 0 : goto out;
619 : : }
620 : :
621 : 0 : gpio->intr.intr_handle = intr_handle;
622 : :
623 [ # # ]: 0 : if (irq) {
624 : 0 : gpio->intr.data = irq->data;
625 : 0 : gpio->intr.handler = irq->handler;
626 : : } else {
627 : 0 : gpio->intr.data = irq2->data;
628 : 0 : gpio->intr.handler2 = irq2->handler;
629 : : }
630 : :
631 [ # # ]: 0 : if (rte_intr_enable(gpio->intr.intr_handle)) {
632 : : ret = -EINVAL;
633 : 0 : goto out;
634 : : }
635 : :
636 : : return 0;
637 : 0 : out:
638 : 0 : rte_intr_instance_free(intr_handle);
639 : :
640 : 0 : return ret;
641 : : }
642 : :
643 : : static int
644 : 0 : cnxk_gpio_register_irq(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq)
645 : : {
646 : 0 : CNXK_GPIO_LOG(WARNING, "using deprecated interrupt registration api");
647 : :
648 : 0 : return cnxk_gpio_register_irq_compat(gpio, irq, NULL);
649 : : }
650 : :
651 : : static int
652 : : cnxk_gpio_register_irq2(struct cnxk_gpio *gpio, struct cnxk_gpio_irq2 *irq)
653 : : {
654 : 0 : return cnxk_gpio_register_irq_compat(gpio, NULL, irq);
655 : : }
656 : :
657 : : static int
658 : 0 : cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf)
659 : : {
660 : 0 : struct cnxk_gpio_msg *msg = rbuf->buf_addr;
661 : 0 : struct gpio_v2_line_values values = {0};
662 : 0 : struct gpio_v2_line_config config = {0};
663 : 0 : struct gpio_v2_line_info info = {0};
664 : : enum cnxk_gpio_pin_edge edge;
665 : : enum cnxk_gpio_pin_dir dir;
666 : : void *rsp = NULL;
667 : : int ret;
668 : :
669 : 0 : info.offset = gpio->num;
670 : 0 : ret = cnxk_gpio_gpiochip_ioctl(gpio->gpiochip, GPIO_V2_GET_LINEINFO_IOCTL, &info);
671 [ # # ]: 0 : if (ret)
672 : : return ret;
673 : :
674 : 0 : info.flags &= ~GPIO_V2_LINE_FLAG_USED;
675 : :
676 [ # # # # : 0 : switch (msg->type) {
# # # # #
# # # ]
677 : 0 : case CNXK_GPIO_MSG_TYPE_SET_PIN_VALUE:
678 [ # # ]: 0 : values.bits = *(int *)msg->data ? RTE_BIT64(gpio->num) : 0;
679 : 0 : values.mask = RTE_BIT64(gpio->num);
680 : :
681 : 0 : ret = cnxk_gpio_ioctl(gpio, GPIO_V2_LINE_SET_VALUES_IOCTL, &values);
682 : 0 : break;
683 : 0 : case CNXK_GPIO_MSG_TYPE_SET_PIN_EDGE:
684 : 0 : edge = *(enum cnxk_gpio_pin_edge *)msg->data;
685 : 0 : info.flags &= ~(GPIO_V2_LINE_FLAG_EDGE_RISING | GPIO_V2_LINE_FLAG_EDGE_FALLING);
686 : : ret = cnxk_gpio_edge_to_flag(edge);
687 [ # # ]: 0 : if (ret < 0)
688 : : break;
689 : 0 : info.flags |= ret;
690 : :
691 : 0 : config.attrs[config.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS;
692 : 0 : config.attrs[config.num_attrs].attr.flags = info.flags;
693 : 0 : config.attrs[config.num_attrs].mask = RTE_BIT64(gpio->num);
694 : 0 : config.num_attrs++;
695 : :
696 : 0 : ret = cnxk_gpio_ioctl(gpio, GPIO_V2_LINE_SET_CONFIG_IOCTL, &config);
697 : 0 : break;
698 : 0 : case CNXK_GPIO_MSG_TYPE_SET_PIN_DIR:
699 : 0 : dir = *(enum cnxk_gpio_pin_dir *)msg->data;
700 : 0 : config.attrs[config.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS;
701 : : ret = cnxk_gpio_dir_to_flag(dir);
702 [ # # ]: 0 : if (ret < 0)
703 : : break;
704 : 0 : config.attrs[config.num_attrs].attr.flags = ret;
705 : 0 : config.attrs[config.num_attrs].mask = RTE_BIT64(gpio->num);
706 : 0 : config.num_attrs++;
707 : :
708 [ # # ]: 0 : if (dir == CNXK_GPIO_PIN_DIR_HIGH || dir == CNXK_GPIO_PIN_DIR_LOW) {
709 : 0 : config.attrs[config.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
710 : 0 : config.attrs[config.num_attrs].attr.values = dir == CNXK_GPIO_PIN_DIR_HIGH ?
711 [ # # ]: 0 : RTE_BIT64(gpio->num) : 0;
712 : 0 : config.attrs[config.num_attrs].mask = RTE_BIT64(gpio->num);
713 : 0 : config.num_attrs++;
714 : : }
715 : :
716 : 0 : ret = cnxk_gpio_ioctl(gpio, GPIO_V2_LINE_SET_CONFIG_IOCTL, &config);
717 : 0 : break;
718 : 0 : case CNXK_GPIO_MSG_TYPE_SET_PIN_ACTIVE_LOW:
719 [ # # ]: 0 : if (*(int *)msg->data)
720 : 0 : info.flags |= GPIO_V2_LINE_FLAG_ACTIVE_LOW;
721 : : else
722 : 0 : info.flags &= ~GPIO_V2_LINE_FLAG_ACTIVE_LOW;
723 : :
724 : 0 : config.attrs[config.num_attrs].attr.id = GPIO_V2_LINE_ATTR_ID_FLAGS;
725 : 0 : config.attrs[config.num_attrs].attr.flags = info.flags;
726 : 0 : config.attrs[config.num_attrs].mask = RTE_BIT64(gpio->num);
727 : 0 : config.num_attrs++;
728 : :
729 : 0 : ret = cnxk_gpio_ioctl(gpio, GPIO_V2_LINE_SET_CONFIG_IOCTL, &config);
730 : 0 : break;
731 : 0 : case CNXK_GPIO_MSG_TYPE_GET_PIN_VALUE:
732 : 0 : values.mask = RTE_BIT64(gpio->num);
733 : 0 : ret = cnxk_gpio_ioctl(gpio, GPIO_V2_LINE_GET_VALUES_IOCTL, &values);
734 [ # # ]: 0 : if (ret)
735 : : break;
736 : :
737 : 0 : rsp = rte_zmalloc(NULL, sizeof(int), 0);
738 [ # # ]: 0 : if (!rsp)
739 : : return -ENOMEM;
740 : :
741 : 0 : *(int *)rsp = !!(values.bits & RTE_BIT64(gpio->num));
742 : 0 : break;
743 : 0 : case CNXK_GPIO_MSG_TYPE_GET_PIN_EDGE:
744 : : ret = cnxk_gpio_flag_to_edge(info.flags);
745 : : if (ret < 0)
746 : : return ret;
747 : :
748 : 0 : rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_edge), 0);
749 [ # # ]: 0 : if (!rsp)
750 : : return -ENOMEM;
751 : :
752 : 0 : *(enum cnxk_gpio_pin_edge *)rsp = ret;
753 : 0 : break;
754 : 0 : case CNXK_GPIO_MSG_TYPE_GET_PIN_DIR:
755 : 0 : ret = cnxk_gpio_flag_to_dir(info.flags);
756 [ # # ]: 0 : if (ret < 0)
757 : 0 : return ret;
758 : :
759 : 0 : rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_edge), 0);
760 [ # # ]: 0 : if (!rsp)
761 : : return -ENOMEM;
762 : :
763 : 0 : *(enum cnxk_gpio_pin_dir *)rsp = ret;
764 : 0 : break;
765 : 0 : case CNXK_GPIO_MSG_TYPE_GET_PIN_ACTIVE_LOW:
766 : 0 : rsp = rte_zmalloc(NULL, sizeof(int), 0);
767 [ # # ]: 0 : if (!rsp)
768 : : return -ENOMEM;
769 : :
770 : 0 : *(int *)rsp = !!(info.flags & GPIO_V2_LINE_FLAG_ACTIVE_LOW);
771 : 0 : break;
772 : 0 : case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ:
773 : 0 : ret = cnxk_gpio_register_irq(gpio, (struct cnxk_gpio_irq *)msg->data);
774 : 0 : break;
775 : 0 : case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ2:
776 : 0 : ret = cnxk_gpio_register_irq2(gpio, (struct cnxk_gpio_irq2 *)msg->data);
777 : 0 : break;
778 : 0 : case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ:
779 : 0 : ret = cnxk_gpio_unregister_irq(gpio);
780 : 0 : break;
781 : : default:
782 : : return -EINVAL;
783 : : }
784 : :
785 : : /* get rid of last response if any */
786 [ # # ]: 0 : if (gpio->rsp) {
787 : 0 : CNXK_GPIO_LOG(WARNING, "previous response got overwritten");
788 : 0 : rte_free(gpio->rsp);
789 : : }
790 : 0 : gpio->rsp = rsp;
791 : :
792 : 0 : return ret;
793 : : }
794 : :
795 : : static bool
796 : : cnxk_gpio_valid(struct cnxk_gpiochip *gpiochip, int gpio)
797 : : {
798 [ # # # # ]: 0 : return gpio < gpiochip->num_gpios && gpiochip->gpios[gpio];
799 : : }
800 : :
801 : : static int
802 : 0 : cnxk_gpio_enqueue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
803 : : unsigned int count, rte_rawdev_obj_t context)
804 : : {
805 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
806 : 0 : unsigned int gpio_num = (size_t)context;
807 : : struct cnxk_gpio *gpio;
808 : : int ret;
809 : :
810 [ # # ]: 0 : if (count == 0)
811 : : return 0;
812 : :
813 [ # # # # ]: 0 : if (!cnxk_gpio_valid(gpiochip, gpio_num))
814 : : return -EINVAL;
815 : 0 : gpio = gpiochip->gpios[gpio_num];
816 : :
817 : 0 : ret = cnxk_gpio_process_buf(gpio, buffers[0]);
818 [ # # ]: 0 : if (ret)
819 : 0 : return ret;
820 : :
821 : : return 1;
822 : : }
823 : :
824 : : static int
825 : 0 : cnxk_gpio_dequeue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
826 : : unsigned int count, rte_rawdev_obj_t context)
827 : : {
828 : 0 : struct cnxk_gpiochip *gpiochip = dev->dev_private;
829 : 0 : unsigned int gpio_num = (size_t)context;
830 : : struct cnxk_gpio *gpio;
831 : :
832 [ # # ]: 0 : if (count == 0)
833 : : return 0;
834 : :
835 [ # # # # ]: 0 : if (!cnxk_gpio_valid(gpiochip, gpio_num))
836 : : return -EINVAL;
837 : 0 : gpio = gpiochip->gpios[gpio_num];
838 : :
839 [ # # ]: 0 : if (gpio->rsp) {
840 : 0 : buffers[0]->buf_addr = gpio->rsp;
841 : 0 : gpio->rsp = NULL;
842 : :
843 : 0 : return 1;
844 : : }
845 : :
846 : : return 0;
847 : : }
848 : :
849 : : static int
850 : 0 : cnxk_gpio_dev_close(struct rte_rawdev *dev)
851 : : {
852 : : RTE_SET_USED(dev);
853 : :
854 : 0 : return 0;
855 : : }
856 : :
857 : : static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
858 : : .dev_close = cnxk_gpio_dev_close,
859 : : .enqueue_bufs = cnxk_gpio_enqueue_bufs,
860 : : .dequeue_bufs = cnxk_gpio_dequeue_bufs,
861 : : .queue_def_conf = cnxk_gpio_queue_def_conf,
862 : : .queue_count = cnxk_gpio_queue_count,
863 : : .queue_setup = cnxk_gpio_queue_setup,
864 : : .queue_release = cnxk_gpio_queue_release,
865 : : .dev_selftest = cnxk_gpio_selftest,
866 : : };
867 : :
868 : : static int
869 : 0 : cnxk_gpio_probe(struct rte_vdev_device *dev)
870 : : {
871 : : struct gpiochip_info gpiochip_info;
872 : : char name[RTE_RAWDEV_NAME_MAX_LEN];
873 : : struct cnxk_gpio_params *params;
874 : : struct cnxk_gpiochip *gpiochip;
875 : : struct rte_rawdev *rawdev;
876 : : int ret;
877 : :
878 : : cnxk_gpio_format_name(name, sizeof(name));
879 : 0 : rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip), rte_socket_id());
880 [ # # ]: 0 : if (!rawdev) {
881 : 0 : CNXK_GPIO_LOG(ERR, "failed to allocate %s rawdev", name);
882 : 0 : return -ENOMEM;
883 : : }
884 : :
885 : 0 : rawdev->dev_ops = &cnxk_gpio_rawdev_ops;
886 : 0 : rawdev->device = &dev->device;
887 : 0 : rawdev->driver_name = dev->device.name;
888 : 0 : gpiochip = rawdev->dev_private;
889 : :
890 [ # # ]: 0 : if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
891 : 0 : ret = cnxk_gpio_parse_store_args(¶ms, rte_vdev_device_args(dev));
892 [ # # ]: 0 : if (ret < 0)
893 : 0 : goto out;
894 : : } else {
895 : : ret = cnxk_gpio_params_restore(¶ms);
896 : : if (ret)
897 : 0 : goto out;
898 : : }
899 : :
900 : 0 : gpiochip->num = params->num;
901 : :
902 : : /* read number of available gpios */
903 : 0 : ret = cnxk_gpio_gpiochip_ioctl(gpiochip, GPIO_GET_CHIPINFO_IOCTL, &gpiochip_info);
904 [ # # ]: 0 : if (ret) {
905 : 0 : CNXK_GPIO_LOG(ERR, "failed to read /dev/gpiochip%d info", gpiochip->num);
906 : 0 : goto out;
907 : : }
908 : :
909 : 0 : gpiochip->num_gpios = gpiochip_info.lines;
910 : 0 : gpiochip->num_queues = gpiochip->num_gpios;
911 : :
912 : 0 : ret = cnxk_gpio_parse_allowlist(gpiochip, params->allowlist);
913 [ # # ]: 0 : if (ret) {
914 : 0 : CNXK_GPIO_LOG(ERR, "failed to parse allowed gpios");
915 : 0 : goto out;
916 : : }
917 : :
918 : 0 : gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios, sizeof(struct cnxk_gpio *), 0);
919 [ # # ]: 0 : if (!gpiochip->gpios) {
920 : 0 : CNXK_GPIO_LOG(ERR, "failed to allocate gpios memory");
921 : : ret = -ENOMEM;
922 : 0 : goto out;
923 : : }
924 : :
925 : : return 0;
926 : 0 : out:
927 : 0 : rte_free(gpiochip->allowlist);
928 : 0 : cnxk_gpio_params_release();
929 : 0 : rte_rawdev_pmd_release(rawdev);
930 : :
931 : 0 : return ret;
932 : : }
933 : :
934 : : static int
935 [ # # ]: 0 : cnxk_gpio_remove(struct rte_vdev_device *dev)
936 : : {
937 : : char name[RTE_RAWDEV_NAME_MAX_LEN];
938 : : struct cnxk_gpiochip *gpiochip;
939 : : struct rte_rawdev *rawdev;
940 : : struct cnxk_gpio *gpio;
941 : : int i;
942 : :
943 : : RTE_SET_USED(dev);
944 : :
945 : : cnxk_gpio_format_name(name, sizeof(name));
946 : 0 : rawdev = rte_rawdev_pmd_get_named_dev(name);
947 [ # # ]: 0 : if (!rawdev)
948 : : return -ENODEV;
949 : :
950 : 0 : gpiochip = rawdev->dev_private;
951 [ # # ]: 0 : for (i = 0; i < gpiochip->num_gpios; i++) {
952 : 0 : gpio = gpiochip->gpios[i];
953 [ # # ]: 0 : if (!gpio)
954 : 0 : continue;
955 : :
956 : 0 : cnxk_gpio_queue_release(rawdev, gpio->num);
957 : : }
958 : :
959 : 0 : rte_free(gpiochip->allowlist);
960 : 0 : rte_free(gpiochip->gpios);
961 : 0 : cnxk_gpio_params_release();
962 : 0 : rte_rawdev_pmd_release(rawdev);
963 : :
964 : 0 : return 0;
965 : : }
966 : :
967 : : static struct rte_vdev_driver cnxk_gpio_drv = {
968 : : .probe = cnxk_gpio_probe,
969 : : .remove = cnxk_gpio_remove,
970 : : };
971 : :
972 : 253 : RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
973 : : RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio,
974 : : "gpiochip=<int> "
975 : : "allowlist=<list>");
976 : :
977 : : #endif /* CNXK_GPIO_V2_PRESENT */
|