eal: check if running in interrupt context
[dpdk.git] / lib / librte_eal / linux / eal / eal_interrupts.c
index be0dd44..cb8e107 100644 (file)
@@ -197,6 +197,28 @@ vfio_disable_intx(const struct rte_intr_handle *intr_handle) {
        return 0;
 }
 
+/* unmask/ack legacy (INTx) interrupts */
+static int
+vfio_ack_intx(const struct rte_intr_handle *intr_handle)
+{
+       struct vfio_irq_set irq_set;
+
+       /* unmask INTx */
+       memset(&irq_set, 0, sizeof(irq_set));
+       irq_set.argsz = sizeof(irq_set);
+       irq_set.count = 1;
+       irq_set.flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK;
+       irq_set.index = VFIO_PCI_INTX_IRQ_INDEX;
+       irq_set.start = 0;
+
+       if (ioctl(intr_handle->vfio_dev_fd, VFIO_DEVICE_SET_IRQS, &irq_set)) {
+               RTE_LOG(ERR, EAL, "Error unmasking INTx interrupts for fd %d\n",
+                       intr_handle->fd);
+               return -1;
+       }
+       return 0;
+}
+
 /* enable MSI interrupts */
 static int
 vfio_enable_msi(const struct rte_intr_handle *intr_handle) {
@@ -522,7 +544,7 @@ rte_intr_callback_register(const struct rte_intr_handle *intr_handle,
        return ret;
 }
 
-int __rte_experimental
+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)
@@ -693,6 +715,66 @@ rte_intr_enable(const struct rte_intr_handle *intr_handle)
        return 0;
 }
 
+/**
+ * PMD generally calls this function at the end of its IRQ callback.
+ * Internally, it unmasks the interrupt if possible.
+ *
+ * For INTx, unmasking is required as the interrupt is auto-masked prior to
+ * invoking callback.
+ *
+ * For MSI/MSI-X, unmasking is typically not needed as the interrupt is not
+ * auto-masked. In fact, for interrupt handle types VFIO_MSIX and VFIO_MSI,
+ * this function is no-op.
+ */
+int
+rte_intr_ack(const struct rte_intr_handle *intr_handle)
+{
+       if (intr_handle && intr_handle->type == RTE_INTR_HANDLE_VDEV)
+               return 0;
+
+       if (!intr_handle || intr_handle->fd < 0 || intr_handle->uio_cfg_fd < 0)
+               return -1;
+
+       switch (intr_handle->type) {
+       /* Both acking and enabling are same for UIO */
+       case RTE_INTR_HANDLE_UIO:
+               if (uio_intr_enable(intr_handle))
+                       return -1;
+               break;
+       case RTE_INTR_HANDLE_UIO_INTX:
+               if (uio_intx_intr_enable(intr_handle))
+                       return -1;
+               break;
+       /* not used at this moment */
+       case RTE_INTR_HANDLE_ALARM:
+               return -1;
+#ifdef VFIO_PRESENT
+       /* VFIO MSI* is implicitly acked unlike INTx, nothing to do */
+       case RTE_INTR_HANDLE_VFIO_MSIX:
+       case RTE_INTR_HANDLE_VFIO_MSI:
+               return 0;
+       case RTE_INTR_HANDLE_VFIO_LEGACY:
+               if (vfio_ack_intx(intr_handle))
+                       return -1;
+               break;
+#ifdef HAVE_VFIO_DEV_REQ_INTERFACE
+       case RTE_INTR_HANDLE_VFIO_REQ:
+               return -1;
+#endif
+#endif
+       /* not used at this moment */
+       case RTE_INTR_HANDLE_DEV_EVENT:
+               return -1;
+       /* unknown handle type */
+       default:
+               RTE_LOG(ERR, EAL, "Unknown handle type of fd %d\n",
+                       intr_handle->fd);
+               return -1;
+       }
+
+       return 0;
+}
+
 int
 rte_intr_disable(const struct rte_intr_handle *intr_handle)
 {
@@ -963,8 +1045,6 @@ eal_intr_handle_interrupts(int pfd, unsigned totalfds)
 static __attribute__((noreturn)) void *
 eal_intr_thread_main(__rte_unused void *arg)
 {
-       struct epoll_event ev;
-
        /* host thread, never break out */
        for (;;) {
                /* build up the epoll fd with all descriptors we are to
@@ -996,8 +1076,11 @@ eal_intr_thread_main(__rte_unused void *arg)
                rte_spinlock_lock(&intr_lock);
 
                TAILQ_FOREACH(src, &intr_sources, next) {
+                       struct epoll_event ev;
+
                        if (src->callbacks.tqh_first == NULL)
                                continue; /* skip those with no callbacks */
+                       memset(&ev, 0, sizeof(ev));
                        ev.events = EPOLLIN | EPOLLPRI | EPOLLRDHUP | EPOLLHUP;
                        ev.data.fd = src->intr_handle.fd;
 
@@ -1405,3 +1488,8 @@ rte_intr_cap_multiple(struct rte_intr_handle *intr_handle)
 
        return 0;
 }
+
+int rte_thread_is_intr(void)
+{
+       return pthread_equal(intr_thread, pthread_self());
+}