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

Generated by: LCOV version 1.14