LCOV - code coverage report
Current view: top level - lib/eal/linux - eal_interrupts.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 140 544 25.7 %
Date: 2025-02-01 18:54:23 Functions: 10 41 24.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 104 381 27.3 %

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

Generated by: LCOV version 1.14