LCOV - code coverage report
Current view: top level - lib/eal/linux - eal_interrupts.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 154 569 27.1 %
Date: 2026-04-01 20:02:27 Functions: 12 43 27.9 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 113 399 28.3 %

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

Generated by: LCOV version 1.14