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