1d0b8a4e1STomasz Duszynski /* SPDX-License-Identifier: BSD-3-Clause
2d0b8a4e1STomasz Duszynski * Copyright(C) 2021 Marvell.
3d0b8a4e1STomasz Duszynski */
4d0b8a4e1STomasz Duszynski
5d0b8a4e1STomasz Duszynski #include <dirent.h>
6d0b8a4e1STomasz Duszynski #include <string.h>
76b41a76fSTomasz Duszynski #include <sys/stat.h>
8d0b8a4e1STomasz Duszynski
94851ef2bSDavid Marchand #include <bus_vdev_driver.h>
10d0b8a4e1STomasz Duszynski #include <rte_eal.h>
11d0b8a4e1STomasz Duszynski #include <rte_kvargs.h>
12d0b8a4e1STomasz Duszynski #include <rte_lcore.h>
13d0b8a4e1STomasz Duszynski #include <rte_rawdev_pmd.h>
14d0b8a4e1STomasz Duszynski
15d0b8a4e1STomasz Duszynski #include <roc_api.h>
16d0b8a4e1STomasz Duszynski
17d0b8a4e1STomasz Duszynski #include "cnxk_gpio.h"
18994cc926STomasz Duszynski #include "rte_pmd_cnxk_gpio.h"
19d0b8a4e1STomasz Duszynski
20d0b8a4e1STomasz Duszynski #define CNXK_GPIO_BUFSZ 128
21d0b8a4e1STomasz Duszynski #define CNXK_GPIO_CLASS_PATH "/sys/class/gpio"
22ef2a3f3bSTomasz Duszynski #define CNXK_GPIO_PARAMS_MZ_NAME "cnxk_gpio_params_mz"
23ef2a3f3bSTomasz Duszynski
24ef2a3f3bSTomasz Duszynski struct cnxk_gpio_params {
25ef2a3f3bSTomasz Duszynski unsigned int num;
26ef2a3f3bSTomasz Duszynski char allowlist[];
27ef2a3f3bSTomasz Duszynski };
28d0b8a4e1STomasz Duszynski
29d0b8a4e1STomasz Duszynski static const char *const cnxk_gpio_args[] = {
30d0b8a4e1STomasz Duszynski #define CNXK_GPIO_ARG_GPIOCHIP "gpiochip"
31d0b8a4e1STomasz Duszynski CNXK_GPIO_ARG_GPIOCHIP,
32ecc0dd45STomasz Duszynski #define CNXK_GPIO_ARG_ALLOWLIST "allowlist"
33ecc0dd45STomasz Duszynski CNXK_GPIO_ARG_ALLOWLIST,
34d0b8a4e1STomasz Duszynski NULL
35d0b8a4e1STomasz Duszynski };
36d0b8a4e1STomasz Duszynski
37d0b8a4e1STomasz Duszynski static void
cnxk_gpio_format_name(char * name,size_t len)38d0b8a4e1STomasz Duszynski cnxk_gpio_format_name(char *name, size_t len)
39d0b8a4e1STomasz Duszynski {
40d0b8a4e1STomasz Duszynski snprintf(name, len, "cnxk_gpio");
41d0b8a4e1STomasz Duszynski }
42d0b8a4e1STomasz Duszynski
43d0b8a4e1STomasz Duszynski static int
cnxk_gpio_filter_gpiochip(const struct dirent * dirent)44d0b8a4e1STomasz Duszynski cnxk_gpio_filter_gpiochip(const struct dirent *dirent)
45d0b8a4e1STomasz Duszynski {
46d0b8a4e1STomasz Duszynski const char *pattern = "gpiochip";
47d0b8a4e1STomasz Duszynski
48d0b8a4e1STomasz Duszynski return !strncmp(dirent->d_name, pattern, strlen(pattern));
49d0b8a4e1STomasz Duszynski }
50d0b8a4e1STomasz Duszynski
51ef2a3f3bSTomasz Duszynski static int
cnxk_gpio_set_defaults(struct cnxk_gpio_params * params)52ef2a3f3bSTomasz Duszynski cnxk_gpio_set_defaults(struct cnxk_gpio_params *params)
53d0b8a4e1STomasz Duszynski {
54d0b8a4e1STomasz Duszynski struct dirent **namelist;
55ef2a3f3bSTomasz Duszynski int ret = 0, n;
56d0b8a4e1STomasz Duszynski
57d0b8a4e1STomasz Duszynski n = scandir(CNXK_GPIO_CLASS_PATH, &namelist, cnxk_gpio_filter_gpiochip,
58d0b8a4e1STomasz Duszynski alphasort);
59d0b8a4e1STomasz Duszynski if (n < 0 || n == 0)
60ef2a3f3bSTomasz Duszynski return -ENODEV;
61d0b8a4e1STomasz Duszynski
62ef2a3f3bSTomasz Duszynski if (sscanf(namelist[0]->d_name, "gpiochip%d", ¶ms->num) != 1)
63ef2a3f3bSTomasz Duszynski ret = -EINVAL;
64ef2a3f3bSTomasz Duszynski
65d0b8a4e1STomasz Duszynski while (n--)
66d0b8a4e1STomasz Duszynski free(namelist[n]);
67d0b8a4e1STomasz Duszynski free(namelist);
68ef2a3f3bSTomasz Duszynski
69ef2a3f3bSTomasz Duszynski return ret;
70d0b8a4e1STomasz Duszynski }
71d0b8a4e1STomasz Duszynski
72d0b8a4e1STomasz Duszynski static int
cnxk_gpio_parse_arg_gpiochip(const char * key __rte_unused,const char * value,void * extra_args)73d0b8a4e1STomasz Duszynski cnxk_gpio_parse_arg_gpiochip(const char *key __rte_unused, const char *value,
74d0b8a4e1STomasz Duszynski void *extra_args)
75d0b8a4e1STomasz Duszynski {
76ef2a3f3bSTomasz Duszynski unsigned long val;
77d0b8a4e1STomasz Duszynski
78d0b8a4e1STomasz Duszynski errno = 0;
79ef2a3f3bSTomasz Duszynski val = strtoul(value, NULL, 10);
80d0b8a4e1STomasz Duszynski if (errno)
81d0b8a4e1STomasz Duszynski return -errno;
82d0b8a4e1STomasz Duszynski
83ef2a3f3bSTomasz Duszynski *(unsigned int *)extra_args = val;
84d0b8a4e1STomasz Duszynski
85d0b8a4e1STomasz Duszynski return 0;
86d0b8a4e1STomasz Duszynski }
87d0b8a4e1STomasz Duszynski
88d0b8a4e1STomasz Duszynski static int
cnxk_gpio_parse_arg_allowlist(const char * key __rte_unused,const char * value,void * extra_args)89ef2a3f3bSTomasz Duszynski cnxk_gpio_parse_arg_allowlist(const char *key __rte_unused, const char *value, void *extra_args)
90ecc0dd45STomasz Duszynski {
91ef2a3f3bSTomasz Duszynski *(const char **)extra_args = value;
92ecc0dd45STomasz Duszynski
93ecc0dd45STomasz Duszynski return 0;
94ecc0dd45STomasz Duszynski }
95ecc0dd45STomasz Duszynski
96ecc0dd45STomasz Duszynski static int
cnxk_gpio_params_restore(struct cnxk_gpio_params ** params)97ef2a3f3bSTomasz Duszynski cnxk_gpio_params_restore(struct cnxk_gpio_params **params)
98d0b8a4e1STomasz Duszynski {
99ef2a3f3bSTomasz Duszynski const struct rte_memzone *mz;
100ef2a3f3bSTomasz Duszynski
101ef2a3f3bSTomasz Duszynski mz = rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME);
102ef2a3f3bSTomasz Duszynski if (!mz)
103ef2a3f3bSTomasz Duszynski return -ENODEV;
104ef2a3f3bSTomasz Duszynski
105ef2a3f3bSTomasz Duszynski *params = mz->addr;
106ef2a3f3bSTomasz Duszynski
107ef2a3f3bSTomasz Duszynski return 0;
108ef2a3f3bSTomasz Duszynski }
109ef2a3f3bSTomasz Duszynski
110ef2a3f3bSTomasz Duszynski static struct cnxk_gpio_params *
cnxk_gpio_params_reserve(size_t len)111ef2a3f3bSTomasz Duszynski cnxk_gpio_params_reserve(size_t len)
112ef2a3f3bSTomasz Duszynski {
113ef2a3f3bSTomasz Duszynski const struct rte_memzone *mz;
114ef2a3f3bSTomasz Duszynski
115ef2a3f3bSTomasz Duszynski mz = rte_memzone_reserve(CNXK_GPIO_PARAMS_MZ_NAME, len, rte_socket_id(), 0);
116ef2a3f3bSTomasz Duszynski if (!mz)
117ef2a3f3bSTomasz Duszynski return NULL;
118ef2a3f3bSTomasz Duszynski
119ef2a3f3bSTomasz Duszynski return mz->addr;
120ef2a3f3bSTomasz Duszynski }
121ef2a3f3bSTomasz Duszynski
122ef2a3f3bSTomasz Duszynski static void
cnxk_gpio_params_release(void)123ef2a3f3bSTomasz Duszynski cnxk_gpio_params_release(void)
124ef2a3f3bSTomasz Duszynski {
125ef2a3f3bSTomasz Duszynski if (rte_eal_process_type() == RTE_PROC_PRIMARY)
126ef2a3f3bSTomasz Duszynski rte_memzone_free(rte_memzone_lookup(CNXK_GPIO_PARAMS_MZ_NAME));
127ef2a3f3bSTomasz Duszynski }
128ef2a3f3bSTomasz Duszynski
129ef2a3f3bSTomasz Duszynski static int
cnxk_gpio_parse_arg(struct rte_kvargs * kvlist,const char * arg,arg_handler_t handler,void * data)130ef2a3f3bSTomasz Duszynski cnxk_gpio_parse_arg(struct rte_kvargs *kvlist, const char *arg, arg_handler_t handler, void *data)
131ef2a3f3bSTomasz Duszynski {
132ef2a3f3bSTomasz Duszynski int ret;
133ef2a3f3bSTomasz Duszynski
134ef2a3f3bSTomasz Duszynski ret = rte_kvargs_count(kvlist, arg);
135ef2a3f3bSTomasz Duszynski if (ret == 0)
136ef2a3f3bSTomasz Duszynski return 0;
137ef2a3f3bSTomasz Duszynski if (ret > 1)
138ef2a3f3bSTomasz Duszynski return -EINVAL;
139ef2a3f3bSTomasz Duszynski
140ef2a3f3bSTomasz Duszynski return rte_kvargs_process(kvlist, arg, handler, data) ? -EIO : 1;
141ef2a3f3bSTomasz Duszynski }
142ef2a3f3bSTomasz Duszynski
143ef2a3f3bSTomasz Duszynski static int
cnxk_gpio_parse_store_args(struct cnxk_gpio_params ** params,const char * args)144ef2a3f3bSTomasz Duszynski cnxk_gpio_parse_store_args(struct cnxk_gpio_params **params, const char *args)
145ef2a3f3bSTomasz Duszynski {
146ef2a3f3bSTomasz Duszynski size_t len = sizeof(**params);
147ef2a3f3bSTomasz Duszynski const char *allowlist = NULL;
148d0b8a4e1STomasz Duszynski struct rte_kvargs *kvlist;
149d0b8a4e1STomasz Duszynski int ret;
150d0b8a4e1STomasz Duszynski
151ecc0dd45STomasz Duszynski kvlist = rte_kvargs_parse(args, cnxk_gpio_args);
152ef2a3f3bSTomasz Duszynski if (!kvlist) {
153ef2a3f3bSTomasz Duszynski *params = cnxk_gpio_params_reserve(len);
154ef2a3f3bSTomasz Duszynski if (!*params)
155ef2a3f3bSTomasz Duszynski return -ENOMEM;
156ef2a3f3bSTomasz Duszynski
157ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_set_defaults(*params);
158ef2a3f3bSTomasz Duszynski if (ret)
159ef2a3f3bSTomasz Duszynski goto out;
160ef2a3f3bSTomasz Duszynski
161d0b8a4e1STomasz Duszynski return 0;
162d0b8a4e1STomasz Duszynski }
163d0b8a4e1STomasz Duszynski
164ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_ALLOWLIST, cnxk_gpio_parse_arg_allowlist,
165ef2a3f3bSTomasz Duszynski &allowlist);
166ef2a3f3bSTomasz Duszynski if (ret < 0)
167ecc0dd45STomasz Duszynski goto out;
168ecc0dd45STomasz Duszynski
169ef2a3f3bSTomasz Duszynski if (allowlist)
170ef2a3f3bSTomasz Duszynski len += strlen(allowlist) + 1;
171ef2a3f3bSTomasz Duszynski
172ef2a3f3bSTomasz Duszynski *params = cnxk_gpio_params_reserve(len);
173d677a3ebSTomasz Duszynski if (!(*params)) {
174d677a3ebSTomasz Duszynski ret = -ENOMEM;
175d677a3ebSTomasz Duszynski goto out;
176d677a3ebSTomasz Duszynski }
177ef2a3f3bSTomasz Duszynski
178ef2a3f3bSTomasz Duszynski strlcpy((*params)->allowlist, allowlist, strlen(allowlist) + 1);
179ef2a3f3bSTomasz Duszynski
180ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_parse_arg(kvlist, CNXK_GPIO_ARG_GPIOCHIP, cnxk_gpio_parse_arg_gpiochip,
181ef2a3f3bSTomasz Duszynski &(*params)->num);
182ef2a3f3bSTomasz Duszynski if (ret == 0)
183ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_set_defaults(*params);
184ef2a3f3bSTomasz Duszynski
185d0b8a4e1STomasz Duszynski out:
186d0b8a4e1STomasz Duszynski rte_kvargs_free(kvlist);
187d0b8a4e1STomasz Duszynski
188d0b8a4e1STomasz Duszynski return ret;
189d0b8a4e1STomasz Duszynski }
190d0b8a4e1STomasz Duszynski
191d0b8a4e1STomasz Duszynski static int
cnxk_gpio_parse_allowlist(struct cnxk_gpiochip * gpiochip,char * allowlist)192ef2a3f3bSTomasz Duszynski cnxk_gpio_parse_allowlist(struct cnxk_gpiochip *gpiochip, char *allowlist)
193ecc0dd45STomasz Duszynski {
194ecc0dd45STomasz Duszynski int i, ret, val, queue = 0;
195ecc0dd45STomasz Duszynski char *token;
196ecc0dd45STomasz Duszynski int *list;
197ecc0dd45STomasz Duszynski
198ecc0dd45STomasz Duszynski list = rte_calloc(NULL, gpiochip->num_gpios, sizeof(*list), 0);
199ecc0dd45STomasz Duszynski if (!list)
200ecc0dd45STomasz Duszynski return -ENOMEM;
201ecc0dd45STomasz Duszynski
202ef2a3f3bSTomasz Duszynski allowlist = strdup(allowlist);
203ef2a3f3bSTomasz Duszynski if (!allowlist) {
204ef2a3f3bSTomasz Duszynski ret = -ENOMEM;
205ef2a3f3bSTomasz Duszynski goto out;
206ef2a3f3bSTomasz Duszynski }
207ef2a3f3bSTomasz Duszynski
208ecc0dd45STomasz Duszynski /* replace brackets with something meaningless for strtol() */
209ecc0dd45STomasz Duszynski allowlist[0] = ' ';
210ecc0dd45STomasz Duszynski allowlist[strlen(allowlist) - 1] = ' ';
211ecc0dd45STomasz Duszynski
212ecc0dd45STomasz Duszynski /* quiesce -Wcast-qual */
213ecc0dd45STomasz Duszynski token = strtok((char *)(uintptr_t)allowlist, ",");
214ecc0dd45STomasz Duszynski do {
215ecc0dd45STomasz Duszynski errno = 0;
216ecc0dd45STomasz Duszynski val = strtol(token, NULL, 10);
217ecc0dd45STomasz Duszynski if (errno) {
218*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to parse %s", token);
219ecc0dd45STomasz Duszynski ret = -errno;
220ecc0dd45STomasz Duszynski goto out;
221ecc0dd45STomasz Duszynski }
222ecc0dd45STomasz Duszynski
223ecc0dd45STomasz Duszynski if (val < 0 || val >= gpiochip->num_gpios) {
224*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "gpio%d out of 0-%d range", val,
225ecc0dd45STomasz Duszynski gpiochip->num_gpios - 1);
226ecc0dd45STomasz Duszynski ret = -EINVAL;
227ecc0dd45STomasz Duszynski goto out;
228ecc0dd45STomasz Duszynski }
229ecc0dd45STomasz Duszynski
230ecc0dd45STomasz Duszynski for (i = 0; i < queue; i++) {
231ecc0dd45STomasz Duszynski if (list[i] != val)
232ecc0dd45STomasz Duszynski continue;
233ecc0dd45STomasz Duszynski
234*0fc53935SStephen Hemminger CNXK_GPIO_LOG(WARNING, "gpio%d already allowed", val);
235ecc0dd45STomasz Duszynski break;
236ecc0dd45STomasz Duszynski }
237ecc0dd45STomasz Duszynski if (i == queue)
238ecc0dd45STomasz Duszynski list[queue++] = val;
239ecc0dd45STomasz Duszynski } while ((token = strtok(NULL, ",")));
240ecc0dd45STomasz Duszynski
241ef2a3f3bSTomasz Duszynski free(allowlist);
242ecc0dd45STomasz Duszynski gpiochip->allowlist = list;
243ecc0dd45STomasz Duszynski gpiochip->num_queues = queue;
244ecc0dd45STomasz Duszynski
245ecc0dd45STomasz Duszynski return 0;
246ecc0dd45STomasz Duszynski out:
247ef2a3f3bSTomasz Duszynski free(allowlist);
248ecc0dd45STomasz Duszynski rte_free(list);
249ecc0dd45STomasz Duszynski
250ecc0dd45STomasz Duszynski return ret;
251ecc0dd45STomasz Duszynski }
252ecc0dd45STomasz Duszynski
253ecc0dd45STomasz Duszynski static int
cnxk_gpio_read_attr(char * attr,char * val)254d0b8a4e1STomasz Duszynski cnxk_gpio_read_attr(char *attr, char *val)
255d0b8a4e1STomasz Duszynski {
256a8e10309STomasz Duszynski int ret, ret2;
257d0b8a4e1STomasz Duszynski FILE *fp;
258d0b8a4e1STomasz Duszynski
259d0b8a4e1STomasz Duszynski fp = fopen(attr, "r");
260d0b8a4e1STomasz Duszynski if (!fp)
261d0b8a4e1STomasz Duszynski return -errno;
262d0b8a4e1STomasz Duszynski
263d0b8a4e1STomasz Duszynski ret = fscanf(fp, "%s", val);
264a8e10309STomasz Duszynski if (ret < 0) {
265a8e10309STomasz Duszynski ret = -errno;
266a8e10309STomasz Duszynski goto out;
267a8e10309STomasz Duszynski }
268a8e10309STomasz Duszynski if (ret != 1) {
269a8e10309STomasz Duszynski ret = -EIO;
270a8e10309STomasz Duszynski goto out;
271a8e10309STomasz Duszynski }
272d0b8a4e1STomasz Duszynski
273a8e10309STomasz Duszynski ret = 0;
274a8e10309STomasz Duszynski out:
275a8e10309STomasz Duszynski ret2 = fclose(fp);
276a8e10309STomasz Duszynski if (!ret)
277a8e10309STomasz Duszynski ret = ret2;
278d0b8a4e1STomasz Duszynski
279a8e10309STomasz Duszynski return ret;
280d0b8a4e1STomasz Duszynski }
281d0b8a4e1STomasz Duszynski
282d0b8a4e1STomasz Duszynski static int
cnxk_gpio_read_attr_int(char * attr,int * val)283d0b8a4e1STomasz Duszynski cnxk_gpio_read_attr_int(char *attr, int *val)
284d0b8a4e1STomasz Duszynski {
285d0b8a4e1STomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
286d0b8a4e1STomasz Duszynski int ret;
287d0b8a4e1STomasz Duszynski
288d0b8a4e1STomasz Duszynski ret = cnxk_gpio_read_attr(attr, buf);
289d0b8a4e1STomasz Duszynski if (ret)
290d0b8a4e1STomasz Duszynski return ret;
291d0b8a4e1STomasz Duszynski
292d0b8a4e1STomasz Duszynski ret = sscanf(buf, "%d", val);
293d0b8a4e1STomasz Duszynski if (ret < 0)
294d0b8a4e1STomasz Duszynski return -errno;
295d0b8a4e1STomasz Duszynski
296d0b8a4e1STomasz Duszynski return 0;
297d0b8a4e1STomasz Duszynski }
298d0b8a4e1STomasz Duszynski
299d0b8a4e1STomasz Duszynski static int
cnxk_gpio_write_attr(const char * attr,const char * val)300a83ba0fbSTomasz Duszynski cnxk_gpio_write_attr(const char *attr, const char *val)
301d0b8a4e1STomasz Duszynski {
302a83ba0fbSTomasz Duszynski FILE *fp;
303a83ba0fbSTomasz Duszynski int ret;
304a83ba0fbSTomasz Duszynski
305a83ba0fbSTomasz Duszynski if (!val)
306a83ba0fbSTomasz Duszynski return -EINVAL;
307a83ba0fbSTomasz Duszynski
308a83ba0fbSTomasz Duszynski fp = fopen(attr, "w");
309a83ba0fbSTomasz Duszynski if (!fp)
310a83ba0fbSTomasz Duszynski return -errno;
311a83ba0fbSTomasz Duszynski
312a83ba0fbSTomasz Duszynski ret = fprintf(fp, "%s", val);
313a83ba0fbSTomasz Duszynski if (ret < 0) {
314a83ba0fbSTomasz Duszynski fclose(fp);
315a83ba0fbSTomasz Duszynski return ret;
316a83ba0fbSTomasz Duszynski }
317a83ba0fbSTomasz Duszynski
318a83ba0fbSTomasz Duszynski ret = fclose(fp);
319a83ba0fbSTomasz Duszynski if (ret)
320a83ba0fbSTomasz Duszynski return -errno;
321a83ba0fbSTomasz Duszynski
322a83ba0fbSTomasz Duszynski return 0;
323a83ba0fbSTomasz Duszynski }
324a83ba0fbSTomasz Duszynski
325a83ba0fbSTomasz Duszynski static int
cnxk_gpio_write_attr_int(const char * attr,int val)326a83ba0fbSTomasz Duszynski cnxk_gpio_write_attr_int(const char *attr, int val)
327a83ba0fbSTomasz Duszynski {
328a83ba0fbSTomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
329a83ba0fbSTomasz Duszynski
330a83ba0fbSTomasz Duszynski snprintf(buf, sizeof(buf), "%d", val);
331a83ba0fbSTomasz Duszynski
332a83ba0fbSTomasz Duszynski return cnxk_gpio_write_attr(attr, buf);
333a83ba0fbSTomasz Duszynski }
334a83ba0fbSTomasz Duszynski
335ecc0dd45STomasz Duszynski static bool
cnxk_gpio_queue_valid(struct cnxk_gpiochip * gpiochip,uint16_t queue)336ecc0dd45STomasz Duszynski cnxk_gpio_queue_valid(struct cnxk_gpiochip *gpiochip, uint16_t queue)
337ecc0dd45STomasz Duszynski {
338ecc0dd45STomasz Duszynski return queue < gpiochip->num_queues;
339ecc0dd45STomasz Duszynski }
340ecc0dd45STomasz Duszynski
341ecc0dd45STomasz Duszynski static int
cnxk_queue_to_gpio(struct cnxk_gpiochip * gpiochip,uint16_t queue)342ecc0dd45STomasz Duszynski cnxk_queue_to_gpio(struct cnxk_gpiochip *gpiochip, uint16_t queue)
343ecc0dd45STomasz Duszynski {
344ecc0dd45STomasz Duszynski return gpiochip->allowlist ? gpiochip->allowlist[queue] : queue;
345ecc0dd45STomasz Duszynski }
346ecc0dd45STomasz Duszynski
347a83ba0fbSTomasz Duszynski static struct cnxk_gpio *
cnxk_gpio_lookup(struct cnxk_gpiochip * gpiochip,uint16_t queue)348a83ba0fbSTomasz Duszynski cnxk_gpio_lookup(struct cnxk_gpiochip *gpiochip, uint16_t queue)
349a83ba0fbSTomasz Duszynski {
350ecc0dd45STomasz Duszynski int gpio = cnxk_queue_to_gpio(gpiochip, queue);
351a83ba0fbSTomasz Duszynski
352ecc0dd45STomasz Duszynski return gpiochip->gpios[gpio];
353a83ba0fbSTomasz Duszynski }
354a83ba0fbSTomasz Duszynski
3556b41a76fSTomasz Duszynski static bool
cnxk_gpio_exists(int num)3566b41a76fSTomasz Duszynski cnxk_gpio_exists(int num)
3576b41a76fSTomasz Duszynski {
3586b41a76fSTomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
3596b41a76fSTomasz Duszynski struct stat st;
3606b41a76fSTomasz Duszynski
3616b41a76fSTomasz Duszynski snprintf(buf, sizeof(buf), "%s/gpio%d", CNXK_GPIO_CLASS_PATH, num);
3626b41a76fSTomasz Duszynski
3636b41a76fSTomasz Duszynski return !stat(buf, &st);
3646b41a76fSTomasz Duszynski }
3656b41a76fSTomasz Duszynski
366a83ba0fbSTomasz Duszynski static int
cnxk_gpio_queue_setup(struct rte_rawdev * dev,uint16_t queue_id,rte_rawdev_obj_t queue_conf,size_t queue_conf_size)367a83ba0fbSTomasz Duszynski cnxk_gpio_queue_setup(struct rte_rawdev *dev, uint16_t queue_id,
368a83ba0fbSTomasz Duszynski rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
369a83ba0fbSTomasz Duszynski {
370a83ba0fbSTomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
371a83ba0fbSTomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
372a83ba0fbSTomasz Duszynski struct cnxk_gpio *gpio;
373ecc0dd45STomasz Duszynski int num, ret;
374a83ba0fbSTomasz Duszynski
375a83ba0fbSTomasz Duszynski RTE_SET_USED(queue_conf);
376a83ba0fbSTomasz Duszynski RTE_SET_USED(queue_conf_size);
377a83ba0fbSTomasz Duszynski
378ecc0dd45STomasz Duszynski if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
379ecc0dd45STomasz Duszynski return -EINVAL;
380ecc0dd45STomasz Duszynski
381a83ba0fbSTomasz Duszynski gpio = cnxk_gpio_lookup(gpiochip, queue_id);
382a83ba0fbSTomasz Duszynski if (gpio)
383a83ba0fbSTomasz Duszynski return -EEXIST;
384a83ba0fbSTomasz Duszynski
385a83ba0fbSTomasz Duszynski gpio = rte_zmalloc(NULL, sizeof(*gpio), 0);
386a83ba0fbSTomasz Duszynski if (!gpio)
387a83ba0fbSTomasz Duszynski return -ENOMEM;
388ecc0dd45STomasz Duszynski
389ecc0dd45STomasz Duszynski num = cnxk_queue_to_gpio(gpiochip, queue_id);
390ecc0dd45STomasz Duszynski gpio->num = num + gpiochip->base;
391a83ba0fbSTomasz Duszynski gpio->gpiochip = gpiochip;
392a83ba0fbSTomasz Duszynski
3936b41a76fSTomasz Duszynski if (!cnxk_gpio_exists(gpio->num)) {
394a83ba0fbSTomasz Duszynski snprintf(buf, sizeof(buf), "%s/export", CNXK_GPIO_CLASS_PATH);
395a83ba0fbSTomasz Duszynski ret = cnxk_gpio_write_attr_int(buf, gpio->num);
396a83ba0fbSTomasz Duszynski if (ret) {
397a83ba0fbSTomasz Duszynski rte_free(gpio);
398a83ba0fbSTomasz Duszynski return ret;
399a83ba0fbSTomasz Duszynski }
4006b41a76fSTomasz Duszynski } else {
401*0fc53935SStephen Hemminger CNXK_GPIO_LOG(WARNING, "using existing gpio%d", gpio->num);
4026b41a76fSTomasz Duszynski }
403a83ba0fbSTomasz Duszynski
404ecc0dd45STomasz Duszynski gpiochip->gpios[num] = gpio;
405d0b8a4e1STomasz Duszynski
406d0b8a4e1STomasz Duszynski return 0;
407d0b8a4e1STomasz Duszynski }
408d0b8a4e1STomasz Duszynski
409d64ef089STomasz Duszynski static int
cnxk_gpio_queue_release(struct rte_rawdev * dev,uint16_t queue_id)410a34ffa49STomasz Duszynski cnxk_gpio_queue_release(struct rte_rawdev *dev, uint16_t queue_id)
411a34ffa49STomasz Duszynski {
412a34ffa49STomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
413a34ffa49STomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
414a34ffa49STomasz Duszynski struct cnxk_gpio *gpio;
415ecc0dd45STomasz Duszynski int num, ret;
416ecc0dd45STomasz Duszynski
417ecc0dd45STomasz Duszynski if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
418ecc0dd45STomasz Duszynski return -EINVAL;
419a34ffa49STomasz Duszynski
420a34ffa49STomasz Duszynski gpio = cnxk_gpio_lookup(gpiochip, queue_id);
421a34ffa49STomasz Duszynski if (!gpio)
422a34ffa49STomasz Duszynski return -ENODEV;
423a34ffa49STomasz Duszynski
424a34ffa49STomasz Duszynski snprintf(buf, sizeof(buf), "%s/unexport", CNXK_GPIO_CLASS_PATH);
425ecc0dd45STomasz Duszynski ret = cnxk_gpio_write_attr_int(buf, gpio->num);
426a34ffa49STomasz Duszynski if (ret)
427a34ffa49STomasz Duszynski return ret;
428a34ffa49STomasz Duszynski
429ecc0dd45STomasz Duszynski num = cnxk_queue_to_gpio(gpiochip, queue_id);
430ecc0dd45STomasz Duszynski gpiochip->gpios[num] = NULL;
431a34ffa49STomasz Duszynski rte_free(gpio);
432a34ffa49STomasz Duszynski
433a34ffa49STomasz Duszynski return 0;
434a34ffa49STomasz Duszynski }
435a34ffa49STomasz Duszynski
436a34ffa49STomasz Duszynski static int
cnxk_gpio_queue_def_conf(struct rte_rawdev * dev,uint16_t queue_id,rte_rawdev_obj_t queue_conf,size_t queue_conf_size)437d64ef089STomasz Duszynski cnxk_gpio_queue_def_conf(struct rte_rawdev *dev, uint16_t queue_id,
438d64ef089STomasz Duszynski rte_rawdev_obj_t queue_conf, size_t queue_conf_size)
439d64ef089STomasz Duszynski {
440ecc0dd45STomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
441ecc0dd45STomasz Duszynski struct cnxk_gpio_queue_conf *conf = queue_conf;
442d64ef089STomasz Duszynski
443ecc0dd45STomasz Duszynski if (!cnxk_gpio_queue_valid(gpiochip, queue_id))
444ecc0dd45STomasz Duszynski return -EINVAL;
445d64ef089STomasz Duszynski
446d64ef089STomasz Duszynski if (queue_conf_size != sizeof(*conf))
447d64ef089STomasz Duszynski return -EINVAL;
448d64ef089STomasz Duszynski
449ecc0dd45STomasz Duszynski conf->size = 1;
450ecc0dd45STomasz Duszynski conf->gpio = cnxk_queue_to_gpio(gpiochip, queue_id);
451d64ef089STomasz Duszynski
452d64ef089STomasz Duszynski return 0;
453d64ef089STomasz Duszynski }
454d64ef089STomasz Duszynski
455dd2019a5STomasz Duszynski static uint16_t
cnxk_gpio_queue_count(struct rte_rawdev * dev)456dd2019a5STomasz Duszynski cnxk_gpio_queue_count(struct rte_rawdev *dev)
457dd2019a5STomasz Duszynski {
458dd2019a5STomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
459dd2019a5STomasz Duszynski
460ecc0dd45STomasz Duszynski return gpiochip->num_queues;
461dd2019a5STomasz Duszynski }
462dd2019a5STomasz Duszynski
463633dae69STomasz Duszynski static const struct {
464633dae69STomasz Duszynski enum cnxk_gpio_pin_edge edge;
465633dae69STomasz Duszynski const char *name;
466633dae69STomasz Duszynski } cnxk_gpio_edge_name[] = {
467633dae69STomasz Duszynski { CNXK_GPIO_PIN_EDGE_NONE, "none" },
468633dae69STomasz Duszynski { CNXK_GPIO_PIN_EDGE_FALLING, "falling" },
469633dae69STomasz Duszynski { CNXK_GPIO_PIN_EDGE_RISING, "rising" },
470633dae69STomasz Duszynski { CNXK_GPIO_PIN_EDGE_BOTH, "both" },
471633dae69STomasz Duszynski };
472633dae69STomasz Duszynski
473633dae69STomasz Duszynski static const char *
cnxk_gpio_edge_to_name(enum cnxk_gpio_pin_edge edge)474633dae69STomasz Duszynski cnxk_gpio_edge_to_name(enum cnxk_gpio_pin_edge edge)
475633dae69STomasz Duszynski {
476633dae69STomasz Duszynski unsigned int i;
477633dae69STomasz Duszynski
478633dae69STomasz Duszynski for (i = 0; i < RTE_DIM(cnxk_gpio_edge_name); i++) {
479633dae69STomasz Duszynski if (cnxk_gpio_edge_name[i].edge == edge)
480633dae69STomasz Duszynski return cnxk_gpio_edge_name[i].name;
481633dae69STomasz Duszynski }
482633dae69STomasz Duszynski
483633dae69STomasz Duszynski return NULL;
484633dae69STomasz Duszynski }
485633dae69STomasz Duszynski
486633dae69STomasz Duszynski static enum cnxk_gpio_pin_edge
cnxk_gpio_name_to_edge(const char * name)487633dae69STomasz Duszynski cnxk_gpio_name_to_edge(const char *name)
488633dae69STomasz Duszynski {
489633dae69STomasz Duszynski unsigned int i;
490633dae69STomasz Duszynski
491633dae69STomasz Duszynski for (i = 0; i < RTE_DIM(cnxk_gpio_edge_name); i++) {
492633dae69STomasz Duszynski if (!strcmp(cnxk_gpio_edge_name[i].name, name))
493633dae69STomasz Duszynski break;
494633dae69STomasz Duszynski }
495633dae69STomasz Duszynski
496633dae69STomasz Duszynski return cnxk_gpio_edge_name[i].edge;
497633dae69STomasz Duszynski }
498633dae69STomasz Duszynski
499633dae69STomasz Duszynski static const struct {
500633dae69STomasz Duszynski enum cnxk_gpio_pin_dir dir;
501633dae69STomasz Duszynski const char *name;
502633dae69STomasz Duszynski } cnxk_gpio_dir_name[] = {
503633dae69STomasz Duszynski { CNXK_GPIO_PIN_DIR_IN, "in" },
504633dae69STomasz Duszynski { CNXK_GPIO_PIN_DIR_OUT, "out" },
505633dae69STomasz Duszynski { CNXK_GPIO_PIN_DIR_HIGH, "high" },
506633dae69STomasz Duszynski { CNXK_GPIO_PIN_DIR_LOW, "low" },
507633dae69STomasz Duszynski };
508633dae69STomasz Duszynski
509633dae69STomasz Duszynski static const char *
cnxk_gpio_dir_to_name(enum cnxk_gpio_pin_dir dir)510633dae69STomasz Duszynski cnxk_gpio_dir_to_name(enum cnxk_gpio_pin_dir dir)
511633dae69STomasz Duszynski {
512633dae69STomasz Duszynski unsigned int i;
513633dae69STomasz Duszynski
514633dae69STomasz Duszynski for (i = 0; i < RTE_DIM(cnxk_gpio_dir_name); i++) {
515633dae69STomasz Duszynski if (cnxk_gpio_dir_name[i].dir == dir)
516633dae69STomasz Duszynski return cnxk_gpio_dir_name[i].name;
517633dae69STomasz Duszynski }
518633dae69STomasz Duszynski
519633dae69STomasz Duszynski return NULL;
520633dae69STomasz Duszynski }
521633dae69STomasz Duszynski
522633dae69STomasz Duszynski static enum cnxk_gpio_pin_dir
cnxk_gpio_name_to_dir(const char * name)523633dae69STomasz Duszynski cnxk_gpio_name_to_dir(const char *name)
524633dae69STomasz Duszynski {
525633dae69STomasz Duszynski unsigned int i;
526633dae69STomasz Duszynski
527633dae69STomasz Duszynski for (i = 0; i < RTE_DIM(cnxk_gpio_dir_name); i++) {
528633dae69STomasz Duszynski if (!strcmp(cnxk_gpio_dir_name[i].name, name))
529633dae69STomasz Duszynski break;
530633dae69STomasz Duszynski }
531633dae69STomasz Duszynski
532633dae69STomasz Duszynski return cnxk_gpio_dir_name[i].dir;
533633dae69STomasz Duszynski }
534633dae69STomasz Duszynski
535a83ba0fbSTomasz Duszynski static int
cnxk_gpio_register_irq(struct cnxk_gpio * gpio,struct cnxk_gpio_irq * irq)536aa22c0f3STomasz Duszynski cnxk_gpio_register_irq(struct cnxk_gpio *gpio, struct cnxk_gpio_irq *irq)
537a83ba0fbSTomasz Duszynski {
538aa22c0f3STomasz Duszynski int ret;
539aa22c0f3STomasz Duszynski
540aa22c0f3STomasz Duszynski ret = cnxk_gpio_irq_request(gpio->num - gpio->gpiochip->base, irq->cpu);
541aa22c0f3STomasz Duszynski if (ret)
542aa22c0f3STomasz Duszynski return ret;
543aa22c0f3STomasz Duszynski
544aa22c0f3STomasz Duszynski gpio->handler = irq->handler;
545aa22c0f3STomasz Duszynski gpio->data = irq->data;
546aa22c0f3STomasz Duszynski gpio->cpu = irq->cpu;
547a83ba0fbSTomasz Duszynski
548a83ba0fbSTomasz Duszynski return 0;
549a83ba0fbSTomasz Duszynski }
550a83ba0fbSTomasz Duszynski
551994cc926STomasz Duszynski static int
cnxk_gpio_unregister_irq(struct cnxk_gpio * gpio)552aa22c0f3STomasz Duszynski cnxk_gpio_unregister_irq(struct cnxk_gpio *gpio)
553aa22c0f3STomasz Duszynski {
554aa22c0f3STomasz Duszynski return cnxk_gpio_irq_free(gpio->num - gpio->gpiochip->base);
555aa22c0f3STomasz Duszynski }
556aa22c0f3STomasz Duszynski
557aa22c0f3STomasz Duszynski static int
cnxk_gpio_process_buf(struct cnxk_gpio * gpio,struct rte_rawdev_buf * rbuf)558994cc926STomasz Duszynski cnxk_gpio_process_buf(struct cnxk_gpio *gpio, struct rte_rawdev_buf *rbuf)
559994cc926STomasz Duszynski {
560994cc926STomasz Duszynski struct cnxk_gpio_msg *msg = rbuf->buf_addr;
561633dae69STomasz Duszynski enum cnxk_gpio_pin_edge edge;
562633dae69STomasz Duszynski enum cnxk_gpio_pin_dir dir;
563633dae69STomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
564994cc926STomasz Duszynski void *rsp = NULL;
565633dae69STomasz Duszynski int ret, val, n;
566633dae69STomasz Duszynski
567633dae69STomasz Duszynski n = snprintf(buf, sizeof(buf), "%s/gpio%d", CNXK_GPIO_CLASS_PATH,
568633dae69STomasz Duszynski gpio->num);
569994cc926STomasz Duszynski
570994cc926STomasz Duszynski switch (msg->type) {
571633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_SET_PIN_VALUE:
572633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/value");
573633dae69STomasz Duszynski ret = cnxk_gpio_write_attr_int(buf, !!*(int *)msg->data);
574633dae69STomasz Duszynski break;
575633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_SET_PIN_EDGE:
576633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/edge");
577633dae69STomasz Duszynski edge = *(enum cnxk_gpio_pin_edge *)msg->data;
578633dae69STomasz Duszynski ret = cnxk_gpio_write_attr(buf, cnxk_gpio_edge_to_name(edge));
579633dae69STomasz Duszynski break;
580633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_SET_PIN_DIR:
581633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/direction");
582633dae69STomasz Duszynski dir = *(enum cnxk_gpio_pin_dir *)msg->data;
583633dae69STomasz Duszynski ret = cnxk_gpio_write_attr(buf, cnxk_gpio_dir_to_name(dir));
584633dae69STomasz Duszynski break;
585633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_SET_PIN_ACTIVE_LOW:
586633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/active_low");
587633dae69STomasz Duszynski val = *(int *)msg->data;
588633dae69STomasz Duszynski ret = cnxk_gpio_write_attr_int(buf, val);
589633dae69STomasz Duszynski break;
590633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_GET_PIN_VALUE:
591633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/value");
592633dae69STomasz Duszynski ret = cnxk_gpio_read_attr_int(buf, &val);
593633dae69STomasz Duszynski if (ret)
594633dae69STomasz Duszynski break;
595633dae69STomasz Duszynski
596633dae69STomasz Duszynski rsp = rte_zmalloc(NULL, sizeof(int), 0);
597633dae69STomasz Duszynski if (!rsp)
598633dae69STomasz Duszynski return -ENOMEM;
599633dae69STomasz Duszynski
600633dae69STomasz Duszynski *(int *)rsp = val;
601633dae69STomasz Duszynski break;
602633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_GET_PIN_EDGE:
603633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/edge");
604633dae69STomasz Duszynski ret = cnxk_gpio_read_attr(buf, buf);
605633dae69STomasz Duszynski if (ret)
606633dae69STomasz Duszynski break;
607633dae69STomasz Duszynski
608633dae69STomasz Duszynski rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_edge), 0);
609633dae69STomasz Duszynski if (!rsp)
610633dae69STomasz Duszynski return -ENOMEM;
611633dae69STomasz Duszynski
612633dae69STomasz Duszynski *(enum cnxk_gpio_pin_edge *)rsp = cnxk_gpio_name_to_edge(buf);
613633dae69STomasz Duszynski break;
614633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_GET_PIN_DIR:
615633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/direction");
616633dae69STomasz Duszynski ret = cnxk_gpio_read_attr(buf, buf);
617633dae69STomasz Duszynski if (ret)
618633dae69STomasz Duszynski break;
619633dae69STomasz Duszynski
620633dae69STomasz Duszynski rsp = rte_zmalloc(NULL, sizeof(enum cnxk_gpio_pin_dir), 0);
621633dae69STomasz Duszynski if (!rsp)
622633dae69STomasz Duszynski return -ENOMEM;
623633dae69STomasz Duszynski
624633dae69STomasz Duszynski *(enum cnxk_gpio_pin_dir *)rsp = cnxk_gpio_name_to_dir(buf);
625633dae69STomasz Duszynski break;
626633dae69STomasz Duszynski case CNXK_GPIO_MSG_TYPE_GET_PIN_ACTIVE_LOW:
627633dae69STomasz Duszynski snprintf(buf + n, sizeof(buf) - n, "/active_low");
628633dae69STomasz Duszynski ret = cnxk_gpio_read_attr_int(buf, &val);
629633dae69STomasz Duszynski if (ret)
630633dae69STomasz Duszynski break;
631633dae69STomasz Duszynski
632633dae69STomasz Duszynski rsp = rte_zmalloc(NULL, sizeof(int), 0);
633633dae69STomasz Duszynski if (!rsp)
634633dae69STomasz Duszynski return -ENOMEM;
635633dae69STomasz Duszynski
636633dae69STomasz Duszynski *(int *)rsp = val;
637633dae69STomasz Duszynski break;
638aa22c0f3STomasz Duszynski case CNXK_GPIO_MSG_TYPE_REGISTER_IRQ:
639ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_register_irq(gpio, (struct cnxk_gpio_irq *)msg->data);
640aa22c0f3STomasz Duszynski break;
641aa22c0f3STomasz Duszynski case CNXK_GPIO_MSG_TYPE_UNREGISTER_IRQ:
642aa22c0f3STomasz Duszynski ret = cnxk_gpio_unregister_irq(gpio);
643aa22c0f3STomasz Duszynski break;
644994cc926STomasz Duszynski default:
645994cc926STomasz Duszynski return -EINVAL;
646994cc926STomasz Duszynski }
647994cc926STomasz Duszynski
648994cc926STomasz Duszynski /* get rid of last response if any */
649994cc926STomasz Duszynski if (gpio->rsp) {
650*0fc53935SStephen Hemminger CNXK_GPIO_LOG(WARNING, "previous response got overwritten");
651994cc926STomasz Duszynski rte_free(gpio->rsp);
652994cc926STomasz Duszynski }
653994cc926STomasz Duszynski gpio->rsp = rsp;
654994cc926STomasz Duszynski
655994cc926STomasz Duszynski return ret;
656994cc926STomasz Duszynski }
657994cc926STomasz Duszynski
658ecc0dd45STomasz Duszynski static bool
cnxk_gpio_valid(struct cnxk_gpiochip * gpiochip,int gpio)659ecc0dd45STomasz Duszynski cnxk_gpio_valid(struct cnxk_gpiochip *gpiochip, int gpio)
660ecc0dd45STomasz Duszynski {
661ecc0dd45STomasz Duszynski return gpio < gpiochip->num_gpios && gpiochip->gpios[gpio];
662ecc0dd45STomasz Duszynski }
663ecc0dd45STomasz Duszynski
664994cc926STomasz Duszynski static int
cnxk_gpio_enqueue_bufs(struct rte_rawdev * dev,struct rte_rawdev_buf ** buffers,unsigned int count,rte_rawdev_obj_t context)665994cc926STomasz Duszynski cnxk_gpio_enqueue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
666994cc926STomasz Duszynski unsigned int count, rte_rawdev_obj_t context)
667994cc926STomasz Duszynski {
668994cc926STomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
669ecc0dd45STomasz Duszynski unsigned int gpio_num = (size_t)context;
670994cc926STomasz Duszynski struct cnxk_gpio *gpio;
671994cc926STomasz Duszynski int ret;
672994cc926STomasz Duszynski
673994cc926STomasz Duszynski if (count == 0)
674994cc926STomasz Duszynski return 0;
675994cc926STomasz Duszynski
676ecc0dd45STomasz Duszynski if (!cnxk_gpio_valid(gpiochip, gpio_num))
677ecc0dd45STomasz Duszynski return -EINVAL;
678ecc0dd45STomasz Duszynski gpio = gpiochip->gpios[gpio_num];
679994cc926STomasz Duszynski
680994cc926STomasz Duszynski ret = cnxk_gpio_process_buf(gpio, buffers[0]);
681994cc926STomasz Duszynski if (ret)
682994cc926STomasz Duszynski return ret;
683994cc926STomasz Duszynski
684994cc926STomasz Duszynski return 1;
685994cc926STomasz Duszynski }
686994cc926STomasz Duszynski
687b655212bSTomasz Duszynski static int
cnxk_gpio_dequeue_bufs(struct rte_rawdev * dev,struct rte_rawdev_buf ** buffers,unsigned int count,rte_rawdev_obj_t context)688b655212bSTomasz Duszynski cnxk_gpio_dequeue_bufs(struct rte_rawdev *dev, struct rte_rawdev_buf **buffers,
689b655212bSTomasz Duszynski unsigned int count, rte_rawdev_obj_t context)
690b655212bSTomasz Duszynski {
691b655212bSTomasz Duszynski struct cnxk_gpiochip *gpiochip = dev->dev_private;
692ecc0dd45STomasz Duszynski unsigned int gpio_num = (size_t)context;
693b655212bSTomasz Duszynski struct cnxk_gpio *gpio;
694b655212bSTomasz Duszynski
695b655212bSTomasz Duszynski if (count == 0)
696b655212bSTomasz Duszynski return 0;
697b655212bSTomasz Duszynski
698ecc0dd45STomasz Duszynski if (!cnxk_gpio_valid(gpiochip, gpio_num))
699ecc0dd45STomasz Duszynski return -EINVAL;
700ecc0dd45STomasz Duszynski gpio = gpiochip->gpios[gpio_num];
701b655212bSTomasz Duszynski
702b655212bSTomasz Duszynski if (gpio->rsp) {
703b655212bSTomasz Duszynski buffers[0]->buf_addr = gpio->rsp;
704b655212bSTomasz Duszynski gpio->rsp = NULL;
705b655212bSTomasz Duszynski
706b655212bSTomasz Duszynski return 1;
707b655212bSTomasz Duszynski }
708b655212bSTomasz Duszynski
709b655212bSTomasz Duszynski return 0;
710b655212bSTomasz Duszynski }
711b655212bSTomasz Duszynski
712aa22c0f3STomasz Duszynski static int
cnxk_gpio_dev_close(struct rte_rawdev * dev)713aa22c0f3STomasz Duszynski cnxk_gpio_dev_close(struct rte_rawdev *dev)
714aa22c0f3STomasz Duszynski {
715aa22c0f3STomasz Duszynski RTE_SET_USED(dev);
716aa22c0f3STomasz Duszynski
717aa22c0f3STomasz Duszynski return 0;
718aa22c0f3STomasz Duszynski }
719aa22c0f3STomasz Duszynski
720d0b8a4e1STomasz Duszynski static const struct rte_rawdev_ops cnxk_gpio_rawdev_ops = {
721d0b8a4e1STomasz Duszynski .dev_close = cnxk_gpio_dev_close,
722994cc926STomasz Duszynski .enqueue_bufs = cnxk_gpio_enqueue_bufs,
723b655212bSTomasz Duszynski .dequeue_bufs = cnxk_gpio_dequeue_bufs,
724d64ef089STomasz Duszynski .queue_def_conf = cnxk_gpio_queue_def_conf,
725dd2019a5STomasz Duszynski .queue_count = cnxk_gpio_queue_count,
726a83ba0fbSTomasz Duszynski .queue_setup = cnxk_gpio_queue_setup,
727a34ffa49STomasz Duszynski .queue_release = cnxk_gpio_queue_release,
7280e6557b4STomasz Duszynski .dev_selftest = cnxk_gpio_selftest,
729d0b8a4e1STomasz Duszynski };
730d0b8a4e1STomasz Duszynski
731d0b8a4e1STomasz Duszynski static int
cnxk_gpio_probe(struct rte_vdev_device * dev)732d0b8a4e1STomasz Duszynski cnxk_gpio_probe(struct rte_vdev_device *dev)
733d0b8a4e1STomasz Duszynski {
734d0b8a4e1STomasz Duszynski char name[RTE_RAWDEV_NAME_MAX_LEN];
735ef2a3f3bSTomasz Duszynski struct cnxk_gpio_params *params;
736d0b8a4e1STomasz Duszynski struct cnxk_gpiochip *gpiochip;
737d0b8a4e1STomasz Duszynski struct rte_rawdev *rawdev;
738d0b8a4e1STomasz Duszynski char buf[CNXK_GPIO_BUFSZ];
739d0b8a4e1STomasz Duszynski int ret;
740d0b8a4e1STomasz Duszynski
741d0b8a4e1STomasz Duszynski cnxk_gpio_format_name(name, sizeof(name));
742ef2a3f3bSTomasz Duszynski rawdev = rte_rawdev_pmd_allocate(name, sizeof(*gpiochip), rte_socket_id());
743d0b8a4e1STomasz Duszynski if (!rawdev) {
744*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to allocate %s rawdev", name);
745d0b8a4e1STomasz Duszynski return -ENOMEM;
746d0b8a4e1STomasz Duszynski }
747d0b8a4e1STomasz Duszynski
748d0b8a4e1STomasz Duszynski rawdev->dev_ops = &cnxk_gpio_rawdev_ops;
749d0b8a4e1STomasz Duszynski rawdev->device = &dev->device;
750d0b8a4e1STomasz Duszynski rawdev->driver_name = dev->device.name;
751d0b8a4e1STomasz Duszynski gpiochip = rawdev->dev_private;
752d0b8a4e1STomasz Duszynski
753ef2a3f3bSTomasz Duszynski if (rte_eal_process_type() == RTE_PROC_PRIMARY) {
754ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_parse_store_args(¶ms, rte_vdev_device_args(dev));
755ef2a3f3bSTomasz Duszynski if (ret < 0)
756ef2a3f3bSTomasz Duszynski goto out;
757ef2a3f3bSTomasz Duszynski } else {
758ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_params_restore(¶ms);
759d0b8a4e1STomasz Duszynski if (ret)
760d0b8a4e1STomasz Duszynski goto out;
761ef2a3f3bSTomasz Duszynski }
762ef2a3f3bSTomasz Duszynski
763ef2a3f3bSTomasz Duszynski gpiochip->num = params->num;
764d0b8a4e1STomasz Duszynski
765aa22c0f3STomasz Duszynski ret = cnxk_gpio_irq_init(gpiochip);
766aa22c0f3STomasz Duszynski if (ret)
767aa22c0f3STomasz Duszynski goto out;
768aa22c0f3STomasz Duszynski
769d0b8a4e1STomasz Duszynski /* read gpio base */
770ef2a3f3bSTomasz Duszynski snprintf(buf, sizeof(buf), "%s/gpiochip%d/base", CNXK_GPIO_CLASS_PATH, gpiochip->num);
771d0b8a4e1STomasz Duszynski ret = cnxk_gpio_read_attr_int(buf, &gpiochip->base);
772d0b8a4e1STomasz Duszynski if (ret) {
773*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to read %s", buf);
774d0b8a4e1STomasz Duszynski goto out;
775d0b8a4e1STomasz Duszynski }
776d0b8a4e1STomasz Duszynski
777d0b8a4e1STomasz Duszynski /* read number of available gpios */
778ef2a3f3bSTomasz Duszynski snprintf(buf, sizeof(buf), "%s/gpiochip%d/ngpio", CNXK_GPIO_CLASS_PATH, gpiochip->num);
779d0b8a4e1STomasz Duszynski ret = cnxk_gpio_read_attr_int(buf, &gpiochip->num_gpios);
780d0b8a4e1STomasz Duszynski if (ret) {
781*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to read %s", buf);
782d0b8a4e1STomasz Duszynski goto out;
783d0b8a4e1STomasz Duszynski }
784ecc0dd45STomasz Duszynski gpiochip->num_queues = gpiochip->num_gpios;
785ecc0dd45STomasz Duszynski
786ef2a3f3bSTomasz Duszynski ret = cnxk_gpio_parse_allowlist(gpiochip, params->allowlist);
787ef2a3f3bSTomasz Duszynski if (ret) {
788*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to parse allowed gpios");
789ecc0dd45STomasz Duszynski goto out;
790ecc0dd45STomasz Duszynski }
791d0b8a4e1STomasz Duszynski
792ef2a3f3bSTomasz Duszynski gpiochip->gpios = rte_calloc(NULL, gpiochip->num_gpios, sizeof(struct cnxk_gpio *), 0);
793d0b8a4e1STomasz Duszynski if (!gpiochip->gpios) {
794*0fc53935SStephen Hemminger CNXK_GPIO_LOG(ERR, "failed to allocate gpios memory");
795d0b8a4e1STomasz Duszynski ret = -ENOMEM;
796d0b8a4e1STomasz Duszynski goto out;
797d0b8a4e1STomasz Duszynski }
798d0b8a4e1STomasz Duszynski
799d0b8a4e1STomasz Duszynski return 0;
800d0b8a4e1STomasz Duszynski out:
801ecc0dd45STomasz Duszynski rte_free(gpiochip->allowlist);
802ef2a3f3bSTomasz Duszynski cnxk_gpio_params_release();
803d0b8a4e1STomasz Duszynski rte_rawdev_pmd_release(rawdev);
804d0b8a4e1STomasz Duszynski
805d0b8a4e1STomasz Duszynski return ret;
806d0b8a4e1STomasz Duszynski }
807d0b8a4e1STomasz Duszynski
808d0b8a4e1STomasz Duszynski static int
cnxk_gpio_remove(struct rte_vdev_device * dev)809d0b8a4e1STomasz Duszynski cnxk_gpio_remove(struct rte_vdev_device *dev)
810d0b8a4e1STomasz Duszynski {
811d0b8a4e1STomasz Duszynski char name[RTE_RAWDEV_NAME_MAX_LEN];
812d0b8a4e1STomasz Duszynski struct cnxk_gpiochip *gpiochip;
813d0b8a4e1STomasz Duszynski struct rte_rawdev *rawdev;
814a34ffa49STomasz Duszynski struct cnxk_gpio *gpio;
815a34ffa49STomasz Duszynski int i;
816d0b8a4e1STomasz Duszynski
817d0b8a4e1STomasz Duszynski RTE_SET_USED(dev);
818d0b8a4e1STomasz Duszynski
819d0b8a4e1STomasz Duszynski cnxk_gpio_format_name(name, sizeof(name));
820d0b8a4e1STomasz Duszynski rawdev = rte_rawdev_pmd_get_named_dev(name);
821d0b8a4e1STomasz Duszynski if (!rawdev)
822d0b8a4e1STomasz Duszynski return -ENODEV;
823d0b8a4e1STomasz Duszynski
824d0b8a4e1STomasz Duszynski gpiochip = rawdev->dev_private;
825a34ffa49STomasz Duszynski for (i = 0; i < gpiochip->num_gpios; i++) {
826a34ffa49STomasz Duszynski gpio = gpiochip->gpios[i];
827a34ffa49STomasz Duszynski if (!gpio)
828a34ffa49STomasz Duszynski continue;
829a34ffa49STomasz Duszynski
830aa22c0f3STomasz Duszynski if (gpio->handler)
831aa22c0f3STomasz Duszynski cnxk_gpio_unregister_irq(gpio);
832aa22c0f3STomasz Duszynski
833a34ffa49STomasz Duszynski cnxk_gpio_queue_release(rawdev, gpio->num);
834a34ffa49STomasz Duszynski }
835a34ffa49STomasz Duszynski
836ecc0dd45STomasz Duszynski rte_free(gpiochip->allowlist);
837d0b8a4e1STomasz Duszynski rte_free(gpiochip->gpios);
838aa22c0f3STomasz Duszynski cnxk_gpio_irq_fini();
839ef2a3f3bSTomasz Duszynski cnxk_gpio_params_release();
840d0b8a4e1STomasz Duszynski rte_rawdev_pmd_release(rawdev);
841d0b8a4e1STomasz Duszynski
842d0b8a4e1STomasz Duszynski return 0;
843d0b8a4e1STomasz Duszynski }
844d0b8a4e1STomasz Duszynski
845d0b8a4e1STomasz Duszynski static struct rte_vdev_driver cnxk_gpio_drv = {
846d0b8a4e1STomasz Duszynski .probe = cnxk_gpio_probe,
847d0b8a4e1STomasz Duszynski .remove = cnxk_gpio_remove,
848d0b8a4e1STomasz Duszynski };
849d0b8a4e1STomasz Duszynski
850d0b8a4e1STomasz Duszynski RTE_PMD_REGISTER_VDEV(cnxk_gpio, cnxk_gpio_drv);
851ecc0dd45STomasz Duszynski RTE_PMD_REGISTER_PARAM_STRING(cnxk_gpio,
852ecc0dd45STomasz Duszynski "gpiochip=<int> "
853ecc0dd45STomasz Duszynski "allowlist=<list>");
854*0fc53935SStephen Hemminger RTE_LOG_REGISTER_SUFFIX(cnxk_logtype_gpio, gpio, INFO);
855