199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation
399a2dd95SBruce Richardson */
499a2dd95SBruce Richardson
599a2dd95SBruce Richardson #include <stdio.h>
699a2dd95SBruce Richardson #include <stdint.h>
799a2dd95SBruce Richardson #include <stdlib.h>
899a2dd95SBruce Richardson #include <sys/queue.h>
999a2dd95SBruce Richardson #include <unistd.h>
1099a2dd95SBruce Richardson #include <string.h>
1199a2dd95SBruce Richardson #include <errno.h>
1299a2dd95SBruce Richardson #include <sys/epoll.h>
1399a2dd95SBruce Richardson #include <sys/ioctl.h>
1499a2dd95SBruce Richardson #include <sys/eventfd.h>
1599a2dd95SBruce Richardson #include <assert.h>
1699a2dd95SBruce Richardson #include <stdbool.h>
1799a2dd95SBruce Richardson
1845a685caSAnkur Dwivedi #include <eal_trace_internal.h>
1999a2dd95SBruce Richardson #include <rte_common.h>
2099a2dd95SBruce Richardson #include <rte_interrupts.h>
211c1abf17SThomas Monjalon #include <rte_thread.h>
2299a2dd95SBruce Richardson #include <rte_per_lcore.h>
2399a2dd95SBruce Richardson #include <rte_lcore.h>
2499a2dd95SBruce Richardson #include <rte_branch_prediction.h>
2599a2dd95SBruce Richardson #include <rte_debug.h>
2699a2dd95SBruce Richardson #include <rte_log.h>
2799a2dd95SBruce Richardson #include <rte_errno.h>
2899a2dd95SBruce Richardson #include <rte_spinlock.h>
2999a2dd95SBruce Richardson #include <rte_pause.h>
3099a2dd95SBruce Richardson #include <rte_vfio.h>
3199a2dd95SBruce Richardson
3299a2dd95SBruce Richardson #include "eal_private.h"
3399a2dd95SBruce Richardson
3499a2dd95SBruce Richardson #define EAL_INTR_EPOLL_WAIT_FOREVER (-1)
3599a2dd95SBruce Richardson #define NB_OTHER_INTR 1
3699a2dd95SBruce Richardson
3799a2dd95SBruce Richardson static RTE_DEFINE_PER_LCORE(int, _epfd) = -1; /**< epoll fd per thread */
3899a2dd95SBruce Richardson
3999a2dd95SBruce Richardson /**
4099a2dd95SBruce Richardson * union for pipe fds.
4199a2dd95SBruce Richardson */
4299a2dd95SBruce Richardson union intr_pipefds{
4399a2dd95SBruce Richardson struct {
4499a2dd95SBruce Richardson int pipefd[2];
4599a2dd95SBruce Richardson };
4699a2dd95SBruce Richardson struct {
4799a2dd95SBruce Richardson int readfd;
4899a2dd95SBruce Richardson int writefd;
4999a2dd95SBruce Richardson };
5099a2dd95SBruce Richardson };
5199a2dd95SBruce Richardson
5299a2dd95SBruce Richardson /**
5399a2dd95SBruce Richardson * union buffer for reading on different devices
5499a2dd95SBruce Richardson */
5599a2dd95SBruce Richardson union rte_intr_read_buffer {
5699a2dd95SBruce Richardson int uio_intr_count; /* for uio device */
5799a2dd95SBruce Richardson #ifdef VFIO_PRESENT
5899a2dd95SBruce Richardson uint64_t vfio_intr_count; /* for vfio device */
5999a2dd95SBruce Richardson #endif
6099a2dd95SBruce Richardson uint64_t timerfd_num; /* for timerfd */
6199a2dd95SBruce Richardson char charbuf[16]; /* for others */
6299a2dd95SBruce Richardson };
6399a2dd95SBruce Richardson
6499a2dd95SBruce Richardson TAILQ_HEAD(rte_intr_cb_list, rte_intr_callback);
6599a2dd95SBruce Richardson TAILQ_HEAD(rte_intr_source_list, rte_intr_source);
6699a2dd95SBruce Richardson
6799a2dd95SBruce Richardson struct rte_intr_callback {
6899a2dd95SBruce Richardson TAILQ_ENTRY(rte_intr_callback) next;
6999a2dd95SBruce Richardson rte_intr_callback_fn cb_fn; /**< callback address */
7099a2dd95SBruce Richardson void *cb_arg; /**< parameter for callback */
7199a2dd95SBruce Richardson uint8_t pending_delete; /**< delete after callback is called */
7299a2dd95SBruce Richardson rte_intr_unregister_callback_fn ucb_fn; /**< fn to call before cb is deleted */
7399a2dd95SBruce Richardson };
7499a2dd95SBruce Richardson
7599a2dd95SBruce Richardson struct rte_intr_source {
7699a2dd95SBruce Richardson TAILQ_ENTRY(rte_intr_source) next;
77bbbac4cdSHarman Kalra struct rte_intr_handle *intr_handle; /**< interrupt handle */
7899a2dd95SBruce Richardson struct rte_intr_cb_list callbacks; /**< user callbacks */
7999a2dd95SBruce Richardson uint32_t active;
8099a2dd95SBruce Richardson };
8199a2dd95SBruce Richardson
8299a2dd95SBruce Richardson /* global spinlock for interrupt data operation */
8399a2dd95SBruce Richardson static rte_spinlock_t intr_lock = RTE_SPINLOCK_INITIALIZER;
8499a2dd95SBruce Richardson
8599a2dd95SBruce Richardson /* union buffer for pipe read/write */
8699a2dd95SBruce Richardson static union intr_pipefds intr_pipe;
8799a2dd95SBruce Richardson
8899a2dd95SBruce Richardson /* interrupt sources list */
8999a2dd95SBruce Richardson static struct rte_intr_source_list intr_sources;
9099a2dd95SBruce Richardson
9199a2dd95SBruce Richardson /* interrupt handling thread */
921c1abf17SThomas Monjalon static rte_thread_t intr_thread;
9399a2dd95SBruce Richardson
9499a2dd95SBruce Richardson /* VFIO interrupts */
9599a2dd95SBruce Richardson #ifdef VFIO_PRESENT
9699a2dd95SBruce Richardson
9799a2dd95SBruce Richardson #define IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + sizeof(int))
9899a2dd95SBruce Richardson /* irq set buffer length for queue interrupts and LSC interrupt */
9999a2dd95SBruce Richardson #define MSIX_IRQ_SET_BUF_LEN (sizeof(struct vfio_irq_set) + \
10099a2dd95SBruce Richardson sizeof(int) * (RTE_MAX_RXTX_INTR_VEC_ID + 1))
10199a2dd95SBruce Richardson
10299a2dd95SBruce Richardson /* enable legacy (INTx) interrupts */
10399a2dd95SBruce Richardson static int
vfio_enable_intx(const struct rte_intr_handle * intr_handle)10499a2dd95SBruce Richardson vfio_enable_intx(const struct rte_intr_handle *intr_handle) {
10599a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
10699a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
107bbbac4cdSHarman Kalra int len, ret, vfio_dev_fd;
10899a2dd95SBruce Richardson int *fd_ptr;
10999a2dd95SBruce Richardson
11099a2dd95SBruce Richardson len = sizeof(irq_set_buf);
11199a2dd95SBruce Richardson
11299a2dd95SBruce Richardson /* enable INTx */
11399a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
11499a2dd95SBruce Richardson irq_set->argsz = len;
11599a2dd95SBruce Richardson irq_set->count = 1;
11699a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
11799a2dd95SBruce Richardson irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
11899a2dd95SBruce Richardson irq_set->start = 0;
11999a2dd95SBruce Richardson fd_ptr = (int *) &irq_set->data;
120bbbac4cdSHarman Kalra *fd_ptr = rte_intr_fd_get(intr_handle);
12199a2dd95SBruce Richardson
122bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
123bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
12499a2dd95SBruce Richardson
12599a2dd95SBruce Richardson if (ret) {
126*ae67895bSDavid Marchand EAL_LOG(ERR, "Error enabling INTx interrupts for fd %d",
127bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
12899a2dd95SBruce Richardson return -1;
12999a2dd95SBruce Richardson }
13099a2dd95SBruce Richardson
13199a2dd95SBruce Richardson /* unmask INTx after enabling */
13299a2dd95SBruce Richardson memset(irq_set, 0, len);
13399a2dd95SBruce Richardson len = sizeof(struct vfio_irq_set);
13499a2dd95SBruce Richardson irq_set->argsz = len;
13599a2dd95SBruce Richardson irq_set->count = 1;
13699a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
13799a2dd95SBruce Richardson irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
13899a2dd95SBruce Richardson irq_set->start = 0;
13999a2dd95SBruce Richardson
140bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
14199a2dd95SBruce Richardson
14299a2dd95SBruce Richardson if (ret) {
143*ae67895bSDavid Marchand EAL_LOG(ERR, "Error unmasking INTx interrupts for fd %d",
144bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
14599a2dd95SBruce Richardson return -1;
14699a2dd95SBruce Richardson }
14799a2dd95SBruce Richardson return 0;
14899a2dd95SBruce Richardson }
14999a2dd95SBruce Richardson
15099a2dd95SBruce Richardson /* disable legacy (INTx) interrupts */
15199a2dd95SBruce Richardson static int
vfio_disable_intx(const struct rte_intr_handle * intr_handle)15299a2dd95SBruce Richardson vfio_disable_intx(const struct rte_intr_handle *intr_handle) {
15399a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
15499a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
155bbbac4cdSHarman Kalra int len, ret, vfio_dev_fd;
15699a2dd95SBruce Richardson
15799a2dd95SBruce Richardson len = sizeof(struct vfio_irq_set);
15899a2dd95SBruce Richardson
15999a2dd95SBruce Richardson /* mask interrupts before disabling */
16099a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
16199a2dd95SBruce Richardson irq_set->argsz = len;
16299a2dd95SBruce Richardson irq_set->count = 1;
16399a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_MASK;
16499a2dd95SBruce Richardson irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
16599a2dd95SBruce Richardson irq_set->start = 0;
16699a2dd95SBruce Richardson
167bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
168bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
16999a2dd95SBruce Richardson
17099a2dd95SBruce Richardson if (ret) {
171*ae67895bSDavid Marchand EAL_LOG(ERR, "Error masking INTx interrupts for fd %d",
172bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
17399a2dd95SBruce Richardson return -1;
17499a2dd95SBruce Richardson }
17599a2dd95SBruce Richardson
17699a2dd95SBruce Richardson /* disable INTx*/
17799a2dd95SBruce Richardson memset(irq_set, 0, len);
17899a2dd95SBruce Richardson irq_set->argsz = len;
17999a2dd95SBruce Richardson irq_set->count = 0;
18099a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
18199a2dd95SBruce Richardson irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
18299a2dd95SBruce Richardson irq_set->start = 0;
18399a2dd95SBruce Richardson
184bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
18599a2dd95SBruce Richardson
18699a2dd95SBruce Richardson if (ret) {
187*ae67895bSDavid Marchand EAL_LOG(ERR, "Error disabling INTx interrupts for fd %d",
188bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
18999a2dd95SBruce Richardson return -1;
19099a2dd95SBruce Richardson }
19199a2dd95SBruce Richardson return 0;
19299a2dd95SBruce Richardson }
19399a2dd95SBruce Richardson
19499a2dd95SBruce Richardson /* unmask/ack legacy (INTx) interrupts */
19599a2dd95SBruce Richardson static int
vfio_ack_intx(const struct rte_intr_handle * intr_handle)19699a2dd95SBruce Richardson vfio_ack_intx(const struct rte_intr_handle *intr_handle)
19799a2dd95SBruce Richardson {
19899a2dd95SBruce Richardson struct vfio_irq_set irq_set;
199bbbac4cdSHarman Kalra int vfio_dev_fd;
20099a2dd95SBruce Richardson
20199a2dd95SBruce Richardson /* unmask INTx */
20299a2dd95SBruce Richardson memset(&irq_set, 0, sizeof(irq_set));
20399a2dd95SBruce Richardson irq_set.argsz = sizeof(irq_set);
20499a2dd95SBruce Richardson irq_set.count = 1;
20599a2dd95SBruce Richardson irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
20699a2dd95SBruce Richardson irq_set.index = VFIO_PCI_INTX_IRQ_INDEX;
20799a2dd95SBruce Richardson irq_set.start = 0;
20899a2dd95SBruce Richardson
209bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
210bbbac4cdSHarman Kalra if (ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, &irq_set)) {
211*ae67895bSDavid Marchand EAL_LOG(ERR, "Error unmasking INTx interrupts for fd %d",
212bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
21399a2dd95SBruce Richardson return -1;
21499a2dd95SBruce Richardson }
21599a2dd95SBruce Richardson return 0;
21699a2dd95SBruce Richardson }
21799a2dd95SBruce Richardson
21899a2dd95SBruce Richardson /* enable MSI interrupts */
21999a2dd95SBruce Richardson static int
vfio_enable_msi(const struct rte_intr_handle * intr_handle)22099a2dd95SBruce Richardson vfio_enable_msi(const struct rte_intr_handle *intr_handle) {
22199a2dd95SBruce Richardson int len, ret;
22299a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
22399a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
224bbbac4cdSHarman Kalra int *fd_ptr, vfio_dev_fd;
22599a2dd95SBruce Richardson
22699a2dd95SBruce Richardson len = sizeof(irq_set_buf);
22799a2dd95SBruce Richardson
22899a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
22999a2dd95SBruce Richardson irq_set->argsz = len;
23099a2dd95SBruce Richardson irq_set->count = 1;
23199a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
23299a2dd95SBruce Richardson irq_set->index = VFIO_PCI_MSI_IRQ_INDEX;
23399a2dd95SBruce Richardson irq_set->start = 0;
23499a2dd95SBruce Richardson fd_ptr = (int *) &irq_set->data;
235bbbac4cdSHarman Kalra *fd_ptr = rte_intr_fd_get(intr_handle);
23699a2dd95SBruce Richardson
237bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
238bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
23999a2dd95SBruce Richardson
24099a2dd95SBruce Richardson if (ret) {
241*ae67895bSDavid Marchand EAL_LOG(ERR, "Error enabling MSI interrupts for fd %d",
242bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
24399a2dd95SBruce Richardson return -1;
24499a2dd95SBruce Richardson }
24599a2dd95SBruce Richardson return 0;
24699a2dd95SBruce Richardson }
24799a2dd95SBruce Richardson
24899a2dd95SBruce Richardson /* disable MSI interrupts */
24999a2dd95SBruce Richardson static int
vfio_disable_msi(const struct rte_intr_handle * intr_handle)25099a2dd95SBruce Richardson vfio_disable_msi(const struct rte_intr_handle *intr_handle) {
25199a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
25299a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
253bbbac4cdSHarman Kalra int len, ret, vfio_dev_fd;
25499a2dd95SBruce Richardson
25599a2dd95SBruce Richardson len = sizeof(struct vfio_irq_set);
25699a2dd95SBruce Richardson
25799a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
25899a2dd95SBruce Richardson irq_set->argsz = len;
25999a2dd95SBruce Richardson irq_set->count = 0;
26099a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
26199a2dd95SBruce Richardson irq_set->index = VFIO_PCI_MSI_IRQ_INDEX;
26299a2dd95SBruce Richardson irq_set->start = 0;
26399a2dd95SBruce Richardson
264bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
265bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
26699a2dd95SBruce Richardson if (ret)
267*ae67895bSDavid Marchand EAL_LOG(ERR, "Error disabling MSI interrupts for fd %d",
268bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
26999a2dd95SBruce Richardson
27099a2dd95SBruce Richardson return ret;
27199a2dd95SBruce Richardson }
27299a2dd95SBruce Richardson
27399a2dd95SBruce Richardson /* enable MSI-X interrupts */
27499a2dd95SBruce Richardson static int
vfio_enable_msix(const struct rte_intr_handle * intr_handle)27599a2dd95SBruce Richardson vfio_enable_msix(const struct rte_intr_handle *intr_handle) {
27699a2dd95SBruce Richardson int len, ret;
27799a2dd95SBruce Richardson char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
27899a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
279bbbac4cdSHarman Kalra int *fd_ptr, vfio_dev_fd, i;
28099a2dd95SBruce Richardson
28199a2dd95SBruce Richardson len = sizeof(irq_set_buf);
28299a2dd95SBruce Richardson
28399a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
28499a2dd95SBruce Richardson irq_set->argsz = len;
28599a2dd95SBruce Richardson /* 0 < irq_set->count < RTE_MAX_RXTX_INTR_VEC_ID + 1 */
286bbbac4cdSHarman Kalra irq_set->count = rte_intr_max_intr_get(intr_handle) ?
287bbbac4cdSHarman Kalra (rte_intr_max_intr_get(intr_handle) >
288bbbac4cdSHarman Kalra RTE_MAX_RXTX_INTR_VEC_ID + 1 ? RTE_MAX_RXTX_INTR_VEC_ID + 1 :
289bbbac4cdSHarman Kalra rte_intr_max_intr_get(intr_handle)) : 1;
290bbbac4cdSHarman Kalra
29199a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
29299a2dd95SBruce Richardson irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
29399a2dd95SBruce Richardson irq_set->start = 0;
29499a2dd95SBruce Richardson fd_ptr = (int *) &irq_set->data;
29599a2dd95SBruce Richardson /* INTR vector offset 0 reserve for non-efds mapping */
296bbbac4cdSHarman Kalra fd_ptr[RTE_INTR_VEC_ZERO_OFFSET] = rte_intr_fd_get(intr_handle);
297bbbac4cdSHarman Kalra for (i = 0; i < rte_intr_nb_efd_get(intr_handle); i++) {
298bbbac4cdSHarman Kalra fd_ptr[RTE_INTR_VEC_RXTX_OFFSET + i] =
299bbbac4cdSHarman Kalra rte_intr_efds_index_get(intr_handle, i);
300bbbac4cdSHarman Kalra }
30199a2dd95SBruce Richardson
302bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
303bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
30499a2dd95SBruce Richardson
30599a2dd95SBruce Richardson if (ret) {
306*ae67895bSDavid Marchand EAL_LOG(ERR, "Error enabling MSI-X interrupts for fd %d",
307bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
30899a2dd95SBruce Richardson return -1;
30999a2dd95SBruce Richardson }
31099a2dd95SBruce Richardson
31199a2dd95SBruce Richardson return 0;
31299a2dd95SBruce Richardson }
31399a2dd95SBruce Richardson
31499a2dd95SBruce Richardson /* disable MSI-X interrupts */
31599a2dd95SBruce Richardson static int
vfio_disable_msix(const struct rte_intr_handle * intr_handle)31699a2dd95SBruce Richardson vfio_disable_msix(const struct rte_intr_handle *intr_handle) {
31799a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
31899a2dd95SBruce Richardson char irq_set_buf[MSIX_IRQ_SET_BUF_LEN];
319bbbac4cdSHarman Kalra int len, ret, vfio_dev_fd;
32099a2dd95SBruce Richardson
32199a2dd95SBruce Richardson len = sizeof(struct vfio_irq_set);
32299a2dd95SBruce Richardson
32399a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
32499a2dd95SBruce Richardson irq_set->argsz = len;
32599a2dd95SBruce Richardson irq_set->count = 0;
32699a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
32799a2dd95SBruce Richardson irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX;
32899a2dd95SBruce Richardson irq_set->start = 0;
32999a2dd95SBruce Richardson
330bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
331bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
33299a2dd95SBruce Richardson
33399a2dd95SBruce Richardson if (ret)
334*ae67895bSDavid Marchand EAL_LOG(ERR, "Error disabling MSI-X interrupts for fd %d",
335bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
33699a2dd95SBruce Richardson
33799a2dd95SBruce Richardson return ret;
33899a2dd95SBruce Richardson }
33999a2dd95SBruce Richardson
34099a2dd95SBruce Richardson #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
34199a2dd95SBruce Richardson /* enable req notifier */
34299a2dd95SBruce Richardson static int
vfio_enable_req(const struct rte_intr_handle * intr_handle)34399a2dd95SBruce Richardson vfio_enable_req(const struct rte_intr_handle *intr_handle)
34499a2dd95SBruce Richardson {
34599a2dd95SBruce Richardson int len, ret;
34699a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
34799a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
348bbbac4cdSHarman Kalra int *fd_ptr, vfio_dev_fd;
34999a2dd95SBruce Richardson
35099a2dd95SBruce Richardson len = sizeof(irq_set_buf);
35199a2dd95SBruce Richardson
35299a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
35399a2dd95SBruce Richardson irq_set->argsz = len;
35499a2dd95SBruce Richardson irq_set->count = 1;
35599a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD |
35699a2dd95SBruce Richardson VFIO_IRQ_SET_ACTION_TRIGGER;
35799a2dd95SBruce Richardson irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
35899a2dd95SBruce Richardson irq_set->start = 0;
35999a2dd95SBruce Richardson fd_ptr = (int *) &irq_set->data;
360bbbac4cdSHarman Kalra *fd_ptr = rte_intr_fd_get(intr_handle);
36199a2dd95SBruce Richardson
362bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
363bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
36499a2dd95SBruce Richardson
36599a2dd95SBruce Richardson if (ret) {
366*ae67895bSDavid Marchand EAL_LOG(ERR, "Error enabling req interrupts for fd %d",
367bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
36899a2dd95SBruce Richardson return -1;
36999a2dd95SBruce Richardson }
37099a2dd95SBruce Richardson
37199a2dd95SBruce Richardson return 0;
37299a2dd95SBruce Richardson }
37399a2dd95SBruce Richardson
37499a2dd95SBruce Richardson /* disable req notifier */
37599a2dd95SBruce Richardson static int
vfio_disable_req(const struct rte_intr_handle * intr_handle)37699a2dd95SBruce Richardson vfio_disable_req(const struct rte_intr_handle *intr_handle)
37799a2dd95SBruce Richardson {
37899a2dd95SBruce Richardson struct vfio_irq_set *irq_set;
37999a2dd95SBruce Richardson char irq_set_buf[IRQ_SET_BUF_LEN];
380bbbac4cdSHarman Kalra int len, ret, vfio_dev_fd;
38199a2dd95SBruce Richardson
38299a2dd95SBruce Richardson len = sizeof(struct vfio_irq_set);
38399a2dd95SBruce Richardson
38499a2dd95SBruce Richardson irq_set = (struct vfio_irq_set *) irq_set_buf;
38599a2dd95SBruce Richardson irq_set->argsz = len;
38699a2dd95SBruce Richardson irq_set->count = 0;
38799a2dd95SBruce Richardson irq_set->flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_TRIGGER;
38899a2dd95SBruce Richardson irq_set->index = VFIO_PCI_REQ_IRQ_INDEX;
38999a2dd95SBruce Richardson irq_set->start = 0;
39099a2dd95SBruce Richardson
391bbbac4cdSHarman Kalra vfio_dev_fd = rte_intr_dev_fd_get(intr_handle);
392bbbac4cdSHarman Kalra ret = ioctl(vfio_dev_fd, VFIO_DEVICE_SET_IRQS, irq_set);
39399a2dd95SBruce Richardson
39499a2dd95SBruce Richardson if (ret)
395*ae67895bSDavid Marchand EAL_LOG(ERR, "Error disabling req interrupts for fd %d",
396bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
39799a2dd95SBruce Richardson
39899a2dd95SBruce Richardson return ret;
39999a2dd95SBruce Richardson }
40099a2dd95SBruce Richardson #endif
40199a2dd95SBruce Richardson #endif
40299a2dd95SBruce Richardson
40399a2dd95SBruce Richardson static int
uio_intx_intr_disable(const struct rte_intr_handle * intr_handle)40499a2dd95SBruce Richardson uio_intx_intr_disable(const struct rte_intr_handle *intr_handle)
40599a2dd95SBruce Richardson {
40699a2dd95SBruce Richardson unsigned char command_high;
407bbbac4cdSHarman Kalra int uio_cfg_fd;
40899a2dd95SBruce Richardson
40999a2dd95SBruce Richardson /* use UIO config file descriptor for uio_pci_generic */
410bbbac4cdSHarman Kalra uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
4113fcca9faSHarman Kalra if (uio_cfg_fd < 0 || pread(uio_cfg_fd, &command_high, 1, 5) != 1) {
412*ae67895bSDavid Marchand EAL_LOG(ERR,
413*ae67895bSDavid Marchand "Error reading interrupts status for fd %d",
414bbbac4cdSHarman Kalra uio_cfg_fd);
41599a2dd95SBruce Richardson return -1;
41699a2dd95SBruce Richardson }
41799a2dd95SBruce Richardson /* disable interrupts */
41899a2dd95SBruce Richardson command_high |= 0x4;
419bbbac4cdSHarman Kalra if (pwrite(uio_cfg_fd, &command_high, 1, 5) != 1) {
420*ae67895bSDavid Marchand EAL_LOG(ERR,
421*ae67895bSDavid Marchand "Error disabling interrupts for fd %d",
422bbbac4cdSHarman Kalra uio_cfg_fd);
42399a2dd95SBruce Richardson return -1;
42499a2dd95SBruce Richardson }
42599a2dd95SBruce Richardson
42699a2dd95SBruce Richardson return 0;
42799a2dd95SBruce Richardson }
42899a2dd95SBruce Richardson
42999a2dd95SBruce Richardson static int
uio_intx_intr_enable(const struct rte_intr_handle * intr_handle)43099a2dd95SBruce Richardson uio_intx_intr_enable(const struct rte_intr_handle *intr_handle)
43199a2dd95SBruce Richardson {
43299a2dd95SBruce Richardson unsigned char command_high;
433bbbac4cdSHarman Kalra int uio_cfg_fd;
43499a2dd95SBruce Richardson
43599a2dd95SBruce Richardson /* use UIO config file descriptor for uio_pci_generic */
436bbbac4cdSHarman Kalra uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
4373fcca9faSHarman Kalra if (uio_cfg_fd < 0 || pread(uio_cfg_fd, &command_high, 1, 5) != 1) {
438*ae67895bSDavid Marchand EAL_LOG(ERR,
439*ae67895bSDavid Marchand "Error reading interrupts status for fd %d",
440bbbac4cdSHarman Kalra uio_cfg_fd);
44199a2dd95SBruce Richardson return -1;
44299a2dd95SBruce Richardson }
44399a2dd95SBruce Richardson /* enable interrupts */
44499a2dd95SBruce Richardson command_high &= ~0x4;
445bbbac4cdSHarman Kalra if (pwrite(uio_cfg_fd, &command_high, 1, 5) != 1) {
446*ae67895bSDavid Marchand EAL_LOG(ERR,
447*ae67895bSDavid Marchand "Error enabling interrupts for fd %d",
448bbbac4cdSHarman Kalra uio_cfg_fd);
44999a2dd95SBruce Richardson return -1;
45099a2dd95SBruce Richardson }
45199a2dd95SBruce Richardson
45299a2dd95SBruce Richardson return 0;
45399a2dd95SBruce Richardson }
45499a2dd95SBruce Richardson
45599a2dd95SBruce Richardson static int
uio_intr_disable(const struct rte_intr_handle * intr_handle)45699a2dd95SBruce Richardson uio_intr_disable(const struct rte_intr_handle *intr_handle)
45799a2dd95SBruce Richardson {
45899a2dd95SBruce Richardson const int value = 0;
45999a2dd95SBruce Richardson
4603fcca9faSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 ||
4613fcca9faSHarman Kalra write(rte_intr_fd_get(intr_handle), &value, sizeof(value)) < 0) {
462*ae67895bSDavid Marchand EAL_LOG(ERR, "Error disabling interrupts for fd %d (%s)",
463bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle), strerror(errno));
46499a2dd95SBruce Richardson return -1;
46599a2dd95SBruce Richardson }
46699a2dd95SBruce Richardson return 0;
46799a2dd95SBruce Richardson }
46899a2dd95SBruce Richardson
46999a2dd95SBruce Richardson static int
uio_intr_enable(const struct rte_intr_handle * intr_handle)47099a2dd95SBruce Richardson uio_intr_enable(const struct rte_intr_handle *intr_handle)
47199a2dd95SBruce Richardson {
47299a2dd95SBruce Richardson const int value = 1;
47399a2dd95SBruce Richardson
4743fcca9faSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 ||
4753fcca9faSHarman Kalra write(rte_intr_fd_get(intr_handle), &value, sizeof(value)) < 0) {
476*ae67895bSDavid Marchand EAL_LOG(ERR, "Error enabling interrupts for fd %d (%s)",
477bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle), strerror(errno));
47899a2dd95SBruce Richardson return -1;
47999a2dd95SBruce Richardson }
48099a2dd95SBruce Richardson return 0;
48199a2dd95SBruce Richardson }
48299a2dd95SBruce Richardson
48399a2dd95SBruce Richardson int
rte_intr_callback_register(const struct rte_intr_handle * intr_handle,rte_intr_callback_fn cb,void * cb_arg)48499a2dd95SBruce Richardson rte_intr_callback_register(const struct rte_intr_handle *intr_handle,
48599a2dd95SBruce Richardson rte_intr_callback_fn cb, void *cb_arg)
48699a2dd95SBruce Richardson {
48799a2dd95SBruce Richardson int ret, wake_thread;
48899a2dd95SBruce Richardson struct rte_intr_source *src;
48999a2dd95SBruce Richardson struct rte_intr_callback *callback;
49099a2dd95SBruce Richardson
49199a2dd95SBruce Richardson wake_thread = 0;
49299a2dd95SBruce Richardson
49399a2dd95SBruce Richardson /* first do parameter checking */
494bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 || cb == NULL) {
495*ae67895bSDavid Marchand EAL_LOG(ERR, "Registering with invalid input parameter");
49699a2dd95SBruce Richardson return -EINVAL;
49799a2dd95SBruce Richardson }
49899a2dd95SBruce Richardson
49999a2dd95SBruce Richardson /* allocate a new interrupt callback entity */
50099a2dd95SBruce Richardson callback = calloc(1, sizeof(*callback));
50199a2dd95SBruce Richardson if (callback == NULL) {
502*ae67895bSDavid Marchand EAL_LOG(ERR, "Can not allocate memory");
50399a2dd95SBruce Richardson return -ENOMEM;
50499a2dd95SBruce Richardson }
50599a2dd95SBruce Richardson callback->cb_fn = cb;
50699a2dd95SBruce Richardson callback->cb_arg = cb_arg;
50799a2dd95SBruce Richardson callback->pending_delete = 0;
50899a2dd95SBruce Richardson callback->ucb_fn = NULL;
50999a2dd95SBruce Richardson
51099a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
51199a2dd95SBruce Richardson
51299a2dd95SBruce Richardson /* check if there is at least one callback registered for the fd */
51399a2dd95SBruce Richardson TAILQ_FOREACH(src, &intr_sources, next) {
514bbbac4cdSHarman Kalra if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle)) {
51599a2dd95SBruce Richardson /* we had no interrupts for this */
51699a2dd95SBruce Richardson if (TAILQ_EMPTY(&src->callbacks))
51799a2dd95SBruce Richardson wake_thread = 1;
51899a2dd95SBruce Richardson
51999a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&(src->callbacks), callback, next);
52099a2dd95SBruce Richardson ret = 0;
52199a2dd95SBruce Richardson break;
52299a2dd95SBruce Richardson }
52399a2dd95SBruce Richardson }
52499a2dd95SBruce Richardson
52599a2dd95SBruce Richardson /* no existing callbacks for this - add new source */
52699a2dd95SBruce Richardson if (src == NULL) {
52799a2dd95SBruce Richardson src = calloc(1, sizeof(*src));
52899a2dd95SBruce Richardson if (src == NULL) {
529*ae67895bSDavid Marchand EAL_LOG(ERR, "Can not allocate memory");
53099a2dd95SBruce Richardson ret = -ENOMEM;
531bbbac4cdSHarman Kalra free(callback);
532bbbac4cdSHarman Kalra callback = NULL;
53399a2dd95SBruce Richardson } else {
534bbbac4cdSHarman Kalra src->intr_handle = rte_intr_instance_dup(intr_handle);
535bbbac4cdSHarman Kalra if (src->intr_handle == NULL) {
536*ae67895bSDavid Marchand EAL_LOG(ERR, "Can not create intr instance");
537bbbac4cdSHarman Kalra ret = -ENOMEM;
538bbbac4cdSHarman Kalra free(callback);
539bbbac4cdSHarman Kalra callback = NULL;
540bbbac4cdSHarman Kalra free(src);
541bbbac4cdSHarman Kalra src = NULL;
542bbbac4cdSHarman Kalra } else {
54399a2dd95SBruce Richardson TAILQ_INIT(&src->callbacks);
544bbbac4cdSHarman Kalra TAILQ_INSERT_TAIL(&(src->callbacks), callback,
545bbbac4cdSHarman Kalra next);
54699a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&intr_sources, src, next);
54799a2dd95SBruce Richardson wake_thread = 1;
54899a2dd95SBruce Richardson ret = 0;
54999a2dd95SBruce Richardson }
55099a2dd95SBruce Richardson }
551bbbac4cdSHarman Kalra }
55299a2dd95SBruce Richardson
55399a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
55499a2dd95SBruce Richardson
55599a2dd95SBruce Richardson /**
55699a2dd95SBruce Richardson * check if need to notify the pipe fd waited by epoll_wait to
55799a2dd95SBruce Richardson * rebuild the wait list.
55899a2dd95SBruce Richardson */
55999a2dd95SBruce Richardson if (wake_thread)
56099a2dd95SBruce Richardson if (write(intr_pipe.writefd, "1", 1) < 0)
56199a2dd95SBruce Richardson ret = -EPIPE;
56299a2dd95SBruce Richardson
56399a2dd95SBruce Richardson rte_eal_trace_intr_callback_register(intr_handle, cb, cb_arg, ret);
56499a2dd95SBruce Richardson return ret;
56599a2dd95SBruce Richardson }
56699a2dd95SBruce Richardson
56799a2dd95SBruce Richardson int
rte_intr_callback_unregister_pending(const struct rte_intr_handle * intr_handle,rte_intr_callback_fn cb_fn,void * cb_arg,rte_intr_unregister_callback_fn ucb_fn)56899a2dd95SBruce Richardson rte_intr_callback_unregister_pending(const struct rte_intr_handle *intr_handle,
56999a2dd95SBruce Richardson rte_intr_callback_fn cb_fn, void *cb_arg,
57099a2dd95SBruce Richardson rte_intr_unregister_callback_fn ucb_fn)
57199a2dd95SBruce Richardson {
57299a2dd95SBruce Richardson int ret;
57399a2dd95SBruce Richardson struct rte_intr_source *src;
57499a2dd95SBruce Richardson struct rte_intr_callback *cb, *next;
57599a2dd95SBruce Richardson
57699a2dd95SBruce Richardson /* do parameter checking first */
577bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0) {
578*ae67895bSDavid Marchand EAL_LOG(ERR, "Unregistering with invalid input parameter");
57999a2dd95SBruce Richardson return -EINVAL;
58099a2dd95SBruce Richardson }
58199a2dd95SBruce Richardson
58299a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
58399a2dd95SBruce Richardson
5847be78d02SJosh Soref /* check if the interrupt source for the fd is existent */
585bbbac4cdSHarman Kalra TAILQ_FOREACH(src, &intr_sources, next) {
586bbbac4cdSHarman Kalra if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle))
58799a2dd95SBruce Richardson break;
588bbbac4cdSHarman Kalra }
58999a2dd95SBruce Richardson
59099a2dd95SBruce Richardson /* No interrupt source registered for the fd */
59199a2dd95SBruce Richardson if (src == NULL) {
59299a2dd95SBruce Richardson ret = -ENOENT;
59399a2dd95SBruce Richardson
59499a2dd95SBruce Richardson /* only usable if the source is active */
59599a2dd95SBruce Richardson } else if (src->active == 0) {
59699a2dd95SBruce Richardson ret = -EAGAIN;
59799a2dd95SBruce Richardson
59899a2dd95SBruce Richardson } else {
59999a2dd95SBruce Richardson ret = 0;
60099a2dd95SBruce Richardson
60199a2dd95SBruce Richardson /* walk through the callbacks and mark all that match. */
60299a2dd95SBruce Richardson for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
60399a2dd95SBruce Richardson next = TAILQ_NEXT(cb, next);
60499a2dd95SBruce Richardson if (cb->cb_fn == cb_fn && (cb_arg == (void *)-1 ||
60599a2dd95SBruce Richardson cb->cb_arg == cb_arg)) {
60699a2dd95SBruce Richardson cb->pending_delete = 1;
60799a2dd95SBruce Richardson cb->ucb_fn = ucb_fn;
60899a2dd95SBruce Richardson ret++;
60999a2dd95SBruce Richardson }
61099a2dd95SBruce Richardson }
61199a2dd95SBruce Richardson }
61299a2dd95SBruce Richardson
61399a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
61499a2dd95SBruce Richardson
61599a2dd95SBruce Richardson return ret;
61699a2dd95SBruce Richardson }
61799a2dd95SBruce Richardson
61899a2dd95SBruce Richardson int
rte_intr_callback_unregister(const struct rte_intr_handle * intr_handle,rte_intr_callback_fn cb_fn,void * cb_arg)61999a2dd95SBruce Richardson rte_intr_callback_unregister(const struct rte_intr_handle *intr_handle,
62099a2dd95SBruce Richardson rte_intr_callback_fn cb_fn, void *cb_arg)
62199a2dd95SBruce Richardson {
62299a2dd95SBruce Richardson int ret;
62399a2dd95SBruce Richardson struct rte_intr_source *src;
62499a2dd95SBruce Richardson struct rte_intr_callback *cb, *next;
62599a2dd95SBruce Richardson
62699a2dd95SBruce Richardson /* do parameter checking first */
627bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0) {
628*ae67895bSDavid Marchand EAL_LOG(ERR, "Unregistering with invalid input parameter");
62999a2dd95SBruce Richardson return -EINVAL;
63099a2dd95SBruce Richardson }
63199a2dd95SBruce Richardson
63299a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
63399a2dd95SBruce Richardson
6347be78d02SJosh Soref /* check if the interrupt source for the fd is existent */
63599a2dd95SBruce Richardson TAILQ_FOREACH(src, &intr_sources, next)
636bbbac4cdSHarman Kalra if (rte_intr_fd_get(src->intr_handle) == rte_intr_fd_get(intr_handle))
63799a2dd95SBruce Richardson break;
63899a2dd95SBruce Richardson
63999a2dd95SBruce Richardson /* No interrupt source registered for the fd */
64099a2dd95SBruce Richardson if (src == NULL) {
64199a2dd95SBruce Richardson ret = -ENOENT;
64299a2dd95SBruce Richardson
64399a2dd95SBruce Richardson /* interrupt source has some active callbacks right now. */
64499a2dd95SBruce Richardson } else if (src->active != 0) {
64599a2dd95SBruce Richardson ret = -EAGAIN;
64699a2dd95SBruce Richardson
64799a2dd95SBruce Richardson /* ok to remove. */
64899a2dd95SBruce Richardson } else {
64999a2dd95SBruce Richardson ret = 0;
65099a2dd95SBruce Richardson
65199a2dd95SBruce Richardson /*walk through the callbacks and remove all that match. */
65299a2dd95SBruce Richardson for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
65399a2dd95SBruce Richardson
65499a2dd95SBruce Richardson next = TAILQ_NEXT(cb, next);
65599a2dd95SBruce Richardson
65699a2dd95SBruce Richardson if (cb->cb_fn == cb_fn && (cb_arg == (void *)-1 ||
65799a2dd95SBruce Richardson cb->cb_arg == cb_arg)) {
65899a2dd95SBruce Richardson TAILQ_REMOVE(&src->callbacks, cb, next);
65999a2dd95SBruce Richardson free(cb);
66099a2dd95SBruce Richardson ret++;
66199a2dd95SBruce Richardson }
66299a2dd95SBruce Richardson }
66399a2dd95SBruce Richardson
66499a2dd95SBruce Richardson /* all callbacks for that source are removed. */
66599a2dd95SBruce Richardson if (TAILQ_EMPTY(&src->callbacks)) {
66699a2dd95SBruce Richardson TAILQ_REMOVE(&intr_sources, src, next);
667bbbac4cdSHarman Kalra rte_intr_instance_free(src->intr_handle);
66899a2dd95SBruce Richardson free(src);
66999a2dd95SBruce Richardson }
67099a2dd95SBruce Richardson }
67199a2dd95SBruce Richardson
67299a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
67399a2dd95SBruce Richardson
67499a2dd95SBruce Richardson /* notify the pipe fd waited by epoll_wait to rebuild the wait list */
67599a2dd95SBruce Richardson if (ret >= 0 && write(intr_pipe.writefd, "1", 1) < 0) {
67699a2dd95SBruce Richardson ret = -EPIPE;
67799a2dd95SBruce Richardson }
67899a2dd95SBruce Richardson
67999a2dd95SBruce Richardson rte_eal_trace_intr_callback_unregister(intr_handle, cb_fn, cb_arg,
68099a2dd95SBruce Richardson ret);
68199a2dd95SBruce Richardson return ret;
68299a2dd95SBruce Richardson }
68399a2dd95SBruce Richardson
68499a2dd95SBruce Richardson int
rte_intr_callback_unregister_sync(const struct rte_intr_handle * intr_handle,rte_intr_callback_fn cb_fn,void * cb_arg)68599a2dd95SBruce Richardson rte_intr_callback_unregister_sync(const struct rte_intr_handle *intr_handle,
68699a2dd95SBruce Richardson rte_intr_callback_fn cb_fn, void *cb_arg)
68799a2dd95SBruce Richardson {
68899a2dd95SBruce Richardson int ret = 0;
68999a2dd95SBruce Richardson
69099a2dd95SBruce Richardson while ((ret = rte_intr_callback_unregister(intr_handle, cb_fn, cb_arg)) == -EAGAIN)
69199a2dd95SBruce Richardson rte_pause();
69299a2dd95SBruce Richardson
69399a2dd95SBruce Richardson return ret;
69499a2dd95SBruce Richardson }
69599a2dd95SBruce Richardson
69699a2dd95SBruce Richardson int
rte_intr_enable(const struct rte_intr_handle * intr_handle)69799a2dd95SBruce Richardson rte_intr_enable(const struct rte_intr_handle *intr_handle)
69899a2dd95SBruce Richardson {
699bbbac4cdSHarman Kalra int rc = 0, uio_cfg_fd;
70099a2dd95SBruce Richardson
70199a2dd95SBruce Richardson if (intr_handle == NULL)
70299a2dd95SBruce Richardson return -1;
70399a2dd95SBruce Richardson
704bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
70599a2dd95SBruce Richardson rc = 0;
70699a2dd95SBruce Richardson goto out;
70799a2dd95SBruce Richardson }
70899a2dd95SBruce Richardson
709bbbac4cdSHarman Kalra uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
710bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0) {
71199a2dd95SBruce Richardson rc = -1;
71299a2dd95SBruce Richardson goto out;
71399a2dd95SBruce Richardson }
71499a2dd95SBruce Richardson
715bbbac4cdSHarman Kalra switch (rte_intr_type_get(intr_handle)) {
71699a2dd95SBruce Richardson /* write to the uio fd to enable the interrupt */
71799a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO:
71899a2dd95SBruce Richardson if (uio_intr_enable(intr_handle))
71999a2dd95SBruce Richardson rc = -1;
72099a2dd95SBruce Richardson break;
72199a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO_INTX:
72299a2dd95SBruce Richardson if (uio_intx_intr_enable(intr_handle))
72399a2dd95SBruce Richardson rc = -1;
72499a2dd95SBruce Richardson break;
72599a2dd95SBruce Richardson /* not used at this moment */
72699a2dd95SBruce Richardson case RTE_INTR_HANDLE_ALARM:
72799a2dd95SBruce Richardson rc = -1;
72899a2dd95SBruce Richardson break;
72999a2dd95SBruce Richardson #ifdef VFIO_PRESENT
73099a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSIX:
73199a2dd95SBruce Richardson if (vfio_enable_msix(intr_handle))
73299a2dd95SBruce Richardson rc = -1;
73399a2dd95SBruce Richardson break;
73499a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSI:
73599a2dd95SBruce Richardson if (vfio_enable_msi(intr_handle))
73699a2dd95SBruce Richardson rc = -1;
73799a2dd95SBruce Richardson break;
73899a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_LEGACY:
73999a2dd95SBruce Richardson if (vfio_enable_intx(intr_handle))
74099a2dd95SBruce Richardson rc = -1;
74199a2dd95SBruce Richardson break;
74299a2dd95SBruce Richardson #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
74399a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_REQ:
74499a2dd95SBruce Richardson if (vfio_enable_req(intr_handle))
74599a2dd95SBruce Richardson rc = -1;
74699a2dd95SBruce Richardson break;
74799a2dd95SBruce Richardson #endif
74899a2dd95SBruce Richardson #endif
74999a2dd95SBruce Richardson /* not used at this moment */
75099a2dd95SBruce Richardson case RTE_INTR_HANDLE_DEV_EVENT:
75199a2dd95SBruce Richardson rc = -1;
75299a2dd95SBruce Richardson break;
75399a2dd95SBruce Richardson /* unknown handle type */
75499a2dd95SBruce Richardson default:
755*ae67895bSDavid Marchand EAL_LOG(ERR, "Unknown handle type of fd %d",
756bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
75799a2dd95SBruce Richardson rc = -1;
75899a2dd95SBruce Richardson break;
75999a2dd95SBruce Richardson }
76099a2dd95SBruce Richardson out:
76199a2dd95SBruce Richardson rte_eal_trace_intr_enable(intr_handle, rc);
76299a2dd95SBruce Richardson return rc;
76399a2dd95SBruce Richardson }
76499a2dd95SBruce Richardson
76599a2dd95SBruce Richardson /**
76699a2dd95SBruce Richardson * PMD generally calls this function at the end of its IRQ callback.
76799a2dd95SBruce Richardson * Internally, it unmasks the interrupt if possible.
76899a2dd95SBruce Richardson *
76999a2dd95SBruce Richardson * For INTx, unmasking is required as the interrupt is auto-masked prior to
77099a2dd95SBruce Richardson * invoking callback.
77199a2dd95SBruce Richardson *
77299a2dd95SBruce Richardson * For MSI/MSI-X, unmasking is typically not needed as the interrupt is not
77399a2dd95SBruce Richardson * auto-masked. In fact, for interrupt handle types VFIO_MSIX and VFIO_MSI,
77499a2dd95SBruce Richardson * this function is no-op.
77599a2dd95SBruce Richardson */
77699a2dd95SBruce Richardson int
rte_intr_ack(const struct rte_intr_handle * intr_handle)77799a2dd95SBruce Richardson rte_intr_ack(const struct rte_intr_handle *intr_handle)
77899a2dd95SBruce Richardson {
779bbbac4cdSHarman Kalra int uio_cfg_fd;
780bbbac4cdSHarman Kalra
781bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV)
78299a2dd95SBruce Richardson return 0;
78399a2dd95SBruce Richardson
784bbbac4cdSHarman Kalra uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
785bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0)
78699a2dd95SBruce Richardson return -1;
78799a2dd95SBruce Richardson
788bbbac4cdSHarman Kalra switch (rte_intr_type_get(intr_handle)) {
78999a2dd95SBruce Richardson /* Both acking and enabling are same for UIO */
79099a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO:
79199a2dd95SBruce Richardson if (uio_intr_enable(intr_handle))
79299a2dd95SBruce Richardson return -1;
79399a2dd95SBruce Richardson break;
79499a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO_INTX:
79599a2dd95SBruce Richardson if (uio_intx_intr_enable(intr_handle))
79699a2dd95SBruce Richardson return -1;
79799a2dd95SBruce Richardson break;
79899a2dd95SBruce Richardson /* not used at this moment */
79999a2dd95SBruce Richardson case RTE_INTR_HANDLE_ALARM:
80099a2dd95SBruce Richardson return -1;
80199a2dd95SBruce Richardson #ifdef VFIO_PRESENT
80299a2dd95SBruce Richardson /* VFIO MSI* is implicitly acked unlike INTx, nothing to do */
80399a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSIX:
80499a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSI:
80599a2dd95SBruce Richardson return 0;
80699a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_LEGACY:
80799a2dd95SBruce Richardson if (vfio_ack_intx(intr_handle))
80899a2dd95SBruce Richardson return -1;
80999a2dd95SBruce Richardson break;
81099a2dd95SBruce Richardson #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
81199a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_REQ:
81299a2dd95SBruce Richardson return -1;
81399a2dd95SBruce Richardson #endif
81499a2dd95SBruce Richardson #endif
81599a2dd95SBruce Richardson /* not used at this moment */
81699a2dd95SBruce Richardson case RTE_INTR_HANDLE_DEV_EVENT:
81799a2dd95SBruce Richardson return -1;
81899a2dd95SBruce Richardson /* unknown handle type */
81999a2dd95SBruce Richardson default:
820*ae67895bSDavid Marchand EAL_LOG(ERR, "Unknown handle type of fd %d",
821bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
82299a2dd95SBruce Richardson return -1;
82399a2dd95SBruce Richardson }
82499a2dd95SBruce Richardson
82599a2dd95SBruce Richardson return 0;
82699a2dd95SBruce Richardson }
82799a2dd95SBruce Richardson
82899a2dd95SBruce Richardson int
rte_intr_disable(const struct rte_intr_handle * intr_handle)82999a2dd95SBruce Richardson rte_intr_disable(const struct rte_intr_handle *intr_handle)
83099a2dd95SBruce Richardson {
831bbbac4cdSHarman Kalra int rc = 0, uio_cfg_fd;
83299a2dd95SBruce Richardson
83399a2dd95SBruce Richardson if (intr_handle == NULL)
83499a2dd95SBruce Richardson return -1;
83599a2dd95SBruce Richardson
836bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
83799a2dd95SBruce Richardson rc = 0;
83899a2dd95SBruce Richardson goto out;
83999a2dd95SBruce Richardson }
84099a2dd95SBruce Richardson
841bbbac4cdSHarman Kalra uio_cfg_fd = rte_intr_dev_fd_get(intr_handle);
842bbbac4cdSHarman Kalra if (rte_intr_fd_get(intr_handle) < 0 || uio_cfg_fd < 0) {
84399a2dd95SBruce Richardson rc = -1;
84499a2dd95SBruce Richardson goto out;
84599a2dd95SBruce Richardson }
84699a2dd95SBruce Richardson
847bbbac4cdSHarman Kalra switch (rte_intr_type_get(intr_handle)) {
84899a2dd95SBruce Richardson /* write to the uio fd to disable the interrupt */
84999a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO:
85099a2dd95SBruce Richardson if (uio_intr_disable(intr_handle))
85199a2dd95SBruce Richardson rc = -1;
85299a2dd95SBruce Richardson break;
85399a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO_INTX:
85499a2dd95SBruce Richardson if (uio_intx_intr_disable(intr_handle))
85599a2dd95SBruce Richardson rc = -1;
85699a2dd95SBruce Richardson break;
85799a2dd95SBruce Richardson /* not used at this moment */
85899a2dd95SBruce Richardson case RTE_INTR_HANDLE_ALARM:
85999a2dd95SBruce Richardson rc = -1;
86099a2dd95SBruce Richardson break;
86199a2dd95SBruce Richardson #ifdef VFIO_PRESENT
86299a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSIX:
86399a2dd95SBruce Richardson if (vfio_disable_msix(intr_handle))
86499a2dd95SBruce Richardson rc = -1;
86599a2dd95SBruce Richardson break;
86699a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSI:
86799a2dd95SBruce Richardson if (vfio_disable_msi(intr_handle))
86899a2dd95SBruce Richardson rc = -1;
86999a2dd95SBruce Richardson break;
87099a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_LEGACY:
87199a2dd95SBruce Richardson if (vfio_disable_intx(intr_handle))
87299a2dd95SBruce Richardson rc = -1;
87399a2dd95SBruce Richardson break;
87499a2dd95SBruce Richardson #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
87599a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_REQ:
87699a2dd95SBruce Richardson if (vfio_disable_req(intr_handle))
87799a2dd95SBruce Richardson rc = -1;
87899a2dd95SBruce Richardson break;
87999a2dd95SBruce Richardson #endif
88099a2dd95SBruce Richardson #endif
88199a2dd95SBruce Richardson /* not used at this moment */
88299a2dd95SBruce Richardson case RTE_INTR_HANDLE_DEV_EVENT:
88399a2dd95SBruce Richardson rc = -1;
88499a2dd95SBruce Richardson break;
88599a2dd95SBruce Richardson /* unknown handle type */
88699a2dd95SBruce Richardson default:
887*ae67895bSDavid Marchand EAL_LOG(ERR, "Unknown handle type of fd %d",
888bbbac4cdSHarman Kalra rte_intr_fd_get(intr_handle));
88999a2dd95SBruce Richardson rc = -1;
89099a2dd95SBruce Richardson break;
89199a2dd95SBruce Richardson }
89299a2dd95SBruce Richardson out:
89399a2dd95SBruce Richardson rte_eal_trace_intr_disable(intr_handle, rc);
89499a2dd95SBruce Richardson return rc;
89599a2dd95SBruce Richardson }
89699a2dd95SBruce Richardson
89799a2dd95SBruce Richardson static int
eal_intr_process_interrupts(struct epoll_event * events,int nfds)89899a2dd95SBruce Richardson eal_intr_process_interrupts(struct epoll_event *events, int nfds)
89999a2dd95SBruce Richardson {
90099a2dd95SBruce Richardson bool call = false;
90199a2dd95SBruce Richardson int n, bytes_read, rv;
90299a2dd95SBruce Richardson struct rte_intr_source *src;
90399a2dd95SBruce Richardson struct rte_intr_callback *cb, *next;
90499a2dd95SBruce Richardson union rte_intr_read_buffer buf;
90599a2dd95SBruce Richardson struct rte_intr_callback active_cb;
90699a2dd95SBruce Richardson
90799a2dd95SBruce Richardson for (n = 0; n < nfds; n++) {
90899a2dd95SBruce Richardson
90999a2dd95SBruce Richardson /**
91099a2dd95SBruce Richardson * if the pipe fd is ready to read, return out to
91199a2dd95SBruce Richardson * rebuild the wait list.
91299a2dd95SBruce Richardson */
91399a2dd95SBruce Richardson if (events[n].data.fd == intr_pipe.readfd){
91499a2dd95SBruce Richardson int r = read(intr_pipe.readfd, buf.charbuf,
91599a2dd95SBruce Richardson sizeof(buf.charbuf));
91699a2dd95SBruce Richardson RTE_SET_USED(r);
91799a2dd95SBruce Richardson return -1;
91899a2dd95SBruce Richardson }
91999a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
92099a2dd95SBruce Richardson TAILQ_FOREACH(src, &intr_sources, next)
921bbbac4cdSHarman Kalra if (rte_intr_fd_get(src->intr_handle) == events[n].data.fd)
92299a2dd95SBruce Richardson break;
92399a2dd95SBruce Richardson if (src == NULL){
92499a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
92599a2dd95SBruce Richardson continue;
92699a2dd95SBruce Richardson }
92799a2dd95SBruce Richardson
92899a2dd95SBruce Richardson /* mark this interrupt source as active and release the lock. */
92999a2dd95SBruce Richardson src->active = 1;
93099a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
93199a2dd95SBruce Richardson
93299a2dd95SBruce Richardson /* set the length to be read dor different handle type */
933bbbac4cdSHarman Kalra switch (rte_intr_type_get(src->intr_handle)) {
93499a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO:
93599a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO_INTX:
93699a2dd95SBruce Richardson bytes_read = sizeof(buf.uio_intr_count);
93799a2dd95SBruce Richardson break;
93899a2dd95SBruce Richardson case RTE_INTR_HANDLE_ALARM:
93999a2dd95SBruce Richardson bytes_read = sizeof(buf.timerfd_num);
94099a2dd95SBruce Richardson break;
94199a2dd95SBruce Richardson #ifdef VFIO_PRESENT
942aeed570aSMaciej Szwed #ifdef HAVE_VFIO_DEV_REQ_INTERFACE
943aeed570aSMaciej Szwed case RTE_INTR_HANDLE_VFIO_REQ:
944aeed570aSMaciej Szwed #endif
94599a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSIX:
94699a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSI:
94799a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_LEGACY:
94899a2dd95SBruce Richardson bytes_read = sizeof(buf.vfio_intr_count);
94999a2dd95SBruce Richardson break;
95099a2dd95SBruce Richardson #endif
95199a2dd95SBruce Richardson case RTE_INTR_HANDLE_VDEV:
95299a2dd95SBruce Richardson case RTE_INTR_HANDLE_EXT:
95399a2dd95SBruce Richardson bytes_read = 0;
95499a2dd95SBruce Richardson call = true;
95599a2dd95SBruce Richardson break;
95699a2dd95SBruce Richardson case RTE_INTR_HANDLE_DEV_EVENT:
95799a2dd95SBruce Richardson bytes_read = 0;
95899a2dd95SBruce Richardson call = true;
95999a2dd95SBruce Richardson break;
96099a2dd95SBruce Richardson default:
96199a2dd95SBruce Richardson bytes_read = 1;
96299a2dd95SBruce Richardson break;
96399a2dd95SBruce Richardson }
96499a2dd95SBruce Richardson
96599a2dd95SBruce Richardson if (bytes_read > 0) {
96699a2dd95SBruce Richardson /**
96799a2dd95SBruce Richardson * read out to clear the ready-to-be-read flag
96899a2dd95SBruce Richardson * for epoll_wait.
96999a2dd95SBruce Richardson */
97099a2dd95SBruce Richardson bytes_read = read(events[n].data.fd, &buf, bytes_read);
97199a2dd95SBruce Richardson if (bytes_read < 0) {
97299a2dd95SBruce Richardson if (errno == EINTR || errno == EWOULDBLOCK)
97399a2dd95SBruce Richardson continue;
97499a2dd95SBruce Richardson
975*ae67895bSDavid Marchand EAL_LOG(ERR, "Error reading from file "
976*ae67895bSDavid Marchand "descriptor %d: %s",
97799a2dd95SBruce Richardson events[n].data.fd,
97899a2dd95SBruce Richardson strerror(errno));
97999a2dd95SBruce Richardson /*
98099a2dd95SBruce Richardson * The device is unplugged or buggy, remove
98199a2dd95SBruce Richardson * it as an interrupt source and return to
98299a2dd95SBruce Richardson * force the wait list to be rebuilt.
98399a2dd95SBruce Richardson */
98499a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
98599a2dd95SBruce Richardson TAILQ_REMOVE(&intr_sources, src, next);
98699a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
98799a2dd95SBruce Richardson
98899a2dd95SBruce Richardson for (cb = TAILQ_FIRST(&src->callbacks); cb;
98999a2dd95SBruce Richardson cb = next) {
99099a2dd95SBruce Richardson next = TAILQ_NEXT(cb, next);
99199a2dd95SBruce Richardson TAILQ_REMOVE(&src->callbacks, cb, next);
99299a2dd95SBruce Richardson free(cb);
99399a2dd95SBruce Richardson }
994bbbac4cdSHarman Kalra rte_intr_instance_free(src->intr_handle);
99599a2dd95SBruce Richardson free(src);
99699a2dd95SBruce Richardson return -1;
99799a2dd95SBruce Richardson } else if (bytes_read == 0)
998*ae67895bSDavid Marchand EAL_LOG(ERR, "Read nothing from file "
999*ae67895bSDavid Marchand "descriptor %d", events[n].data.fd);
100099a2dd95SBruce Richardson else
100199a2dd95SBruce Richardson call = true;
100299a2dd95SBruce Richardson }
100399a2dd95SBruce Richardson
100499a2dd95SBruce Richardson /* grab a lock, again to call callbacks and update status. */
100599a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
100699a2dd95SBruce Richardson
100799a2dd95SBruce Richardson if (call) {
100899a2dd95SBruce Richardson
100999a2dd95SBruce Richardson /* Finally, call all callbacks. */
101099a2dd95SBruce Richardson TAILQ_FOREACH(cb, &src->callbacks, next) {
101199a2dd95SBruce Richardson
101299a2dd95SBruce Richardson /* make a copy and unlock. */
101399a2dd95SBruce Richardson active_cb = *cb;
101499a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
101599a2dd95SBruce Richardson
101699a2dd95SBruce Richardson /* call the actual callback */
101799a2dd95SBruce Richardson active_cb.cb_fn(active_cb.cb_arg);
101899a2dd95SBruce Richardson
101999a2dd95SBruce Richardson /*get the lock back. */
102099a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
102199a2dd95SBruce Richardson }
102299a2dd95SBruce Richardson }
102399a2dd95SBruce Richardson /* we done with that interrupt source, release it. */
102499a2dd95SBruce Richardson src->active = 0;
102599a2dd95SBruce Richardson
102699a2dd95SBruce Richardson rv = 0;
102799a2dd95SBruce Richardson
102899a2dd95SBruce Richardson /* check if any callback are supposed to be removed */
102999a2dd95SBruce Richardson for (cb = TAILQ_FIRST(&src->callbacks); cb != NULL; cb = next) {
103099a2dd95SBruce Richardson next = TAILQ_NEXT(cb, next);
103199a2dd95SBruce Richardson if (cb->pending_delete) {
103299a2dd95SBruce Richardson TAILQ_REMOVE(&src->callbacks, cb, next);
103399a2dd95SBruce Richardson if (cb->ucb_fn)
1034bbbac4cdSHarman Kalra cb->ucb_fn(src->intr_handle, cb->cb_arg);
103599a2dd95SBruce Richardson free(cb);
103699a2dd95SBruce Richardson rv++;
103799a2dd95SBruce Richardson }
103899a2dd95SBruce Richardson }
103999a2dd95SBruce Richardson
104099a2dd95SBruce Richardson /* all callbacks for that source are removed. */
104199a2dd95SBruce Richardson if (TAILQ_EMPTY(&src->callbacks)) {
104299a2dd95SBruce Richardson TAILQ_REMOVE(&intr_sources, src, next);
1043bbbac4cdSHarman Kalra rte_intr_instance_free(src->intr_handle);
104499a2dd95SBruce Richardson free(src);
104599a2dd95SBruce Richardson }
104699a2dd95SBruce Richardson
104799a2dd95SBruce Richardson /* notify the pipe fd waited by epoll_wait to rebuild the wait list */
104899a2dd95SBruce Richardson if (rv > 0 && write(intr_pipe.writefd, "1", 1) < 0) {
104999a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
105099a2dd95SBruce Richardson return -EPIPE;
105199a2dd95SBruce Richardson }
105299a2dd95SBruce Richardson
105399a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
105499a2dd95SBruce Richardson }
105599a2dd95SBruce Richardson
105699a2dd95SBruce Richardson return 0;
105799a2dd95SBruce Richardson }
105899a2dd95SBruce Richardson
105999a2dd95SBruce Richardson /**
106099a2dd95SBruce Richardson * It handles all the interrupts.
106199a2dd95SBruce Richardson *
106299a2dd95SBruce Richardson * @param pfd
106399a2dd95SBruce Richardson * epoll file descriptor.
106499a2dd95SBruce Richardson * @param totalfds
106599a2dd95SBruce Richardson * The number of file descriptors added in epoll.
106699a2dd95SBruce Richardson *
106799a2dd95SBruce Richardson * @return
106899a2dd95SBruce Richardson * void
106999a2dd95SBruce Richardson */
107099a2dd95SBruce Richardson static void
eal_intr_handle_interrupts(int pfd,unsigned totalfds)107199a2dd95SBruce Richardson eal_intr_handle_interrupts(int pfd, unsigned totalfds)
107299a2dd95SBruce Richardson {
107399a2dd95SBruce Richardson struct epoll_event events[totalfds];
107499a2dd95SBruce Richardson int nfds = 0;
107599a2dd95SBruce Richardson
107699a2dd95SBruce Richardson for(;;) {
107799a2dd95SBruce Richardson nfds = epoll_wait(pfd, events, totalfds,
107899a2dd95SBruce Richardson EAL_INTR_EPOLL_WAIT_FOREVER);
107999a2dd95SBruce Richardson /* epoll_wait fail */
108099a2dd95SBruce Richardson if (nfds < 0) {
108199a2dd95SBruce Richardson if (errno == EINTR)
108299a2dd95SBruce Richardson continue;
1083*ae67895bSDavid Marchand EAL_LOG(ERR,
1084*ae67895bSDavid Marchand "epoll_wait returns with fail");
108599a2dd95SBruce Richardson return;
108699a2dd95SBruce Richardson }
108799a2dd95SBruce Richardson /* epoll_wait timeout, will never happens here */
108899a2dd95SBruce Richardson else if (nfds == 0)
108999a2dd95SBruce Richardson continue;
109099a2dd95SBruce Richardson /* epoll_wait has at least one fd ready to read */
109199a2dd95SBruce Richardson if (eal_intr_process_interrupts(events, nfds) < 0)
109299a2dd95SBruce Richardson return;
109399a2dd95SBruce Richardson }
109499a2dd95SBruce Richardson }
109599a2dd95SBruce Richardson
109699a2dd95SBruce Richardson /**
109799a2dd95SBruce Richardson * It builds/rebuilds up the epoll file descriptor with all the
109899a2dd95SBruce Richardson * file descriptors being waited on. Then handles the interrupts.
109999a2dd95SBruce Richardson *
110099a2dd95SBruce Richardson * @param arg
110199a2dd95SBruce Richardson * pointer. (unused)
110299a2dd95SBruce Richardson *
110399a2dd95SBruce Richardson * @return
110499a2dd95SBruce Richardson * never return;
110599a2dd95SBruce Richardson */
11061c1abf17SThomas Monjalon static __rte_noreturn uint32_t
eal_intr_thread_main(__rte_unused void * arg)110799a2dd95SBruce Richardson eal_intr_thread_main(__rte_unused void *arg)
110899a2dd95SBruce Richardson {
110999a2dd95SBruce Richardson /* host thread, never break out */
111099a2dd95SBruce Richardson for (;;) {
111199a2dd95SBruce Richardson /* build up the epoll fd with all descriptors we are to
111299a2dd95SBruce Richardson * wait on then pass it to the handle_interrupts function
111399a2dd95SBruce Richardson */
111499a2dd95SBruce Richardson static struct epoll_event pipe_event = {
111599a2dd95SBruce Richardson .events = EPOLLIN | EPOLLPRI,
111699a2dd95SBruce Richardson };
111799a2dd95SBruce Richardson struct rte_intr_source *src;
111899a2dd95SBruce Richardson unsigned numfds = 0;
111999a2dd95SBruce Richardson
112099a2dd95SBruce Richardson /* create epoll fd */
112199a2dd95SBruce Richardson int pfd = epoll_create(1);
112299a2dd95SBruce Richardson if (pfd < 0)
112399a2dd95SBruce Richardson rte_panic("Cannot create epoll instance\n");
112499a2dd95SBruce Richardson
112599a2dd95SBruce Richardson pipe_event.data.fd = intr_pipe.readfd;
112699a2dd95SBruce Richardson /**
112799a2dd95SBruce Richardson * add pipe fd into wait list, this pipe is used to
112899a2dd95SBruce Richardson * rebuild the wait list.
112999a2dd95SBruce Richardson */
113099a2dd95SBruce Richardson if (epoll_ctl(pfd, EPOLL_CTL_ADD, intr_pipe.readfd,
113199a2dd95SBruce Richardson &pipe_event) < 0) {
113299a2dd95SBruce Richardson rte_panic("Error adding fd to %d epoll_ctl, %s\n",
113399a2dd95SBruce Richardson intr_pipe.readfd, strerror(errno));
113499a2dd95SBruce Richardson }
113599a2dd95SBruce Richardson numfds++;
113699a2dd95SBruce Richardson
113799a2dd95SBruce Richardson rte_spinlock_lock(&intr_lock);
113899a2dd95SBruce Richardson
113999a2dd95SBruce Richardson TAILQ_FOREACH(src, &intr_sources, next) {
114099a2dd95SBruce Richardson struct epoll_event ev;
114199a2dd95SBruce Richardson
114299a2dd95SBruce Richardson if (src->callbacks.tqh_first == NULL)
114399a2dd95SBruce Richardson continue; /* skip those with no callbacks */
114499a2dd95SBruce Richardson memset(&ev, 0, sizeof(ev));
114599a2dd95SBruce Richardson ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;
1146bbbac4cdSHarman Kalra ev.data.fd = rte_intr_fd_get(src->intr_handle);
114799a2dd95SBruce Richardson
114899a2dd95SBruce Richardson /**
114999a2dd95SBruce Richardson * add all the uio device file descriptor
115099a2dd95SBruce Richardson * into wait list.
115199a2dd95SBruce Richardson */
115299a2dd95SBruce Richardson if (epoll_ctl(pfd, EPOLL_CTL_ADD,
1153bbbac4cdSHarman Kalra rte_intr_fd_get(src->intr_handle), &ev) < 0) {
115499a2dd95SBruce Richardson rte_panic("Error adding fd %d epoll_ctl, %s\n",
1155bbbac4cdSHarman Kalra rte_intr_fd_get(src->intr_handle),
1156bbbac4cdSHarman Kalra strerror(errno));
115799a2dd95SBruce Richardson }
115899a2dd95SBruce Richardson else
115999a2dd95SBruce Richardson numfds++;
116099a2dd95SBruce Richardson }
116199a2dd95SBruce Richardson rte_spinlock_unlock(&intr_lock);
116299a2dd95SBruce Richardson /* serve the interrupt */
116399a2dd95SBruce Richardson eal_intr_handle_interrupts(pfd, numfds);
116499a2dd95SBruce Richardson
116599a2dd95SBruce Richardson /**
116699a2dd95SBruce Richardson * when we return, we need to rebuild the
116799a2dd95SBruce Richardson * list of fds to monitor.
116899a2dd95SBruce Richardson */
116999a2dd95SBruce Richardson close(pfd);
117099a2dd95SBruce Richardson }
117199a2dd95SBruce Richardson }
117299a2dd95SBruce Richardson
117399a2dd95SBruce Richardson int
rte_eal_intr_init(void)117499a2dd95SBruce Richardson rte_eal_intr_init(void)
117599a2dd95SBruce Richardson {
117699a2dd95SBruce Richardson int ret = 0;
117799a2dd95SBruce Richardson
117899a2dd95SBruce Richardson /* init the global interrupt source head */
117999a2dd95SBruce Richardson TAILQ_INIT(&intr_sources);
118099a2dd95SBruce Richardson
118199a2dd95SBruce Richardson /**
118299a2dd95SBruce Richardson * create a pipe which will be waited by epoll and notified to
118399a2dd95SBruce Richardson * rebuild the wait list of epoll.
118499a2dd95SBruce Richardson */
118599a2dd95SBruce Richardson if (pipe(intr_pipe.pipefd) < 0) {
118699a2dd95SBruce Richardson rte_errno = errno;
118799a2dd95SBruce Richardson return -1;
118899a2dd95SBruce Richardson }
118999a2dd95SBruce Richardson
119099a2dd95SBruce Richardson /* create the host thread to wait/handle the interrupt */
11911c1abf17SThomas Monjalon ret = rte_thread_create_internal_control(&intr_thread, "intr",
119299a2dd95SBruce Richardson eal_intr_thread_main, NULL);
119399a2dd95SBruce Richardson if (ret != 0) {
119499a2dd95SBruce Richardson rte_errno = -ret;
1195*ae67895bSDavid Marchand EAL_LOG(ERR,
1196*ae67895bSDavid Marchand "Failed to create thread for interrupt handling");
119799a2dd95SBruce Richardson }
119899a2dd95SBruce Richardson
119999a2dd95SBruce Richardson return ret;
120099a2dd95SBruce Richardson }
120199a2dd95SBruce Richardson
120299a2dd95SBruce Richardson static void
eal_intr_proc_rxtx_intr(int fd,const struct rte_intr_handle * intr_handle)120399a2dd95SBruce Richardson eal_intr_proc_rxtx_intr(int fd, const struct rte_intr_handle *intr_handle)
120499a2dd95SBruce Richardson {
120599a2dd95SBruce Richardson union rte_intr_read_buffer buf;
120699a2dd95SBruce Richardson int bytes_read = 0;
120799a2dd95SBruce Richardson int nbytes;
120899a2dd95SBruce Richardson
1209bbbac4cdSHarman Kalra switch (rte_intr_type_get(intr_handle)) {
121099a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO:
121199a2dd95SBruce Richardson case RTE_INTR_HANDLE_UIO_INTX:
121299a2dd95SBruce Richardson bytes_read = sizeof(buf.uio_intr_count);
121399a2dd95SBruce Richardson break;
121499a2dd95SBruce Richardson #ifdef VFIO_PRESENT
121599a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSIX:
121699a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_MSI:
121799a2dd95SBruce Richardson case RTE_INTR_HANDLE_VFIO_LEGACY:
121899a2dd95SBruce Richardson bytes_read = sizeof(buf.vfio_intr_count);
121999a2dd95SBruce Richardson break;
122099a2dd95SBruce Richardson #endif
122199a2dd95SBruce Richardson case RTE_INTR_HANDLE_VDEV:
1222bbbac4cdSHarman Kalra bytes_read = rte_intr_efd_counter_size_get(intr_handle);
122399a2dd95SBruce Richardson /* For vdev, number of bytes to read is set by driver */
122499a2dd95SBruce Richardson break;
122599a2dd95SBruce Richardson case RTE_INTR_HANDLE_EXT:
122699a2dd95SBruce Richardson return;
122799a2dd95SBruce Richardson default:
122899a2dd95SBruce Richardson bytes_read = 1;
1229*ae67895bSDavid Marchand EAL_LOG(INFO, "unexpected intr type");
123099a2dd95SBruce Richardson break;
123199a2dd95SBruce Richardson }
123299a2dd95SBruce Richardson
123399a2dd95SBruce Richardson /**
123499a2dd95SBruce Richardson * read out to clear the ready-to-be-read flag
123599a2dd95SBruce Richardson * for epoll_wait.
123699a2dd95SBruce Richardson */
123799a2dd95SBruce Richardson if (bytes_read == 0)
123899a2dd95SBruce Richardson return;
123999a2dd95SBruce Richardson do {
124099a2dd95SBruce Richardson nbytes = read(fd, &buf, bytes_read);
124199a2dd95SBruce Richardson if (nbytes < 0) {
124299a2dd95SBruce Richardson if (errno == EINTR || errno == EWOULDBLOCK ||
124399a2dd95SBruce Richardson errno == EAGAIN)
124499a2dd95SBruce Richardson continue;
1245*ae67895bSDavid Marchand EAL_LOG(ERR,
1246*ae67895bSDavid Marchand "Error reading from fd %d: %s",
124799a2dd95SBruce Richardson fd, strerror(errno));
124899a2dd95SBruce Richardson } else if (nbytes == 0)
1249*ae67895bSDavid Marchand EAL_LOG(ERR, "Read nothing from fd %d", fd);
125099a2dd95SBruce Richardson return;
125199a2dd95SBruce Richardson } while (1);
125299a2dd95SBruce Richardson }
125399a2dd95SBruce Richardson
125499a2dd95SBruce Richardson static int
eal_epoll_process_event(struct epoll_event * evs,unsigned int n,struct rte_epoll_event * events)125599a2dd95SBruce Richardson eal_epoll_process_event(struct epoll_event *evs, unsigned int n,
125699a2dd95SBruce Richardson struct rte_epoll_event *events)
125799a2dd95SBruce Richardson {
125899a2dd95SBruce Richardson unsigned int i, count = 0;
125999a2dd95SBruce Richardson struct rte_epoll_event *rev;
126099a2dd95SBruce Richardson uint32_t valid_status;
126199a2dd95SBruce Richardson
126299a2dd95SBruce Richardson for (i = 0; i < n; i++) {
126399a2dd95SBruce Richardson rev = evs[i].data.ptr;
126499a2dd95SBruce Richardson valid_status = RTE_EPOLL_VALID;
126599a2dd95SBruce Richardson /* ACQUIRE memory ordering here pairs with RELEASE
126699a2dd95SBruce Richardson * ordering below acting as a lock to synchronize
126799a2dd95SBruce Richardson * the event data updating.
126899a2dd95SBruce Richardson */
12692a7a42a5STyler Retzlaff if (!rev || !rte_atomic_compare_exchange_strong_explicit(&rev->status,
12702a7a42a5STyler Retzlaff &valid_status, RTE_EPOLL_EXEC,
12712a7a42a5STyler Retzlaff rte_memory_order_acquire, rte_memory_order_relaxed))
127299a2dd95SBruce Richardson continue;
127399a2dd95SBruce Richardson
127499a2dd95SBruce Richardson events[count].status = RTE_EPOLL_VALID;
127599a2dd95SBruce Richardson events[count].fd = rev->fd;
127699a2dd95SBruce Richardson events[count].epfd = rev->epfd;
127799a2dd95SBruce Richardson events[count].epdata.event = evs[i].events;
127899a2dd95SBruce Richardson events[count].epdata.data = rev->epdata.data;
127999a2dd95SBruce Richardson if (rev->epdata.cb_fun)
128099a2dd95SBruce Richardson rev->epdata.cb_fun(rev->fd,
128199a2dd95SBruce Richardson rev->epdata.cb_arg);
128299a2dd95SBruce Richardson
128399a2dd95SBruce Richardson /* the status update should be observed after
128499a2dd95SBruce Richardson * the other fields change.
128599a2dd95SBruce Richardson */
12862a7a42a5STyler Retzlaff rte_atomic_store_explicit(&rev->status, RTE_EPOLL_VALID,
12872a7a42a5STyler Retzlaff rte_memory_order_release);
128899a2dd95SBruce Richardson count++;
128999a2dd95SBruce Richardson }
129099a2dd95SBruce Richardson return count;
129199a2dd95SBruce Richardson }
129299a2dd95SBruce Richardson
129399a2dd95SBruce Richardson static inline int
eal_init_tls_epfd(void)129499a2dd95SBruce Richardson eal_init_tls_epfd(void)
129599a2dd95SBruce Richardson {
129699a2dd95SBruce Richardson int pfd = epoll_create(255);
129799a2dd95SBruce Richardson
129899a2dd95SBruce Richardson if (pfd < 0) {
1299*ae67895bSDavid Marchand EAL_LOG(ERR,
1300*ae67895bSDavid Marchand "Cannot create epoll instance");
130199a2dd95SBruce Richardson return -1;
130299a2dd95SBruce Richardson }
130399a2dd95SBruce Richardson return pfd;
130499a2dd95SBruce Richardson }
130599a2dd95SBruce Richardson
130699a2dd95SBruce Richardson int
rte_intr_tls_epfd(void)130799a2dd95SBruce Richardson rte_intr_tls_epfd(void)
130899a2dd95SBruce Richardson {
130999a2dd95SBruce Richardson if (RTE_PER_LCORE(_epfd) == -1)
131099a2dd95SBruce Richardson RTE_PER_LCORE(_epfd) = eal_init_tls_epfd();
131199a2dd95SBruce Richardson
131299a2dd95SBruce Richardson return RTE_PER_LCORE(_epfd);
131399a2dd95SBruce Richardson }
131499a2dd95SBruce Richardson
131599a2dd95SBruce Richardson static int
eal_epoll_wait(int epfd,struct rte_epoll_event * events,int maxevents,int timeout,bool interruptible)131699a2dd95SBruce Richardson eal_epoll_wait(int epfd, struct rte_epoll_event *events,
131799a2dd95SBruce Richardson int maxevents, int timeout, bool interruptible)
131899a2dd95SBruce Richardson {
131999a2dd95SBruce Richardson struct epoll_event evs[maxevents];
132099a2dd95SBruce Richardson int rc;
132199a2dd95SBruce Richardson
132299a2dd95SBruce Richardson if (!events) {
1323*ae67895bSDavid Marchand EAL_LOG(ERR, "rte_epoll_event can't be NULL");
132499a2dd95SBruce Richardson return -1;
132599a2dd95SBruce Richardson }
132699a2dd95SBruce Richardson
132799a2dd95SBruce Richardson /* using per thread epoll fd */
132899a2dd95SBruce Richardson if (epfd == RTE_EPOLL_PER_THREAD)
132999a2dd95SBruce Richardson epfd = rte_intr_tls_epfd();
133099a2dd95SBruce Richardson
133199a2dd95SBruce Richardson while (1) {
133299a2dd95SBruce Richardson rc = epoll_wait(epfd, evs, maxevents, timeout);
133399a2dd95SBruce Richardson if (likely(rc > 0)) {
133499a2dd95SBruce Richardson /* epoll_wait has at least one fd ready to read */
133599a2dd95SBruce Richardson rc = eal_epoll_process_event(evs, rc, events);
133699a2dd95SBruce Richardson break;
133799a2dd95SBruce Richardson } else if (rc < 0) {
133899a2dd95SBruce Richardson if (errno == EINTR) {
133999a2dd95SBruce Richardson if (interruptible)
134099a2dd95SBruce Richardson return -1;
134199a2dd95SBruce Richardson else
134299a2dd95SBruce Richardson continue;
134399a2dd95SBruce Richardson }
134499a2dd95SBruce Richardson /* epoll_wait fail */
1345*ae67895bSDavid Marchand EAL_LOG(ERR, "epoll_wait returns with fail %s",
134699a2dd95SBruce Richardson strerror(errno));
134799a2dd95SBruce Richardson rc = -1;
134899a2dd95SBruce Richardson break;
134999a2dd95SBruce Richardson } else {
135099a2dd95SBruce Richardson /* rc == 0, epoll_wait timed out */
135199a2dd95SBruce Richardson break;
135299a2dd95SBruce Richardson }
135399a2dd95SBruce Richardson }
135499a2dd95SBruce Richardson
135599a2dd95SBruce Richardson return rc;
135699a2dd95SBruce Richardson }
135799a2dd95SBruce Richardson
135899a2dd95SBruce Richardson int
rte_epoll_wait(int epfd,struct rte_epoll_event * events,int maxevents,int timeout)135999a2dd95SBruce Richardson rte_epoll_wait(int epfd, struct rte_epoll_event *events,
136099a2dd95SBruce Richardson int maxevents, int timeout)
136199a2dd95SBruce Richardson {
136299a2dd95SBruce Richardson return eal_epoll_wait(epfd, events, maxevents, timeout, false);
136399a2dd95SBruce Richardson }
136499a2dd95SBruce Richardson
136599a2dd95SBruce Richardson int
rte_epoll_wait_interruptible(int epfd,struct rte_epoll_event * events,int maxevents,int timeout)136699a2dd95SBruce Richardson rte_epoll_wait_interruptible(int epfd, struct rte_epoll_event *events,
136799a2dd95SBruce Richardson int maxevents, int timeout)
136899a2dd95SBruce Richardson {
136999a2dd95SBruce Richardson return eal_epoll_wait(epfd, events, maxevents, timeout, true);
137099a2dd95SBruce Richardson }
137199a2dd95SBruce Richardson
137299a2dd95SBruce Richardson static inline void
eal_epoll_data_safe_free(struct rte_epoll_event * ev)137399a2dd95SBruce Richardson eal_epoll_data_safe_free(struct rte_epoll_event *ev)
137499a2dd95SBruce Richardson {
137599a2dd95SBruce Richardson uint32_t valid_status = RTE_EPOLL_VALID;
137699a2dd95SBruce Richardson
13772a7a42a5STyler Retzlaff while (!rte_atomic_compare_exchange_strong_explicit(&ev->status, &valid_status,
13782a7a42a5STyler Retzlaff RTE_EPOLL_INVALID, rte_memory_order_acquire, rte_memory_order_relaxed)) {
13792a7a42a5STyler Retzlaff while (rte_atomic_load_explicit(&ev->status,
13802a7a42a5STyler Retzlaff rte_memory_order_relaxed) != RTE_EPOLL_VALID)
138199a2dd95SBruce Richardson rte_pause();
138299a2dd95SBruce Richardson valid_status = RTE_EPOLL_VALID;
138399a2dd95SBruce Richardson }
138499a2dd95SBruce Richardson memset(&ev->epdata, 0, sizeof(ev->epdata));
138599a2dd95SBruce Richardson ev->fd = -1;
138699a2dd95SBruce Richardson ev->epfd = -1;
138799a2dd95SBruce Richardson }
138899a2dd95SBruce Richardson
138999a2dd95SBruce Richardson int
rte_epoll_ctl(int epfd,int op,int fd,struct rte_epoll_event * event)139099a2dd95SBruce Richardson rte_epoll_ctl(int epfd, int op, int fd,
139199a2dd95SBruce Richardson struct rte_epoll_event *event)
139299a2dd95SBruce Richardson {
139399a2dd95SBruce Richardson struct epoll_event ev;
139499a2dd95SBruce Richardson
139599a2dd95SBruce Richardson if (!event) {
1396*ae67895bSDavid Marchand EAL_LOG(ERR, "rte_epoll_event can't be NULL");
139799a2dd95SBruce Richardson return -1;
139899a2dd95SBruce Richardson }
139999a2dd95SBruce Richardson
140099a2dd95SBruce Richardson /* using per thread epoll fd */
140199a2dd95SBruce Richardson if (epfd == RTE_EPOLL_PER_THREAD)
140299a2dd95SBruce Richardson epfd = rte_intr_tls_epfd();
140399a2dd95SBruce Richardson
140499a2dd95SBruce Richardson if (op == EPOLL_CTL_ADD) {
14052a7a42a5STyler Retzlaff rte_atomic_store_explicit(&event->status, RTE_EPOLL_VALID,
14062a7a42a5STyler Retzlaff rte_memory_order_relaxed);
140799a2dd95SBruce Richardson event->fd = fd; /* ignore fd in event */
140899a2dd95SBruce Richardson event->epfd = epfd;
140999a2dd95SBruce Richardson ev.data.ptr = (void *)event;
141099a2dd95SBruce Richardson }
141199a2dd95SBruce Richardson
141299a2dd95SBruce Richardson ev.events = event->epdata.event;
141399a2dd95SBruce Richardson if (epoll_ctl(epfd, op, fd, &ev) < 0) {
1414*ae67895bSDavid Marchand EAL_LOG(ERR, "Error op %d fd %d epoll_ctl, %s",
141599a2dd95SBruce Richardson op, fd, strerror(errno));
141699a2dd95SBruce Richardson if (op == EPOLL_CTL_ADD)
141799a2dd95SBruce Richardson /* rollback status when CTL_ADD fail */
14182a7a42a5STyler Retzlaff rte_atomic_store_explicit(&event->status, RTE_EPOLL_INVALID,
14192a7a42a5STyler Retzlaff rte_memory_order_relaxed);
142099a2dd95SBruce Richardson return -1;
142199a2dd95SBruce Richardson }
142299a2dd95SBruce Richardson
14232a7a42a5STyler Retzlaff if (op == EPOLL_CTL_DEL && rte_atomic_load_explicit(&event->status,
14242a7a42a5STyler Retzlaff rte_memory_order_relaxed) != RTE_EPOLL_INVALID)
142599a2dd95SBruce Richardson eal_epoll_data_safe_free(event);
142699a2dd95SBruce Richardson
142799a2dd95SBruce Richardson return 0;
142899a2dd95SBruce Richardson }
142999a2dd95SBruce Richardson
143099a2dd95SBruce Richardson int
rte_intr_rx_ctl(struct rte_intr_handle * intr_handle,int epfd,int op,unsigned int vec,void * data)143199a2dd95SBruce Richardson rte_intr_rx_ctl(struct rte_intr_handle *intr_handle, int epfd,
143299a2dd95SBruce Richardson int op, unsigned int vec, void *data)
143399a2dd95SBruce Richardson {
143499a2dd95SBruce Richardson struct rte_epoll_event *rev;
143599a2dd95SBruce Richardson struct rte_epoll_data *epdata;
143699a2dd95SBruce Richardson int epfd_op;
143799a2dd95SBruce Richardson unsigned int efd_idx;
143899a2dd95SBruce Richardson int rc = 0;
143999a2dd95SBruce Richardson
144099a2dd95SBruce Richardson efd_idx = (vec >= RTE_INTR_VEC_RXTX_OFFSET) ?
144199a2dd95SBruce Richardson (vec - RTE_INTR_VEC_RXTX_OFFSET) : vec;
144299a2dd95SBruce Richardson
1443bbbac4cdSHarman Kalra if (intr_handle == NULL || rte_intr_nb_efd_get(intr_handle) == 0 ||
1444bbbac4cdSHarman Kalra efd_idx >= (unsigned int)rte_intr_nb_efd_get(intr_handle)) {
1445*ae67895bSDavid Marchand EAL_LOG(ERR, "Wrong intr vector number.");
144699a2dd95SBruce Richardson return -EPERM;
144799a2dd95SBruce Richardson }
144899a2dd95SBruce Richardson
144999a2dd95SBruce Richardson switch (op) {
145099a2dd95SBruce Richardson case RTE_INTR_EVENT_ADD:
145199a2dd95SBruce Richardson epfd_op = EPOLL_CTL_ADD;
1452bbbac4cdSHarman Kalra rev = rte_intr_elist_index_get(intr_handle, efd_idx);
14532a7a42a5STyler Retzlaff if (rte_atomic_load_explicit(&rev->status,
14542a7a42a5STyler Retzlaff rte_memory_order_relaxed) != RTE_EPOLL_INVALID) {
1455*ae67895bSDavid Marchand EAL_LOG(INFO, "Event already been added.");
145699a2dd95SBruce Richardson return -EEXIST;
145799a2dd95SBruce Richardson }
145899a2dd95SBruce Richardson
145999a2dd95SBruce Richardson /* attach to intr vector fd */
146099a2dd95SBruce Richardson epdata = &rev->epdata;
146199a2dd95SBruce Richardson epdata->event = EPOLLIN | EPOLLPRI | EPOLLET;
146299a2dd95SBruce Richardson epdata->data = data;
146399a2dd95SBruce Richardson epdata->cb_fun = (rte_intr_event_cb_t)eal_intr_proc_rxtx_intr;
146499a2dd95SBruce Richardson epdata->cb_arg = (void *)intr_handle;
146599a2dd95SBruce Richardson rc = rte_epoll_ctl(epfd, epfd_op,
1466bbbac4cdSHarman Kalra rte_intr_efds_index_get(intr_handle, efd_idx), rev);
146799a2dd95SBruce Richardson if (!rc)
1468*ae67895bSDavid Marchand EAL_LOG(DEBUG,
1469*ae67895bSDavid Marchand "efd %d associated with vec %d added on epfd %d",
1470*ae67895bSDavid Marchand rev->fd, vec, epfd);
147199a2dd95SBruce Richardson else
147299a2dd95SBruce Richardson rc = -EPERM;
147399a2dd95SBruce Richardson break;
147499a2dd95SBruce Richardson case RTE_INTR_EVENT_DEL:
147599a2dd95SBruce Richardson epfd_op = EPOLL_CTL_DEL;
1476bbbac4cdSHarman Kalra rev = rte_intr_elist_index_get(intr_handle, efd_idx);
14772a7a42a5STyler Retzlaff if (rte_atomic_load_explicit(&rev->status,
14782a7a42a5STyler Retzlaff rte_memory_order_relaxed) == RTE_EPOLL_INVALID) {
1479*ae67895bSDavid Marchand EAL_LOG(INFO, "Event does not exist.");
148099a2dd95SBruce Richardson return -EPERM;
148199a2dd95SBruce Richardson }
148299a2dd95SBruce Richardson
148399a2dd95SBruce Richardson rc = rte_epoll_ctl(rev->epfd, epfd_op, rev->fd, rev);
148499a2dd95SBruce Richardson if (rc)
148599a2dd95SBruce Richardson rc = -EPERM;
148699a2dd95SBruce Richardson break;
148799a2dd95SBruce Richardson default:
1488*ae67895bSDavid Marchand EAL_LOG(ERR, "event op type mismatch");
148999a2dd95SBruce Richardson rc = -EPERM;
149099a2dd95SBruce Richardson }
149199a2dd95SBruce Richardson
149299a2dd95SBruce Richardson return rc;
149399a2dd95SBruce Richardson }
149499a2dd95SBruce Richardson
149599a2dd95SBruce Richardson void
rte_intr_free_epoll_fd(struct rte_intr_handle * intr_handle)149699a2dd95SBruce Richardson rte_intr_free_epoll_fd(struct rte_intr_handle *intr_handle)
149799a2dd95SBruce Richardson {
149899a2dd95SBruce Richardson uint32_t i;
149999a2dd95SBruce Richardson struct rte_epoll_event *rev;
150099a2dd95SBruce Richardson
1501bbbac4cdSHarman Kalra for (i = 0; i < (uint32_t)rte_intr_nb_efd_get(intr_handle); i++) {
1502bbbac4cdSHarman Kalra rev = rte_intr_elist_index_get(intr_handle, i);
15032a7a42a5STyler Retzlaff if (rte_atomic_load_explicit(&rev->status,
15042a7a42a5STyler Retzlaff rte_memory_order_relaxed) == RTE_EPOLL_INVALID)
150599a2dd95SBruce Richardson continue;
150699a2dd95SBruce Richardson if (rte_epoll_ctl(rev->epfd, EPOLL_CTL_DEL, rev->fd, rev)) {
150799a2dd95SBruce Richardson /* force free if the entry valid */
150899a2dd95SBruce Richardson eal_epoll_data_safe_free(rev);
150999a2dd95SBruce Richardson }
151099a2dd95SBruce Richardson }
151199a2dd95SBruce Richardson }
151299a2dd95SBruce Richardson
151399a2dd95SBruce Richardson int
rte_intr_efd_enable(struct rte_intr_handle * intr_handle,uint32_t nb_efd)151499a2dd95SBruce Richardson rte_intr_efd_enable(struct rte_intr_handle *intr_handle, uint32_t nb_efd)
151599a2dd95SBruce Richardson {
151699a2dd95SBruce Richardson uint32_t i;
151799a2dd95SBruce Richardson int fd;
151899a2dd95SBruce Richardson uint32_t n = RTE_MIN(nb_efd, (uint32_t)RTE_MAX_RXTX_INTR_VEC_ID);
151999a2dd95SBruce Richardson
152099a2dd95SBruce Richardson assert(nb_efd != 0);
152199a2dd95SBruce Richardson
1522bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VFIO_MSIX) {
152399a2dd95SBruce Richardson for (i = 0; i < n; i++) {
152499a2dd95SBruce Richardson fd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
152599a2dd95SBruce Richardson if (fd < 0) {
1526*ae67895bSDavid Marchand EAL_LOG(ERR,
1527*ae67895bSDavid Marchand "can't setup eventfd, error %i (%s)",
152899a2dd95SBruce Richardson errno, strerror(errno));
152999a2dd95SBruce Richardson return -errno;
153099a2dd95SBruce Richardson }
1531bbbac4cdSHarman Kalra
1532bbbac4cdSHarman Kalra if (rte_intr_efds_index_set(intr_handle, i, fd))
1533bbbac4cdSHarman Kalra return -rte_errno;
153499a2dd95SBruce Richardson }
1535bbbac4cdSHarman Kalra
1536bbbac4cdSHarman Kalra if (rte_intr_nb_efd_set(intr_handle, n))
1537bbbac4cdSHarman Kalra return -rte_errno;
1538bbbac4cdSHarman Kalra
1539bbbac4cdSHarman Kalra if (rte_intr_max_intr_set(intr_handle, NB_OTHER_INTR + n))
1540bbbac4cdSHarman Kalra return -rte_errno;
1541bbbac4cdSHarman Kalra } else if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV) {
154299a2dd95SBruce Richardson /* only check, initialization would be done in vdev driver.*/
1543bbbac4cdSHarman Kalra if ((uint64_t)rte_intr_efd_counter_size_get(intr_handle) >
154499a2dd95SBruce Richardson sizeof(union rte_intr_read_buffer)) {
1545*ae67895bSDavid Marchand EAL_LOG(ERR, "the efd_counter_size is oversized");
154699a2dd95SBruce Richardson return -EINVAL;
154799a2dd95SBruce Richardson }
154899a2dd95SBruce Richardson } else {
1549bbbac4cdSHarman Kalra if (rte_intr_efds_index_set(intr_handle, 0, rte_intr_fd_get(intr_handle)))
1550bbbac4cdSHarman Kalra return -rte_errno;
1551bbbac4cdSHarman Kalra if (rte_intr_nb_efd_set(intr_handle, RTE_MIN(nb_efd, 1U)))
1552bbbac4cdSHarman Kalra return -rte_errno;
1553bbbac4cdSHarman Kalra if (rte_intr_max_intr_set(intr_handle, NB_OTHER_INTR))
1554bbbac4cdSHarman Kalra return -rte_errno;
155599a2dd95SBruce Richardson }
155699a2dd95SBruce Richardson
155799a2dd95SBruce Richardson return 0;
155899a2dd95SBruce Richardson }
155999a2dd95SBruce Richardson
156099a2dd95SBruce Richardson void
rte_intr_efd_disable(struct rte_intr_handle * intr_handle)156199a2dd95SBruce Richardson rte_intr_efd_disable(struct rte_intr_handle *intr_handle)
156299a2dd95SBruce Richardson {
156399a2dd95SBruce Richardson uint32_t i;
156499a2dd95SBruce Richardson
156599a2dd95SBruce Richardson rte_intr_free_epoll_fd(intr_handle);
1566bbbac4cdSHarman Kalra if (rte_intr_max_intr_get(intr_handle) > rte_intr_nb_efd_get(intr_handle)) {
1567bbbac4cdSHarman Kalra for (i = 0; i < (uint32_t)rte_intr_nb_efd_get(intr_handle); i++)
1568bbbac4cdSHarman Kalra close(rte_intr_efds_index_get(intr_handle, i));
156999a2dd95SBruce Richardson }
1570bbbac4cdSHarman Kalra rte_intr_nb_efd_set(intr_handle, 0);
1571bbbac4cdSHarman Kalra rte_intr_max_intr_set(intr_handle, 0);
157299a2dd95SBruce Richardson }
157399a2dd95SBruce Richardson
157499a2dd95SBruce Richardson int
rte_intr_dp_is_en(struct rte_intr_handle * intr_handle)157599a2dd95SBruce Richardson rte_intr_dp_is_en(struct rte_intr_handle *intr_handle)
157699a2dd95SBruce Richardson {
1577bbbac4cdSHarman Kalra return !(!rte_intr_nb_efd_get(intr_handle));
157899a2dd95SBruce Richardson }
157999a2dd95SBruce Richardson
158099a2dd95SBruce Richardson int
rte_intr_allow_others(struct rte_intr_handle * intr_handle)158199a2dd95SBruce Richardson rte_intr_allow_others(struct rte_intr_handle *intr_handle)
158299a2dd95SBruce Richardson {
158399a2dd95SBruce Richardson if (!rte_intr_dp_is_en(intr_handle))
158499a2dd95SBruce Richardson return 1;
158599a2dd95SBruce Richardson else
1586bbbac4cdSHarman Kalra return !!(rte_intr_max_intr_get(intr_handle) -
1587bbbac4cdSHarman Kalra rte_intr_nb_efd_get(intr_handle));
158899a2dd95SBruce Richardson }
158999a2dd95SBruce Richardson
159099a2dd95SBruce Richardson int
rte_intr_cap_multiple(struct rte_intr_handle * intr_handle)159199a2dd95SBruce Richardson rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
159299a2dd95SBruce Richardson {
1593bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VFIO_MSIX)
159499a2dd95SBruce Richardson return 1;
159599a2dd95SBruce Richardson
1596bbbac4cdSHarman Kalra if (rte_intr_type_get(intr_handle) == RTE_INTR_HANDLE_VDEV)
159799a2dd95SBruce Richardson return 1;
159899a2dd95SBruce Richardson
159999a2dd95SBruce Richardson return 0;
160099a2dd95SBruce Richardson }
160199a2dd95SBruce Richardson
rte_thread_is_intr(void)160299a2dd95SBruce Richardson int rte_thread_is_intr(void)
160399a2dd95SBruce Richardson {
16041c1abf17SThomas Monjalon return rte_thread_equal(intr_thread, rte_thread_self());
160599a2dd95SBruce Richardson }
1606