Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2014 Intel Corporation
3 : : */
4 : :
5 : : #include <uapi/linux/vfio.h>
6 : :
7 : : #include <stdio.h>
8 : : #include <stdint.h>
9 : : #include <stdlib.h>
10 : : #include <sys/queue.h>
11 : : #include <unistd.h>
12 : : #include <string.h>
13 : : #include <errno.h>
14 : : #include <sys/epoll.h>
15 : : #include <sys/ioctl.h>
16 : : #include <sys/eventfd.h>
17 : : #include <assert.h>
18 : : #include <stdbool.h>
19 : :
20 : : #include <eal_export.h>
21 : : #include <eal_trace_internal.h>
22 : : #include <rte_common.h>
23 : : #include <rte_interrupts.h>
24 : : #include <rte_thread.h>
25 : : #include <rte_per_lcore.h>
26 : : #include <rte_lcore.h>
27 : : #include <rte_branch_prediction.h>
28 : : #include <rte_debug.h>
29 : : #include <rte_log.h>
30 : : #include <rte_errno.h>
31 : : #include <rte_spinlock.h>
32 : : #include <rte_pause.h>
33 : :
34 : : #include "eal_private.h"
35 : :
36 : : #define EAL_INTR_EPOLL_WAIT_FOREVER (-1)
37 : : #define NB_OTHER_INTR 1
38 : :
39 : : #define MAX_ITER_EVNUM RTE_EVENT_ETH_INTR_RING_SIZE
40 : :
41 : : static RTE_DEFINE_PER_LCORE(int, _epfd) = -1; /**< epoll fd per thread */
42 : :
43 : : static uint32_t active_events; /**< events for active interrupt */
44 : :
45 : : /**
46 : : * union for pipe fds.
47 : : */
48 : : union intr_pipefds{
49 : : struct {
50 : : int pipefd[2];
51 : : };
52 : : struct {
53 : : int readfd;
54 : : int writefd;
55 : : };
56 : : };
57 : :
58 : : /**
59 : : * union buffer for reading on different devices
60 : : */
61 : : union rte_intr_read_buffer {
62 : : int uio_intr_count; /* for uio device */
63 : : uint64_t vfio_intr_count; /* for vfio device */
64 : : uint64_t timerfd_num; /* for timerfd */
65 : : char charbuf[16]; /* for others */
66 : : };
67 : :
68 : : TAILQ_HEAD(rte_intr_cb_list, rte_intr_callback);
69 : : TAILQ_HEAD(rte_intr_source_list, rte_intr_source);
70 : :
71 : : struct rte_intr_callback {
72 : : TAILQ_ENTRY(rte_intr_callback) next;
73 : : rte_intr_callback_fn cb_fn; /**< callback address */
74 : : void *cb_arg; /**< parameter for callback */
75 : : uint8_t pending_delete; /**< delete after callback is called */
76 : : rte_intr_unregister_callback_fn ucb_fn; /**< fn to call before cb is deleted */
77 : : };
78 : :
79 : : struct rte_intr_source {
80 : : TAILQ_ENTRY(rte_intr_source) next;
81 : : struct rte_intr_handle *intr_handle; /**< interrupt handle */
82 : : struct rte_intr_cb_list callbacks; /**< user callbacks */
83 : : uint32_t active;
84 : : };
85 : :
86 : : /* global spinlock for interrupt data operation */
87 : : static rte_spinlock_t intr_lock = RTE_SPINLOCK_INITIALIZER;
88 : :
89 : : /* union buffer for pipe read/write */
90 : : static union intr_pipefds intr_pipe;
91 : :
92 : : /* interrupt sources list */
93 : : static struct rte_intr_source_list intr_sources;
94 : :
95 : : /* interrupt handling thread */
96 : : static rte_thread_t intr_thread;
97 : :
98 : : /* VFIO interrupts */
99 : : #define IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + sizeof(int))
100 : : /* irq set buffer length for queue interrupts and LSC interrupt */
101 : : #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
102 : : sizeof(int) * (RTE_MAX_RXTX_INTR_VEC_ID + 1))
103 : :
104 : : /* enable legacy (INTx) interrupts */
105 : : static int
106 : 0 : vfio_enable_intx(const struct rte_intr_handle *intr_handle) {
107 : : struct vfio_irq_set *irq_set;
108 : : char irq_set_buf[IRQ_SET_BUF_LEN];
109 : : int len, ret, vfio_dev_fd;
110 : : int *fd_ptr;
111 : :
112 : : len = sizeof(irq_set_buf);
113 : :
114 : : /* enable INTx */
115 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
116 : 0 : irq_set->argsz = len;
117 : 0 : irq_set->count = 1;
118 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
119 : 0 : irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
120 : 0 : irq_set->start = 0;
121 : : fd_ptr = (int *) &irq_set->data;
122 : 0 : *fd_ptr = rte_intr_fd_get(intr_handle);
123 : :
124 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
125 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
126 : :
127 [ # # ]: 0 : if (ret) {
128 : 0 : EAL_LOG(ERR, "Error enabling INTx interrupts for fd %d",
129 : : rte_intr_fd_get(intr_handle));
130 : 0 : return -1;
131 : : }
132 : :
133 : : /* unmask INTx after enabling */
134 : : memset(irq_set, 0, len);
135 : : len = sizeof(struct vfio_irq_set);
136 : 0 : irq_set->argsz = len;
137 : 0 : irq_set->count = 1;
138 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
139 : : irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
140 : : irq_set->start = 0;
141 : :
142 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
143 : :
144 [ # # ]: 0 : if (ret) {
145 : 0 : EAL_LOG(ERR, "Error unmasking INTx interrupts for fd %d",
146 : : rte_intr_fd_get(intr_handle));
147 : 0 : return -1;
148 : : }
149 : : return 0;
150 : : }
151 : :
152 : : /* disable legacy (INTx) interrupts */
153 : : static int
154 : 0 : vfio_disable_intx(const struct rte_intr_handle *intr_handle) {
155 : : struct vfio_irq_set *irq_set;
156 : : char irq_set_buf[IRQ_SET_BUF_LEN];
157 : : int len, ret, vfio_dev_fd;
158 : :
159 : : len = sizeof(struct vfio_irq_set);
160 : :
161 : : /* mask interrupts before disabling */
162 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
163 : 0 : irq_set->argsz = len;
164 : 0 : irq_set->count = 1;
165 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK;
166 : 0 : irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
167 : 0 : irq_set->start = 0;
168 : :
169 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
170 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
171 : :
172 [ # # ]: 0 : if (ret) {
173 : 0 : EAL_LOG(ERR, "Error masking INTx interrupts for fd %d",
174 : : rte_intr_fd_get(intr_handle));
175 : 0 : return -1;
176 : : }
177 : :
178 : : /* disable INTx*/
179 : : memset(irq_set, 0, len);
180 : 0 : irq_set->argsz = len;
181 : : irq_set->count = 0;
182 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
183 : : irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
184 : : irq_set->start = 0;
185 : :
186 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
187 : :
188 [ # # ]: 0 : if (ret) {
189 : 0 : EAL_LOG(ERR, "Error disabling INTx interrupts for fd %d",
190 : : rte_intr_fd_get(intr_handle));
191 : 0 : return -1;
192 : : }
193 : : return 0;
194 : : }
195 : :
196 : : /* unmask/ack legacy (INTx) interrupts */
197 : : static int
198 : 0 : vfio_ack_intx(const struct rte_intr_handle *intr_handle)
199 : : {
200 : : struct vfio_irq_set irq_set;
201 : : int vfio_dev_fd;
202 : :
203 : : /* unmask INTx */
204 : : memset(&irq_set, 0, sizeof(irq_set));
205 : 0 : irq_set.argsz = sizeof(irq_set);
206 : 0 : irq_set.count = 1;
207 : 0 : irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
208 : : irq_set.index = VFIO_PCI_INTX_IRQ_INDEX;
209 : : irq_set.start = 0;
210 : :
211 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
212 [ # # ]: 0 : if (ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, &irq_set)) {
213 : 0 : EAL_LOG(ERR, "Error unmasking INTx interrupts for fd %d",
214 : : rte_intr_fd_get(intr_handle));
215 : 0 : return -1;
216 : : }
217 : : return 0;
218 : : }
219 : :
220 : : /* enable MSI interrupts */
221 : : static int
222 : 0 : vfio_enable_msi(const struct rte_intr_handle *intr_handle) {
223 : : int len, ret;
224 : : char irq_set_buf[IRQ_SET_BUF_LEN];
225 : : struct vfio_irq_set *irq_set;
226 : : int *fd_ptr, vfio_dev_fd;
227 : :
228 : : len = sizeof(irq_set_buf);
229 : :
230 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
231 : 0 : irq_set->argsz = len;
232 : 0 : irq_set->count = 1;
233 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
234 : 0 : irq_set->index = VFIO_PCI_MSI_IRQ_INDEX;
235 : 0 : irq_set->start = 0;
236 : : fd_ptr = (int *) &irq_set->data;
237 : 0 : *fd_ptr = rte_intr_fd_get(intr_handle);
238 : :
239 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
240 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
241 : :
242 [ # # ]: 0 : if (ret) {
243 : 0 : EAL_LOG(ERR, "Error enabling MSI interrupts for fd %d",
244 : : rte_intr_fd_get(intr_handle));
245 : 0 : return -1;
246 : : }
247 : : return 0;
248 : : }
249 : :
250 : : /* disable MSI interrupts */
251 : : static int
252 : 0 : vfio_disable_msi(const struct rte_intr_handle *intr_handle) {
253 : : struct vfio_irq_set *irq_set;
254 : : char irq_set_buf[IRQ_SET_BUF_LEN];
255 : : int len, ret, vfio_dev_fd;
256 : :
257 : : len = sizeof(struct vfio_irq_set);
258 : :
259 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
260 : 0 : irq_set->argsz = len;
261 : 0 : irq_set->count = 0;
262 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
263 : 0 : irq_set->index = VFIO_PCI_MSI_IRQ_INDEX;
264 : 0 : irq_set->start = 0;
265 : :
266 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
267 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
268 [ # # ]: 0 : if (ret)
269 : 0 : EAL_LOG(ERR, "Error disabling MSI interrupts for fd %d",
270 : : rte_intr_fd_get(intr_handle));
271 : :
272 : 0 : return ret;
273 : : }
274 : :
275 : : /* enable MSI-X interrupts */
276 : : static int
277 : 0 : vfio_enable_msix(const struct rte_intr_handle *intr_handle) {
278 : : int len, ret;
279 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
280 : : struct vfio_irq_set *irq_set;
281 : : int *fd_ptr, vfio_dev_fd, i;
282 : :
283 : : len = sizeof(irq_set_buf);
284 : :
285 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
286 : 0 : irq_set->argsz = len;
287 : : /* 0 < irq_set->count < RTE_MAX_RXTX_INTR_VEC_ID + 1 */
288 : 0 : irq_set->count = rte_intr_max_intr_get(intr_handle) ?
289 : 0 : (rte_intr_max_intr_get(intr_handle) >
290 : : RTE_MAX_RXTX_INTR_VEC_ID + 1 ? RTE_MAX_RXTX_INTR_VEC_ID + 1 :
291 [ # # # # ]: 0 : rte_intr_max_intr_get(intr_handle)) : 1;
292 : :
293 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
294 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
295 : 0 : irq_set->start = 0;
296 : : fd_ptr = (int *) &irq_set->data;
297 : : /* INTR vector offset 0 reserve for non-efds mapping */
298 : 0 : fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = rte_intr_fd_get(intr_handle);
299 [ # # ]: 0 : for (i = 0; i < rte_intr_nb_efd_get(intr_handle); i++) {
300 : 0 : fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] =
301 : 0 : rte_intr_efds_index_get(intr_handle, i);
302 : : }
303 : :
304 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
305 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
306 : :
307 [ # # ]: 0 : if (ret) {
308 : 0 : EAL_LOG(ERR, "Error enabling MSI-X interrupts for fd %d",
309 : : rte_intr_fd_get(intr_handle));
310 : 0 : return -1;
311 : : }
312 : :
313 : : return 0;
314 : : }
315 : :
316 : : /* disable MSI-X interrupts */
317 : : static int
318 : 0 : vfio_disable_msix(const struct rte_intr_handle *intr_handle) {
319 : : struct vfio_irq_set *irq_set;
320 : : char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
321 : : int len, ret, vfio_dev_fd;
322 : :
323 : : len = sizeof(struct vfio_irq_set);
324 : :
325 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
326 : 0 : irq_set->argsz = len;
327 : 0 : irq_set->count = 0;
328 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
329 : 0 : irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
330 : 0 : irq_set->start = 0;
331 : :
332 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
333 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
334 : :
335 [ # # ]: 0 : if (ret)
336 : 0 : EAL_LOG(ERR, "Error disabling MSI-X interrupts for fd %d",
337 : : rte_intr_fd_get(intr_handle));
338 : :
339 : 0 : return ret;
340 : : }
341 : :
342 : : /* enable req notifier */
343 : : static int
344 : 0 : vfio_enable_req(const struct rte_intr_handle *intr_handle)
345 : : {
346 : : int len, ret;
347 : : char irq_set_buf[IRQ_SET_BUF_LEN];
348 : : struct vfio_irq_set *irq_set;
349 : : int *fd_ptr, vfio_dev_fd;
350 : :
351 : : len = sizeof(irq_set_buf);
352 : :
353 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
354 : 0 : irq_set->argsz = len;
355 : 0 : irq_set->count = 1;
356 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
357 : : VFIO_IRQ_SET_ACTION_TRIGGER;
358 : 0 : irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
359 : 0 : irq_set->start = 0;
360 : : fd_ptr = (int *) &irq_set->data;
361 : 0 : *fd_ptr = rte_intr_fd_get(intr_handle);
362 : :
363 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
364 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
365 : :
366 [ # # ]: 0 : if (ret) {
367 : 0 : EAL_LOG(ERR, "Error enabling req interrupts for fd %d",
368 : : rte_intr_fd_get(intr_handle));
369 : 0 : return -1;
370 : : }
371 : :
372 : : return 0;
373 : : }
374 : :
375 : : /* disable req notifier */
376 : : static int
377 : 0 : vfio_disable_req(const struct rte_intr_handle *intr_handle)
378 : : {
379 : : struct vfio_irq_set *irq_set;
380 : : char irq_set_buf[IRQ_SET_BUF_LEN];
381 : : int len, ret, vfio_dev_fd;
382 : :
383 : : len = sizeof(struct vfio_irq_set);
384 : :
385 : : irq_set = (struct vfio_irq_set *) irq_set_buf;
386 : 0 : irq_set->argsz = len;
387 : 0 : irq_set->count = 0;
388 : 0 : irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
389 : 0 : irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
390 : 0 : irq_set->start = 0;
391 : :
392 : 0 : vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
393 : 0 : ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
394 : :
395 [ # # ]: 0 : if (ret)
396 : 0 : EAL_LOG(ERR, "Error disabling req interrupts for fd %d",
397 : : rte_intr_fd_get(intr_handle));
398 : :
399 : 0 : return ret;
400 : : }
401 : :
402 : : static int
403 : 0 : uio_intx_intr_disable(const struct rte_intr_handle *intr_handle)
404 : : {
405 : : unsigned char command_high;
406 : : int uio_cfg_fd;
407 : :
408 : : /* use UIO config file descriptor for uio_pci_generic */
409 : 0 : uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
410 [ # # # # ]: 0 : if (uio_cfg_fd < 0 || pread(uio_cfg_fd, &command_high, 1, 5) != 1) {
411 : 0 : EAL_LOG(ERR,
412 : : "Error reading interrupts status for fd %d",
413 : : uio_cfg_fd);
414 : 0 : return -1;
415 : : }
416 : : /* disable interrupts */
417 : 0 : command_high |= 0x4;
418 [ # # ]: 0 : if (pwrite(uio_cfg_fd, &command_high, 1, 5) != 1) {
419 : 0 : EAL_LOG(ERR,
420 : : "Error disabling interrupts for fd %d",
421 : : uio_cfg_fd);
422 : 0 : return -1;
423 : : }
424 : :
425 : : return 0;
426 : : }
427 : :
428 : : static int
429 : 0 : uio_intx_intr_enable(const struct rte_intr_handle *intr_handle)
430 : : {
431 : : unsigned char command_high;
432 : : int uio_cfg_fd;
433 : :
434 : : /* use UIO config file descriptor for uio_pci_generic */
435 : 0 : uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
436 [ # # # # ]: 0 : if (uio_cfg_fd < 0 || pread(uio_cfg_fd, &command_high, 1, 5) != 1) {
437 : 0 : EAL_LOG(ERR,
438 : : "Error reading interrupts status for fd %d",
439 : : uio_cfg_fd);
440 : 0 : return -1;
441 : : }
442 : : /* enable interrupts */
443 : 0 : command_high &= ~0x4;
444 [ # # ]: 0 : if (pwrite(uio_cfg_fd, &command_high, 1, 5) != 1) {
445 : 0 : EAL_LOG(ERR,
446 : : "Error enabling interrupts for fd %d",
447 : : uio_cfg_fd);
448 : 0 : return -1;
449 : : }
450 : :
451 : : return 0;
452 : : }
453 : :
454 : : static int
455 : 2 : uio_intr_disable(const struct rte_intr_handle *intr_handle)
456 : : {
457 : 2 : const int value = 0;
458 : :
459 [ + - + + ]: 4 : if (rte_intr_fd_get(intr_handle) < 0 ||
460 : 2 : write(rte_intr_fd_get(intr_handle), &value, sizeof(value)) < 0) {
461 : 1 : EAL_LOG(ERR, "Error disabling interrupts for fd %d (%s)",
462 : : rte_intr_fd_get(intr_handle), strerror(errno));
463 : 1 : return -1;
464 : : }
465 : : return 0;
466 : : }
467 : :
468 : : static int
469 : 2 : uio_intr_enable(const struct rte_intr_handle *intr_handle)
470 : : {
471 : 2 : const int value = 1;
472 : :
473 [ + - + + ]: 4 : if (rte_intr_fd_get(intr_handle) < 0 ||
474 : 2 : write(rte_intr_fd_get(intr_handle), &value, sizeof(value)) < 0) {
475 : 1 : EAL_LOG(ERR, "Error enabling interrupts for fd %d (%s)",
476 : : rte_intr_fd_get(intr_handle), strerror(errno));
477 : 1 : return -1;
478 : : }
479 : : return 0;
480 : : }
481 : :
482 : : RTE_EXPORT_SYMBOL(rte_intr_callback_register)
483 : : int
484 : 11 : rte_intr_callback_register(const struct rte_intr_handle *intr_handle,
485 : : rte_intr_callback_fn cb, void *cb_arg)
486 : : {
487 : : int ret, wake_thread;
488 : : struct rte_intr_source *src;
489 : : struct rte_intr_callback *callback;
490 : :
491 : : wake_thread = 0;
492 : :
493 : : /* first do parameter checking */
494 [ + + + + ]: 11 : if (rte_intr_fd_get(intr_handle) < 0 || cb == NULL) {
495 : 3 : EAL_LOG(ERR, "Registering with invalid input parameter");
496 : 3 : return -EINVAL;
497 : : }
498 : :
499 : : /* allocate a new interrupt callback entity */
500 : 8 : callback = calloc(1, sizeof(*callback));
501 [ - + ]: 8 : if (callback == NULL) {
502 : 0 : EAL_LOG(ERR, "Can not allocate memory");
503 : 0 : return -ENOMEM;
504 : : }
505 : 8 : callback->cb_fn = cb;
506 : 8 : callback->cb_arg = cb_arg;
507 : 8 : callback->pending_delete = 0;
508 : 8 : callback->ucb_fn = NULL;
509 : :
510 : : rte_spinlock_lock(&intr_lock);
511 : :
512 : : /* check if there is at least one callback registered for the fd */
513 [ + + ]: 8 : TAILQ_FOREACH(src, &intr_sources, next) {
514 [ + - ]: 1 : if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle)) {
515 : : /* we had no interrupts for this */
516 [ - + ]: 1 : if (TAILQ_EMPTY(&src->callbacks))
517 : : wake_thread = 1;
518 : :
519 : 1 : TAILQ_INSERT_TAIL(&(src->callbacks), callback, next);
520 : : ret = 0;
521 : 1 : break;
522 : : }
523 : : }
524 : :
525 : : /* no existing callbacks for this - add new source */
526 [ + + ]: 8 : if (src == NULL) {
527 : 7 : src = calloc(1, sizeof(*src));
528 [ - + ]: 7 : if (src == NULL) {
529 : 0 : EAL_LOG(ERR, "Can not allocate memory");
530 : : ret = -ENOMEM;
531 : 0 : free(callback);
532 : : callback = NULL;
533 : : } else {
534 : 7 : src->intr_handle = rte_intr_instance_dup(intr_handle);
535 [ - + ]: 7 : if (src->intr_handle == NULL) {
536 : 0 : EAL_LOG(ERR, "Can not create intr instance");
537 : : ret = -ENOMEM;
538 : 0 : free(callback);
539 : : callback = NULL;
540 : 0 : free(src);
541 : : src = NULL;
542 : : } else {
543 : 7 : TAILQ_INIT(&src->callbacks);
544 : 7 : TAILQ_INSERT_TAIL(&(src->callbacks), callback,
545 : : next);
546 : 7 : TAILQ_INSERT_TAIL(&intr_sources, src, next);
547 : : wake_thread = 1;
548 : : ret = 0;
549 : : }
550 : : }
551 : : }
552 : :
553 : : rte_spinlock_unlock(&intr_lock);
554 : :
555 : : /**
556 : : * check if need to notify the pipe fd waited by epoll_wait to
557 : : * rebuild the wait list.
558 : : */
559 [ + + ]: 8 : if (wake_thread)
560 [ - + ]: 7 : if (write(intr_pipe.writefd, "1", 1) < 0)
561 : : ret = -EPIPE;
562 : :
563 : 8 : rte_eal_trace_intr_callback_register(intr_handle, cb, cb_arg, ret);
564 : 8 : return ret;
565 : : }
566 : :
567 : : RTE_EXPORT_SYMBOL(rte_intr_callback_unregister_pending)
568 : : int
569 : 0 : rte_intr_callback_unregister_pending(const struct rte_intr_handle *intr_handle,
570 : : rte_intr_callback_fn cb_fn, void *cb_arg,
571 : : rte_intr_unregister_callback_fn ucb_fn)
572 : : {
573 : : int ret;
574 : : struct rte_intr_source *src;
575 : : struct rte_intr_callback *cb, *next;
576 : :
577 : : /* do parameter checking first */
578 [ # # ]: 0 : if (rte_intr_fd_get(intr_handle) < 0) {
579 : 0 : EAL_LOG(ERR, "Unregistering with invalid input parameter");
580 : 0 : return -EINVAL;
581 : : }
582 : :
583 : : rte_spinlock_lock(&intr_lock);
584 : :
585 : : /* check if the interrupt source for the fd is existent */
586 [ # # ]: 0 : TAILQ_FOREACH(src, &intr_sources, next) {
587 [ # # ]: 0 : if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle))
588 : : break;
589 : : }
590 : :
591 : : /* No interrupt source registered for the fd */
592 [ # # ]: 0 : if (src == NULL) {
593 : : ret = -ENOENT;
594 : :
595 : : /* only usable if the source is active */
596 [ # # ]: 0 : } else if (src->active == 0) {
597 : : ret = -EAGAIN;
598 : :
599 : : } else {
600 : : ret = 0;
601 : :
602 : : /* walk through the callbacks and mark all that match. */
603 [ # # ]: 0 : for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
604 : 0 : next = TAILQ_NEXT(cb, next);
605 [ # # # # ]: 0 : if (cb->cb_fn == cb_fn && (cb_arg == (void *)-1 ||
606 [ # # ]: 0 : cb->cb_arg == cb_arg)) {
607 : 0 : cb->pending_delete = 1;
608 : 0 : cb->ucb_fn = ucb_fn;
609 : 0 : ret++;
610 : : }
611 : : }
612 : : }
613 : :
614 : : rte_spinlock_unlock(&intr_lock);
615 : :
616 : 0 : return ret;
617 : : }
618 : :
619 : : RTE_EXPORT_SYMBOL(rte_intr_callback_unregister)
620 : : int
621 : 526849 : rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle,
622 : : rte_intr_callback_fn cb_fn, void *cb_arg)
623 : : {
624 : : int ret;
625 : : struct rte_intr_source *src;
626 : : struct rte_intr_callback *cb, *next;
627 : :
628 : : /* do parameter checking first */
629 [ + + ]: 526849 : if (rte_intr_fd_get(intr_handle) < 0) {
630 : 62 : EAL_LOG(ERR, "Unregistering with invalid input parameter");
631 : 62 : return -EINVAL;
632 : : }
633 : :
634 : : rte_spinlock_lock(&intr_lock);
635 : :
636 : : /* check if the interrupt source for the fd is existent */
637 [ + + ]: 526787 : TAILQ_FOREACH(src, &intr_sources, next)
638 [ - + ]: 526572 : if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle))
639 : : break;
640 : :
641 : : /* No interrupt source registered for the fd */
642 [ + + ]: 526787 : if (src == NULL) {
643 : : ret = -ENOENT;
644 : :
645 : : /* interrupt source has some active callbacks right now. */
646 [ + + ]: 526572 : } else if (src->active != 0) {
647 : : ret = -EAGAIN;
648 : :
649 : : /* ok to remove. */
650 : : } else {
651 : : ret = 0;
652 : :
653 : : /*walk through the callbacks and remove all that match. */
654 [ + + ]: 20 : for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
655 : :
656 : 11 : next = TAILQ_NEXT(cb, next);
657 : :
658 [ + + + + ]: 11 : if (cb->cb_fn == cb_fn && (cb_arg == (void *)-1 ||
659 [ + + ]: 6 : cb->cb_arg == cb_arg)) {
660 [ + + ]: 8 : TAILQ_REMOVE(&src->callbacks, cb, next);
661 : 8 : free(cb);
662 : 8 : ret++;
663 : : }
664 : : }
665 : :
666 : : /* all callbacks for that source are removed. */
667 [ + + ]: 9 : if (TAILQ_EMPTY(&src->callbacks)) {
668 [ - + ]: 7 : TAILQ_REMOVE(&intr_sources, src, next);
669 : 7 : rte_intr_instance_free(src->intr_handle);
670 : 7 : free(src);
671 : : }
672 : : }
673 : :
674 : : rte_spinlock_unlock(&intr_lock);
675 : :
676 : : /* notify the pipe fd waited by epoll_wait to rebuild the wait list */
677 [ + + - + ]: 526787 : if (ret >= 0 && write(intr_pipe.writefd, "1", 1) < 0) {
678 : : ret = -EPIPE;
679 : : }
680 : :
681 : 526787 : rte_eal_trace_intr_callback_unregister(intr_handle, cb_fn, cb_arg,
682 : : ret);
683 : 526787 : return ret;
684 : : }
685 : :
686 : : RTE_EXPORT_SYMBOL(rte_intr_callback_unregister_sync)
687 : : int
688 : 269 : rte_intr_callback_unregister_sync(const struct rte_intr_handle *intr_handle,
689 : : rte_intr_callback_fn cb_fn, void *cb_arg)
690 : : {
691 : : int ret = 0;
692 : :
693 [ - + ]: 269 : while ((ret = rte_intr_callback_unregister(intr_handle, cb_fn, cb_arg)) == -EAGAIN)
694 : : rte_pause();
695 : :
696 : 269 : return ret;
697 : : }
698 : :
699 : : RTE_EXPORT_SYMBOL(rte_intr_enable)
700 : : int
701 : 7 : rte_intr_enable(const struct rte_intr_handle *intr_handle)
702 : : {
703 : : int rc = 0, uio_cfg_fd;
704 : :
705 [ + + ]: 7 : if (intr_handle == NULL)
706 : : return -1;
707 : :
708 [ - + ]: 6 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
709 : : rc = 0;
710 : 0 : goto out;
711 : : }
712 : :
713 : 6 : uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
714 [ + + - + ]: 6 : if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0) {
715 : : rc = -1;
716 : 1 : goto out;
717 : : }
718 : :
719 [ + - - - : 5 : switch (rte_intr_type_get(intr_handle)) {
- - + + ]
720 : : /* write to the uio fd to enable the interrupt */
721 : 2 : case RTE_INTR_HANDLE_UIO:
722 [ + + ]: 2 : if (uio_intr_enable(intr_handle))
723 : : rc = -1;
724 : : break;
725 : 0 : case RTE_INTR_HANDLE_UIO_INTX:
726 [ # # ]: 0 : if (uio_intx_intr_enable(intr_handle))
727 : : rc = -1;
728 : : break;
729 : : /* not used at this moment */
730 : : case RTE_INTR_HANDLE_ALARM:
731 : : rc = -1;
732 : : break;
733 : 0 : case RTE_INTR_HANDLE_VFIO_MSIX:
734 [ # # ]: 0 : if (vfio_enable_msix(intr_handle))
735 : : rc = -1;
736 : : break;
737 : 0 : case RTE_INTR_HANDLE_VFIO_MSI:
738 [ # # ]: 0 : if (vfio_enable_msi(intr_handle))
739 : : rc = -1;
740 : : break;
741 : 0 : case RTE_INTR_HANDLE_VFIO_LEGACY:
742 [ # # ]: 0 : if (vfio_enable_intx(intr_handle))
743 : : rc = -1;
744 : : break;
745 : 0 : case RTE_INTR_HANDLE_VFIO_REQ:
746 [ # # ]: 0 : if (vfio_enable_req(intr_handle))
747 : : rc = -1;
748 : : break;
749 : : /* not used at this moment */
750 : : case RTE_INTR_HANDLE_DEV_EVENT:
751 : : rc = -1;
752 : : break;
753 : : /* unknown handle type */
754 : 1 : default:
755 : 1 : EAL_LOG(ERR, "Unknown handle type of fd %d",
756 : : rte_intr_fd_get(intr_handle));
757 : : rc = -1;
758 : 1 : break;
759 : : }
760 [ - + ]: 6 : out:
761 : 6 : rte_eal_trace_intr_enable(intr_handle, rc);
762 : 6 : return rc;
763 : : }
764 : :
765 : : /**
766 : : * PMD generally calls this function at the end of its IRQ callback.
767 : : * Internally, it unmasks the interrupt if possible.
768 : : *
769 : : * For INTx, unmasking is required as the interrupt is auto-masked prior to
770 : : * invoking callback.
771 : : *
772 : : * For MSI/MSI-X, unmasking is typically not needed as the interrupt is not
773 : : * auto-masked. In fact, for interrupt handle types VFIO_MSIX and VFIO_MSI,
774 : : * this function is no-op.
775 : : */
776 : : RTE_EXPORT_SYMBOL(rte_intr_ack)
777 : : int
778 : 0 : rte_intr_ack(const struct rte_intr_handle *intr_handle)
779 : : {
780 : : int uio_cfg_fd;
781 : :
782 [ # # ]: 0 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV)
783 : : return 0;
784 : :
785 : 0 : uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
786 [ # # # # ]: 0 : if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0)
787 : : return -1;
788 : :
789 [ # # # # : 0 : switch (rte_intr_type_get(intr_handle)) {
# # ]
790 : : /* Both acking and enabling are same for UIO */
791 : 0 : case RTE_INTR_HANDLE_UIO:
792 [ # # ]: 0 : if (uio_intr_enable(intr_handle))
793 : 0 : return -1;
794 : : break;
795 : 0 : case RTE_INTR_HANDLE_UIO_INTX:
796 [ # # ]: 0 : if (uio_intx_intr_enable(intr_handle))
797 : 0 : return -1;
798 : : break;
799 : : /* not used at this moment */
800 : : case RTE_INTR_HANDLE_ALARM:
801 : : return -1;
802 : : /* VFIO MSI* is implicitly acked unlike INTx, nothing to do */
803 : 0 : case RTE_INTR_HANDLE_VFIO_MSIX:
804 : : case RTE_INTR_HANDLE_VFIO_MSI:
805 : 0 : return 0;
806 : 0 : case RTE_INTR_HANDLE_VFIO_LEGACY:
807 [ # # ]: 0 : if (vfio_ack_intx(intr_handle))
808 : 0 : return -1;
809 : : break;
810 : : case RTE_INTR_HANDLE_VFIO_REQ:
811 : : return -1;
812 : : /* not used at this moment */
813 : : case RTE_INTR_HANDLE_DEV_EVENT:
814 : : return -1;
815 : : /* unknown handle type */
816 : 0 : default:
817 : 0 : EAL_LOG(ERR, "Unknown handle type of fd %d",
818 : : rte_intr_fd_get(intr_handle));
819 : 0 : return -1;
820 : : }
821 : :
822 : : return 0;
823 : : }
824 : :
825 : : RTE_EXPORT_SYMBOL(rte_intr_disable)
826 : : int
827 : 7 : rte_intr_disable(const struct rte_intr_handle *intr_handle)
828 : : {
829 : : int rc = 0, uio_cfg_fd;
830 : :
831 [ + + ]: 7 : if (intr_handle == NULL)
832 : : return -1;
833 : :
834 [ - + ]: 6 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
835 : : rc = 0;
836 : 0 : goto out;
837 : : }
838 : :
839 : 6 : uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
840 [ + + - + ]: 6 : if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0) {
841 : : rc = -1;
842 : 1 : goto out;
843 : : }
844 : :
845 [ + - - - : 5 : switch (rte_intr_type_get(intr_handle)) {
- - + + ]
846 : : /* write to the uio fd to disable the interrupt */
847 : 2 : case RTE_INTR_HANDLE_UIO:
848 [ + + ]: 2 : if (uio_intr_disable(intr_handle))
849 : : rc = -1;
850 : : break;
851 : 0 : case RTE_INTR_HANDLE_UIO_INTX:
852 [ # # ]: 0 : if (uio_intx_intr_disable(intr_handle))
853 : : rc = -1;
854 : : break;
855 : : /* not used at this moment */
856 : : case RTE_INTR_HANDLE_ALARM:
857 : : rc = -1;
858 : : break;
859 : 0 : case RTE_INTR_HANDLE_VFIO_MSIX:
860 [ # # ]: 0 : if (vfio_disable_msix(intr_handle))
861 : : rc = -1;
862 : : break;
863 : 0 : case RTE_INTR_HANDLE_VFIO_MSI:
864 [ # # ]: 0 : if (vfio_disable_msi(intr_handle))
865 : : rc = -1;
866 : : break;
867 : 0 : case RTE_INTR_HANDLE_VFIO_LEGACY:
868 [ # # ]: 0 : if (vfio_disable_intx(intr_handle))
869 : : rc = -1;
870 : : break;
871 : 0 : case RTE_INTR_HANDLE_VFIO_REQ:
872 [ # # ]: 0 : if (vfio_disable_req(intr_handle))
873 : : rc = -1;
874 : : break;
875 : : /* not used at this moment */
876 : : case RTE_INTR_HANDLE_DEV_EVENT:
877 : : rc = -1;
878 : : break;
879 : : /* unknown handle type */
880 : 1 : default:
881 : 1 : EAL_LOG(ERR, "Unknown handle type of fd %d",
882 : : rte_intr_fd_get(intr_handle));
883 : : rc = -1;
884 : 1 : break;
885 : : }
886 [ - + ]: 6 : out:
887 : 6 : rte_eal_trace_intr_disable(intr_handle, rc);
888 : 6 : return rc;
889 : : }
890 : :
891 : : static uint32_t
892 : : epoll_to_intr_events(uint32_t epoll_events)
893 : : {
894 : : uint32_t ev = 0;
895 : :
896 : 70501 : if (epoll_events & EPOLLIN)
897 : : ev |= RTE_INTR_EVENT_IN;
898 [ - + ]: 70501 : if (epoll_events & EPOLLERR)
899 : 0 : ev |= RTE_INTR_EVENT_ERR;
900 [ - + ]: 70501 : if (epoll_events & EPOLLHUP)
901 : 0 : ev |= RTE_INTR_EVENT_HUP;
902 [ - + ]: 70501 : if (epoll_events & EPOLLRDHUP)
903 : 0 : ev |= RTE_INTR_EVENT_RDHUP;
904 : : return ev;
905 : : }
906 : :
907 : : static void
908 : 0 : eal_intr_source_remove_and_free(struct rte_intr_source *src)
909 : : {
910 : : struct rte_intr_callback *cb, *next;
911 : :
912 : : /* Remove the interrupt source */
913 : : rte_spinlock_lock(&intr_lock);
914 [ # # ]: 0 : TAILQ_REMOVE(&intr_sources, src, next);
915 : : rte_spinlock_unlock(&intr_lock);
916 : :
917 : : /* Free callbacks */
918 [ # # ]: 0 : for (cb = TAILQ_FIRST(&src->callbacks); cb; cb = next) {
919 : 0 : next = TAILQ_NEXT(cb, next);
920 [ # # ]: 0 : TAILQ_REMOVE(&src->callbacks, cb, next);
921 : 0 : free(cb);
922 : : }
923 : :
924 : : /* Free the interrupt source */
925 : 0 : rte_intr_instance_free(src->intr_handle);
926 : 0 : free(src);
927 : 0 : }
928 : :
929 : : static int
930 : 70516 : eal_intr_process_interrupts(struct epoll_event *events, int nfds)
931 : : {
932 : : bool call = false;
933 : : int n, bytes_read, rv;
934 : : struct rte_intr_source *src;
935 : : struct rte_intr_callback *cb, *next;
936 : : union rte_intr_read_buffer buf;
937 : : struct rte_intr_callback active_cb;
938 : :
939 [ + + ]: 141017 : for (n = 0; n < nfds; n++) {
940 : :
941 : : /**
942 : : * if the pipe fd is ready to read, return out to
943 : : * rebuild the wait list.
944 : : */
945 [ + + ]: 70516 : if (events[n].data.fd == intr_pipe.readfd){
946 : : int r = read(intr_pipe.readfd, buf.charbuf,
947 : : sizeof(buf.charbuf));
948 : : RTE_SET_USED(r);
949 : 15 : return -1;
950 : : }
951 : : rte_spinlock_lock(&intr_lock);
952 [ + - ]: 70501 : TAILQ_FOREACH(src, &intr_sources, next)
953 [ - + ]: 70501 : if (rte_intr_fd_get(src->intr_handle) == events[n].data.fd)
954 : : break;
955 [ - + ]: 70501 : if (src == NULL){
956 : : rte_spinlock_unlock(&intr_lock);
957 : 0 : continue;
958 : : }
959 : :
960 : : /* mark this interrupt source as active and release the lock. */
961 : 70501 : src->active = 1;
962 : : rte_spinlock_unlock(&intr_lock);
963 : :
964 : : /* set the length to be read dor different handle type */
965 [ + - + + : 70501 : switch (rte_intr_type_get(src->intr_handle)) {
+ ]
966 : : case RTE_INTR_HANDLE_UIO:
967 : : case RTE_INTR_HANDLE_UIO_INTX:
968 : : bytes_read = sizeof(buf.uio_intr_count);
969 : : break;
970 : : case RTE_INTR_HANDLE_ALARM:
971 : : bytes_read = sizeof(buf.timerfd_num);
972 : : break;
973 : : case RTE_INTR_HANDLE_VFIO_REQ:
974 : : case RTE_INTR_HANDLE_VFIO_MSIX:
975 : : case RTE_INTR_HANDLE_VFIO_MSI:
976 : : case RTE_INTR_HANDLE_VFIO_LEGACY:
977 : : bytes_read = sizeof(buf.vfio_intr_count);
978 : : break;
979 : : case RTE_INTR_HANDLE_VDEV:
980 : : case RTE_INTR_HANDLE_EXT:
981 : : bytes_read = 0;
982 : : call = true;
983 : : break;
984 : : case RTE_INTR_HANDLE_DEV_EVENT:
985 : : bytes_read = 0;
986 : : call = true;
987 : : break;
988 : : default:
989 : : bytes_read = 1;
990 : : break;
991 : : }
992 : :
993 : : if (bytes_read > 0) {
994 : : /*
995 : : * Check for epoll error or disconnect events for
996 : : * interrupts that are read directly in eal.
997 : : */
998 [ - + ]: 4 : if (events[n].events & (EPOLLERR | EPOLLHUP | EPOLLRDHUP)) {
999 : 0 : EAL_LOG(ERR, "Disconnect condition on fd %d "
1000 : : "(events=0x%x), removing from epoll",
1001 : : events[n].data.fd, events[n].events);
1002 : 0 : eal_intr_source_remove_and_free(src);
1003 : 0 : return -1;
1004 : : }
1005 : :
1006 : : /*
1007 : : * read out to clear the ready-to-be-read flag
1008 : : * for epoll_wait.
1009 : : */
1010 : 4 : bytes_read = read(events[n].data.fd, &buf, bytes_read);
1011 [ - + ]: 4 : if (bytes_read > 0) {
1012 : : call = true;
1013 [ # # ]: 0 : } else if (bytes_read < 0) {
1014 [ # # ]: 0 : if (errno == EINTR || errno == EWOULDBLOCK)
1015 : 0 : continue;
1016 : :
1017 : 0 : EAL_LOG(ERR, "Error reading from file descriptor %d: %s",
1018 : : events[n].data.fd,
1019 : : strerror(errno));
1020 : : } else {
1021 : 0 : EAL_LOG(ERR, "Read nothing from file descriptor %d",
1022 : : events[n].data.fd);
1023 : : }
1024 [ - + ]: 4 : if (bytes_read <= 0) {
1025 : 0 : eal_intr_source_remove_and_free(src);
1026 : 0 : return -1;
1027 : : }
1028 : : }
1029 : :
1030 : : /* grab a lock, again to call callbacks and update status. */
1031 : : rte_spinlock_lock(&intr_lock);
1032 : :
1033 [ + - ]: 70501 : if (call) {
1034 [ + - ]: 70501 : active_events = epoll_to_intr_events(events[n].events);
1035 : : /* Finally, call all callbacks. */
1036 [ + + ]: 141002 : TAILQ_FOREACH(cb, &src->callbacks, next) {
1037 : :
1038 : : /* make a copy and unlock. */
1039 : 70501 : active_cb = *cb;
1040 : : rte_spinlock_unlock(&intr_lock);
1041 : :
1042 : : /* call the actual callback */
1043 : 70501 : active_cb.cb_fn(active_cb.cb_arg);
1044 : :
1045 : : /*get the lock back. */
1046 : : rte_spinlock_lock(&intr_lock);
1047 : : }
1048 : 70501 : active_events = 0;
1049 : : }
1050 : : /* we done with that interrupt source, release it. */
1051 : 70501 : src->active = 0;
1052 : :
1053 : : rv = 0;
1054 : :
1055 : : /* check if any callback are supposed to be removed */
1056 [ + + ]: 141002 : for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
1057 : 70501 : next = TAILQ_NEXT(cb, next);
1058 [ - + ]: 70501 : if (cb->pending_delete) {
1059 [ # # ]: 0 : TAILQ_REMOVE(&src->callbacks, cb, next);
1060 [ # # ]: 0 : if (cb->ucb_fn)
1061 : 0 : cb->ucb_fn(src->intr_handle, cb->cb_arg);
1062 : 0 : free(cb);
1063 : 0 : rv++;
1064 : : }
1065 : : }
1066 : :
1067 : : /* all callbacks for that source are removed. */
1068 [ - + ]: 70501 : if (TAILQ_EMPTY(&src->callbacks)) {
1069 [ # # ]: 0 : TAILQ_REMOVE(&intr_sources, src, next);
1070 : 0 : rte_intr_instance_free(src->intr_handle);
1071 : 0 : free(src);
1072 : : }
1073 : :
1074 : : /* notify the pipe fd waited by epoll_wait to rebuild the wait list */
1075 [ - + - - ]: 70501 : if (rv > 0 && write(intr_pipe.writefd, "1", 1) < 0) {
1076 : : rte_spinlock_unlock(&intr_lock);
1077 : 0 : return -EPIPE;
1078 : : }
1079 : :
1080 : : rte_spinlock_unlock(&intr_lock);
1081 : : }
1082 : :
1083 : : return 0;
1084 : : }
1085 : :
1086 : : /**
1087 : : * It handles all the interrupts.
1088 : : *
1089 : : * @param pfd
1090 : : * epoll file descriptor.
1091 : : * @param totalfds
1092 : : * The number of file descriptors added in epoll.
1093 : : *
1094 : : * @return
1095 : : * void
1096 : : */
1097 : : static void
1098 : 224 : eal_intr_handle_interrupts(int pfd, unsigned totalfds)
1099 : : {
1100 : 224 : struct epoll_event *events = alloca(sizeof(struct epoll_event) * totalfds);
1101 : : int nfds = 0;
1102 : :
1103 : : for(;;) {
1104 : 70731 : nfds = epoll_wait(pfd, events, totalfds,
1105 : : EAL_INTR_EPOLL_WAIT_FOREVER);
1106 : : /* epoll_wait fail */
1107 [ + + ]: 70522 : if (nfds < 0) {
1108 [ + - ]: 6 : if (errno == EINTR)
1109 : 6 : continue;
1110 : 0 : EAL_LOG(ERR,
1111 : : "epoll_wait returns with fail");
1112 : 0 : return;
1113 : : }
1114 : : /* epoll_wait timeout, will never happens here */
1115 [ - + ]: 70516 : else if (nfds == 0)
1116 : 0 : continue;
1117 : : /* epoll_wait has at least one fd ready to read */
1118 [ + + ]: 70516 : if (eal_intr_process_interrupts(events, nfds) < 0)
1119 : : return;
1120 : : }
1121 : : }
1122 : :
1123 : : /**
1124 : : * It builds/rebuilds up the epoll file descriptor with all the
1125 : : * file descriptors being waited on. Then handles the interrupts.
1126 : : *
1127 : : * @param arg
1128 : : * pointer. (unused)
1129 : : *
1130 : : * @return
1131 : : * never return;
1132 : : */
1133 : : static __rte_noreturn uint32_t
1134 : 209 : eal_intr_thread_main(__rte_unused void *arg)
1135 : : {
1136 : : /* host thread, never break out */
1137 : 15 : for (;;) {
1138 : : /* build up the epoll fd with all descriptors we are to
1139 : : * wait on then pass it to the handle_interrupts function
1140 : : */
1141 : : static struct epoll_event pipe_event = {
1142 : : .events = EPOLLIN | EPOLLPRI,
1143 : : };
1144 : : struct rte_intr_source *src;
1145 : : unsigned numfds = 0;
1146 : :
1147 : : /* create epoll fd */
1148 : 224 : int pfd = epoll_create(1);
1149 [ - + ]: 224 : if (pfd < 0)
1150 : 0 : rte_panic("Cannot create epoll instance\n");
1151 : :
1152 : 224 : pipe_event.data.fd = intr_pipe.readfd;
1153 : : /**
1154 : : * add pipe fd into wait list, this pipe is used to
1155 : : * rebuild the wait list.
1156 : : */
1157 [ - + ]: 224 : if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd,
1158 : : &pipe_event) < 0) {
1159 : 0 : rte_panic("Error adding fd to %d epoll_ctl, %s\n",
1160 : : intr_pipe.readfd, strerror(errno));
1161 : : }
1162 : : numfds++;
1163 : :
1164 : : rte_spinlock_lock(&intr_lock);
1165 : :
1166 [ + + ]: 233 : TAILQ_FOREACH(src, &intr_sources, next) {
1167 : : struct epoll_event ev;
1168 : :
1169 [ - + ]: 9 : if (src->callbacks.tqh_first == NULL)
1170 : 0 : continue; /* skip those with no callbacks */
1171 : : memset(&ev, 0, sizeof(ev));
1172 : 9 : ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;
1173 : 9 : ev.data.fd = rte_intr_fd_get(src->intr_handle);
1174 : :
1175 : : /**
1176 : : * add all the uio device file descriptor
1177 : : * into wait list.
1178 : : */
1179 [ - + ]: 9 : if (epoll_ctl(pfd, EPOLL_CTL_ADD,
1180 : 9 : rte_intr_fd_get(src->intr_handle), &ev) < 0) {
1181 : 0 : rte_panic("Error adding fd %d epoll_ctl, %s\n",
1182 : : rte_intr_fd_get(src->intr_handle),
1183 : : strerror(errno));
1184 : : }
1185 : : else
1186 : 9 : numfds++;
1187 : : }
1188 : : rte_spinlock_unlock(&intr_lock);
1189 : : /* serve the interrupt */
1190 : 224 : eal_intr_handle_interrupts(pfd, numfds);
1191 : :
1192 : : /**
1193 : : * when we return, we need to rebuild the
1194 : : * list of fds to monitor.
1195 : : */
1196 : 15 : close(pfd);
1197 : : }
1198 : : }
1199 : :
1200 : : int
1201 : 209 : rte_eal_intr_init(void)
1202 : : {
1203 : : int ret = 0;
1204 : :
1205 : : /* init the global interrupt source head */
1206 : 209 : TAILQ_INIT(&intr_sources);
1207 : :
1208 : : /**
1209 : : * create a pipe which will be waited by epoll and notified to
1210 : : * rebuild the wait list of epoll.
1211 : : */
1212 [ - + ]: 209 : if (pipe(intr_pipe.pipefd) < 0) {
1213 : 0 : rte_errno = errno;
1214 : 0 : return -1;
1215 : : }
1216 : :
1217 : : /* create the host thread to wait/handle the interrupt */
1218 : 209 : ret = rte_thread_create_internal_control(&intr_thread, "intr",
1219 : : eal_intr_thread_main, NULL);
1220 [ - + ]: 209 : if (ret != 0) {
1221 : 0 : rte_errno = -ret;
1222 : 0 : EAL_LOG(ERR,
1223 : : "Failed to create thread for interrupt handling");
1224 : : }
1225 : :
1226 : : return ret;
1227 : : }
1228 : :
1229 : : static void
1230 : 0 : eal_intr_proc_rxtx_intr(int fd, const struct rte_intr_handle *intr_handle)
1231 : : {
1232 : : union rte_intr_read_buffer buf;
1233 : : int bytes_read = 0;
1234 : : int nbytes;
1235 : :
1236 [ # # # # : 0 : switch (rte_intr_type_get(intr_handle)) {
# ]
1237 : : case RTE_INTR_HANDLE_UIO:
1238 : : case RTE_INTR_HANDLE_UIO_INTX:
1239 : : bytes_read = sizeof(buf.uio_intr_count);
1240 : : break;
1241 : : case RTE_INTR_HANDLE_VFIO_MSIX:
1242 : : case RTE_INTR_HANDLE_VFIO_MSI:
1243 : : case RTE_INTR_HANDLE_VFIO_LEGACY:
1244 : : bytes_read = sizeof(buf.vfio_intr_count);
1245 : : break;
1246 : 0 : case RTE_INTR_HANDLE_VDEV:
1247 : 0 : bytes_read = rte_intr_efd_counter_size_get(intr_handle);
1248 : : /* For vdev, number of bytes to read is set by driver */
1249 : : break;
1250 : : case RTE_INTR_HANDLE_EXT:
1251 : : return;
1252 : 0 : default:
1253 : : bytes_read = 1;
1254 : 0 : EAL_LOG(INFO, "unexpected intr type");
1255 : : break;
1256 : : }
1257 : :
1258 : : /**
1259 : : * read out to clear the ready-to-be-read flag
1260 : : * for epoll_wait.
1261 : : */
1262 [ # # ]: 0 : if (bytes_read == 0)
1263 : : return;
1264 : : do {
1265 [ # # ]: 0 : nbytes = read(fd, &buf, bytes_read);
1266 [ # # ]: 0 : if (nbytes < 0) {
1267 [ # # ]: 0 : if (errno == EINTR || errno == EWOULDBLOCK ||
1268 : : errno == EAGAIN)
1269 : : continue;
1270 : 0 : EAL_LOG(ERR,
1271 : : "Error reading from fd %d: %s",
1272 : : fd, strerror(errno));
1273 [ # # ]: 0 : } else if (nbytes == 0)
1274 : 0 : EAL_LOG(ERR, "Read nothing from fd %d", fd);
1275 : : return;
1276 : : } while (1);
1277 : : }
1278 : :
1279 : : static int
1280 : 0 : eal_epoll_process_event(struct epoll_event *evs, unsigned int n,
1281 : : struct rte_epoll_event *events)
1282 : : {
1283 : : unsigned int i, count = 0;
1284 : : struct rte_epoll_event *rev;
1285 : : uint32_t valid_status;
1286 : :
1287 [ # # ]: 0 : for (i = 0; i < n; i++) {
1288 : 0 : rev = evs[i].data.ptr;
1289 : : valid_status = RTE_EPOLL_VALID;
1290 : : /* ACQUIRE memory ordering here pairs with RELEASE
1291 : : * ordering below acting as a lock to synchronize
1292 : : * the event data updating.
1293 : : */
1294 [ # # # # ]: 0 : if (!rev || !rte_atomic_compare_exchange_strong_explicit(&rev->status,
1295 : : &valid_status, RTE_EPOLL_EXEC,
1296 : : rte_memory_order_acquire, rte_memory_order_relaxed))
1297 : 0 : continue;
1298 : :
1299 : 0 : events[count].status = RTE_EPOLL_VALID;
1300 : 0 : events[count].fd = rev->fd;
1301 : 0 : events[count].epfd = rev->epfd;
1302 : 0 : events[count].epdata.event = evs[i].events;
1303 : 0 : events[count].epdata.data = rev->epdata.data;
1304 [ # # ]: 0 : if (rev->epdata.cb_fun)
1305 : 0 : rev->epdata.cb_fun(rev->fd,
1306 : : rev->epdata.cb_arg);
1307 : :
1308 : : /* the status update should be observed after
1309 : : * the other fields change.
1310 : : */
1311 : 0 : rte_atomic_store_explicit(&rev->status, RTE_EPOLL_VALID,
1312 : : rte_memory_order_release);
1313 : 0 : count++;
1314 : : }
1315 : 0 : return count;
1316 : : }
1317 : :
1318 : : static inline int
1319 : 0 : eal_init_tls_epfd(void)
1320 : : {
1321 : 0 : int pfd = epoll_create(255);
1322 : :
1323 [ # # ]: 0 : if (pfd < 0) {
1324 : 0 : EAL_LOG(ERR,
1325 : : "Cannot create epoll instance");
1326 : 0 : return -1;
1327 : : }
1328 : : return pfd;
1329 : : }
1330 : :
1331 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_tls_epfd)
1332 : : int
1333 : 0 : rte_intr_tls_epfd(void)
1334 : : {
1335 [ # # ]: 0 : if (RTE_PER_LCORE(_epfd) == -1)
1336 : 0 : RTE_PER_LCORE(_epfd) = eal_init_tls_epfd();
1337 : :
1338 : 0 : return RTE_PER_LCORE(_epfd);
1339 : : }
1340 : :
1341 : : static int
1342 : 0 : eal_epoll_wait(int epfd, struct rte_epoll_event *events,
1343 : : int maxevents, int timeout, bool interruptible)
1344 : : {
1345 : : int rc;
1346 : : uint32_t i, k, n, num;
1347 : : struct epoll_event evs[MAX_ITER_EVNUM];
1348 : :
1349 [ # # ]: 0 : if (!events) {
1350 : 0 : EAL_LOG(ERR, "rte_epoll_event can't be NULL");
1351 : 0 : return -1;
1352 : : }
1353 : :
1354 : : /* using per thread epoll fd */
1355 [ # # ]: 0 : if (epfd == RTE_EPOLL_PER_THREAD)
1356 : 0 : epfd = rte_intr_tls_epfd();
1357 : :
1358 : 0 : num = maxevents;
1359 : 0 : n = RTE_MIN(RTE_DIM(evs), num);
1360 : :
1361 : : /* Process events in chunks of MAX_ITER_EVNUM */
1362 : :
1363 : : while (1) {
1364 : 0 : rc = epoll_wait(epfd, evs, n, timeout);
1365 [ # # ]: 0 : if (likely(rc > 0)) {
1366 : :
1367 : : /* epoll_wait has at least one fd ready to read */
1368 [ # # ]: 0 : for (i = 0, k = 0; rc > 0;) {
1369 : 0 : k += rc;
1370 : 0 : rc = eal_epoll_process_event(evs, rc,
1371 : 0 : events + i);
1372 : 0 : i += rc;
1373 : :
1374 : : /*
1375 : : * try to read more events that are already
1376 : : * available (up to maxevents in total).
1377 : : */
1378 : 0 : n = RTE_MIN(RTE_DIM(evs), num - k);
1379 [ # # ]: 0 : rc = (n == 0) ? 0 : epoll_wait(epfd, evs, n, 0);
1380 : : }
1381 : 0 : return i;
1382 : :
1383 [ # # ]: 0 : } else if (rc < 0) {
1384 [ # # ]: 0 : if (errno == EINTR) {
1385 [ # # ]: 0 : if (interruptible)
1386 : : return -1;
1387 : : else
1388 : : continue;
1389 : : }
1390 : : /* epoll_wait fail */
1391 : 0 : EAL_LOG(ERR, "epoll_wait returns with fail %s",
1392 : : strerror(errno));
1393 : : rc = -1;
1394 : 0 : break;
1395 : : } else {
1396 : : /* rc == 0, epoll_wait timed out */
1397 : : break;
1398 : : }
1399 : : }
1400 : :
1401 : : return rc;
1402 : : }
1403 : :
1404 : : RTE_EXPORT_SYMBOL(rte_epoll_wait)
1405 : : int
1406 : 0 : rte_epoll_wait(int epfd, struct rte_epoll_event *events,
1407 : : int maxevents, int timeout)
1408 : : {
1409 : 0 : return eal_epoll_wait(epfd, events, maxevents, timeout, false);
1410 : : }
1411 : :
1412 : : RTE_EXPORT_SYMBOL(rte_epoll_wait_interruptible)
1413 : : int
1414 : 0 : rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events,
1415 : : int maxevents, int timeout)
1416 : : {
1417 : 0 : return eal_epoll_wait(epfd, events, maxevents, timeout, true);
1418 : : }
1419 : :
1420 : : static inline void
1421 : 0 : eal_epoll_data_safe_free(struct rte_epoll_event *ev)
1422 : : {
1423 : : uint32_t valid_status = RTE_EPOLL_VALID;
1424 : :
1425 [ # # ]: 0 : while (!rte_atomic_compare_exchange_strong_explicit(&ev->status, &valid_status,
1426 : : RTE_EPOLL_INVALID, rte_memory_order_acquire, rte_memory_order_relaxed)) {
1427 : 0 : while (rte_atomic_load_explicit(&ev->status,
1428 [ # # ]: 0 : rte_memory_order_relaxed) != RTE_EPOLL_VALID)
1429 : : rte_pause();
1430 : : valid_status = RTE_EPOLL_VALID;
1431 : : }
1432 : 0 : memset(&ev->epdata, 0, sizeof(ev->epdata));
1433 : 0 : ev->fd = -1;
1434 : 0 : ev->epfd = -1;
1435 : 0 : }
1436 : :
1437 : : RTE_EXPORT_SYMBOL(rte_epoll_ctl)
1438 : : int
1439 : 0 : rte_epoll_ctl(int epfd, int op, int fd,
1440 : : struct rte_epoll_event *event)
1441 : : {
1442 : : struct epoll_event ev;
1443 : :
1444 [ # # ]: 0 : if (!event) {
1445 : 0 : EAL_LOG(ERR, "rte_epoll_event can't be NULL");
1446 : 0 : return -1;
1447 : : }
1448 : :
1449 : : /* using per thread epoll fd */
1450 [ # # ]: 0 : if (epfd == RTE_EPOLL_PER_THREAD)
1451 : 0 : epfd = rte_intr_tls_epfd();
1452 : :
1453 [ # # ]: 0 : if (op == EPOLL_CTL_ADD) {
1454 : 0 : rte_atomic_store_explicit(&event->status, RTE_EPOLL_VALID,
1455 : : rte_memory_order_relaxed);
1456 : 0 : event->fd = fd; /* ignore fd in event */
1457 : 0 : event->epfd = epfd;
1458 : 0 : ev.data.ptr = (void *)event;
1459 : : }
1460 : :
1461 : 0 : ev.events = event->epdata.event;
1462 [ # # ]: 0 : if (epoll_ctl(epfd, op, fd, &ev) < 0) {
1463 : 0 : EAL_LOG(ERR, "Error op %d fd %d epoll_ctl, %s",
1464 : : op, fd, strerror(errno));
1465 [ # # ]: 0 : if (op == EPOLL_CTL_ADD)
1466 : : /* rollback status when CTL_ADD fail */
1467 : 0 : rte_atomic_store_explicit(&event->status, RTE_EPOLL_INVALID,
1468 : : rte_memory_order_relaxed);
1469 : 0 : return -1;
1470 : : }
1471 : :
1472 [ # # # # ]: 0 : if (op == EPOLL_CTL_DEL && rte_atomic_load_explicit(&event->status,
1473 : : rte_memory_order_relaxed) != RTE_EPOLL_INVALID)
1474 : 0 : eal_epoll_data_safe_free(event);
1475 : :
1476 : : return 0;
1477 : : }
1478 : :
1479 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_rx_ctl)
1480 : : int
1481 : 0 : rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
1482 : : int op, unsigned int vec, void *data)
1483 : : {
1484 : : struct rte_epoll_event *rev;
1485 : : struct rte_epoll_data *epdata;
1486 : : int epfd_op;
1487 : : unsigned int efd_idx;
1488 : : int rc = 0;
1489 : :
1490 : : efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
1491 [ # # ]: 0 : (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
1492 : :
1493 [ # # # # ]: 0 : if (intr_handle == NULL || rte_intr_nb_efd_get(intr_handle) == 0 ||
1494 [ # # ]: 0 : efd_idx >= (unsigned int)rte_intr_nb_efd_get(intr_handle)) {
1495 : 0 : EAL_LOG(ERR, "Wrong intr vector number.");
1496 : 0 : return -EPERM;
1497 : : }
1498 : :
1499 [ # # # ]: 0 : switch (op) {
1500 : 0 : case RTE_INTR_EVENT_ADD:
1501 : : epfd_op = EPOLL_CTL_ADD;
1502 : 0 : rev = rte_intr_elist_index_get(intr_handle, efd_idx);
1503 [ # # ]: 0 : if (rte_atomic_load_explicit(&rev->status,
1504 : : rte_memory_order_relaxed) != RTE_EPOLL_INVALID) {
1505 : 0 : EAL_LOG(INFO, "Event already been added.");
1506 : 0 : return -EEXIST;
1507 : : }
1508 : :
1509 : : /* attach to intr vector fd */
1510 : : epdata = &rev->epdata;
1511 : 0 : epdata->event = EPOLLIN | EPOLLPRI | EPOLLET;
1512 : 0 : epdata->data = data;
1513 : 0 : epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
1514 : 0 : epdata->cb_arg = (void *)intr_handle;
1515 : 0 : rc = rte_epoll_ctl(epfd, epfd_op,
1516 : : rte_intr_efds_index_get(intr_handle, efd_idx), rev);
1517 [ # # ]: 0 : if (!rc)
1518 : 0 : EAL_LOG(DEBUG,
1519 : : "efd %d associated with vec %d added on epfd %d",
1520 : : rev->fd, vec, epfd);
1521 : : else
1522 : : rc = -EPERM;
1523 : : break;
1524 : 0 : case RTE_INTR_EVENT_DEL:
1525 : : epfd_op = EPOLL_CTL_DEL;
1526 : 0 : rev = rte_intr_elist_index_get(intr_handle, efd_idx);
1527 [ # # ]: 0 : if (rte_atomic_load_explicit(&rev->status,
1528 : : rte_memory_order_relaxed) == RTE_EPOLL_INVALID) {
1529 : 0 : EAL_LOG(INFO, "Event does not exist.");
1530 : 0 : return -EPERM;
1531 : : }
1532 : :
1533 : 0 : rc = rte_epoll_ctl(rev->epfd, epfd_op, rev->fd, rev);
1534 [ # # ]: 0 : if (rc)
1535 : : rc = -EPERM;
1536 : : break;
1537 : 0 : default:
1538 : 0 : EAL_LOG(ERR, "event op type mismatch");
1539 : : rc = -EPERM;
1540 : : }
1541 : :
1542 : : return rc;
1543 : : }
1544 : :
1545 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_free_epoll_fd)
1546 : : void
1547 : 8 : rte_intr_free_epoll_fd(struct rte_intr_handle *intr_handle)
1548 : : {
1549 : : uint32_t i;
1550 : : struct rte_epoll_event *rev;
1551 : :
1552 [ - + ]: 8 : for (i = 0; i < (uint32_t)rte_intr_nb_efd_get(intr_handle); i++) {
1553 : 0 : rev = rte_intr_elist_index_get(intr_handle, i);
1554 [ # # ]: 0 : if (rte_atomic_load_explicit(&rev->status,
1555 : : rte_memory_order_relaxed) == RTE_EPOLL_INVALID)
1556 : 0 : continue;
1557 [ # # ]: 0 : if (rte_epoll_ctl(rev->epfd, EPOLL_CTL_DEL, rev->fd, rev)) {
1558 : : /* force free if the entry valid */
1559 : 0 : eal_epoll_data_safe_free(rev);
1560 : : }
1561 : : }
1562 : 8 : }
1563 : :
1564 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_efd_enable)
1565 : : int
1566 : 0 : rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
1567 : : {
1568 : : uint32_t i;
1569 : : int fd;
1570 : 0 : uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);
1571 : :
1572 [ # # ]: 0 : assert(nb_efd != 0);
1573 : :
1574 [ # # ]: 0 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VFIO_MSIX) {
1575 [ # # ]: 0 : for (i = 0; i < n; i++) {
1576 : 0 : fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
1577 [ # # ]: 0 : if (fd < 0) {
1578 : 0 : EAL_LOG(ERR,
1579 : : "can't setup eventfd, error %i (%s)",
1580 : : errno, strerror(errno));
1581 : 0 : return -errno;
1582 : : }
1583 : :
1584 [ # # ]: 0 : if (rte_intr_efds_index_set(intr_handle, i, fd))
1585 : 0 : return -rte_errno;
1586 : : }
1587 : :
1588 [ # # ]: 0 : if (rte_intr_nb_efd_set(intr_handle, n))
1589 : 0 : return -rte_errno;
1590 : :
1591 [ # # ]: 0 : if (rte_intr_max_intr_set(intr_handle, NB_OTHER_INTR + n))
1592 : 0 : return -rte_errno;
1593 [ # # ]: 0 : } else if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
1594 : : /* only check, initialization would be done in vdev driver.*/
1595 [ # # ]: 0 : if ((uint64_t)rte_intr_efd_counter_size_get(intr_handle) >
1596 : : sizeof(union rte_intr_read_buffer)) {
1597 : 0 : EAL_LOG(ERR, "the efd_counter_size is oversized");
1598 : 0 : return -EINVAL;
1599 : : }
1600 : : } else {
1601 [ # # ]: 0 : if (rte_intr_efds_index_set(intr_handle, 0, rte_intr_fd_get(intr_handle)))
1602 : 0 : return -rte_errno;
1603 [ # # ]: 0 : if (rte_intr_nb_efd_set(intr_handle, RTE_MIN(nb_efd, 1U)))
1604 : 0 : return -rte_errno;
1605 [ # # ]: 0 : if (rte_intr_max_intr_set(intr_handle, NB_OTHER_INTR))
1606 : 0 : return -rte_errno;
1607 : : }
1608 : :
1609 : : return 0;
1610 : : }
1611 : :
1612 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_efd_disable)
1613 : : void
1614 : 0 : rte_intr_efd_disable(struct rte_intr_handle *intr_handle)
1615 : : {
1616 : : uint32_t i;
1617 : :
1618 : 0 : rte_intr_free_epoll_fd(intr_handle);
1619 [ # # ]: 0 : if (rte_intr_max_intr_get(intr_handle) > rte_intr_nb_efd_get(intr_handle)) {
1620 [ # # ]: 0 : for (i = 0; i < (uint32_t)rte_intr_nb_efd_get(intr_handle); i++)
1621 : 0 : close(rte_intr_efds_index_get(intr_handle, i));
1622 : : }
1623 : 0 : rte_intr_nb_efd_set(intr_handle, 0);
1624 : 0 : rte_intr_max_intr_set(intr_handle, 0);
1625 : 0 : }
1626 : :
1627 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_dp_is_en)
1628 : : int
1629 : 0 : rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
1630 : : {
1631 : 0 : return !(!rte_intr_nb_efd_get(intr_handle));
1632 : : }
1633 : :
1634 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_allow_others)
1635 : : int
1636 : 0 : rte_intr_allow_others(struct rte_intr_handle *intr_handle)
1637 : : {
1638 [ # # ]: 0 : if (!rte_intr_dp_is_en(intr_handle))
1639 : : return 1;
1640 : : else
1641 : 0 : return !!(rte_intr_max_intr_get(intr_handle) -
1642 : 0 : rte_intr_nb_efd_get(intr_handle));
1643 : : }
1644 : :
1645 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_cap_multiple)
1646 : : int
1647 : 0 : rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
1648 : : {
1649 [ # # ]: 0 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VFIO_MSIX)
1650 : : return 1;
1651 : :
1652 [ # # ]: 0 : if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV)
1653 : 0 : return 1;
1654 : :
1655 : : return 0;
1656 : : }
1657 : :
1658 : : RTE_EXPORT_SYMBOL(rte_thread_is_intr)
1659 : 0 : int rte_thread_is_intr(void)
1660 : : {
1661 : 0 : return rte_thread_equal(intr_thread, rte_thread_self());
1662 : : }
1663 : :
1664 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_intr_active_events_flags)
1665 : : uint32_t
1666 : 0 : rte_intr_active_events_flags(void)
1667 : : {
1668 [ # # ]: 0 : if (rte_thread_is_intr())
1669 : 0 : return active_events;
1670 : :
1671 : : return 0;
1672 : : }
|