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