drivers: remove direct access to interrupt handle
[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, vfio_dev_fd;
30
31         irq.index = VFIO_PCI_MSIX_IRQ_INDEX;
32
33         vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
34         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_GET_IRQ_INFO, &irq);
35         if (rc < 0) {
36                 otx2_err("Failed to get IRQ info rc=%d errno=%d", rc, errno);
37                 return rc;
38         }
39
40         otx2_base_dbg("Flags=0x%x index=0x%x count=0x%x max_intr_vec_id=0x%x",
41                       irq.flags, irq.index, irq.count, MAX_INTR_VEC_ID);
42
43         if (irq.count > MAX_INTR_VEC_ID) {
44                 otx2_err("HW max=%d > MAX_INTR_VEC_ID: %d",
45                          rte_intr_max_intr_get(intr_handle),
46                          MAX_INTR_VEC_ID);
47                 if (rte_intr_max_intr_set(intr_handle, MAX_INTR_VEC_ID))
48                         return -1;
49         } else {
50                 if (rte_intr_max_intr_set(intr_handle, irq.count))
51                         return -1;
52         }
53
54         return 0;
55 }
56
57 static int
58 irq_config(struct rte_intr_handle *intr_handle, unsigned int vec)
59 {
60         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
61         struct vfio_irq_set *irq_set;
62         int len, rc, vfio_dev_fd;
63         int32_t *fd_ptr;
64
65         if (vec > (uint32_t)rte_intr_max_intr_get(intr_handle)) {
66                 otx2_err("vector=%d greater than max_intr=%d", vec,
67                          rte_intr_max_intr_get(intr_handle));
68                 return -EINVAL;
69         }
70
71         len = sizeof(struct vfio_irq_set) + sizeof(int32_t);
72
73         irq_set = (struct vfio_irq_set *)irq_set_buf;
74         irq_set->argsz = len;
75
76         irq_set->start = vec;
77         irq_set->count = 1;
78         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
79                         VFIO_IRQ_SET_ACTION_TRIGGER;
80         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
81
82         /* Use vec fd to set interrupt vectors */
83         fd_ptr = (int32_t *)&irq_set->data[0];
84         fd_ptr[0] = rte_intr_efds_index_get(intr_handle, vec);
85
86         vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
87         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
88         if (rc)
89                 otx2_err("Failed to set_irqs vector=0x%x rc=%d", vec, rc);
90
91         return rc;
92 }
93
94 static int
95 irq_init(struct rte_intr_handle *intr_handle)
96 {
97         char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
98         struct vfio_irq_set *irq_set;
99         int len, rc, vfio_dev_fd;
100         int32_t *fd_ptr;
101         uint32_t i;
102
103         if (rte_intr_max_intr_get(intr_handle) > MAX_INTR_VEC_ID) {
104                 otx2_err("Max_intr=%d greater than MAX_INTR_VEC_ID=%d",
105                          rte_intr_max_intr_get(intr_handle),
106                          MAX_INTR_VEC_ID);
107                 return -ERANGE;
108         }
109
110         len = sizeof(struct vfio_irq_set) +
111                 sizeof(int32_t) * rte_intr_max_intr_get(intr_handle);
112
113         irq_set = (struct vfio_irq_set *)irq_set_buf;
114         irq_set->argsz = len;
115         irq_set->start = 0;
116         irq_set->count = rte_intr_max_intr_get(intr_handle);
117         irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
118                         VFIO_IRQ_SET_ACTION_TRIGGER;
119         irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
120
121         fd_ptr = (int32_t *)&irq_set->data[0];
122         for (i = 0; i < irq_set->count; i++)
123                 fd_ptr[i] = -1;
124
125         vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
126         rc = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
127         if (rc)
128                 otx2_err("Failed to set irqs vector rc=%d", rc);
129
130         return rc;
131 }
132
133 /**
134  * @internal
135  * Disable IRQ
136  */
137 int
138 otx2_disable_irqs(struct rte_intr_handle *intr_handle)
139 {
140         /* Clear max_intr to indicate re-init next time */
141         if (rte_intr_max_intr_set(intr_handle, 0))
142                 return -1;
143         return rte_intr_disable(intr_handle);
144 }
145
146 /**
147  * @internal
148  * Register IRQ
149  */
150 int
151 otx2_register_irq(struct rte_intr_handle *intr_handle,
152                   rte_intr_callback_fn cb, void *data, unsigned int vec)
153 {
154         struct rte_intr_handle *tmp_handle;
155         uint32_t nb_efd, tmp_nb_efd;
156         int rc, fd;
157
158         /* If no max_intr read from VFIO */
159         if (rte_intr_max_intr_get(intr_handle) == 0) {
160                 irq_get_info(intr_handle);
161                 irq_init(intr_handle);
162         }
163
164         if (vec > (uint32_t)rte_intr_max_intr_get(intr_handle)) {
165                 otx2_err("Vector=%d greater than max_intr=%d", vec,
166                         rte_intr_max_intr_get(intr_handle));
167                 return -EINVAL;
168         }
169
170         tmp_handle = intr_handle;
171         /* Create new eventfd for interrupt vector */
172         fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
173         if (fd == -1)
174                 return -ENODEV;
175
176         if (rte_intr_fd_set(tmp_handle, fd))
177                 return errno;
178
179         /* Register vector interrupt callback */
180         rc = rte_intr_callback_register(tmp_handle, cb, data);
181         if (rc) {
182                 otx2_err("Failed to register vector:0x%x irq callback.", vec);
183                 return rc;
184         }
185
186         rte_intr_efds_index_set(intr_handle, vec, fd);
187         nb_efd = (vec > (uint32_t)rte_intr_nb_efd_get(intr_handle)) ?
188                 vec : (uint32_t)rte_intr_nb_efd_get(intr_handle);
189         rte_intr_nb_efd_set(intr_handle, nb_efd);
190
191         tmp_nb_efd = rte_intr_nb_efd_get(intr_handle) + 1;
192         if (tmp_nb_efd > (uint32_t)rte_intr_max_intr_get(intr_handle))
193                 rte_intr_max_intr_set(intr_handle, tmp_nb_efd);
194
195         otx2_base_dbg("Enable vector:0x%x for vfio (efds: %d, max:%d)", vec,
196                      rte_intr_nb_efd_get(intr_handle),
197                      rte_intr_max_intr_get(intr_handle));
198
199         /* Enable MSIX vectors to VFIO */
200         return irq_config(intr_handle, vec);
201 }
202
203 /**
204  * @internal
205  * Unregister IRQ
206  */
207 void
208 otx2_unregister_irq(struct rte_intr_handle *intr_handle,
209                     rte_intr_callback_fn cb, void *data, unsigned int vec)
210 {
211         struct rte_intr_handle *tmp_handle;
212         uint8_t retries = 5; /* 5 ms */
213         int rc, fd;
214
215         if (vec > (uint32_t)rte_intr_max_intr_get(intr_handle)) {
216                 otx2_err("Error unregistering MSI-X interrupts vec:%d > %d",
217                          vec, rte_intr_max_intr_get(intr_handle));
218                 return;
219         }
220
221         tmp_handle = intr_handle;
222         fd = rte_intr_efds_index_get(intr_handle, vec);
223         if (fd == -1)
224                 return;
225
226         if (rte_intr_fd_set(tmp_handle, fd))
227                 return;
228
229         do {
230                 /* Un-register callback func from platform lib */
231                 rc = rte_intr_callback_unregister(tmp_handle, cb, data);
232                 /* Retry only if -EAGAIN */
233                 if (rc != -EAGAIN)
234                         break;
235                 rte_delay_ms(1);
236                 retries--;
237         } while (retries);
238
239         if (rc < 0) {
240                 otx2_err("Error unregistering MSI-X vec %d cb, rc=%d", vec, rc);
241                 return;
242         }
243
244         otx2_base_dbg("Disable vector:0x%x for vfio (efds: %d, max:%d)", vec,
245                      rte_intr_nb_efd_get(intr_handle),
246                      rte_intr_max_intr_get(intr_handle));
247
248         if (rte_intr_efds_index_get(intr_handle, vec) != -1)
249                 close(rte_intr_efds_index_get(intr_handle, vec));
250         /* Disable MSIX vectors from VFIO */
251         rte_intr_efds_index_set(intr_handle, vec, -1);
252         irq_config(intr_handle, vec);
253 }
254
255 #else
256
257 /**
258  * @internal
259  * Register IRQ
260  */
261 int otx2_register_irq(__rte_unused struct rte_intr_handle *intr_handle,
262                       __rte_unused rte_intr_callback_fn cb,
263                       __rte_unused void *data, __rte_unused unsigned int vec)
264 {
265         return -ENOTSUP;
266 }
267
268
269 /**
270  * @internal
271  * Unregister IRQ
272  */
273 void otx2_unregister_irq(__rte_unused struct rte_intr_handle *intr_handle,
274                          __rte_unused rte_intr_callback_fn cb,
275                          __rte_unused void *data, __rte_unused unsigned int vec)
276 {
277 }
278
279 /**
280  * @internal
281  * Disable IRQ
282  */
283 int otx2_disable_irqs(__rte_unused struct rte_intr_handle *intr_handle)
284 {
285         return -ENOTSUP;
286 }
287
288 #endif /* RTE_EAL_VFIO */