LCOV - code coverage report
Current view: top level - drivers/net/virtio/virtio_user - virtio_user_dev.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 0 642 0.0 %
Date: 2024-04-01 19:00:53 Functions: 0 36 0.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 0 336 0.0 %

           Branch data     Line data    Source code
       1                 :            : /* SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  * Copyright(c) 2010-2016 Intel Corporation
       3                 :            :  */
       4                 :            : 
       5                 :            : #include <stdint.h>
       6                 :            : #include <stdio.h>
       7                 :            : #include <stdlib.h>
       8                 :            : #include <fcntl.h>
       9                 :            : #include <string.h>
      10                 :            : #include <errno.h>
      11                 :            : #include <sys/mman.h>
      12                 :            : #include <unistd.h>
      13                 :            : #include <sys/eventfd.h>
      14                 :            : #include <sys/types.h>
      15                 :            : #include <sys/stat.h>
      16                 :            : 
      17                 :            : #include <rte_alarm.h>
      18                 :            : #include <rte_string_fns.h>
      19                 :            : #include <rte_eal_memconfig.h>
      20                 :            : #include <rte_malloc.h>
      21                 :            : #include <rte_io.h>
      22                 :            : 
      23                 :            : #include "vhost.h"
      24                 :            : #include "virtio_user_dev.h"
      25                 :            : #include "../virtio_ethdev.h"
      26                 :            : 
      27                 :            : #define VIRTIO_USER_MEM_EVENT_CLB_NAME "virtio_user_mem_event_clb"
      28                 :            : 
      29                 :            : const char * const virtio_user_backend_strings[] = {
      30                 :            :         [VIRTIO_USER_BACKEND_UNKNOWN] = "VIRTIO_USER_BACKEND_UNKNOWN",
      31                 :            :         [VIRTIO_USER_BACKEND_VHOST_USER] = "VHOST_USER",
      32                 :            :         [VIRTIO_USER_BACKEND_VHOST_KERNEL] = "VHOST_NET",
      33                 :            :         [VIRTIO_USER_BACKEND_VHOST_VDPA] = "VHOST_VDPA",
      34                 :            : };
      35                 :            : 
      36                 :            : static int
      37                 :          0 : virtio_user_create_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
      38                 :            : {
      39                 :            :         /* Of all per virtqueue MSGs, make sure VHOST_SET_VRING_CALL come
      40                 :            :          * firstly because vhost depends on this msg to allocate virtqueue
      41                 :            :          * pair.
      42                 :            :          */
      43                 :            :         struct vhost_vring_file file;
      44                 :            :         int ret;
      45                 :            : 
      46                 :          0 :         file.index = queue_sel;
      47                 :          0 :         file.fd = dev->callfds[queue_sel];
      48                 :          0 :         ret = dev->ops->set_vring_call(dev, &file);
      49         [ #  # ]:          0 :         if (ret < 0) {
      50                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to create queue %u", dev->path, queue_sel);
      51                 :          0 :                 return -1;
      52                 :            :         }
      53                 :            : 
      54                 :            :         return 0;
      55                 :            : }
      56                 :            : 
      57                 :            : static int
      58                 :          0 : virtio_user_kick_queue(struct virtio_user_dev *dev, uint32_t queue_sel)
      59                 :            : {
      60                 :            :         int ret;
      61                 :            :         struct vhost_vring_file file;
      62                 :            :         struct vhost_vring_state state;
      63                 :          0 :         struct vring *vring = &dev->vrings.split[queue_sel];
      64                 :            :         struct vring_packed *pq_vring = &dev->vrings.packed[queue_sel];
      65                 :          0 :         struct vhost_vring_addr addr = {
      66                 :            :                 .index = queue_sel,
      67                 :            :                 .log_guest_addr = 0,
      68                 :            :                 .flags = 0, /* disable log */
      69                 :            :         };
      70                 :            : 
      71         [ #  # ]:          0 :         if (queue_sel == dev->max_queue_pairs * 2) {
      72         [ #  # ]:          0 :                 if (!dev->scvq) {
      73                 :          0 :                         PMD_INIT_LOG(ERR, "(%s) Shadow control queue expected but missing",
      74                 :            :                                         dev->path);
      75                 :          0 :                         goto err;
      76                 :            :                 }
      77                 :            : 
      78                 :            :                 /* Use shadow control queue information */
      79                 :          0 :                 vring = &dev->scvq->vq_split.ring;
      80                 :          0 :                 pq_vring = &dev->scvq->vq_packed.ring;
      81                 :            :         }
      82                 :            : 
      83         [ #  # ]:          0 :         if (dev->features & (1ULL << VIRTIO_F_RING_PACKED)) {
      84                 :          0 :                 addr.desc_user_addr =
      85                 :          0 :                         (uint64_t)(uintptr_t)pq_vring->desc;
      86                 :          0 :                 addr.avail_user_addr =
      87                 :          0 :                         (uint64_t)(uintptr_t)pq_vring->driver;
      88                 :          0 :                 addr.used_user_addr =
      89                 :          0 :                         (uint64_t)(uintptr_t)pq_vring->device;
      90                 :            :         } else {
      91                 :          0 :                 addr.desc_user_addr = (uint64_t)(uintptr_t)vring->desc;
      92                 :          0 :                 addr.avail_user_addr = (uint64_t)(uintptr_t)vring->avail;
      93                 :          0 :                 addr.used_user_addr = (uint64_t)(uintptr_t)vring->used;
      94                 :            :         }
      95                 :            : 
      96                 :          0 :         state.index = queue_sel;
      97                 :          0 :         state.num = vring->num;
      98                 :          0 :         ret = dev->ops->set_vring_num(dev, &state);
      99         [ #  # ]:          0 :         if (ret < 0)
     100                 :          0 :                 goto err;
     101                 :            : 
     102                 :          0 :         state.index = queue_sel;
     103                 :          0 :         state.num = 0; /* no reservation */
     104         [ #  # ]:          0 :         if (dev->features & (1ULL << VIRTIO_F_RING_PACKED))
     105                 :          0 :                 state.num |= (1 << 15);
     106                 :          0 :         ret = dev->ops->set_vring_base(dev, &state);
     107         [ #  # ]:          0 :         if (ret < 0)
     108                 :          0 :                 goto err;
     109                 :            : 
     110                 :          0 :         ret = dev->ops->set_vring_addr(dev, &addr);
     111         [ #  # ]:          0 :         if (ret < 0)
     112                 :          0 :                 goto err;
     113                 :            : 
     114                 :            :         /* Of all per virtqueue MSGs, make sure VHOST_USER_SET_VRING_KICK comes
     115                 :            :          * lastly because vhost depends on this msg to judge if
     116                 :            :          * virtio is ready.
     117                 :            :          */
     118                 :          0 :         file.index = queue_sel;
     119                 :          0 :         file.fd = dev->kickfds[queue_sel];
     120                 :          0 :         ret = dev->ops->set_vring_kick(dev, &file);
     121         [ #  # ]:          0 :         if (ret < 0)
     122                 :          0 :                 goto err;
     123                 :            : 
     124                 :            :         return 0;
     125                 :          0 : err:
     126                 :          0 :         PMD_INIT_LOG(ERR, "(%s) Failed to kick queue %u", dev->path, queue_sel);
     127                 :            : 
     128                 :          0 :         return -1;
     129                 :            : }
     130                 :            : 
     131                 :            : static int
     132                 :          0 : virtio_user_queue_setup(struct virtio_user_dev *dev,
     133                 :            :                         int (*fn)(struct virtio_user_dev *, uint32_t))
     134                 :            : {
     135                 :            :         uint32_t i, nr_vq;
     136                 :            : 
     137                 :          0 :         nr_vq = dev->max_queue_pairs * 2;
     138         [ #  # ]:          0 :         if (dev->hw_cvq)
     139                 :          0 :                 nr_vq++;
     140                 :            : 
     141         [ #  # ]:          0 :         for (i = 0; i < nr_vq; i++) {
     142         [ #  # ]:          0 :                 if (fn(dev, i) < 0) {
     143                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) setup VQ %u failed", dev->path, i);
     144                 :          0 :                         return -1;
     145                 :            :                 }
     146                 :            :         }
     147                 :            : 
     148                 :            :         return 0;
     149                 :            : }
     150                 :            : 
     151                 :            : int
     152                 :          0 : virtio_user_dev_set_features(struct virtio_user_dev *dev)
     153                 :            : {
     154                 :            :         uint64_t features;
     155                 :            :         int ret = -1;
     156                 :            : 
     157                 :          0 :         pthread_mutex_lock(&dev->mutex);
     158                 :            : 
     159                 :            :         /* Step 0: tell vhost to create queues */
     160         [ #  # ]:          0 :         if (virtio_user_queue_setup(dev, virtio_user_create_queue) < 0)
     161                 :          0 :                 goto error;
     162                 :            : 
     163                 :          0 :         features = dev->features;
     164                 :            : 
     165                 :            :         /* Strip VIRTIO_NET_F_MAC, as MAC address is handled in vdev init */
     166                 :          0 :         features &= ~(1ull << VIRTIO_NET_F_MAC);
     167                 :            :         /* Strip VIRTIO_NET_F_CTRL_VQ if the devices does not really support control VQ */
     168         [ #  # ]:          0 :         if (!dev->hw_cvq)
     169                 :          0 :                 features &= ~(1ull << VIRTIO_NET_F_CTRL_VQ);
     170                 :          0 :         features &= ~(1ull << VIRTIO_NET_F_STATUS);
     171                 :          0 :         ret = dev->ops->set_features(dev, features);
     172         [ #  # ]:          0 :         if (ret < 0)
     173                 :          0 :                 goto error;
     174                 :          0 :         PMD_DRV_LOG(INFO, "(%s) set features: 0x%" PRIx64, dev->path, features);
     175                 :          0 : error:
     176                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     177                 :            : 
     178                 :          0 :         return ret;
     179                 :            : }
     180                 :            : 
     181                 :            : int
     182                 :          0 : virtio_user_start_device(struct virtio_user_dev *dev)
     183                 :            : {
     184                 :            :         int ret;
     185                 :            : 
     186                 :            :         /*
     187                 :            :          * XXX workaround!
     188                 :            :          *
     189                 :            :          * We need to make sure that the locks will be
     190                 :            :          * taken in the correct order to avoid deadlocks.
     191                 :            :          *
     192                 :            :          * Before releasing this lock, this thread should
     193                 :            :          * not trigger any memory hotplug events.
     194                 :            :          *
     195                 :            :          * This is a temporary workaround, and should be
     196                 :            :          * replaced when we get proper supports from the
     197                 :            :          * memory subsystem in the future.
     198                 :            :          */
     199                 :          0 :         rte_mcfg_mem_read_lock();
     200                 :          0 :         pthread_mutex_lock(&dev->mutex);
     201                 :            : 
     202                 :            :         /* Step 2: share memory regions */
     203                 :          0 :         ret = dev->ops->set_memory_table(dev);
     204         [ #  # ]:          0 :         if (ret < 0)
     205                 :          0 :                 goto error;
     206                 :            : 
     207                 :            :         /* Step 3: kick queues */
     208                 :          0 :         ret = virtio_user_queue_setup(dev, virtio_user_kick_queue);
     209         [ #  # ]:          0 :         if (ret < 0)
     210                 :          0 :                 goto error;
     211                 :            : 
     212                 :            :         /* Step 4: enable queues
     213                 :            :          * we enable the 1st queue pair by default.
     214                 :            :          */
     215                 :          0 :         ret = dev->ops->enable_qp(dev, 0, 1);
     216         [ #  # ]:          0 :         if (ret < 0)
     217                 :          0 :                 goto error;
     218                 :            : 
     219         [ #  # ]:          0 :         if (dev->scvq) {
     220                 :          0 :                 ret = dev->ops->cvq_enable(dev, 1);
     221         [ #  # ]:          0 :                 if (ret < 0)
     222                 :          0 :                         goto error;
     223                 :            :         }
     224                 :            : 
     225                 :          0 :         dev->started = true;
     226                 :            : 
     227                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     228                 :          0 :         rte_mcfg_mem_read_unlock();
     229                 :            : 
     230                 :          0 :         return 0;
     231                 :          0 : error:
     232                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     233                 :          0 :         rte_mcfg_mem_read_unlock();
     234                 :            : 
     235                 :          0 :         PMD_INIT_LOG(ERR, "(%s) Failed to start device", dev->path);
     236                 :            : 
     237                 :            :         /* TODO: free resource here or caller to check */
     238                 :          0 :         return -1;
     239                 :            : }
     240                 :            : 
     241                 :          0 : int virtio_user_stop_device(struct virtio_user_dev *dev)
     242                 :            : {
     243                 :            :         struct vhost_vring_state state;
     244                 :            :         uint32_t i;
     245                 :            :         int ret;
     246                 :            : 
     247                 :          0 :         pthread_mutex_lock(&dev->mutex);
     248         [ #  # ]:          0 :         if (!dev->started)
     249                 :          0 :                 goto out;
     250                 :            : 
     251         [ #  # ]:          0 :         for (i = 0; i < dev->max_queue_pairs; ++i) {
     252                 :          0 :                 ret = dev->ops->enable_qp(dev, i, 0);
     253         [ #  # ]:          0 :                 if (ret < 0)
     254                 :          0 :                         goto err;
     255                 :            :         }
     256                 :            : 
     257         [ #  # ]:          0 :         if (dev->scvq) {
     258                 :          0 :                 ret = dev->ops->cvq_enable(dev, 0);
     259         [ #  # ]:          0 :                 if (ret < 0)
     260                 :          0 :                         goto err;
     261                 :            :         }
     262                 :            : 
     263                 :            :         /* Stop the backend. */
     264         [ #  # ]:          0 :         for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
     265                 :          0 :                 state.index = i;
     266                 :          0 :                 ret = dev->ops->get_vring_base(dev, &state);
     267         [ #  # ]:          0 :                 if (ret < 0) {
     268                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) get_vring_base failed, index=%u", dev->path, i);
     269                 :          0 :                         goto err;
     270                 :            :                 }
     271                 :            :         }
     272                 :            : 
     273                 :          0 :         dev->started = false;
     274                 :            : 
     275                 :          0 : out:
     276                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     277                 :            : 
     278                 :          0 :         return 0;
     279                 :          0 : err:
     280                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     281                 :            : 
     282                 :          0 :         PMD_INIT_LOG(ERR, "(%s) Failed to stop device", dev->path);
     283                 :            : 
     284                 :          0 :         return -1;
     285                 :            : }
     286                 :            : 
     287                 :            : static int
     288                 :          0 : virtio_user_dev_init_max_queue_pairs(struct virtio_user_dev *dev, uint32_t user_max_qp)
     289                 :            : {
     290                 :            :         int ret;
     291                 :            : 
     292         [ #  # ]:          0 :         if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MQ))) {
     293                 :          0 :                 dev->max_queue_pairs = 1;
     294                 :          0 :                 return 0;
     295                 :            :         }
     296                 :            : 
     297         [ #  # ]:          0 :         if (!dev->ops->get_config) {
     298                 :          0 :                 dev->max_queue_pairs = user_max_qp;
     299                 :          0 :                 return 0;
     300                 :            :         }
     301                 :            : 
     302                 :          0 :         ret = dev->ops->get_config(dev, (uint8_t *)&dev->max_queue_pairs,
     303                 :            :                         offsetof(struct virtio_net_config, max_virtqueue_pairs),
     304                 :            :                         sizeof(uint16_t));
     305         [ #  # ]:          0 :         if (ret) {
     306                 :            :                 /*
     307                 :            :                  * We need to know the max queue pair from the device so that
     308                 :            :                  * the control queue gets the right index.
     309                 :            :                  */
     310                 :          0 :                 dev->max_queue_pairs = 1;
     311                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Failed to get max queue pairs from device", dev->path);
     312                 :            : 
     313                 :          0 :                 return ret;
     314                 :            :         }
     315                 :            : 
     316                 :            :         return 0;
     317                 :            : }
     318                 :            : 
     319                 :            : int
     320                 :          0 : virtio_user_dev_get_rss_config(struct virtio_user_dev *dev, void *dst, size_t offset, int length)
     321                 :            : {
     322                 :            :         int ret = 0;
     323                 :            : 
     324         [ #  # ]:          0 :         if (!(dev->device_features & (1ULL << VIRTIO_NET_F_RSS)))
     325                 :            :                 return -ENOTSUP;
     326                 :            : 
     327         [ #  # ]:          0 :         if (!dev->ops->get_config)
     328                 :            :                 return -ENOTSUP;
     329                 :            : 
     330                 :          0 :         ret = dev->ops->get_config(dev, dst, offset, length);
     331         [ #  # ]:          0 :         if (ret)
     332                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Failed to get rss config in device", dev->path);
     333                 :            : 
     334                 :            :         return ret;
     335                 :            : }
     336                 :            : 
     337                 :            : int
     338                 :          0 : virtio_user_dev_set_mac(struct virtio_user_dev *dev)
     339                 :            : {
     340                 :            :         int ret = 0;
     341                 :            : 
     342         [ #  # ]:          0 :         if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
     343                 :            :                 return -ENOTSUP;
     344                 :            : 
     345         [ #  # ]:          0 :         if (!dev->ops->set_config)
     346                 :            :                 return -ENOTSUP;
     347                 :            : 
     348                 :          0 :         ret = dev->ops->set_config(dev, dev->mac_addr,
     349                 :            :                         offsetof(struct virtio_net_config, mac),
     350                 :            :                         RTE_ETHER_ADDR_LEN);
     351         [ #  # ]:          0 :         if (ret)
     352                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Failed to set MAC address in device", dev->path);
     353                 :            : 
     354                 :            :         return ret;
     355                 :            : }
     356                 :            : 
     357                 :            : int
     358                 :          0 : virtio_user_dev_get_mac(struct virtio_user_dev *dev)
     359                 :            : {
     360                 :            :         int ret = 0;
     361                 :            : 
     362         [ #  # ]:          0 :         if (!(dev->device_features & (1ULL << VIRTIO_NET_F_MAC)))
     363                 :            :                 return -ENOTSUP;
     364                 :            : 
     365         [ #  # ]:          0 :         if (!dev->ops->get_config)
     366                 :            :                 return -ENOTSUP;
     367                 :            : 
     368                 :          0 :         ret = dev->ops->get_config(dev, dev->mac_addr,
     369                 :            :                         offsetof(struct virtio_net_config, mac),
     370                 :            :                         RTE_ETHER_ADDR_LEN);
     371         [ #  # ]:          0 :         if (ret)
     372                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Failed to get MAC address from device", dev->path);
     373                 :            : 
     374                 :            :         return ret;
     375                 :            : }
     376                 :            : 
     377                 :            : static void
     378                 :          0 : virtio_user_dev_init_mac(struct virtio_user_dev *dev, const char *mac)
     379                 :            : {
     380                 :            :         struct rte_ether_addr cmdline_mac;
     381                 :            :         char buf[RTE_ETHER_ADDR_FMT_SIZE];
     382                 :            :         int ret;
     383                 :            : 
     384   [ #  #  #  # ]:          0 :         if (mac && rte_ether_unformat_addr(mac, &cmdline_mac) == 0) {
     385                 :            :                 /*
     386                 :            :                  * MAC address was passed from command-line, try to store
     387                 :            :                  * it in the device if it supports it. Otherwise try to use
     388                 :            :                  * the device one.
     389                 :            :                  */
     390                 :          0 :                 memcpy(dev->mac_addr, &cmdline_mac, RTE_ETHER_ADDR_LEN);
     391                 :          0 :                 dev->mac_specified = 1;
     392                 :            : 
     393                 :            :                 /* Setting MAC may fail, continue to get the device one in this case */
     394                 :          0 :                 virtio_user_dev_set_mac(dev);
     395                 :          0 :                 ret = virtio_user_dev_get_mac(dev);
     396         [ #  # ]:          0 :                 if (ret == -ENOTSUP)
     397                 :          0 :                         goto out;
     398                 :            : 
     399         [ #  # ]:          0 :                 if (memcmp(&cmdline_mac, dev->mac_addr, RTE_ETHER_ADDR_LEN))
     400                 :          0 :                         PMD_DRV_LOG(INFO, "(%s) Device MAC update failed", dev->path);
     401                 :            :         } else {
     402                 :          0 :                 ret = virtio_user_dev_get_mac(dev);
     403         [ #  # ]:          0 :                 if (ret) {
     404                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) No valid MAC in devargs or device, use random",
     405                 :            :                                         dev->path);
     406                 :          0 :                         return;
     407                 :            :                 }
     408                 :            : 
     409                 :          0 :                 dev->mac_specified = 1;
     410                 :            :         }
     411                 :          0 : out:
     412                 :          0 :         rte_ether_format_addr(buf, RTE_ETHER_ADDR_FMT_SIZE,
     413                 :          0 :                         (struct rte_ether_addr *)dev->mac_addr);
     414                 :          0 :         PMD_DRV_LOG(INFO, "(%s) MAC %s specified", dev->path, buf);
     415                 :            : }
     416                 :            : 
     417                 :            : static int
     418                 :          0 : virtio_user_dev_init_notify(struct virtio_user_dev *dev)
     419                 :            : {
     420                 :            :         uint32_t i, j, nr_vq;
     421                 :            :         int callfd;
     422                 :            :         int kickfd;
     423                 :            : 
     424                 :          0 :         nr_vq = dev->max_queue_pairs * 2;
     425         [ #  # ]:          0 :         if (dev->hw_cvq)
     426                 :          0 :                 nr_vq++;
     427                 :            : 
     428         [ #  # ]:          0 :         for (i = 0; i < nr_vq; i++) {
     429                 :            :                 /* May use invalid flag, but some backend uses kickfd and
     430                 :            :                  * callfd as criteria to judge if dev is alive. so finally we
     431                 :            :                  * use real event_fd.
     432                 :            :                  */
     433                 :          0 :                 callfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
     434         [ #  # ]:          0 :                 if (callfd < 0) {
     435                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) callfd error, %s", dev->path, strerror(errno));
     436                 :          0 :                         goto err;
     437                 :            :                 }
     438                 :          0 :                 kickfd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
     439         [ #  # ]:          0 :                 if (kickfd < 0) {
     440                 :          0 :                         close(callfd);
     441                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) kickfd error, %s", dev->path, strerror(errno));
     442                 :          0 :                         goto err;
     443                 :            :                 }
     444                 :          0 :                 dev->callfds[i] = callfd;
     445                 :          0 :                 dev->kickfds[i] = kickfd;
     446                 :            :         }
     447                 :            : 
     448         [ #  # ]:          0 :         if (dev->device_features & (1ULL << VIRTIO_F_NOTIFICATION_DATA))
     449   [ #  #  #  # ]:          0 :                 if (dev->ops->map_notification_area &&
     450                 :          0 :                                 dev->ops->map_notification_area(dev))
     451                 :          0 :                         goto err;
     452                 :            : 
     453                 :            :         return 0;
     454                 :          0 : err:
     455         [ #  # ]:          0 :         for (j = 0; j < i; j++) {
     456         [ #  # ]:          0 :                 if (dev->kickfds[j] >= 0) {
     457                 :          0 :                         close(dev->kickfds[j]);
     458                 :          0 :                         dev->kickfds[j] = -1;
     459                 :            :                 }
     460         [ #  # ]:          0 :                 if (dev->callfds[j] >= 0) {
     461                 :          0 :                         close(dev->callfds[j]);
     462                 :          0 :                         dev->callfds[j] = -1;
     463                 :            :                 }
     464                 :            :         }
     465                 :            : 
     466                 :            :         return -1;
     467                 :            : }
     468                 :            : 
     469                 :            : static void
     470                 :          0 : virtio_user_dev_uninit_notify(struct virtio_user_dev *dev)
     471                 :            : {
     472                 :            :         uint32_t i;
     473                 :            : 
     474         [ #  # ]:          0 :         for (i = 0; i < dev->max_queue_pairs * 2; ++i) {
     475         [ #  # ]:          0 :                 if (dev->kickfds[i] >= 0) {
     476                 :          0 :                         close(dev->kickfds[i]);
     477                 :          0 :                         dev->kickfds[i] = -1;
     478                 :            :                 }
     479         [ #  # ]:          0 :                 if (dev->callfds[i] >= 0) {
     480                 :          0 :                         close(dev->callfds[i]);
     481                 :          0 :                         dev->callfds[i] = -1;
     482                 :            :                 }
     483                 :            :         }
     484   [ #  #  #  # ]:          0 :         if (dev->ops->unmap_notification_area && dev->notify_area)
     485                 :          0 :                 dev->ops->unmap_notification_area(dev);
     486                 :          0 : }
     487                 :            : 
     488                 :            : static int
     489                 :          0 : virtio_user_fill_intr_handle(struct virtio_user_dev *dev)
     490                 :            : {
     491                 :            :         uint32_t i;
     492                 :          0 :         struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
     493                 :            : 
     494         [ #  # ]:          0 :         if (eth_dev->intr_handle == NULL) {
     495                 :          0 :                 eth_dev->intr_handle =
     496                 :          0 :                         rte_intr_instance_alloc(RTE_INTR_INSTANCE_F_PRIVATE);
     497         [ #  # ]:          0 :                 if (eth_dev->intr_handle == NULL) {
     498                 :          0 :                         PMD_DRV_LOG(ERR, "(%s) failed to allocate intr_handle", dev->path);
     499                 :          0 :                         return -1;
     500                 :            :                 }
     501                 :            :         }
     502                 :            : 
     503         [ #  # ]:          0 :         for (i = 0; i < dev->max_queue_pairs; ++i) {
     504         [ #  # ]:          0 :                 if (rte_intr_efds_index_set(eth_dev->intr_handle, i,
     505                 :          0 :                                 dev->callfds[2 * i + VTNET_SQ_RQ_QUEUE_IDX]))
     506                 :          0 :                         return -rte_errno;
     507                 :            :         }
     508                 :            : 
     509         [ #  # ]:          0 :         if (rte_intr_nb_efd_set(eth_dev->intr_handle, dev->max_queue_pairs))
     510                 :          0 :                 return -rte_errno;
     511                 :            : 
     512         [ #  # ]:          0 :         if (rte_intr_max_intr_set(eth_dev->intr_handle,
     513                 :          0 :                         dev->max_queue_pairs + 1))
     514                 :          0 :                 return -rte_errno;
     515                 :            : 
     516         [ #  # ]:          0 :         if (rte_intr_type_set(eth_dev->intr_handle, RTE_INTR_HANDLE_VDEV))
     517                 :          0 :                 return -rte_errno;
     518                 :            : 
     519                 :            :         /* For virtio vdev, no need to read counter for clean */
     520         [ #  # ]:          0 :         if (rte_intr_efd_counter_size_set(eth_dev->intr_handle, 0))
     521                 :          0 :                 return -rte_errno;
     522                 :            : 
     523         [ #  # ]:          0 :         if (rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev)))
     524                 :          0 :                 return -rte_errno;
     525                 :            : 
     526                 :            :         return 0;
     527                 :            : }
     528                 :            : 
     529                 :            : static void
     530                 :          0 : virtio_user_mem_event_cb(enum rte_mem_event type __rte_unused,
     531                 :            :                          const void *addr,
     532                 :            :                          size_t len __rte_unused,
     533                 :            :                          void *arg)
     534                 :            : {
     535                 :            :         struct virtio_user_dev *dev = arg;
     536                 :            :         struct rte_memseg_list *msl;
     537                 :            :         uint16_t i;
     538                 :            :         int ret = 0;
     539                 :            : 
     540                 :            :         /* ignore externally allocated memory */
     541                 :          0 :         msl = rte_mem_virt2memseg_list(addr);
     542         [ #  # ]:          0 :         if (msl->external)
     543                 :            :                 return;
     544                 :            : 
     545                 :          0 :         pthread_mutex_lock(&dev->mutex);
     546                 :            : 
     547         [ #  # ]:          0 :         if (dev->started == false)
     548                 :          0 :                 goto exit;
     549                 :            : 
     550                 :            :         /* Step 1: pause the active queues */
     551         [ #  # ]:          0 :         for (i = 0; i < dev->queue_pairs; i++) {
     552                 :          0 :                 ret = dev->ops->enable_qp(dev, i, 0);
     553         [ #  # ]:          0 :                 if (ret < 0)
     554                 :          0 :                         goto exit;
     555                 :            :         }
     556                 :            : 
     557                 :            :         /* Step 2: update memory regions */
     558                 :          0 :         ret = dev->ops->set_memory_table(dev);
     559         [ #  # ]:          0 :         if (ret < 0)
     560                 :          0 :                 goto exit;
     561                 :            : 
     562                 :            :         /* Step 3: resume the active queues */
     563         [ #  # ]:          0 :         for (i = 0; i < dev->queue_pairs; i++) {
     564                 :          0 :                 ret = dev->ops->enable_qp(dev, i, 1);
     565         [ #  # ]:          0 :                 if (ret < 0)
     566                 :          0 :                         goto exit;
     567                 :            :         }
     568                 :            : 
     569                 :          0 : exit:
     570                 :          0 :         pthread_mutex_unlock(&dev->mutex);
     571                 :            : 
     572         [ #  # ]:          0 :         if (ret < 0)
     573                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Failed to update memory table", dev->path);
     574                 :            : }
     575                 :            : 
     576                 :            : static int
     577                 :          0 : virtio_user_dev_setup(struct virtio_user_dev *dev)
     578                 :            : {
     579         [ #  # ]:          0 :         if (dev->is_server) {
     580         [ #  # ]:          0 :                 if (dev->backend_type != VIRTIO_USER_BACKEND_VHOST_USER) {
     581                 :          0 :                         PMD_DRV_LOG(ERR, "Server mode only supports vhost-user!");
     582                 :          0 :                         return -1;
     583                 :            :                 }
     584                 :            :         }
     585                 :            : 
     586   [ #  #  #  # ]:          0 :         switch (dev->backend_type) {
     587                 :          0 :         case VIRTIO_USER_BACKEND_VHOST_USER:
     588                 :          0 :                 dev->ops = &virtio_ops_user;
     589                 :          0 :                 break;
     590                 :          0 :         case VIRTIO_USER_BACKEND_VHOST_KERNEL:
     591                 :          0 :                 dev->ops = &virtio_ops_kernel;
     592                 :          0 :                 break;
     593                 :          0 :         case VIRTIO_USER_BACKEND_VHOST_VDPA:
     594                 :          0 :                 dev->ops = &virtio_ops_vdpa;
     595                 :          0 :                 break;
     596                 :          0 :         default:
     597                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Unknown backend type", dev->path);
     598                 :          0 :                 return -1;
     599                 :            :         }
     600                 :            : 
     601         [ #  # ]:          0 :         if (dev->ops->setup(dev) < 0) {
     602                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to setup backend", dev->path);
     603                 :          0 :                 return -1;
     604                 :            :         }
     605                 :            : 
     606                 :            :         return 0;
     607                 :            : }
     608                 :            : 
     609                 :            : static int
     610                 :          0 : virtio_user_alloc_vrings(struct virtio_user_dev *dev)
     611                 :            : {
     612                 :            :         int i, size, nr_vrings;
     613                 :          0 :         bool packed_ring = !!(dev->device_features & (1ull << VIRTIO_F_RING_PACKED));
     614                 :            : 
     615                 :          0 :         nr_vrings = dev->max_queue_pairs * 2;
     616         [ #  # ]:          0 :         if (dev->device_features & (1ull << VIRTIO_NET_F_MQ))
     617                 :          0 :                 nr_vrings++;
     618                 :            : 
     619                 :          0 :         dev->callfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->callfds), 0);
     620         [ #  # ]:          0 :         if (!dev->callfds) {
     621                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to alloc callfds", dev->path);
     622                 :          0 :                 return -1;
     623                 :            :         }
     624                 :            : 
     625                 :          0 :         dev->kickfds = rte_zmalloc("virtio_user_dev", nr_vrings * sizeof(*dev->kickfds), 0);
     626         [ #  # ]:          0 :         if (!dev->kickfds) {
     627                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to alloc kickfds", dev->path);
     628                 :          0 :                 goto free_callfds;
     629                 :            :         }
     630                 :            : 
     631         [ #  # ]:          0 :         for (i = 0; i < nr_vrings; i++) {
     632                 :          0 :                 dev->callfds[i] = -1;
     633                 :          0 :                 dev->kickfds[i] = -1;
     634                 :            :         }
     635                 :            : 
     636                 :            :         if (packed_ring)
     637                 :            :                 size = sizeof(*dev->vrings.packed);
     638                 :            :         else
     639                 :            :                 size = sizeof(*dev->vrings.split);
     640                 :          0 :         dev->vrings.ptr = rte_zmalloc("virtio_user_dev", nr_vrings * size, 0);
     641         [ #  # ]:          0 :         if (!dev->vrings.ptr) {
     642                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to alloc vrings metadata", dev->path);
     643                 :          0 :                 goto free_kickfds;
     644                 :            :         }
     645                 :            : 
     646         [ #  # ]:          0 :         if (packed_ring) {
     647                 :          0 :                 dev->packed_queues = rte_zmalloc("virtio_user_dev",
     648                 :            :                                 nr_vrings * sizeof(*dev->packed_queues), 0);
     649         [ #  # ]:          0 :                 if (!dev->packed_queues) {
     650                 :          0 :                         PMD_INIT_LOG(ERR, "(%s) Failed to alloc packed queues metadata",
     651                 :            :                                         dev->path);
     652                 :          0 :                         goto free_vrings;
     653                 :            :                 }
     654                 :            :         }
     655                 :            : 
     656                 :          0 :         dev->qp_enabled = rte_zmalloc("virtio_user_dev",
     657                 :          0 :                         dev->max_queue_pairs * sizeof(*dev->qp_enabled), 0);
     658         [ #  # ]:          0 :         if (!dev->qp_enabled) {
     659                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to alloc QP enable states", dev->path);
     660                 :          0 :                 goto free_packed_queues;
     661                 :            :         }
     662                 :            : 
     663                 :            :         return 0;
     664                 :            : 
     665                 :            : free_packed_queues:
     666                 :          0 :         rte_free(dev->packed_queues);
     667                 :          0 :         dev->packed_queues = NULL;
     668                 :          0 : free_vrings:
     669                 :          0 :         rte_free(dev->vrings.ptr);
     670                 :          0 :         dev->vrings.ptr = NULL;
     671                 :          0 : free_kickfds:
     672                 :          0 :         rte_free(dev->kickfds);
     673                 :          0 :         dev->kickfds = NULL;
     674                 :          0 : free_callfds:
     675                 :          0 :         rte_free(dev->callfds);
     676                 :          0 :         dev->callfds = NULL;
     677                 :            : 
     678                 :          0 :         return -1;
     679                 :            : }
     680                 :            : 
     681                 :            : static void
     682                 :          0 : virtio_user_free_vrings(struct virtio_user_dev *dev)
     683                 :            : {
     684                 :          0 :         rte_free(dev->qp_enabled);
     685                 :          0 :         dev->qp_enabled = NULL;
     686                 :          0 :         rte_free(dev->packed_queues);
     687                 :          0 :         dev->packed_queues = NULL;
     688                 :          0 :         rte_free(dev->vrings.ptr);
     689                 :          0 :         dev->vrings.ptr = NULL;
     690                 :          0 :         rte_free(dev->kickfds);
     691                 :          0 :         dev->kickfds = NULL;
     692                 :          0 :         rte_free(dev->callfds);
     693                 :          0 :         dev->callfds = NULL;
     694                 :          0 : }
     695                 :            : 
     696                 :            : /* Use below macro to filter features from vhost backend */
     697                 :            : #define VIRTIO_USER_SUPPORTED_FEATURES                  \
     698                 :            :         (1ULL << VIRTIO_NET_F_MAC         |       \
     699                 :            :          1ULL << VIRTIO_NET_F_STATUS              |       \
     700                 :            :          1ULL << VIRTIO_NET_F_MQ          |       \
     701                 :            :          1ULL << VIRTIO_NET_F_CTRL_MAC_ADDR       |       \
     702                 :            :          1ULL << VIRTIO_NET_F_CTRL_VQ             |       \
     703                 :            :          1ULL << VIRTIO_NET_F_CTRL_RX             |       \
     704                 :            :          1ULL << VIRTIO_NET_F_CTRL_VLAN           |       \
     705                 :            :          1ULL << VIRTIO_NET_F_CSUM                |       \
     706                 :            :          1ULL << VIRTIO_NET_F_HOST_TSO4           |       \
     707                 :            :          1ULL << VIRTIO_NET_F_HOST_TSO6           |       \
     708                 :            :          1ULL << VIRTIO_NET_F_MRG_RXBUF           |       \
     709                 :            :          1ULL << VIRTIO_RING_F_INDIRECT_DESC      |       \
     710                 :            :          1ULL << VIRTIO_NET_F_GUEST_CSUM  |       \
     711                 :            :          1ULL << VIRTIO_NET_F_GUEST_TSO4  |       \
     712                 :            :          1ULL << VIRTIO_NET_F_GUEST_TSO6  |       \
     713                 :            :          1ULL << VIRTIO_F_IN_ORDER                |       \
     714                 :            :          1ULL << VIRTIO_F_VERSION_1               |       \
     715                 :            :          1ULL << VIRTIO_F_RING_PACKED             |       \
     716                 :            :          1ULL << VIRTIO_F_NOTIFICATION_DATA       |       \
     717                 :            :          1ULL << VIRTIO_NET_F_RSS)
     718                 :            : 
     719                 :            : int
     720                 :          0 : virtio_user_dev_init(struct virtio_user_dev *dev, char *path, uint16_t queues,
     721                 :            :                      int cq, int queue_size, const char *mac, char **ifname,
     722                 :            :                      int server, int mrg_rxbuf, int in_order, int packed_vq,
     723                 :            :                      enum virtio_user_backend_type backend_type)
     724                 :            : {
     725                 :            :         uint64_t backend_features;
     726                 :            : 
     727                 :          0 :         pthread_mutex_init(&dev->mutex, NULL);
     728                 :          0 :         strlcpy(dev->path, path, PATH_MAX);
     729                 :            : 
     730                 :          0 :         dev->started = 0;
     731                 :          0 :         dev->queue_pairs = 1; /* mq disabled by default */
     732                 :          0 :         dev->max_queue_pairs = queues; /* initialize to user requested value for kernel backend */
     733                 :          0 :         dev->queue_size = queue_size;
     734                 :          0 :         dev->is_server = server;
     735                 :          0 :         dev->mac_specified = 0;
     736                 :          0 :         dev->frontend_features = 0;
     737                 :          0 :         dev->unsupported_features = 0;
     738                 :          0 :         dev->backend_type = backend_type;
     739                 :          0 :         dev->ifname = *ifname;
     740                 :            : 
     741         [ #  # ]:          0 :         if (virtio_user_dev_setup(dev) < 0) {
     742                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) backend set up fails", dev->path);
     743                 :          0 :                 return -1;
     744                 :            :         }
     745                 :            : 
     746         [ #  # ]:          0 :         if (dev->ops->set_owner(dev) < 0) {
     747                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to set backend owner", dev->path);
     748                 :          0 :                 goto destroy;
     749                 :            :         }
     750                 :            : 
     751         [ #  # ]:          0 :         if (dev->ops->get_backend_features(&backend_features) < 0) {
     752                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to get backend features", dev->path);
     753                 :          0 :                 goto destroy;
     754                 :            :         }
     755                 :            : 
     756                 :          0 :         dev->unsupported_features = ~(VIRTIO_USER_SUPPORTED_FEATURES | backend_features);
     757                 :            : 
     758         [ #  # ]:          0 :         if (dev->ops->get_features(dev, &dev->device_features) < 0) {
     759                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to get device features", dev->path);
     760                 :          0 :                 goto destroy;
     761                 :            :         }
     762                 :            : 
     763                 :          0 :         virtio_user_dev_init_mac(dev, mac);
     764                 :            : 
     765         [ #  # ]:          0 :         if (virtio_user_dev_init_max_queue_pairs(dev, queues))
     766                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
     767                 :            : 
     768   [ #  #  #  # ]:          0 :         if (dev->max_queue_pairs > 1 || dev->hw_cvq)
     769                 :            :                 cq = 1;
     770                 :            : 
     771         [ #  # ]:          0 :         if (!mrg_rxbuf)
     772                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_MRG_RXBUF);
     773                 :            : 
     774         [ #  # ]:          0 :         if (!in_order)
     775                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_F_IN_ORDER);
     776                 :            : 
     777         [ #  # ]:          0 :         if (!packed_vq)
     778                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_F_RING_PACKED);
     779                 :            : 
     780         [ #  # ]:          0 :         if (dev->mac_specified)
     781                 :          0 :                 dev->frontend_features |= (1ull << VIRTIO_NET_F_MAC);
     782                 :            :         else
     783                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_MAC);
     784                 :            : 
     785         [ #  # ]:          0 :         if (cq) {
     786                 :            :                 /* Except for vDPA, the device does not really need to know
     787                 :            :                  * anything about CQ, so if necessary, we just claim to support
     788                 :            :                  * control queue.
     789                 :            :                  */
     790                 :          0 :                 dev->frontend_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
     791                 :            :         } else {
     792                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VQ);
     793                 :            :                 /* Also disable features that depend on VIRTIO_NET_F_CTRL_VQ */
     794                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_RX);
     795                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_CTRL_VLAN);
     796                 :          0 :                 dev->unsupported_features |=
     797                 :            :                         (1ull << VIRTIO_NET_F_GUEST_ANNOUNCE);
     798                 :          0 :                 dev->unsupported_features |= (1ull << VIRTIO_NET_F_MQ);
     799                 :          0 :                 dev->unsupported_features |=
     800                 :            :                         (1ull << VIRTIO_NET_F_CTRL_MAC_ADDR);
     801                 :            :         }
     802                 :            : 
     803                 :            :         /* The backend will not report this feature, we add it explicitly */
     804         [ #  # ]:          0 :         if (dev->backend_type == VIRTIO_USER_BACKEND_VHOST_USER)
     805                 :          0 :                 dev->frontend_features |= (1ull << VIRTIO_NET_F_STATUS);
     806                 :            : 
     807                 :          0 :         dev->frontend_features &= ~dev->unsupported_features;
     808                 :          0 :         dev->device_features &= ~dev->unsupported_features;
     809                 :            : 
     810         [ #  # ]:          0 :         if (virtio_user_alloc_vrings(dev) < 0) {
     811                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to allocate vring metadata", dev->path);
     812                 :          0 :                 goto destroy;
     813                 :            :         }
     814                 :            : 
     815         [ #  # ]:          0 :         if (virtio_user_dev_init_notify(dev) < 0) {
     816                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to init notifiers", dev->path);
     817                 :          0 :                 goto free_vrings;
     818                 :            :         }
     819                 :            : 
     820         [ #  # ]:          0 :         if (virtio_user_fill_intr_handle(dev) < 0) {
     821                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to init interrupt handler", dev->path);
     822                 :          0 :                 goto notify_uninit;
     823                 :            :         }
     824                 :            : 
     825         [ #  # ]:          0 :         if (rte_mem_event_callback_register(VIRTIO_USER_MEM_EVENT_CLB_NAME,
     826                 :            :                                 virtio_user_mem_event_cb, dev)) {
     827         [ #  # ]:          0 :                 if (rte_errno != ENOTSUP) {
     828                 :          0 :                         PMD_INIT_LOG(ERR, "(%s) Failed to register mem event callback",
     829                 :            :                                         dev->path);
     830                 :          0 :                         goto notify_uninit;
     831                 :            :                 }
     832                 :            :         }
     833                 :            : 
     834                 :          0 :         *ifname = NULL;
     835                 :          0 :         return 0;
     836                 :            : 
     837                 :          0 : notify_uninit:
     838                 :          0 :         virtio_user_dev_uninit_notify(dev);
     839                 :          0 : free_vrings:
     840                 :          0 :         virtio_user_free_vrings(dev);
     841                 :          0 : destroy:
     842                 :          0 :         dev->ops->destroy(dev);
     843                 :            : 
     844                 :          0 :         return -1;
     845                 :            : }
     846                 :            : 
     847                 :            : void
     848                 :          0 : virtio_user_dev_uninit(struct virtio_user_dev *dev)
     849                 :            : {
     850                 :          0 :         struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
     851                 :            : 
     852                 :          0 :         rte_intr_instance_free(eth_dev->intr_handle);
     853                 :          0 :         eth_dev->intr_handle = NULL;
     854                 :            : 
     855                 :          0 :         virtio_user_stop_device(dev);
     856                 :            : 
     857                 :          0 :         rte_mem_event_callback_unregister(VIRTIO_USER_MEM_EVENT_CLB_NAME, dev);
     858                 :            : 
     859                 :          0 :         virtio_user_dev_uninit_notify(dev);
     860                 :            : 
     861                 :          0 :         virtio_user_free_vrings(dev);
     862                 :            : 
     863                 :          0 :         free(dev->ifname);
     864                 :            : 
     865         [ #  # ]:          0 :         if (dev->is_server)
     866                 :          0 :                 unlink(dev->path);
     867                 :            : 
     868                 :          0 :         dev->ops->destroy(dev);
     869                 :          0 : }
     870                 :            : 
     871                 :            : static uint8_t
     872                 :          0 : virtio_user_handle_mq(struct virtio_user_dev *dev, uint16_t q_pairs)
     873                 :            : {
     874                 :            :         uint16_t i;
     875                 :            :         uint8_t ret = 0;
     876                 :            : 
     877         [ #  # ]:          0 :         if (q_pairs > dev->max_queue_pairs) {
     878                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) multi-q config %u, but only %u supported",
     879                 :            :                              dev->path, q_pairs, dev->max_queue_pairs);
     880                 :          0 :                 return -1;
     881                 :            :         }
     882                 :            : 
     883         [ #  # ]:          0 :         for (i = 0; i < q_pairs; ++i)
     884                 :          0 :                 ret |= dev->ops->enable_qp(dev, i, 1);
     885         [ #  # ]:          0 :         for (i = q_pairs; i < dev->max_queue_pairs; ++i)
     886                 :          0 :                 ret |= dev->ops->enable_qp(dev, i, 0);
     887                 :            : 
     888                 :          0 :         dev->queue_pairs = q_pairs;
     889                 :            : 
     890                 :          0 :         return ret;
     891                 :            : }
     892                 :            : 
     893                 :            : #define CVQ_MAX_DATA_DESCS 32
     894                 :            : 
     895                 :            : static uint32_t
     896                 :          0 : virtio_user_handle_ctrl_msg_split(struct virtio_user_dev *dev, struct vring *vring,
     897                 :            :                             uint16_t idx_hdr)
     898                 :            : {
     899                 :            :         struct virtio_net_ctrl_hdr *hdr;
     900                 :            :         virtio_net_ctrl_ack status = ~0;
     901                 :            :         uint16_t i, idx_data, idx_status;
     902                 :            :         uint32_t n_descs = 0;
     903                 :            :         int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
     904                 :            : 
     905                 :            :         /* locate desc for header, data, and status */
     906                 :          0 :         idx_data = vring->desc[idx_hdr].next;
     907                 :            :         n_descs++;
     908                 :            : 
     909                 :            :         i = idx_data;
     910         [ #  # ]:          0 :         while (vring->desc[i].flags == VRING_DESC_F_NEXT) {
     911                 :          0 :                 dlen[nb_dlen++] = vring->desc[i].len;
     912                 :          0 :                 i = vring->desc[i].next;
     913                 :          0 :                 n_descs++;
     914                 :            :         }
     915                 :            : 
     916                 :            :         /* locate desc for status */
     917                 :            :         idx_status = i;
     918                 :          0 :         n_descs++;
     919                 :            : 
     920                 :          0 :         hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
     921         [ #  # ]:          0 :         if (hdr->class == VIRTIO_NET_CTRL_MQ &&
     922         [ #  # ]:          0 :             hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
     923                 :            :                 uint16_t queues;
     924                 :            : 
     925                 :          0 :                 queues = *(uint16_t *)(uintptr_t)vring->desc[idx_data].addr;
     926                 :          0 :                 status = virtio_user_handle_mq(dev, queues);
     927   [ #  #  #  # ]:          0 :         } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
     928                 :            :                 struct virtio_net_ctrl_rss *rss;
     929                 :            : 
     930                 :          0 :                 rss = (struct virtio_net_ctrl_rss *)(uintptr_t)vring->desc[idx_data].addr;
     931                 :          0 :                 status = virtio_user_handle_mq(dev, rss->max_tx_vq);
     932         [ #  # ]:          0 :         } else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
     933                 :            :                    hdr->class == VIRTIO_NET_CTRL_MAC ||
     934                 :            :                    hdr->class == VIRTIO_NET_CTRL_VLAN) {
     935                 :            :                 status = 0;
     936                 :            :         }
     937                 :            : 
     938   [ #  #  #  # ]:          0 :         if (!status && dev->scvq)
     939                 :          0 :                 status = virtio_send_command(&dev->scvq->cq,
     940                 :            :                                 (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
     941                 :            : 
     942                 :            :         /* Update status */
     943                 :          0 :         *(virtio_net_ctrl_ack *)(uintptr_t)vring->desc[idx_status].addr = status;
     944                 :            : 
     945                 :          0 :         return n_descs;
     946                 :            : }
     947                 :            : 
     948                 :            : static inline int
     949                 :            : desc_is_avail(struct vring_packed_desc *desc, bool wrap_counter)
     950                 :            : {
     951                 :          0 :         uint16_t flags = __atomic_load_n(&desc->flags, __ATOMIC_ACQUIRE);
     952                 :            : 
     953                 :          0 :         return wrap_counter == !!(flags & VRING_PACKED_DESC_F_AVAIL) &&
     954         [ #  # ]:          0 :                 wrap_counter != !!(flags & VRING_PACKED_DESC_F_USED);
     955                 :            : }
     956                 :            : 
     957                 :            : static uint32_t
     958                 :          0 : virtio_user_handle_ctrl_msg_packed(struct virtio_user_dev *dev,
     959                 :            :                                    struct vring_packed *vring,
     960                 :            :                                    uint16_t idx_hdr)
     961                 :            : {
     962                 :            :         struct virtio_net_ctrl_hdr *hdr;
     963                 :            :         virtio_net_ctrl_ack status = ~0;
     964                 :            :         uint16_t idx_data, idx_status;
     965                 :            :         /* initialize to one, header is first */
     966                 :            :         uint32_t n_descs = 1;
     967                 :            :         int dlen[CVQ_MAX_DATA_DESCS], nb_dlen = 0;
     968                 :            : 
     969                 :            :         /* locate desc for header, data, and status */
     970                 :          0 :         idx_data = idx_hdr + 1;
     971         [ #  # ]:          0 :         if (idx_data >= dev->queue_size)
     972                 :          0 :                 idx_data -= dev->queue_size;
     973                 :            : 
     974                 :            :         n_descs++;
     975                 :            : 
     976                 :            :         idx_status = idx_data;
     977         [ #  # ]:          0 :         while (vring->desc[idx_status].flags & VRING_DESC_F_NEXT) {
     978                 :          0 :                 dlen[nb_dlen++] = vring->desc[idx_status].len;
     979                 :          0 :                 idx_status++;
     980         [ #  # ]:          0 :                 if (idx_status >= dev->queue_size)
     981                 :          0 :                         idx_status -= dev->queue_size;
     982                 :          0 :                 n_descs++;
     983                 :            :         }
     984                 :            : 
     985                 :          0 :         hdr = (void *)(uintptr_t)vring->desc[idx_hdr].addr;
     986         [ #  # ]:          0 :         if (hdr->class == VIRTIO_NET_CTRL_MQ &&
     987         [ #  # ]:          0 :             hdr->cmd == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET) {
     988                 :            :                 uint16_t queues;
     989                 :            : 
     990                 :          0 :                 queues = *(uint16_t *)(uintptr_t)
     991                 :          0 :                                 vring->desc[idx_data].addr;
     992                 :          0 :                 status = virtio_user_handle_mq(dev, queues);
     993   [ #  #  #  # ]:          0 :         } else if (hdr->class == VIRTIO_NET_CTRL_MQ && hdr->cmd == VIRTIO_NET_CTRL_MQ_RSS_CONFIG) {
     994                 :            :                 struct virtio_net_ctrl_rss *rss;
     995                 :            : 
     996                 :          0 :                 rss = (struct virtio_net_ctrl_rss *)(uintptr_t)vring->desc[idx_data].addr;
     997                 :          0 :                 status = virtio_user_handle_mq(dev, rss->max_tx_vq);
     998         [ #  # ]:          0 :         } else if (hdr->class == VIRTIO_NET_CTRL_RX  ||
     999                 :            :                    hdr->class == VIRTIO_NET_CTRL_MAC ||
    1000                 :            :                    hdr->class == VIRTIO_NET_CTRL_VLAN) {
    1001                 :            :                 status = 0;
    1002                 :            :         }
    1003                 :            : 
    1004   [ #  #  #  # ]:          0 :         if (!status && dev->scvq)
    1005                 :          0 :                 status = virtio_send_command(&dev->scvq->cq,
    1006                 :            :                                 (struct virtio_pmd_ctrl *)hdr, dlen, nb_dlen);
    1007                 :            : 
    1008                 :            :         /* Update status */
    1009                 :          0 :         *(virtio_net_ctrl_ack *)(uintptr_t)
    1010                 :          0 :                 vring->desc[idx_status].addr = status;
    1011                 :            : 
    1012                 :            :         /* Update used descriptor */
    1013                 :          0 :         vring->desc[idx_hdr].id = vring->desc[idx_status].id;
    1014                 :          0 :         vring->desc[idx_hdr].len = sizeof(status);
    1015                 :            : 
    1016                 :          0 :         return n_descs;
    1017                 :            : }
    1018                 :            : 
    1019                 :            : static void
    1020                 :          0 : virtio_user_handle_cq_packed(struct virtio_user_dev *dev, uint16_t queue_idx)
    1021                 :            : {
    1022                 :          0 :         struct virtio_user_queue *vq = &dev->packed_queues[queue_idx];
    1023                 :          0 :         struct vring_packed *vring = &dev->vrings.packed[queue_idx];
    1024                 :            :         uint16_t n_descs, flags;
    1025                 :            : 
    1026                 :            :         /* Perform a load-acquire barrier in desc_is_avail to
    1027                 :            :          * enforce the ordering between desc flags and desc
    1028                 :            :          * content.
    1029                 :            :          */
    1030                 :          0 :         while (desc_is_avail(&vring->desc[vq->used_idx],
    1031         [ #  # ]:          0 :                              vq->used_wrap_counter)) {
    1032                 :            : 
    1033                 :          0 :                 n_descs = virtio_user_handle_ctrl_msg_packed(dev, vring,
    1034                 :          0 :                                 vq->used_idx);
    1035                 :            : 
    1036                 :            :                 flags = VRING_DESC_F_WRITE;
    1037         [ #  # ]:          0 :                 if (vq->used_wrap_counter)
    1038                 :            :                         flags |= VRING_PACKED_DESC_F_AVAIL_USED;
    1039                 :            : 
    1040                 :          0 :                 __atomic_store_n(&vring->desc[vq->used_idx].flags, flags,
    1041                 :            :                                  __ATOMIC_RELEASE);
    1042                 :            : 
    1043                 :          0 :                 vq->used_idx += n_descs;
    1044         [ #  # ]:          0 :                 if (vq->used_idx >= dev->queue_size) {
    1045                 :          0 :                         vq->used_idx -= dev->queue_size;
    1046                 :          0 :                         vq->used_wrap_counter ^= 1;
    1047                 :            :                 }
    1048                 :            :         }
    1049                 :          0 : }
    1050                 :            : 
    1051                 :            : static void
    1052                 :          0 : virtio_user_handle_cq_split(struct virtio_user_dev *dev, uint16_t queue_idx)
    1053                 :            : {
    1054                 :            :         uint16_t avail_idx, desc_idx;
    1055                 :            :         struct vring_used_elem *uep;
    1056                 :            :         uint32_t n_descs;
    1057                 :          0 :         struct vring *vring = &dev->vrings.split[queue_idx];
    1058                 :            : 
    1059                 :            :         /* Consume avail ring, using used ring idx as first one */
    1060                 :          0 :         while (__atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
    1061         [ #  # ]:          0 :                != vring->avail->idx) {
    1062                 :          0 :                 avail_idx = __atomic_load_n(&vring->used->idx, __ATOMIC_RELAXED)
    1063                 :          0 :                             & (vring->num - 1);
    1064                 :          0 :                 desc_idx = vring->avail->ring[avail_idx];
    1065                 :            : 
    1066                 :          0 :                 n_descs = virtio_user_handle_ctrl_msg_split(dev, vring, desc_idx);
    1067                 :            : 
    1068                 :            :                 /* Update used ring */
    1069                 :          0 :                 uep = &vring->used->ring[avail_idx];
    1070                 :          0 :                 uep->id = desc_idx;
    1071                 :          0 :                 uep->len = n_descs;
    1072                 :            : 
    1073                 :          0 :                 __atomic_fetch_add(&vring->used->idx, 1, __ATOMIC_RELAXED);
    1074                 :            :         }
    1075                 :          0 : }
    1076                 :            : 
    1077                 :            : void
    1078         [ #  # ]:          0 : virtio_user_handle_cq(struct virtio_user_dev *dev, uint16_t queue_idx)
    1079                 :            : {
    1080         [ #  # ]:          0 :         if (virtio_with_packed_queue(&dev->hw))
    1081                 :          0 :                 virtio_user_handle_cq_packed(dev, queue_idx);
    1082                 :            :         else
    1083                 :          0 :                 virtio_user_handle_cq_split(dev, queue_idx);
    1084                 :          0 : }
    1085                 :            : 
    1086                 :            : static void
    1087                 :          0 : virtio_user_control_queue_notify(struct virtqueue *vq, void *cookie)
    1088                 :            : {
    1089                 :            :         struct virtio_user_dev *dev = cookie;
    1090                 :          0 :         uint64_t notify_data = 1;
    1091                 :            : 
    1092         [ #  # ]:          0 :         if (!dev->notify_area) {
    1093         [ #  # ]:          0 :                 if (write(dev->kickfds[vq->vq_queue_index], &notify_data, sizeof(notify_data)) < 0)
    1094                 :          0 :                         PMD_DRV_LOG(ERR, "failed to kick backend: %s",
    1095                 :            :                                     strerror(errno));
    1096                 :          0 :                 return;
    1097         [ #  # ]:          0 :         } else if (!virtio_with_feature(&dev->hw, VIRTIO_F_NOTIFICATION_DATA)) {
    1098                 :          0 :                 rte_write16(vq->vq_queue_index, vq->notify_addr);
    1099                 :          0 :                 return;
    1100                 :            :         }
    1101                 :            : 
    1102         [ #  # ]:          0 :         if (virtio_with_packed_queue(&dev->hw)) {
    1103                 :            :                 /* Bit[0:15]: vq queue index
    1104                 :            :                  * Bit[16:30]: avail index
    1105                 :            :                  * Bit[31]: avail wrap counter
    1106                 :            :                  */
    1107                 :          0 :                 notify_data = ((uint32_t)(!!(vq->vq_packed.cached_flags &
    1108                 :          0 :                                 VRING_PACKED_DESC_F_AVAIL)) << 31) |
    1109                 :          0 :                                 ((uint32_t)vq->vq_avail_idx << 16) |
    1110                 :          0 :                                 vq->vq_queue_index;
    1111                 :            :         } else {
    1112                 :            :                 /* Bit[0:15]: vq queue index
    1113                 :            :                  * Bit[16:31]: avail index
    1114                 :            :                  */
    1115                 :          0 :                 notify_data = ((uint32_t)vq->vq_avail_idx << 16) |
    1116                 :          0 :                                 vq->vq_queue_index;
    1117                 :            :         }
    1118                 :          0 :         rte_write32(notify_data, vq->notify_addr);
    1119                 :            : }
    1120                 :            : 
    1121                 :            : int
    1122                 :          0 : virtio_user_dev_create_shadow_cvq(struct virtio_user_dev *dev, struct virtqueue *vq)
    1123                 :            : {
    1124                 :            :         char name[VIRTQUEUE_MAX_NAME_SZ];
    1125                 :            :         struct virtqueue *scvq;
    1126                 :            : 
    1127                 :          0 :         snprintf(name, sizeof(name), "port%d_shadow_cvq", vq->hw->port_id);
    1128                 :          0 :         scvq = virtqueue_alloc(&dev->hw, vq->vq_queue_index, vq->vq_nentries,
    1129                 :            :                         VTNET_CQ, SOCKET_ID_ANY, name);
    1130         [ #  # ]:          0 :         if (!scvq) {
    1131                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to alloc shadow control vq\n", dev->path);
    1132                 :          0 :                 return -ENOMEM;
    1133                 :            :         }
    1134                 :            : 
    1135                 :          0 :         scvq->cq.notify_queue = &virtio_user_control_queue_notify;
    1136                 :          0 :         scvq->cq.notify_cookie = dev;
    1137                 :          0 :         scvq->notify_addr = vq->notify_addr;
    1138                 :          0 :         dev->scvq = scvq;
    1139                 :            : 
    1140                 :          0 :         return 0;
    1141                 :            : }
    1142                 :            : 
    1143                 :            : void
    1144                 :          0 : virtio_user_dev_destroy_shadow_cvq(struct virtio_user_dev *dev)
    1145                 :            : {
    1146         [ #  # ]:          0 :         if (!dev->scvq)
    1147                 :            :                 return;
    1148                 :            : 
    1149                 :          0 :         virtqueue_free(dev->scvq);
    1150                 :          0 :         dev->scvq = NULL;
    1151                 :            : }
    1152                 :            : 
    1153                 :            : int
    1154                 :          0 : virtio_user_dev_set_status(struct virtio_user_dev *dev, uint8_t status)
    1155                 :            : {
    1156                 :            :         int ret;
    1157                 :            : 
    1158                 :          0 :         pthread_mutex_lock(&dev->mutex);
    1159                 :          0 :         dev->status = status;
    1160                 :          0 :         ret = dev->ops->set_status(dev, status);
    1161         [ #  # ]:          0 :         if (ret && ret != -ENOTSUP)
    1162                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to set backend status", dev->path);
    1163                 :            : 
    1164                 :          0 :         pthread_mutex_unlock(&dev->mutex);
    1165                 :          0 :         return ret;
    1166                 :            : }
    1167                 :            : 
    1168                 :            : int
    1169                 :          0 : virtio_user_dev_update_status(struct virtio_user_dev *dev)
    1170                 :            : {
    1171                 :            :         int ret;
    1172                 :            :         uint8_t status;
    1173                 :            : 
    1174                 :          0 :         pthread_mutex_lock(&dev->mutex);
    1175                 :            : 
    1176                 :          0 :         ret = dev->ops->get_status(dev, &status);
    1177         [ #  # ]:          0 :         if (!ret) {
    1178                 :          0 :                 dev->status = status;
    1179                 :          0 :                 PMD_INIT_LOG(DEBUG, "Updated Device Status(0x%08x):\n"
    1180                 :            :                         "\t-RESET: %u\n"
    1181                 :            :                         "\t-ACKNOWLEDGE: %u\n"
    1182                 :            :                         "\t-DRIVER: %u\n"
    1183                 :            :                         "\t-DRIVER_OK: %u\n"
    1184                 :            :                         "\t-FEATURES_OK: %u\n"
    1185                 :            :                         "\t-DEVICE_NEED_RESET: %u\n"
    1186                 :            :                         "\t-FAILED: %u",
    1187                 :            :                         dev->status,
    1188                 :            :                         (dev->status == VIRTIO_CONFIG_STATUS_RESET),
    1189                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_ACK),
    1190                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER),
    1191                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_DRIVER_OK),
    1192                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_FEATURES_OK),
    1193                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_DEV_NEED_RESET),
    1194                 :            :                         !!(dev->status & VIRTIO_CONFIG_STATUS_FAILED));
    1195         [ #  # ]:          0 :         } else if (ret != -ENOTSUP) {
    1196                 :          0 :                 PMD_INIT_LOG(ERR, "(%s) Failed to get backend status", dev->path);
    1197                 :            :         }
    1198                 :            : 
    1199                 :          0 :         pthread_mutex_unlock(&dev->mutex);
    1200                 :          0 :         return ret;
    1201                 :            : }
    1202                 :            : 
    1203                 :            : int
    1204                 :          0 : virtio_user_dev_update_link_state(struct virtio_user_dev *dev)
    1205                 :            : {
    1206         [ #  # ]:          0 :         if (dev->ops->update_link_state)
    1207                 :          0 :                 return dev->ops->update_link_state(dev);
    1208                 :            : 
    1209                 :            :         return 0;
    1210                 :            : }
    1211                 :            : 
    1212                 :            : static void
    1213                 :          0 : virtio_user_dev_reset_queues_packed(struct rte_eth_dev *eth_dev)
    1214                 :            : {
    1215                 :          0 :         struct virtio_user_dev *dev = eth_dev->data->dev_private;
    1216                 :            :         struct virtio_hw *hw = &dev->hw;
    1217                 :            :         struct virtnet_rx *rxvq;
    1218                 :            :         struct virtnet_tx *txvq;
    1219                 :            :         uint16_t i;
    1220                 :            : 
    1221                 :            :         /* Add lock to avoid queue contention. */
    1222                 :          0 :         rte_spinlock_lock(&hw->state_lock);
    1223                 :          0 :         hw->started = 0;
    1224                 :            : 
    1225                 :            :         /*
    1226                 :            :          * Waiting for datapath to complete before resetting queues.
    1227                 :            :          * 1 ms should be enough for the ongoing Tx/Rx function to finish.
    1228                 :            :          */
    1229                 :            :         rte_delay_ms(1);
    1230                 :            : 
    1231                 :            :         /* Vring reset for each Tx queue and Rx queue. */
    1232         [ #  # ]:          0 :         for (i = 0; i < eth_dev->data->nb_rx_queues; i++) {
    1233                 :          0 :                 rxvq = eth_dev->data->rx_queues[i];
    1234                 :          0 :                 virtqueue_rxvq_reset_packed(virtnet_rxq_to_vq(rxvq));
    1235                 :          0 :                 virtio_dev_rx_queue_setup_finish(eth_dev, i);
    1236                 :            :         }
    1237                 :            : 
    1238         [ #  # ]:          0 :         for (i = 0; i < eth_dev->data->nb_tx_queues; i++) {
    1239                 :          0 :                 txvq = eth_dev->data->tx_queues[i];
    1240                 :          0 :                 virtqueue_txvq_reset_packed(virtnet_txq_to_vq(txvq));
    1241                 :            :         }
    1242                 :            : 
    1243                 :          0 :         hw->started = 1;
    1244                 :            :         rte_spinlock_unlock(&hw->state_lock);
    1245                 :          0 : }
    1246                 :            : 
    1247                 :            : void
    1248                 :          0 : virtio_user_dev_delayed_disconnect_handler(void *param)
    1249                 :            : {
    1250                 :            :         struct virtio_user_dev *dev = param;
    1251                 :          0 :         struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
    1252                 :            : 
    1253         [ #  # ]:          0 :         if (rte_intr_disable(eth_dev->intr_handle) < 0) {
    1254                 :          0 :                 PMD_DRV_LOG(ERR, "interrupt disable failed");
    1255                 :          0 :                 return;
    1256                 :            :         }
    1257                 :          0 :         PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
    1258                 :            :                     rte_intr_fd_get(eth_dev->intr_handle));
    1259         [ #  # ]:          0 :         if (rte_intr_callback_unregister(eth_dev->intr_handle,
    1260                 :            :                                          virtio_interrupt_handler,
    1261                 :            :                                          eth_dev) != 1)
    1262                 :          0 :                 PMD_DRV_LOG(ERR, "interrupt unregister failed");
    1263                 :            : 
    1264         [ #  # ]:          0 :         if (dev->is_server) {
    1265         [ #  # ]:          0 :                 if (dev->ops->server_disconnect)
    1266                 :          0 :                         dev->ops->server_disconnect(dev);
    1267                 :            : 
    1268                 :          0 :                 rte_intr_fd_set(eth_dev->intr_handle,
    1269                 :          0 :                         dev->ops->get_intr_fd(dev));
    1270                 :            : 
    1271                 :          0 :                 PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
    1272                 :            :                             rte_intr_fd_get(eth_dev->intr_handle));
    1273                 :            : 
    1274         [ #  # ]:          0 :                 if (rte_intr_callback_register(eth_dev->intr_handle,
    1275                 :            :                                                virtio_interrupt_handler,
    1276                 :            :                                                eth_dev))
    1277                 :          0 :                         PMD_DRV_LOG(ERR, "interrupt register failed");
    1278                 :            : 
    1279         [ #  # ]:          0 :                 if (rte_intr_enable(eth_dev->intr_handle) < 0) {
    1280                 :          0 :                         PMD_DRV_LOG(ERR, "interrupt enable failed");
    1281                 :          0 :                         return;
    1282                 :            :                 }
    1283                 :            :         }
    1284                 :            : }
    1285                 :            : 
    1286                 :            : static void
    1287                 :          0 : virtio_user_dev_delayed_intr_reconfig_handler(void *param)
    1288                 :            : {
    1289                 :            :         struct virtio_user_dev *dev = param;
    1290                 :          0 :         struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
    1291                 :            : 
    1292                 :          0 :         PMD_DRV_LOG(DEBUG, "Unregistering intr fd: %d",
    1293                 :            :                     rte_intr_fd_get(eth_dev->intr_handle));
    1294                 :            : 
    1295         [ #  # ]:          0 :         if (rte_intr_callback_unregister(eth_dev->intr_handle,
    1296                 :            :                                          virtio_interrupt_handler,
    1297                 :            :                                          eth_dev) != 1)
    1298                 :          0 :                 PMD_DRV_LOG(ERR, "interrupt unregister failed");
    1299                 :            : 
    1300                 :          0 :         rte_intr_fd_set(eth_dev->intr_handle, dev->ops->get_intr_fd(dev));
    1301                 :            : 
    1302                 :          0 :         PMD_DRV_LOG(DEBUG, "Registering intr fd: %d",
    1303                 :            :                     rte_intr_fd_get(eth_dev->intr_handle));
    1304                 :            : 
    1305         [ #  # ]:          0 :         if (rte_intr_callback_register(eth_dev->intr_handle,
    1306                 :            :                                        virtio_interrupt_handler, eth_dev))
    1307                 :          0 :                 PMD_DRV_LOG(ERR, "interrupt register failed");
    1308                 :            : 
    1309         [ #  # ]:          0 :         if (rte_intr_enable(eth_dev->intr_handle) < 0)
    1310                 :          0 :                 PMD_DRV_LOG(ERR, "interrupt enable failed");
    1311                 :          0 : }
    1312                 :            : 
    1313                 :            : int
    1314                 :          0 : virtio_user_dev_server_reconnect(struct virtio_user_dev *dev)
    1315                 :            : {
    1316                 :            :         int ret, old_status;
    1317                 :          0 :         struct rte_eth_dev *eth_dev = &rte_eth_devices[dev->hw.port_id];
    1318                 :          0 :         struct virtio_hw *hw = &dev->hw;
    1319                 :            : 
    1320         [ #  # ]:          0 :         if (!dev->ops->server_reconnect) {
    1321                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Missing server reconnect callback", dev->path);
    1322                 :          0 :                 return -1;
    1323                 :            :         }
    1324                 :            : 
    1325         [ #  # ]:          0 :         if (dev->ops->server_reconnect(dev)) {
    1326                 :          0 :                 PMD_DRV_LOG(ERR, "(%s) Reconnect callback call failed", dev->path);
    1327                 :          0 :                 return -1;
    1328                 :            :         }
    1329                 :            : 
    1330                 :          0 :         old_status = dev->status;
    1331                 :            : 
    1332                 :          0 :         virtio_reset(hw);
    1333                 :            : 
    1334                 :          0 :         virtio_set_status(hw, VIRTIO_CONFIG_STATUS_ACK);
    1335                 :            : 
    1336                 :          0 :         virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER);
    1337                 :            : 
    1338         [ #  # ]:          0 :         if (dev->ops->get_features(dev, &dev->device_features) < 0) {
    1339                 :          0 :                 PMD_INIT_LOG(ERR, "get_features failed: %s",
    1340                 :            :                              strerror(errno));
    1341                 :          0 :                 return -1;
    1342                 :            :         }
    1343                 :            : 
    1344                 :            :         /* unmask vhost-user unsupported features */
    1345                 :          0 :         dev->device_features &= ~(dev->unsupported_features);
    1346                 :            : 
    1347         [ #  # ]:          0 :         dev->features &= (dev->device_features | dev->frontend_features);
    1348                 :            : 
    1349                 :            :         /* For packed ring, resetting queues is required in reconnection. */
    1350   [ #  #  #  # ]:          0 :         if (virtio_with_packed_queue(hw) &&
    1351                 :            :            (old_status & VIRTIO_CONFIG_STATUS_DRIVER_OK)) {
    1352                 :          0 :                 PMD_INIT_LOG(NOTICE, "Packets on the fly will be dropped"
    1353                 :            :                                 " when packed ring reconnecting.");
    1354                 :          0 :                 virtio_user_dev_reset_queues_packed(eth_dev);
    1355                 :            :         }
    1356                 :            : 
    1357                 :          0 :         virtio_set_status(hw, VIRTIO_CONFIG_STATUS_FEATURES_OK);
    1358                 :            : 
    1359                 :            :         /* Start the device */
    1360                 :          0 :         virtio_set_status(hw, VIRTIO_CONFIG_STATUS_DRIVER_OK);
    1361         [ #  # ]:          0 :         if (!dev->started)
    1362                 :            :                 return -1;
    1363                 :            : 
    1364         [ #  # ]:          0 :         if (dev->queue_pairs > 1) {
    1365                 :          0 :                 ret = virtio_user_handle_mq(dev, dev->queue_pairs);
    1366         [ #  # ]:          0 :                 if (ret != 0) {
    1367                 :          0 :                         PMD_INIT_LOG(ERR, "Fails to enable multi-queue pairs!");
    1368                 :          0 :                         return -1;
    1369                 :            :                 }
    1370                 :            :         }
    1371         [ #  # ]:          0 :         if (eth_dev->data->dev_flags & RTE_ETH_DEV_INTR_LSC) {
    1372         [ #  # ]:          0 :                 if (rte_intr_disable(eth_dev->intr_handle) < 0) {
    1373                 :          0 :                         PMD_DRV_LOG(ERR, "interrupt disable failed");
    1374                 :          0 :                         return -1;
    1375                 :            :                 }
    1376                 :            :                 /*
    1377                 :            :                  * This function can be called from the interrupt handler, so
    1378                 :            :                  * we can't unregister interrupt handler here.  Setting
    1379                 :            :                  * alarm to do that later.
    1380                 :            :                  */
    1381                 :          0 :                 rte_eal_alarm_set(1,
    1382                 :            :                         virtio_user_dev_delayed_intr_reconfig_handler,
    1383                 :            :                         (void *)dev);
    1384                 :            :         }
    1385                 :          0 :         PMD_INIT_LOG(NOTICE, "server mode virtio-user reconnection succeeds!");
    1386                 :          0 :         return 0;
    1387                 :            : }

Generated by: LCOV version 1.14