a90c055ffda9865d9998c03843dc32151abb4b7d
[dpdk.git] / drivers / common / cnxk / roc_bphy_irq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2021 Marvell.
3  */
4 #include <fcntl.h>
5 #include <pthread.h>
6 #include <sys/ioctl.h>
7 #include <sys/queue.h>
8 #include <unistd.h>
9
10 #include "roc_api.h"
11 #include "roc_bphy_irq.h"
12
13 struct roc_bphy_irq_stack {
14         STAILQ_ENTRY(roc_bphy_irq_stack) entries;
15         void *sp_buffer;
16         int cpu;
17         int inuse;
18 };
19
20 #define ROC_BPHY_MEMZONE_NAME "roc_bphy_mz"
21 #define ROC_BPHY_CTR_DEV_PATH "/dev/otx-bphy-ctr"
22
23 #define ROC_BPHY_IOC_MAGIC 0xF3
24 #define ROC_BPHY_IOC_GET_BPHY_MAX_IRQ   _IOR(ROC_BPHY_IOC_MAGIC, 3, uint64_t)
25 #define ROC_BPHY_IOC_GET_BPHY_BMASK_IRQ _IOR(ROC_BPHY_IOC_MAGIC, 4, uint64_t)
26
27 static STAILQ_HEAD(slisthead, roc_bphy_irq_stack)
28         irq_stacks = STAILQ_HEAD_INITIALIZER(irq_stacks);
29
30 /* Note: it is assumed that as for now there is no multiprocess support */
31 static pthread_mutex_t stacks_mutex = PTHREAD_MUTEX_INITIALIZER;
32
33 struct roc_bphy_irq_chip *
34 roc_bphy_intr_init(void)
35 {
36         struct roc_bphy_irq_chip *irq_chip;
37         uint64_t max_irq, i, avail_irqs;
38         int fd, ret;
39
40         fd = open(ROC_BPHY_CTR_DEV_PATH, O_RDWR | O_SYNC);
41         if (fd < 0) {
42                 plt_err("Failed to open %s", ROC_BPHY_CTR_DEV_PATH);
43                 return NULL;
44         }
45
46         ret = ioctl(fd, ROC_BPHY_IOC_GET_BPHY_MAX_IRQ, &max_irq);
47         if (ret < 0) {
48                 plt_err("Failed to get max irq number via ioctl");
49                 goto err_ioctl;
50         }
51
52         ret = ioctl(fd, ROC_BPHY_IOC_GET_BPHY_BMASK_IRQ, &avail_irqs);
53         if (ret < 0) {
54                 plt_err("Failed to get available irqs bitmask via ioctl");
55                 goto err_ioctl;
56         }
57
58         irq_chip = plt_zmalloc(sizeof(*irq_chip), 0);
59         if (irq_chip == NULL) {
60                 plt_err("Failed to alloc irq_chip");
61                 goto err_alloc_chip;
62         }
63
64         irq_chip->intfd = fd;
65         irq_chip->max_irq = max_irq;
66         irq_chip->avail_irq_bmask = avail_irqs;
67         irq_chip->irq_vecs =
68                 plt_zmalloc(irq_chip->max_irq * sizeof(*irq_chip->irq_vecs), 0);
69         if (irq_chip->irq_vecs == NULL) {
70                 plt_err("Failed to alloc irq_chip irq_vecs");
71                 goto err_alloc_irq;
72         }
73
74         irq_chip->mz_name = plt_zmalloc(strlen(ROC_BPHY_MEMZONE_NAME) + 1, 0);
75         if (irq_chip->mz_name == NULL) {
76                 plt_err("Failed to alloc irq_chip name");
77                 goto err_alloc_name;
78         }
79         plt_strlcpy(irq_chip->mz_name, ROC_BPHY_MEMZONE_NAME,
80                     strlen(ROC_BPHY_MEMZONE_NAME) + 1);
81
82         for (i = 0; i < irq_chip->max_irq; i++) {
83                 irq_chip->irq_vecs[i].fd = -1;
84                 irq_chip->irq_vecs[i].handler_cpu = -1;
85         }
86
87         return irq_chip;
88
89 err_alloc_name:
90         plt_free(irq_chip->irq_vecs);
91
92 err_alloc_irq:
93         plt_free(irq_chip);
94
95 err_ioctl:
96 err_alloc_chip:
97         close(fd);
98         return NULL;
99 }
100
101 void
102 roc_bphy_intr_fini(struct roc_bphy_irq_chip *irq_chip)
103 {
104         if (irq_chip == NULL)
105                 return;
106
107         close(irq_chip->intfd);
108         plt_free(irq_chip->mz_name);
109         plt_free(irq_chip->irq_vecs);
110         plt_free(irq_chip);
111 }
112
113 void
114 roc_bphy_irq_stack_remove(int cpu)
115 {
116         struct roc_bphy_irq_stack *curr_stack;
117
118         if (pthread_mutex_lock(&stacks_mutex))
119                 return;
120
121         STAILQ_FOREACH(curr_stack, &irq_stacks, entries) {
122                 if (curr_stack->cpu == cpu)
123                         break;
124         }
125
126         if (curr_stack == NULL)
127                 goto leave;
128
129         if (curr_stack->inuse > 0)
130                 curr_stack->inuse--;
131
132         if (curr_stack->inuse == 0) {
133                 STAILQ_REMOVE(&irq_stacks, curr_stack, roc_bphy_irq_stack,
134                               entries);
135                 plt_free(curr_stack->sp_buffer);
136                 plt_free(curr_stack);
137         }
138
139 leave:
140         pthread_mutex_unlock(&stacks_mutex);
141 }
142
143 void *
144 roc_bphy_irq_stack_get(int cpu)
145 {
146 #define ARM_STACK_ALIGNMENT (2 * sizeof(void *))
147 #define IRQ_ISR_STACK_SIZE  0x200000
148
149         struct roc_bphy_irq_stack *curr_stack;
150         void *retval = NULL;
151
152         if (pthread_mutex_lock(&stacks_mutex))
153                 return NULL;
154
155         STAILQ_FOREACH(curr_stack, &irq_stacks, entries) {
156                 if (curr_stack->cpu == cpu) {
157                         curr_stack->inuse++;
158                         retval = ((char *)curr_stack->sp_buffer) +
159                                  IRQ_ISR_STACK_SIZE;
160                         goto found_stack;
161                 }
162         }
163
164         curr_stack = plt_zmalloc(sizeof(struct roc_bphy_irq_stack), 0);
165         if (curr_stack == NULL)
166                 goto err_stack;
167
168         curr_stack->sp_buffer =
169                 plt_zmalloc(IRQ_ISR_STACK_SIZE * 2, ARM_STACK_ALIGNMENT);
170         if (curr_stack->sp_buffer == NULL)
171                 goto err_buffer;
172
173         curr_stack->cpu = cpu;
174         curr_stack->inuse = 0;
175         STAILQ_INSERT_TAIL(&irq_stacks, curr_stack, entries);
176         retval = ((char *)curr_stack->sp_buffer) + IRQ_ISR_STACK_SIZE;
177
178 found_stack:
179         pthread_mutex_unlock(&stacks_mutex);
180         return retval;
181
182 err_buffer:
183         plt_free(curr_stack);
184
185 err_stack:
186         pthread_mutex_unlock(&stacks_mutex);
187         return NULL;
188 }
189
190 bool
191 roc_bphy_intr_available(struct roc_bphy_irq_chip *irq_chip, int irq_num)
192 {
193         if (irq_num < 0 || (uint64_t)irq_num >= irq_chip->max_irq)
194                 return false;
195
196         return irq_chip->avail_irq_bmask & BIT(irq_num);
197 }