xref: /dpdk/drivers/raw/cnxk_gpio/cnxk_gpio.c (revision 0fc53935ff100750973203b970c2a7a9d808ea17)
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", &params->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(&params, rte_vdev_device_args(dev));
755ef2a3f3bSTomasz Duszynski 		if (ret < 0)
756ef2a3f3bSTomasz Duszynski 			goto out;
757ef2a3f3bSTomasz Duszynski 	} else {
758ef2a3f3bSTomasz Duszynski 		ret = cnxk_gpio_params_restore(&params);
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