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