LCOV - code coverage report
Current view: top level - drivers/vdpa/mlx5 - mlx5_vdpa_event.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 340 0.0 %
Date: 2024-12-01 18:57:19 Functions: 0 23 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 178 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright 2019 Mellanox Technologies, Ltd
       3                 :            :  */
       4                 :            : #include <unistd.h>
       5                 :            : #include <stdint.h>
       6                 :            : #include <sched.h>
       7                 :            : #include <fcntl.h>
       8                 :            : #include <sys/eventfd.h>
       9                 :            : 
      10                 :            : #include <rte_malloc.h>
      11                 :            : #include <rte_memory.h>
      12                 :            : #include <rte_errno.h>
      13                 :            : #include <rte_lcore.h>
      14                 :            : #include <rte_atomic.h>
      15                 :            : #include <rte_common.h>
      16                 :            : #include <rte_io.h>
      17                 :            : #include <rte_alarm.h>
      18                 :            : 
      19                 :            : #include <mlx5_common.h>
      20                 :            : #include <mlx5_common_os.h>
      21                 :            : #include <mlx5_common_devx.h>
      22                 :            : #include <mlx5_glue.h>
      23                 :            : 
      24                 :            : #include "mlx5_vdpa_utils.h"
      25                 :            : #include "mlx5_vdpa.h"
      26                 :            : 
      27                 :            : 
      28                 :            : #define MLX5_VDPA_ERROR_TIME_SEC 3u
      29                 :            : 
      30                 :            : void
      31                 :          0 : mlx5_vdpa_event_qp_global_release(struct mlx5_vdpa_priv *priv)
      32                 :            : {
      33                 :          0 :         mlx5_devx_uar_release(&priv->uar);
      34                 :            : #ifdef HAVE_IBV_DEVX_EVENT
      35         [ #  # ]:          0 :         if (priv->eventc) {
      36                 :            :                 mlx5_os_devx_destroy_event_channel(priv->eventc);
      37                 :          0 :                 priv->eventc = NULL;
      38                 :            :         }
      39                 :            : #endif
      40                 :          0 : }
      41                 :            : 
      42                 :            : /* Prepare all the global resources for all the event objects.*/
      43                 :            : int
      44                 :          0 : mlx5_vdpa_event_qp_global_prepare(struct mlx5_vdpa_priv *priv)
      45                 :            : {
      46                 :          0 :         priv->eventc = mlx5_os_devx_create_event_channel(priv->cdev->ctx,
      47                 :            :                            MLX5DV_DEVX_CREATE_EVENT_CHANNEL_FLAGS_OMIT_EV_DATA);
      48         [ #  # ]:          0 :         if (!priv->eventc) {
      49                 :          0 :                 rte_errno = errno;
      50                 :          0 :                 DRV_LOG(ERR, "Failed to create event channel %d.",
      51                 :            :                         rte_errno);
      52                 :          0 :                 goto error;
      53                 :            :         }
      54         [ #  # ]:          0 :         if (mlx5_devx_uar_prepare(priv->cdev, &priv->uar) != 0) {
      55                 :          0 :                 DRV_LOG(ERR, "Failed to allocate UAR.");
      56                 :          0 :                 goto error;
      57                 :            :         }
      58                 :            :         return 0;
      59                 :          0 : error:
      60                 :          0 :         mlx5_vdpa_event_qp_global_release(priv);
      61                 :          0 :         return -1;
      62                 :            : }
      63                 :            : 
      64                 :            : static void
      65                 :          0 : mlx5_vdpa_cq_destroy(struct mlx5_vdpa_cq *cq)
      66                 :            : {
      67                 :          0 :         mlx5_devx_cq_destroy(&cq->cq_obj);
      68                 :            :         memset(cq, 0, sizeof(*cq));
      69                 :          0 : }
      70                 :            : 
      71                 :            : static inline void __rte_unused
      72                 :          0 : mlx5_vdpa_cq_arm(struct mlx5_vdpa_priv *priv, struct mlx5_vdpa_cq *cq)
      73                 :            : {
      74                 :          0 :         uint32_t arm_sn = cq->arm_sn << MLX5_CQ_SQN_OFFSET;
      75                 :          0 :         uint32_t cq_ci = cq->cq_ci & MLX5_CI_MASK;
      76                 :          0 :         uint32_t doorbell_hi = arm_sn | MLX5_CQ_DBR_CMD_ALL | cq_ci;
      77                 :          0 :         uint64_t doorbell = ((uint64_t)doorbell_hi << 32) | cq->cq_obj.cq->id;
      78         [ #  # ]:          0 :         uint64_t db_be = rte_cpu_to_be_64(doorbell);
      79                 :            : 
      80                 :            :         mlx5_doorbell_ring(&priv->uar.cq_db, db_be, doorbell_hi,
      81                 :          0 :                            &cq->cq_obj.db_rec[MLX5_CQ_ARM_DB], 0);
      82                 :          0 :         cq->arm_sn++;
      83                 :          0 :         cq->armed = 1;
      84                 :          0 : }
      85                 :            : 
      86                 :            : static int
      87                 :          0 : mlx5_vdpa_cq_create(struct mlx5_vdpa_priv *priv, uint16_t log_desc_n,
      88                 :            :                 int callfd, struct mlx5_vdpa_virtq *virtq)
      89                 :            : {
      90                 :          0 :         struct mlx5_devx_cq_attr attr = {
      91                 :            :                 .use_first_only = 1,
      92         [ #  # ]:          0 :                 .uar_page_id = mlx5_os_get_devx_uar_page_id(priv->uar.obj),
      93                 :            :         };
      94                 :          0 :         struct mlx5_vdpa_cq *cq = &virtq->eqp.cq;
      95                 :          0 :         uint16_t event_nums[1] = {0};
      96                 :            :         int ret;
      97                 :            : 
      98                 :          0 :         ret = mlx5_devx_cq_create(priv->cdev->ctx, &cq->cq_obj, log_desc_n,
      99                 :            :                                   &attr, SOCKET_ID_ANY);
     100         [ #  # ]:          0 :         if (ret)
     101                 :          0 :                 goto error;
     102                 :          0 :         cq->cq_ci = 0;
     103                 :          0 :         cq->log_desc_n = log_desc_n;
     104                 :            :         rte_spinlock_init(&cq->sl);
     105                 :            :         /* Subscribe CQ event to the event channel controlled by the driver. */
     106                 :          0 :         ret = mlx5_glue->devx_subscribe_devx_event(priv->eventc,
     107                 :          0 :                                                         cq->cq_obj.cq->obj,
     108                 :            :                                                    sizeof(event_nums),
     109                 :            :                                                    event_nums,
     110                 :            :                                                    (uint64_t)(uintptr_t)virtq);
     111         [ #  # ]:          0 :         if (ret) {
     112                 :          0 :                 DRV_LOG(ERR, "Failed to subscribe CQE event.");
     113                 :          0 :                 rte_errno = errno;
     114                 :          0 :                 goto error;
     115                 :            :         }
     116                 :          0 :         cq->callfd = callfd;
     117                 :            :         /* Init CQ to ones to be in HW owner in the start. */
     118                 :          0 :         cq->cq_obj.cqes[0].op_own = MLX5_CQE_OWNER_MASK;
     119                 :          0 :         cq->cq_obj.cqes[0].wqe_counter = rte_cpu_to_be_16(UINT16_MAX);
     120                 :            :         /* First arming. */
     121                 :          0 :         mlx5_vdpa_cq_arm(priv, cq);
     122                 :          0 :         return 0;
     123                 :          0 : error:
     124                 :          0 :         mlx5_vdpa_cq_destroy(cq);
     125                 :          0 :         return -1;
     126                 :            : }
     127                 :            : 
     128                 :            : static inline uint32_t
     129                 :          0 : mlx5_vdpa_cq_poll(struct mlx5_vdpa_cq *cq)
     130                 :            : {
     131                 :            :         struct mlx5_vdpa_event_qp *eqp =
     132                 :            :                                 container_of(cq, struct mlx5_vdpa_event_qp, cq);
     133                 :          0 :         const unsigned int cq_size = 1 << cq->log_desc_n;
     134                 :            :         union {
     135                 :            :                 struct {
     136                 :            :                         uint16_t wqe_counter;
     137                 :            :                         uint8_t rsvd5;
     138                 :            :                         uint8_t op_own;
     139                 :            :                 };
     140                 :            :                 uint32_t word;
     141                 :            :         } last_word;
     142                 :          0 :         uint16_t next_wqe_counter = eqp->qp_pi;
     143                 :            :         uint16_t cur_wqe_counter;
     144                 :            :         uint16_t comp;
     145                 :            : 
     146                 :          0 :         last_word.word = rte_read32(&cq->cq_obj.cqes[0].wqe_counter);
     147         [ #  # ]:          0 :         cur_wqe_counter = rte_be_to_cpu_16(last_word.wqe_counter);
     148                 :          0 :         comp = cur_wqe_counter + (uint16_t)1 - next_wqe_counter;
     149         [ #  # ]:          0 :         if (comp) {
     150                 :          0 :                 cq->cq_ci += comp;
     151                 :            :                 MLX5_ASSERT(MLX5_CQE_OPCODE(last_word.op_own) !=
     152                 :            :                             MLX5_CQE_INVALID);
     153         [ #  # ]:          0 :                 if (unlikely(!(MLX5_CQE_OPCODE(last_word.op_own) ==
     154                 :            :                                MLX5_CQE_RESP_ERR ||
     155                 :            :                                MLX5_CQE_OPCODE(last_word.op_own) ==
     156                 :            :                                MLX5_CQE_REQ_ERR)))
     157                 :          0 :                         cq->errors++;
     158                 :          0 :                 rte_io_wmb();
     159                 :            :                 /* Ring CQ doorbell record. */
     160         [ #  # ]:          0 :                 cq->cq_obj.db_rec[0] = rte_cpu_to_be_32(cq->cq_ci);
     161                 :          0 :                 eqp->qp_pi += comp;
     162                 :          0 :                 rte_io_wmb();
     163                 :            :                 /* Ring SW QP doorbell record. */
     164         [ #  # ]:          0 :                 eqp->sw_qp.db_rec[0] = rte_cpu_to_be_32(eqp->qp_pi + cq_size);
     165                 :            :         }
     166                 :          0 :         return comp;
     167                 :            : }
     168                 :            : 
     169                 :            : static void
     170                 :          0 : mlx5_vdpa_arm_all_cqs(struct mlx5_vdpa_priv *priv)
     171                 :            : {
     172                 :            :         struct mlx5_vdpa_virtq *virtq;
     173                 :            :         struct mlx5_vdpa_cq *cq;
     174                 :            :         int i;
     175                 :            : 
     176         [ #  # ]:          0 :         for (i = 0; i < priv->nr_virtqs; i++) {
     177                 :            :                 virtq = &priv->virtqs[i];
     178                 :          0 :                 pthread_mutex_lock(&virtq->virtq_lock);
     179                 :          0 :                 cq = &priv->virtqs[i].eqp.cq;
     180   [ #  #  #  # ]:          0 :                 if (cq->cq_obj.cq && !cq->armed)
     181                 :          0 :                         mlx5_vdpa_cq_arm(priv, cq);
     182                 :          0 :                 pthread_mutex_unlock(&virtq->virtq_lock);
     183                 :            :         }
     184                 :          0 : }
     185                 :            : 
     186                 :            : static void
     187                 :          0 : mlx5_vdpa_timer_sleep(struct mlx5_vdpa_priv *priv, uint32_t max)
     188                 :            : {
     189         [ #  # ]:          0 :         if (priv->event_mode == MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER) {
     190      [ #  #  # ]:          0 :                 switch (max) {
     191                 :          0 :                 case 0:
     192                 :          0 :                         priv->timer_delay_us += priv->event_us;
     193                 :          0 :                         break;
     194                 :            :                 case 1:
     195                 :            :                         break;
     196                 :          0 :                 default:
     197                 :          0 :                         priv->timer_delay_us /= max;
     198                 :          0 :                         break;
     199                 :            :                 }
     200                 :            :         }
     201         [ #  # ]:          0 :         if (priv->timer_delay_us)
     202                 :          0 :                 usleep(priv->timer_delay_us);
     203                 :            :         else
     204                 :            :                 /* Give-up CPU to improve polling threads scheduling. */
     205                 :          0 :                 sched_yield();
     206                 :          0 : }
     207                 :            : 
     208                 :            : /* Notify virtio device for specific virtq new traffic. */
     209                 :            : static uint32_t
     210                 :          0 : mlx5_vdpa_queue_complete(struct mlx5_vdpa_cq *cq)
     211                 :            : {
     212                 :            :         uint32_t comp = 0;
     213                 :            : 
     214         [ #  # ]:          0 :         if (cq->cq_obj.cq) {
     215                 :          0 :                 comp = mlx5_vdpa_cq_poll(cq);
     216         [ #  # ]:          0 :                 if (comp) {
     217         [ #  # ]:          0 :                         if (cq->callfd != -1)
     218                 :          0 :                                 eventfd_write(cq->callfd, (eventfd_t)1);
     219                 :          0 :                         cq->armed = 0;
     220                 :            :                 }
     221                 :            :         }
     222                 :          0 :         return comp;
     223                 :            : }
     224                 :            : 
     225                 :            : /* Notify virtio device for any virtq new traffic. */
     226                 :            : static uint32_t
     227                 :          0 : mlx5_vdpa_queues_complete(struct mlx5_vdpa_priv *priv)
     228                 :            : {
     229                 :            :         struct mlx5_vdpa_virtq *virtq;
     230                 :            :         struct mlx5_vdpa_cq *cq;
     231                 :            :         uint32_t max = 0;
     232                 :            :         uint32_t comp;
     233                 :            :         int i;
     234                 :            : 
     235         [ #  # ]:          0 :         for (i = 0; i < priv->nr_virtqs; i++) {
     236                 :            :                 virtq = &priv->virtqs[i];
     237                 :          0 :                 pthread_mutex_lock(&virtq->virtq_lock);
     238                 :          0 :                 cq = &virtq->eqp.cq;
     239                 :          0 :                 comp = mlx5_vdpa_queue_complete(cq);
     240                 :          0 :                 pthread_mutex_unlock(&virtq->virtq_lock);
     241                 :            :                 if (comp > max)
     242                 :            :                         max = comp;
     243                 :            :         }
     244                 :          0 :         return max;
     245                 :            : }
     246                 :            : 
     247                 :            : static void
     248                 :          0 : mlx5_vdpa_drain_cq_one(struct mlx5_vdpa_priv *priv,
     249                 :            :         struct mlx5_vdpa_virtq *virtq)
     250                 :            : {
     251                 :          0 :         struct mlx5_vdpa_cq *cq = &virtq->eqp.cq;
     252                 :            : 
     253                 :          0 :         mlx5_vdpa_queue_complete(cq);
     254         [ #  # ]:          0 :         if (cq->cq_obj.cq) {
     255                 :          0 :                 cq->cq_obj.cqes[0].wqe_counter = rte_cpu_to_be_16(UINT16_MAX);
     256                 :          0 :                 virtq->eqp.qp_pi = 0;
     257         [ #  # ]:          0 :                 if (!cq->armed)
     258                 :          0 :                         mlx5_vdpa_cq_arm(priv, cq);
     259                 :            :         }
     260                 :          0 : }
     261                 :            : 
     262                 :            : void
     263                 :          0 : mlx5_vdpa_drain_cq(struct mlx5_vdpa_priv *priv)
     264                 :            : {
     265                 :            :         struct mlx5_vdpa_virtq *virtq;
     266                 :            :         unsigned int i;
     267                 :            : 
     268         [ #  # ]:          0 :         for (i = 0; i < priv->caps.max_num_virtio_queues; i++) {
     269                 :          0 :                 virtq = &priv->virtqs[i];
     270                 :          0 :                 mlx5_vdpa_drain_cq_one(priv, virtq);
     271                 :            :         }
     272                 :          0 : }
     273                 :            : 
     274                 :            : /* Wait on all CQs channel for completion event. */
     275                 :            : static struct mlx5_vdpa_virtq *
     276                 :          0 : mlx5_vdpa_event_wait(struct mlx5_vdpa_priv *priv __rte_unused)
     277                 :            : {
     278                 :            : #ifdef HAVE_IBV_DEVX_EVENT
     279                 :            :         union {
     280                 :            :                 struct mlx5dv_devx_async_event_hdr event_resp;
     281                 :            :                 uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
     282                 :            :         } out;
     283                 :          0 :         int ret = mlx5_glue->devx_get_event(priv->eventc, &out.event_resp,
     284                 :            :                                             sizeof(out.buf));
     285                 :            : 
     286         [ #  # ]:          0 :         if (ret >= 0)
     287                 :          0 :                 return (struct mlx5_vdpa_virtq *)
     288                 :          0 :                                 (uintptr_t)out.event_resp.cookie;
     289                 :          0 :         DRV_LOG(INFO, "Got error in devx_get_event, ret = %d, errno = %d.",
     290                 :            :                 ret, errno);
     291                 :            : #endif
     292                 :          0 :         return NULL;
     293                 :            : }
     294                 :            : 
     295                 :            : static uint32_t
     296                 :          0 : mlx5_vdpa_event_handle(void *arg)
     297                 :            : {
     298                 :            :         struct mlx5_vdpa_priv *priv = arg;
     299                 :            :         struct mlx5_vdpa_virtq *virtq;
     300                 :            :         uint32_t max;
     301                 :            : 
     302      [ #  #  # ]:          0 :         switch (priv->event_mode) {
     303                 :          0 :         case MLX5_VDPA_EVENT_MODE_DYNAMIC_TIMER:
     304                 :            :         case MLX5_VDPA_EVENT_MODE_FIXED_TIMER:
     305                 :          0 :                 priv->timer_delay_us = priv->event_us;
     306                 :            :                 while (1) {
     307                 :          0 :                         max = mlx5_vdpa_queues_complete(priv);
     308         [ #  # ]:          0 :                         if (max == 0 && priv->no_traffic_counter++ >=
     309         [ #  # ]:          0 :                             priv->no_traffic_max) {
     310                 :          0 :                                 DRV_LOG(DEBUG, "Device %s traffic was stopped.",
     311                 :            :                                         priv->vdev->device->name);
     312                 :          0 :                                 mlx5_vdpa_arm_all_cqs(priv);
     313                 :            :                                 do {
     314                 :          0 :                                         virtq = mlx5_vdpa_event_wait(priv);
     315         [ #  # ]:          0 :                                         if (virtq == NULL)
     316                 :            :                                                 break;
     317                 :          0 :                                         pthread_mutex_lock(
     318                 :            :                                                 &virtq->virtq_lock);
     319         [ #  # ]:          0 :                                         if (mlx5_vdpa_queue_complete(
     320                 :            :                                                 &virtq->eqp.cq) > 0) {
     321                 :          0 :                                                 pthread_mutex_unlock(
     322                 :            :                                                         &virtq->virtq_lock);
     323                 :          0 :                                                 break;
     324                 :            :                                         }
     325                 :          0 :                                         pthread_mutex_unlock(
     326                 :            :                                                 &virtq->virtq_lock);
     327                 :            :                                 } while (1);
     328                 :          0 :                                 priv->timer_delay_us = priv->event_us;
     329                 :          0 :                                 priv->no_traffic_counter = 0;
     330         [ #  # ]:          0 :                         } else if (max != 0) {
     331                 :          0 :                                 priv->no_traffic_counter = 0;
     332                 :            :                         }
     333                 :          0 :                         mlx5_vdpa_timer_sleep(priv, max);
     334                 :            :                 }
     335                 :            :                 return 0;
     336                 :          0 :         case MLX5_VDPA_EVENT_MODE_ONLY_INTERRUPT:
     337                 :            :                 do {
     338                 :          0 :                         virtq = mlx5_vdpa_event_wait(priv);
     339         [ #  # ]:          0 :                         if (virtq != NULL) {
     340                 :          0 :                                 pthread_mutex_lock(&virtq->virtq_lock);
     341         [ #  # ]:          0 :                                 if (mlx5_vdpa_queue_complete(
     342                 :            :                                         &virtq->eqp.cq) > 0)
     343                 :          0 :                                         mlx5_vdpa_cq_arm(priv, &virtq->eqp.cq);
     344                 :          0 :                                 pthread_mutex_unlock(&virtq->virtq_lock);
     345                 :            :                         }
     346                 :            :                 } while (1);
     347                 :            :                 return 0;
     348                 :          0 :         default:
     349                 :            :                 return 0;
     350                 :            :         }
     351                 :            : }
     352                 :            : 
     353                 :            : static void
     354                 :          0 : mlx5_vdpa_err_interrupt_handler(void *cb_arg __rte_unused)
     355                 :            : {
     356                 :            : #ifdef HAVE_IBV_DEVX_EVENT
     357                 :            :         struct mlx5_vdpa_priv *priv = cb_arg;
     358                 :            :         union {
     359                 :            :                 struct mlx5dv_devx_async_event_hdr event_resp;
     360                 :            :                 uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) + 128];
     361                 :            :         } out;
     362                 :            :         uint32_t vq_index, i, version;
     363                 :            :         struct mlx5_vdpa_virtq *virtq;
     364                 :            :         uint64_t sec;
     365                 :            : 
     366                 :          0 :         while (mlx5_glue->devx_get_event(priv->err_chnl, &out.event_resp,
     367         [ #  # ]:          0 :                                          sizeof(out.buf)) >=
     368                 :            :                                        (ssize_t)sizeof(out.event_resp.cookie)) {
     369                 :          0 :                 vq_index = out.event_resp.cookie & UINT32_MAX;
     370                 :          0 :                 version = out.event_resp.cookie >> 32;
     371         [ #  # ]:          0 :                 if (vq_index >= priv->nr_virtqs) {
     372                 :          0 :                         DRV_LOG(ERR, "Invalid device %s error event virtq %d.",
     373                 :            :                                 priv->vdev->device->name, vq_index);
     374                 :          0 :                         continue;
     375                 :            :                 }
     376                 :            :                 virtq = &priv->virtqs[vq_index];
     377                 :          0 :                 pthread_mutex_lock(&virtq->virtq_lock);
     378   [ #  #  #  # ]:          0 :                 if (!virtq->enable || virtq->version != version)
     379                 :          0 :                         goto unlock;
     380         [ #  # ]:          0 :                 if (rte_rdtsc() / rte_get_tsc_hz() < MLX5_VDPA_ERROR_TIME_SEC)
     381                 :          0 :                         goto unlock;
     382                 :          0 :                 virtq->stopped = 1;
     383                 :            :                 /* Query error info. */
     384         [ #  # ]:          0 :                 if (mlx5_vdpa_virtq_query(priv, vq_index))
     385                 :          0 :                         goto log;
     386                 :            :                 /* Disable vq. */
     387         [ #  # ]:          0 :                 if (mlx5_vdpa_virtq_enable(priv, vq_index, 0)) {
     388                 :          0 :                         DRV_LOG(ERR, "Failed to disable virtq %d.", vq_index);
     389                 :          0 :                         goto log;
     390                 :            :                 }
     391                 :            :                 /* Retry if error happens less than N times in 3 seconds. */
     392                 :          0 :                 sec = (rte_rdtsc() - virtq->err_time[0]) / rte_get_tsc_hz();
     393         [ #  # ]:          0 :                 if (sec > MLX5_VDPA_ERROR_TIME_SEC) {
     394                 :            :                         /* Retry. */
     395         [ #  # ]:          0 :                         if (mlx5_vdpa_virtq_enable(priv, vq_index, 1))
     396                 :          0 :                                 DRV_LOG(ERR, "Failed to enable virtq %d.",
     397                 :            :                                         vq_index);
     398                 :            :                         else
     399                 :          0 :                                 DRV_LOG(WARNING, "Recover virtq %d: %u.",
     400                 :            :                                         vq_index, ++virtq->n_retry);
     401                 :            :                 } else {
     402                 :            :                         /* Retry timeout, give up. */
     403                 :          0 :                         DRV_LOG(ERR, "Device %s virtq %d failed to recover.",
     404                 :            :                                 priv->vdev->device->name, vq_index);
     405                 :            :                 }
     406                 :            : log:
     407                 :            :                 /* Shift in current time to error time log end. */
     408         [ #  # ]:          0 :                 for (i = 1; i < RTE_DIM(virtq->err_time); i++)
     409                 :          0 :                         virtq->err_time[i - 1] = virtq->err_time[i];
     410                 :          0 :                 virtq->err_time[RTE_DIM(virtq->err_time) - 1] = rte_rdtsc();
     411                 :          0 : unlock:
     412                 :          0 :                 pthread_mutex_unlock(&virtq->virtq_lock);
     413                 :            :         }
     414                 :            : #endif
     415                 :          0 : }
     416                 :            : 
     417                 :            : int
     418                 :          0 : mlx5_vdpa_err_event_setup(struct mlx5_vdpa_priv *priv)
     419                 :            : {
     420                 :            :         int ret;
     421                 :            :         int flags;
     422                 :            : 
     423                 :            :         /* Setup device event channel. */
     424                 :          0 :         priv->err_chnl = mlx5_glue->devx_create_event_channel(priv->cdev->ctx,
     425                 :            :                                                               0);
     426         [ #  # ]:          0 :         if (!priv->err_chnl) {
     427                 :          0 :                 rte_errno = errno;
     428                 :          0 :                 DRV_LOG(ERR, "Failed to create device event channel %d.",
     429                 :            :                         rte_errno);
     430                 :          0 :                 goto error;
     431                 :            :         }
     432                 :          0 :         flags = fcntl(priv->err_chnl->fd, F_GETFL);
     433                 :          0 :         ret = fcntl(priv->err_chnl->fd, F_SETFL, flags | O_NONBLOCK);
     434         [ #  # ]:          0 :         if (ret) {
     435                 :          0 :                 rte_errno = errno;
     436                 :          0 :                 DRV_LOG(ERR, "Failed to change device event channel FD.");
     437                 :          0 :                 goto error;
     438                 :            :         }
     439                 :          0 :         priv->err_intr_handle =
     440                 :          0 :                 rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_SHARED);
     441         [ #  # ]:          0 :         if (priv->err_intr_handle == NULL) {
     442                 :          0 :                 DRV_LOG(ERR, "Fail to allocate intr_handle");
     443                 :          0 :                 goto error;
     444                 :            :         }
     445         [ #  # ]:          0 :         if (rte_intr_fd_set(priv->err_intr_handle, priv->err_chnl->fd))
     446                 :          0 :                 goto error;
     447                 :            : 
     448         [ #  # ]:          0 :         if (rte_intr_type_set(priv->err_intr_handle, RTE_INTR_HANDLE_EXT))
     449                 :          0 :                 goto error;
     450                 :            : 
     451                 :          0 :         ret = rte_intr_callback_register(priv->err_intr_handle,
     452                 :            :                                          mlx5_vdpa_err_interrupt_handler,
     453                 :            :                                          priv);
     454         [ #  # ]:          0 :         if (ret != 0) {
     455                 :          0 :                 rte_intr_fd_set(priv->err_intr_handle, 0);
     456                 :          0 :                 DRV_LOG(ERR, "Failed to register error interrupt for device %d.",
     457                 :            :                         priv->vid);
     458                 :          0 :                 rte_errno = -ret;
     459                 :          0 :                 goto error;
     460                 :            :         } else {
     461                 :          0 :                 DRV_LOG(DEBUG, "Registered error interrupt for device%d.",
     462                 :            :                         priv->vid);
     463                 :            :         }
     464                 :          0 :         return 0;
     465                 :          0 : error:
     466                 :          0 :         mlx5_vdpa_err_event_unset(priv);
     467                 :          0 :         return -1;
     468                 :            : }
     469                 :            : 
     470                 :            : void
     471                 :          0 : mlx5_vdpa_err_event_unset(struct mlx5_vdpa_priv *priv)
     472                 :            : {
     473                 :            :         int retries = MLX5_VDPA_INTR_RETRIES;
     474                 :            :         int ret = -EAGAIN;
     475                 :            : 
     476         [ #  # ]:          0 :         if (!rte_intr_fd_get(priv->err_intr_handle))
     477                 :            :                 return;
     478   [ #  #  #  # ]:          0 :         while (retries-- && ret == -EAGAIN) {
     479                 :          0 :                 ret = rte_intr_callback_unregister(priv->err_intr_handle,
     480                 :            :                                             mlx5_vdpa_err_interrupt_handler,
     481                 :            :                                             priv);
     482         [ #  # ]:          0 :                 if (ret == -EAGAIN) {
     483                 :          0 :                         DRV_LOG(DEBUG, "Try again to unregister fd %d "
     484                 :            :                                 "of error interrupt, retries = %d.",
     485                 :            :                                 rte_intr_fd_get(priv->err_intr_handle),
     486                 :            :                                 retries);
     487                 :            :                         rte_pause();
     488                 :            :                 }
     489                 :            :         }
     490         [ #  # ]:          0 :         if (priv->err_chnl) {
     491                 :            : #ifdef HAVE_IBV_DEVX_EVENT
     492                 :            :                 union {
     493                 :            :                         struct mlx5dv_devx_async_event_hdr event_resp;
     494                 :            :                         uint8_t buf[sizeof(struct mlx5dv_devx_async_event_hdr) +
     495                 :            :                                     128];
     496                 :            :                 } out;
     497                 :            : 
     498                 :            :                 /* Clean all pending events. */
     499                 :          0 :                 while (mlx5_glue->devx_get_event(priv->err_chnl,
     500         [ #  # ]:          0 :                        &out.event_resp, sizeof(out.buf)) >=
     501                 :            :                        (ssize_t)sizeof(out.event_resp.cookie))
     502                 :            :                         ;
     503                 :            : #endif
     504                 :          0 :                 mlx5_glue->devx_destroy_event_channel(priv->err_chnl);
     505                 :          0 :                 priv->err_chnl = NULL;
     506                 :            :         }
     507                 :          0 :         rte_intr_instance_free(priv->err_intr_handle);
     508                 :            : }
     509                 :            : 
     510                 :            : int
     511                 :          0 : mlx5_vdpa_cqe_event_setup(struct mlx5_vdpa_priv *priv)
     512                 :            : {
     513                 :            :         int ret;
     514                 :            :         rte_thread_attr_t attr;
     515                 :            :         char name[RTE_THREAD_INTERNAL_NAME_SIZE];
     516                 :            : 
     517         [ #  # ]:          0 :         if (!priv->eventc)
     518                 :            :                 /* All virtqs are in poll mode. */
     519                 :            :                 return 0;
     520                 :          0 :         ret = rte_thread_attr_init(&attr);
     521         [ #  # ]:          0 :         if (ret != 0) {
     522                 :          0 :                 DRV_LOG(ERR, "Failed to initialize thread attributes");
     523                 :          0 :                 goto out;
     524                 :            :         }
     525         [ #  # ]:          0 :         if (priv->event_core != -1)
     526         [ #  # ]:          0 :                 CPU_SET(priv->event_core, &attr.cpuset);
     527                 :            :         else
     528                 :          0 :                 attr.cpuset = rte_lcore_cpuset(rte_get_main_lcore());
     529                 :          0 :         ret = rte_thread_create(&priv->timer_tid,
     530                 :            :                         &attr, mlx5_vdpa_event_handle, priv);
     531         [ #  # ]:          0 :         if (ret != 0) {
     532                 :          0 :                 DRV_LOG(ERR, "Failed to create timer thread.");
     533                 :          0 :                 goto out;
     534                 :            :         }
     535                 :          0 :         snprintf(name, sizeof(name), "vmlx5-%d", priv->vid);
     536                 :          0 :         rte_thread_set_prefixed_name(priv->timer_tid, name);
     537                 :          0 : out:
     538         [ #  # ]:          0 :         if (ret != 0)
     539                 :          0 :                 return -1;
     540                 :            :         return 0;
     541                 :            : }
     542                 :            : 
     543                 :            : void
     544                 :          0 : mlx5_vdpa_cqe_event_unset(struct mlx5_vdpa_priv *priv)
     545                 :            : {
     546                 :            :         struct mlx5_vdpa_virtq *virtq;
     547                 :            :         int i;
     548                 :            : 
     549         [ #  # ]:          0 :         if (priv->timer_tid.opaque_id != 0) {
     550                 :          0 :                 pthread_cancel((pthread_t)priv->timer_tid.opaque_id);
     551                 :          0 :                 rte_thread_join(priv->timer_tid, NULL);
     552                 :            :                 /* The mutex may stay locked after event thread cancel, initiate it. */
     553         [ #  # ]:          0 :                 for (i = 0; i < priv->nr_virtqs; i++) {
     554                 :            :                         virtq = &priv->virtqs[i];
     555                 :          0 :                         pthread_mutex_init(&virtq->virtq_lock, NULL);
     556                 :            :                 }
     557                 :            :         }
     558                 :          0 :         priv->timer_tid.opaque_id = 0;
     559                 :          0 : }
     560                 :            : 
     561                 :            : void
     562                 :          0 : mlx5_vdpa_event_qp_destroy(struct mlx5_vdpa_event_qp *eqp)
     563                 :            : {
     564                 :          0 :         mlx5_devx_qp_destroy(&eqp->sw_qp);
     565         [ #  # ]:          0 :         if (eqp->fw_qp)
     566                 :          0 :                 claim_zero(mlx5_devx_cmd_destroy(eqp->fw_qp));
     567                 :          0 :         mlx5_vdpa_cq_destroy(&eqp->cq);
     568                 :            :         memset(eqp, 0, sizeof(*eqp));
     569                 :          0 : }
     570                 :            : 
     571                 :            : static int
     572                 :          0 : mlx5_vdpa_qps2rts(struct mlx5_vdpa_event_qp *eqp)
     573                 :            : {
     574         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RST2INIT_QP,
     575                 :          0 :                                           eqp->sw_qp.qp->id)) {
     576                 :          0 :                 DRV_LOG(ERR, "Failed to modify FW QP to INIT state(%u).",
     577                 :            :                         rte_errno);
     578                 :          0 :                 return -1;
     579                 :            :         }
     580         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
     581                 :          0 :                         MLX5_CMD_OP_RST2INIT_QP, eqp->fw_qp->id)) {
     582                 :          0 :                 DRV_LOG(ERR, "Failed to modify SW QP to INIT state(%u).",
     583                 :            :                         rte_errno);
     584                 :          0 :                 return -1;
     585                 :            :         }
     586         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_INIT2RTR_QP,
     587                 :          0 :                                           eqp->sw_qp.qp->id)) {
     588                 :          0 :                 DRV_LOG(ERR, "Failed to modify FW QP to RTR state(%u).",
     589                 :            :                         rte_errno);
     590                 :          0 :                 return -1;
     591                 :            :         }
     592         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
     593                 :          0 :                         MLX5_CMD_OP_INIT2RTR_QP, eqp->fw_qp->id)) {
     594                 :          0 :                 DRV_LOG(ERR, "Failed to modify SW QP to RTR state(%u).",
     595                 :            :                         rte_errno);
     596                 :          0 :                 return -1;
     597                 :            :         }
     598         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_RTR2RTS_QP,
     599                 :          0 :                                           eqp->sw_qp.qp->id)) {
     600                 :          0 :                 DRV_LOG(ERR, "Failed to modify FW QP to RTS state(%u).",
     601                 :            :                         rte_errno);
     602                 :          0 :                 return -1;
     603                 :            :         }
     604         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp, MLX5_CMD_OP_RTR2RTS_QP,
     605                 :          0 :                                           eqp->fw_qp->id)) {
     606                 :          0 :                 DRV_LOG(ERR, "Failed to modify SW QP to RTS state(%u).",
     607                 :            :                         rte_errno);
     608                 :          0 :                 return -1;
     609                 :            :         }
     610                 :            :         return 0;
     611                 :            : }
     612                 :            : 
     613                 :            : int
     614                 :          0 : mlx5_vdpa_qps2rst2rts(struct mlx5_vdpa_event_qp *eqp)
     615                 :            : {
     616         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->fw_qp, MLX5_CMD_OP_QP_2RST,
     617                 :          0 :                                           eqp->sw_qp.qp->id)) {
     618                 :          0 :                 DRV_LOG(ERR, "Failed to modify FW QP to RST state(%u).",
     619                 :            :                         rte_errno);
     620                 :          0 :                 return -1;
     621                 :            :         }
     622         [ #  # ]:          0 :         if (mlx5_devx_cmd_modify_qp_state(eqp->sw_qp.qp,
     623                 :          0 :                         MLX5_CMD_OP_QP_2RST, eqp->fw_qp->id)) {
     624                 :          0 :                 DRV_LOG(ERR, "Failed to modify SW QP to RST state(%u).",
     625                 :            :                         rte_errno);
     626                 :          0 :                 return -1;
     627                 :            :         }
     628                 :          0 :         return mlx5_vdpa_qps2rts(eqp);
     629                 :            : }
     630                 :            : 
     631                 :            : int
     632                 :          0 : mlx5_vdpa_event_qp_prepare(struct mlx5_vdpa_priv *priv, uint16_t desc_n,
     633                 :            :         int callfd, struct mlx5_vdpa_virtq *virtq, bool reset)
     634                 :            : {
     635                 :          0 :         struct mlx5_vdpa_event_qp *eqp = &virtq->eqp;
     636                 :          0 :         struct mlx5_devx_qp_attr attr = {0};
     637         [ #  # ]:          0 :         uint16_t log_desc_n = rte_log2_u32(desc_n);
     638                 :            :         uint32_t ret;
     639                 :            : 
     640   [ #  #  #  # ]:          0 :         if (eqp->cq.cq_obj.cq != NULL && log_desc_n == eqp->cq.log_desc_n) {
     641                 :            :                 /* Reuse existing resources. */
     642                 :          0 :                 eqp->cq.callfd = callfd;
     643                 :          0 :                 mlx5_vdpa_drain_cq_one(priv, virtq);
     644                 :            :                 /* FW will set event qp to error state in q destroy. */
     645   [ #  #  #  # ]:          0 :                 if (reset && !mlx5_vdpa_qps2rst2rts(eqp))
     646                 :          0 :                         rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
     647         [ #  # ]:          0 :                                         &eqp->sw_qp.db_rec[0]);
     648                 :          0 :                 return 0;
     649                 :            :         }
     650         [ #  # ]:          0 :         if (eqp->fw_qp)
     651                 :          0 :                 mlx5_vdpa_event_qp_destroy(eqp);
     652         [ #  # ]:          0 :         if (mlx5_vdpa_cq_create(priv, log_desc_n, callfd, virtq) ||
     653         [ #  # ]:          0 :                 !eqp->cq.cq_obj.cq)
     654                 :            :                 return -1;
     655                 :          0 :         attr.pd = priv->cdev->pdn;
     656                 :          0 :         attr.ts_format =
     657                 :          0 :                 mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
     658                 :          0 :         eqp->fw_qp = mlx5_devx_cmd_create_qp(priv->cdev->ctx, &attr);
     659         [ #  # ]:          0 :         if (!eqp->fw_qp) {
     660                 :          0 :                 DRV_LOG(ERR, "Failed to create FW QP(%u).", rte_errno);
     661                 :          0 :                 goto error;
     662                 :            :         }
     663         [ #  # ]:          0 :         attr.uar_index = mlx5_os_get_devx_uar_page_id(priv->uar.obj);
     664                 :          0 :         attr.cqn = eqp->cq.cq_obj.cq->id;
     665                 :          0 :         attr.num_of_receive_wqes = RTE_BIT32(log_desc_n);
     666                 :          0 :         attr.log_rq_stride = rte_log2_u32(MLX5_WSEG_SIZE);
     667                 :          0 :         attr.num_of_send_wqbbs = 0; /* No need SQ. */
     668                 :          0 :         attr.ts_format =
     669                 :          0 :                 mlx5_ts_format_conv(priv->cdev->config.hca_attr.qp_ts_format);
     670                 :          0 :         ret = mlx5_devx_qp_create(priv->cdev->ctx, &(eqp->sw_qp),
     671                 :          0 :                                   attr.num_of_receive_wqes * MLX5_WSEG_SIZE,
     672                 :            :                                   &attr, SOCKET_ID_ANY);
     673         [ #  # ]:          0 :         if (ret) {
     674                 :          0 :                 DRV_LOG(ERR, "Failed to create SW QP(%u).", rte_errno);
     675                 :          0 :                 goto error;
     676                 :            :         }
     677         [ #  # ]:          0 :         if (mlx5_vdpa_qps2rts(eqp))
     678                 :          0 :                 goto error;
     679                 :          0 :         eqp->qp_pi = 0;
     680                 :            :         /* First ringing. */
     681         [ #  # ]:          0 :         if (eqp->sw_qp.db_rec)
     682         [ #  # ]:          0 :                 rte_write32(rte_cpu_to_be_32(RTE_BIT32(log_desc_n)),
     683                 :            :                         &eqp->sw_qp.db_rec[0]);
     684                 :            :         return 0;
     685                 :          0 : error:
     686                 :          0 :         mlx5_vdpa_event_qp_destroy(eqp);
     687                 :          0 :         return -1;
     688                 :            : }
     689                 :            : 

Generated by: LCOV version 1.14