xref: /dpdk/drivers/raw/cnxk_gpio/cnxk_gpio_irq.c (revision aa22c0f3846b067c6b33020a46c27467c6a6122a)
1*aa22c0f3STomasz Duszynski /* SPDX-License-Identifier: BSD-3-Clause
2*aa22c0f3STomasz Duszynski  * Copyright(C) 2021 Marvell.
3*aa22c0f3STomasz Duszynski  */
4*aa22c0f3STomasz Duszynski 
5*aa22c0f3STomasz Duszynski #include <fcntl.h>
6*aa22c0f3STomasz Duszynski #include <pthread.h>
7*aa22c0f3STomasz Duszynski #include <sys/ioctl.h>
8*aa22c0f3STomasz Duszynski #include <sys/mman.h>
9*aa22c0f3STomasz Duszynski #include <sys/queue.h>
10*aa22c0f3STomasz Duszynski #include <unistd.h>
11*aa22c0f3STomasz Duszynski 
12*aa22c0f3STomasz Duszynski #include <rte_rawdev_pmd.h>
13*aa22c0f3STomasz Duszynski 
14*aa22c0f3STomasz Duszynski #include <roc_api.h>
15*aa22c0f3STomasz Duszynski 
16*aa22c0f3STomasz Duszynski #include "cnxk_gpio.h"
17*aa22c0f3STomasz Duszynski 
18*aa22c0f3STomasz Duszynski #define OTX_IOC_MAGIC 0xF2
19*aa22c0f3STomasz Duszynski #define OTX_IOC_SET_GPIO_HANDLER                                               \
20*aa22c0f3STomasz Duszynski 	_IOW(OTX_IOC_MAGIC, 1, struct otx_gpio_usr_data)
21*aa22c0f3STomasz Duszynski #define OTX_IOC_CLR_GPIO_HANDLER                                               \
22*aa22c0f3STomasz Duszynski 	_IO(OTX_IOC_MAGIC, 2)
23*aa22c0f3STomasz Duszynski 
24*aa22c0f3STomasz Duszynski struct otx_gpio_usr_data {
25*aa22c0f3STomasz Duszynski 	uint64_t isr_base;
26*aa22c0f3STomasz Duszynski 	uint64_t sp;
27*aa22c0f3STomasz Duszynski 	uint64_t cpu;
28*aa22c0f3STomasz Duszynski 	uint64_t gpio_num;
29*aa22c0f3STomasz Duszynski };
30*aa22c0f3STomasz Duszynski 
31*aa22c0f3STomasz Duszynski struct cnxk_gpio_irq_stack {
32*aa22c0f3STomasz Duszynski 	LIST_ENTRY(cnxk_gpio_irq_stack) next;
33*aa22c0f3STomasz Duszynski 	void *sp_buffer;
34*aa22c0f3STomasz Duszynski 	int cpu;
35*aa22c0f3STomasz Duszynski 	int inuse;
36*aa22c0f3STomasz Duszynski };
37*aa22c0f3STomasz Duszynski 
38*aa22c0f3STomasz Duszynski struct cnxk_gpio_irqchip {
39*aa22c0f3STomasz Duszynski 	int fd;
40*aa22c0f3STomasz Duszynski 	/* serialize access to this struct */
41*aa22c0f3STomasz Duszynski 	pthread_mutex_t lock;
42*aa22c0f3STomasz Duszynski 	LIST_HEAD(, cnxk_gpio_irq_stack) stacks;
43*aa22c0f3STomasz Duszynski 
44*aa22c0f3STomasz Duszynski 	struct cnxk_gpiochip *gpiochip;
45*aa22c0f3STomasz Duszynski };
46*aa22c0f3STomasz Duszynski 
47*aa22c0f3STomasz Duszynski static struct cnxk_gpio_irqchip *irqchip;
48*aa22c0f3STomasz Duszynski 
49*aa22c0f3STomasz Duszynski static void
cnxk_gpio_irq_stack_free(int cpu)50*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_free(int cpu)
51*aa22c0f3STomasz Duszynski {
52*aa22c0f3STomasz Duszynski 	struct cnxk_gpio_irq_stack *stack;
53*aa22c0f3STomasz Duszynski 
54*aa22c0f3STomasz Duszynski 	LIST_FOREACH(stack, &irqchip->stacks, next) {
55*aa22c0f3STomasz Duszynski 		if (stack->cpu == cpu)
56*aa22c0f3STomasz Duszynski 			break;
57*aa22c0f3STomasz Duszynski 	}
58*aa22c0f3STomasz Duszynski 
59*aa22c0f3STomasz Duszynski 	if (!stack)
60*aa22c0f3STomasz Duszynski 		return;
61*aa22c0f3STomasz Duszynski 
62*aa22c0f3STomasz Duszynski 	if (stack->inuse)
63*aa22c0f3STomasz Duszynski 		stack->inuse--;
64*aa22c0f3STomasz Duszynski 
65*aa22c0f3STomasz Duszynski 	if (stack->inuse == 0) {
66*aa22c0f3STomasz Duszynski 		LIST_REMOVE(stack, next);
67*aa22c0f3STomasz Duszynski 		rte_free(stack->sp_buffer);
68*aa22c0f3STomasz Duszynski 		rte_free(stack);
69*aa22c0f3STomasz Duszynski 	}
70*aa22c0f3STomasz Duszynski }
71*aa22c0f3STomasz Duszynski 
72*aa22c0f3STomasz Duszynski static void *
cnxk_gpio_irq_stack_alloc(int cpu)73*aa22c0f3STomasz Duszynski cnxk_gpio_irq_stack_alloc(int cpu)
74*aa22c0f3STomasz Duszynski {
75*aa22c0f3STomasz Duszynski #define ARM_STACK_ALIGNMENT (2 * sizeof(void *))
76*aa22c0f3STomasz Duszynski #define IRQ_STACK_SIZE 0x200000
77*aa22c0f3STomasz Duszynski 
78*aa22c0f3STomasz Duszynski 	struct cnxk_gpio_irq_stack *stack;
79*aa22c0f3STomasz Duszynski 
80*aa22c0f3STomasz Duszynski 	LIST_FOREACH(stack, &irqchip->stacks, next) {
81*aa22c0f3STomasz Duszynski 		if (stack->cpu == cpu)
82*aa22c0f3STomasz Duszynski 			break;
83*aa22c0f3STomasz Duszynski 	}
84*aa22c0f3STomasz Duszynski 
85*aa22c0f3STomasz Duszynski 	if (stack) {
86*aa22c0f3STomasz Duszynski 		stack->inuse++;
87*aa22c0f3STomasz Duszynski 		return (char *)stack->sp_buffer + IRQ_STACK_SIZE;
88*aa22c0f3STomasz Duszynski 	}
89*aa22c0f3STomasz Duszynski 
90*aa22c0f3STomasz Duszynski 	stack = rte_malloc(NULL, sizeof(*stack), 0);
91*aa22c0f3STomasz Duszynski 	if (!stack)
92*aa22c0f3STomasz Duszynski 		return NULL;
93*aa22c0f3STomasz Duszynski 
94*aa22c0f3STomasz Duszynski 	stack->sp_buffer =
95*aa22c0f3STomasz Duszynski 		rte_zmalloc(NULL, IRQ_STACK_SIZE * 2, ARM_STACK_ALIGNMENT);
96*aa22c0f3STomasz Duszynski 	if (!stack->sp_buffer) {
97*aa22c0f3STomasz Duszynski 		rte_free(stack);
98*aa22c0f3STomasz Duszynski 		return NULL;
99*aa22c0f3STomasz Duszynski 	}
100*aa22c0f3STomasz Duszynski 
101*aa22c0f3STomasz Duszynski 	stack->cpu = cpu;
102*aa22c0f3STomasz Duszynski 	stack->inuse = 1;
103*aa22c0f3STomasz Duszynski 	LIST_INSERT_HEAD(&irqchip->stacks, stack, next);
104*aa22c0f3STomasz Duszynski 
105*aa22c0f3STomasz Duszynski 	return (char *)stack->sp_buffer + IRQ_STACK_SIZE;
106*aa22c0f3STomasz Duszynski }
107*aa22c0f3STomasz Duszynski 
108*aa22c0f3STomasz Duszynski static void
cnxk_gpio_irq_handler(int gpio_num)109*aa22c0f3STomasz Duszynski cnxk_gpio_irq_handler(int gpio_num)
110*aa22c0f3STomasz Duszynski {
111*aa22c0f3STomasz Duszynski 	struct cnxk_gpiochip *gpiochip = irqchip->gpiochip;
112*aa22c0f3STomasz Duszynski 	struct cnxk_gpio *gpio;
113*aa22c0f3STomasz Duszynski 
114*aa22c0f3STomasz Duszynski 	if (gpio_num >= gpiochip->num_gpios)
115*aa22c0f3STomasz Duszynski 		goto out;
116*aa22c0f3STomasz Duszynski 
117*aa22c0f3STomasz Duszynski 	gpio = gpiochip->gpios[gpio_num];
118*aa22c0f3STomasz Duszynski 	if (likely(gpio->handler))
119*aa22c0f3STomasz Duszynski 		gpio->handler(gpio_num, gpio->data);
120*aa22c0f3STomasz Duszynski 
121*aa22c0f3STomasz Duszynski out:
122*aa22c0f3STomasz Duszynski 	roc_atf_ret();
123*aa22c0f3STomasz Duszynski }
124*aa22c0f3STomasz Duszynski 
125*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_init(struct cnxk_gpiochip * gpiochip)126*aa22c0f3STomasz Duszynski cnxk_gpio_irq_init(struct cnxk_gpiochip *gpiochip)
127*aa22c0f3STomasz Duszynski {
128*aa22c0f3STomasz Duszynski 	if (irqchip)
129*aa22c0f3STomasz Duszynski 		return 0;
130*aa22c0f3STomasz Duszynski 
131*aa22c0f3STomasz Duszynski 	irqchip = rte_zmalloc(NULL, sizeof(*irqchip), 0);
132*aa22c0f3STomasz Duszynski 	if (!irqchip)
133*aa22c0f3STomasz Duszynski 		return -ENOMEM;
134*aa22c0f3STomasz Duszynski 
135*aa22c0f3STomasz Duszynski 	irqchip->fd = open("/dev/otx-gpio-ctr", O_RDWR | O_SYNC);
136*aa22c0f3STomasz Duszynski 	if (irqchip->fd < 0) {
137*aa22c0f3STomasz Duszynski 		rte_free(irqchip);
138*aa22c0f3STomasz Duszynski 		return -errno;
139*aa22c0f3STomasz Duszynski 	}
140*aa22c0f3STomasz Duszynski 
141*aa22c0f3STomasz Duszynski 	pthread_mutex_init(&irqchip->lock, NULL);
142*aa22c0f3STomasz Duszynski 	LIST_INIT(&irqchip->stacks);
143*aa22c0f3STomasz Duszynski 	irqchip->gpiochip = gpiochip;
144*aa22c0f3STomasz Duszynski 
145*aa22c0f3STomasz Duszynski 	return 0;
146*aa22c0f3STomasz Duszynski }
147*aa22c0f3STomasz Duszynski 
148*aa22c0f3STomasz Duszynski void
cnxk_gpio_irq_fini(void)149*aa22c0f3STomasz Duszynski cnxk_gpio_irq_fini(void)
150*aa22c0f3STomasz Duszynski {
151*aa22c0f3STomasz Duszynski 	if (!irqchip)
152*aa22c0f3STomasz Duszynski 		return;
153*aa22c0f3STomasz Duszynski 
154*aa22c0f3STomasz Duszynski 	close(irqchip->fd);
155*aa22c0f3STomasz Duszynski 	rte_free(irqchip);
156*aa22c0f3STomasz Duszynski 	irqchip = NULL;
157*aa22c0f3STomasz Duszynski }
158*aa22c0f3STomasz Duszynski 
159*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_request(int gpio,int cpu)160*aa22c0f3STomasz Duszynski cnxk_gpio_irq_request(int gpio, int cpu)
161*aa22c0f3STomasz Duszynski {
162*aa22c0f3STomasz Duszynski 	struct otx_gpio_usr_data data;
163*aa22c0f3STomasz Duszynski 	void *sp;
164*aa22c0f3STomasz Duszynski 	int ret;
165*aa22c0f3STomasz Duszynski 
166*aa22c0f3STomasz Duszynski 	pthread_mutex_lock(&irqchip->lock);
167*aa22c0f3STomasz Duszynski 
168*aa22c0f3STomasz Duszynski 	sp = cnxk_gpio_irq_stack_alloc(cpu);
169*aa22c0f3STomasz Duszynski 	if (!sp) {
170*aa22c0f3STomasz Duszynski 		ret = -ENOMEM;
171*aa22c0f3STomasz Duszynski 		goto out_unlock;
172*aa22c0f3STomasz Duszynski 	}
173*aa22c0f3STomasz Duszynski 
174*aa22c0f3STomasz Duszynski 	data.isr_base = (uint64_t)cnxk_gpio_irq_handler;
175*aa22c0f3STomasz Duszynski 	data.sp = (uint64_t)sp;
176*aa22c0f3STomasz Duszynski 	data.cpu = (uint64_t)cpu;
177*aa22c0f3STomasz Duszynski 	data.gpio_num = (uint64_t)gpio;
178*aa22c0f3STomasz Duszynski 
179*aa22c0f3STomasz Duszynski 	mlockall(MCL_CURRENT | MCL_FUTURE);
180*aa22c0f3STomasz Duszynski 	ret = ioctl(irqchip->fd, OTX_IOC_SET_GPIO_HANDLER, &data);
181*aa22c0f3STomasz Duszynski 	if (ret) {
182*aa22c0f3STomasz Duszynski 		ret = -errno;
183*aa22c0f3STomasz Duszynski 		goto out_free_stack;
184*aa22c0f3STomasz Duszynski 	}
185*aa22c0f3STomasz Duszynski 
186*aa22c0f3STomasz Duszynski 	pthread_mutex_unlock(&irqchip->lock);
187*aa22c0f3STomasz Duszynski 
188*aa22c0f3STomasz Duszynski 	return 0;
189*aa22c0f3STomasz Duszynski 
190*aa22c0f3STomasz Duszynski out_free_stack:
191*aa22c0f3STomasz Duszynski 	cnxk_gpio_irq_stack_free(cpu);
192*aa22c0f3STomasz Duszynski out_unlock:
193*aa22c0f3STomasz Duszynski 	pthread_mutex_unlock(&irqchip->lock);
194*aa22c0f3STomasz Duszynski 
195*aa22c0f3STomasz Duszynski 	return ret;
196*aa22c0f3STomasz Duszynski }
197*aa22c0f3STomasz Duszynski 
198*aa22c0f3STomasz Duszynski int
cnxk_gpio_irq_free(int gpio)199*aa22c0f3STomasz Duszynski cnxk_gpio_irq_free(int gpio)
200*aa22c0f3STomasz Duszynski {
201*aa22c0f3STomasz Duszynski 	int ret;
202*aa22c0f3STomasz Duszynski 
203*aa22c0f3STomasz Duszynski 	pthread_mutex_lock(&irqchip->lock);
204*aa22c0f3STomasz Duszynski 
205*aa22c0f3STomasz Duszynski 	ret = ioctl(irqchip->fd, OTX_IOC_CLR_GPIO_HANDLER, gpio);
206*aa22c0f3STomasz Duszynski 	if (ret) {
207*aa22c0f3STomasz Duszynski 		pthread_mutex_unlock(&irqchip->lock);
208*aa22c0f3STomasz Duszynski 		return -errno;
209*aa22c0f3STomasz Duszynski 	}
210*aa22c0f3STomasz Duszynski 
211*aa22c0f3STomasz Duszynski 	cnxk_gpio_irq_stack_free(irqchip->gpiochip->gpios[gpio]->cpu);
212*aa22c0f3STomasz Duszynski 
213*aa22c0f3STomasz Duszynski 	pthread_mutex_unlock(&irqchip->lock);
214*aa22c0f3STomasz Duszynski 
215*aa22c0f3STomasz Duszynski 	return 0;
216*aa22c0f3STomasz Duszynski }
217