common/octeontx2: introduce irq handling functions
[dpdk.git] / drivers / common / octeontx2 / otx2_irq.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(C) 2019 Marvell International Ltd.
3  */
4
5 #include <rte_alarm.h>
6 #include <rte_common.h>
7 #include <rte_eal.h>
8 #include <rte_interrupts.h>
9
10 #include "otx2_common.h"
11 #include "otx2_irq.h"
12
13 #ifdef RTE_EAL_VFIO
14
15 #include <inttypes.h>
16 #include <linux/vfio.h>
17 #include <sys/eventfd.h>
18 #include <sys/ioctl.h>
19 #include <unistd.h>
20
21 #define MAX_INTR_VEC_ID RTE_MAX_RXTX_INTR_VEC_ID
22 #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
23                               sizeof(int) * (MAX_INTR_VEC_ID))
24
25 static int
26 irq_get_info(struct rte_intr_handle *intr_handle)
27 {
28         struct vfio_irq_info irq = { .argsz = sizeof(irq) };
29         int rc;
30
31         irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
32
33         rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
34         if (rc < 0) {
35                 otx2_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
36                 return rc;
37         }
38
39         otx2_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
40                       irq.flags, irq.index, irq.count, MAX_INTR_VEC_ID);
41
42         if (irq.count > MAX_INTR_VEC_ID) {
43                 otx2_err("HW max=%d > MAX_INTR_VEC_ID: %d",
44                          intr_handle->max_intr, MAX_INTR_VEC_ID);
45                 intr_handle->max_intr = MAX_INTR_VEC_ID;
46         } else {
47                 intr_handle->max_intr = irq.count;
48         }
49
50         return 0;
51 }
52
53 static int
54 irq_config(struct rte_intr_handle *intr_handle, unsigned int vec)
55 {
56         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
57         struct vfio_irq_set *irq_set;
58         int32_t *fd_ptr;
59         int len, rc;
60
61         if (vec > intr_handle->max_intr) {
62                 otx2_err("vector=%d greater than max_intr=%d", vec,
63                                 intr_handle->max_intr);
64                 return -EINVAL;
65         }
66
67         len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
68
69         irq_set = (struct vfio_irq_set *)irq_set_buf;
70         irq_set->argsz = len;
71
72         irq_set->start = vec;
73         irq_set->count = 1;
74         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
75                         VFIO_IRQ_SET_ACTION_TRIGGER;
76         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
77
78         /* Use vec fd to set interrupt vectors */
79         fd_ptr = (int32_t *)&irq_set->data[0];
80         fd_ptr[0] = intr_handle->efds[vec];
81
82         rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
83         if (rc)
84                 otx2_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
85
86         return rc;
87 }
88
89 static int
90 irq_init(struct rte_intr_handle *intr_handle)
91 {
92         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
93         struct vfio_irq_set *irq_set;
94         int32_t *fd_ptr;
95         int len, rc;
96         uint32_t i;
97
98         if (intr_handle->max_intr > MAX_INTR_VEC_ID) {
99                 otx2_err("Max_intr=%d greater than MAX_INTR_VEC_ID=%d",
100                                 intr_handle->max_intr, MAX_INTR_VEC_ID);
101                 return -ERANGE;
102         }
103
104         len = sizeof(struct vfio_irq_set) +
105                 sizeof(int32_t) * intr_handle->max_intr;
106
107         irq_set = (struct vfio_irq_set *)irq_set_buf;
108         irq_set->argsz = len;
109         irq_set->start = 0;
110         irq_set->count = intr_handle->max_intr;
111         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
112                         VFIO_IRQ_SET_ACTION_TRIGGER;
113         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
114
115         fd_ptr = (int32_t *)&irq_set->data[0];
116         for (i = 0; i < irq_set->count; i++)
117                 fd_ptr[i] = -1;
118
119         rc = ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
120         if (rc)
121                 otx2_err("Failed to set irqs vector rc=%d", rc);
122
123         return rc;
124 }
125
126 /**
127  * @internal
128  * Disable IRQ
129  */
130 int
131 otx2_disable_irqs(struct rte_intr_handle *intr_handle)
132 {
133         /* Clear max_intr to indicate re-init next time */
134         intr_handle->max_intr = 0;
135         return rte_intr_disable(intr_handle);
136 }
137
138 /**
139  * @internal
140  * Register IRQ
141  */
142 int
143 otx2_register_irq(struct rte_intr_handle *intr_handle,
144                   rte_intr_callback_fn cb, void *data, unsigned int vec)
145 {
146         struct rte_intr_handle tmp_handle;
147         int rc;
148
149         /* If no max_intr read from VFIO */
150         if (intr_handle->max_intr == 0) {
151                 irq_get_info(intr_handle);
152                 irq_init(intr_handle);
153         }
154
155         if (vec > intr_handle->max_intr) {
156                 otx2_err("Vector=%d greater than max_intr=%d", vec,
157                                  intr_handle->max_intr);
158                 return -EINVAL;
159         }
160
161         tmp_handle = *intr_handle;
162         /* Create new eventfd for interrupt vector */
163         tmp_handle.fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
164         if (tmp_handle.fd == -1)
165                 return -ENODEV;
166
167         /* Register vector interrupt callback */
168         rc = rte_intr_callback_register(&tmp_handle, cb, data);
169         if (rc) {
170                 otx2_err("Failed to register vector:0x%x irq callback.", vec);
171                 return rc;
172         }
173
174         intr_handle->efds[vec] = tmp_handle.fd;
175         intr_handle->nb_efd = (vec > intr_handle->nb_efd) ?
176                         vec : intr_handle->nb_efd;
177         if ((intr_handle->nb_efd + 1) > intr_handle->max_intr)
178                 intr_handle->max_intr = intr_handle->nb_efd + 1;
179
180         otx2_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)",
181                 vec, intr_handle->nb_efd, intr_handle->max_intr);
182
183         /* Enable MSIX vectors to VFIO */
184         return irq_config(intr_handle, vec);
185 }
186
187 /**
188  * @internal
189  * Unregister IRQ
190  */
191 void
192 otx2_unregister_irq(struct rte_intr_handle *intr_handle,
193                     rte_intr_callback_fn cb, void *data, unsigned int vec)
194 {
195         struct rte_intr_handle tmp_handle;
196
197         if (vec > intr_handle->max_intr) {
198                 otx2_err("Error unregistering MSI-X interrupts vec:%d > %d",
199                         vec, intr_handle->max_intr);
200                 return;
201         }
202
203         tmp_handle = *intr_handle;
204         tmp_handle.fd = intr_handle->efds[vec];
205         if (tmp_handle.fd == -1)
206                 return;
207
208         /* Un-register callback func from eal lib */
209         rte_intr_callback_unregister(&tmp_handle, cb, data);
210
211         otx2_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)",
212                         vec, intr_handle->nb_efd, intr_handle->max_intr);
213
214         if (intr_handle->efds[vec] != -1)
215                 close(intr_handle->efds[vec]);
216         /* Disable MSIX vectors from VFIO */
217         intr_handle->efds[vec] = -1;
218         irq_config(intr_handle, vec);
219 }
220
221 #else
222
223 /**
224  * @internal
225  * Register IRQ
226  */
227 int otx2_register_irq(__rte_unused struct rte_intr_handle *intr_handle,
228                       __rte_unused rte_intr_callback_fn cb,
229                       __rte_unused void *data, __rte_unused unsigned int vec)
230 {
231         return -ENOTSUP;
232 }
233
234
235 /**
236  * @internal
237  * Unregister IRQ
238  */
239 void otx2_unregister_irq(__rte_unused struct rte_intr_handle *intr_handle,
240                          __rte_unused rte_intr_callback_fn cb,
241                          __rte_unused void *data, __rte_unused unsigned int vec)
242 {
243 }
244
245 /**
246  * @internal
247  * Disable IRQ
248  */
249 int otx2_disable_irqs(__rte_unused struct rte_intr_handle *intr_handle)
250 {
251         return -ENOTSUP;
252 }
253
254 #endif /* RTE_EAL_VFIO */