LCOV - code coverage report
Current view: top level - lib/eal/linux - eal_interrupts.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 139 549 25.3 %
Date: 2025-05-01 17:49:45 Functions: 10 41 24.4 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 104 385 27.0 %

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

Generated by: LCOV version 1.14