LCOV - code coverage report
Current view: top level - spdk/lib/virtio - virtio.c (source / functions) Hit Total Coverage
Test: Combined Lines: 264 336 78.6 %
Date: 2024-07-15 21:16:48 Functions: 28 31 90.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 98 186 52.7 %

           Branch data     Line data    Source code
       1                 :            : /*   SPDX-License-Identifier: BSD-3-Clause
       2                 :            :  *   Copyright (C) 2010-2016 Intel Corporation. All rights reserved.
       3                 :            :  *   All rights reserved.
       4                 :            :  */
       5                 :            : 
       6                 :            : #include "spdk/stdinc.h"
       7                 :            : 
       8                 :            : #include "spdk/env.h"
       9                 :            : #include "spdk/util.h"
      10                 :            : #include "spdk/barrier.h"
      11                 :            : 
      12                 :            : #include "spdk_internal/virtio.h"
      13                 :            : 
      14                 :            : /* We use SMP memory barrier variants as all virtio_pci devices
      15                 :            :  * are purely virtual. All MMIO is executed on a CPU core, so
      16                 :            :  * there's no need to do full MMIO synchronization.
      17                 :            :  */
      18                 :            : #define virtio_mb()     spdk_smp_mb()
      19                 :            : #define virtio_rmb()    spdk_smp_rmb()
      20                 :            : #define virtio_wmb()    spdk_smp_wmb()
      21                 :            : 
      22                 :            : /* Chain all the descriptors in the ring with an END */
      23                 :            : static inline void
      24                 :        172 : vring_desc_init(struct vring_desc *dp, uint16_t n)
      25                 :            : {
      26                 :            :         uint16_t i;
      27                 :            : 
      28         [ +  + ]:      97280 :         for (i = 0; i < n - 1; i++) {
      29                 :      97108 :                 dp[i].next = (uint16_t)(i + 1);
      30                 :            :         }
      31                 :        172 :         dp[i].next = VQ_RING_DESC_CHAIN_END;
      32                 :        172 : }
      33                 :            : 
      34                 :            : static void
      35                 :        172 : virtio_init_vring(struct virtqueue *vq)
      36                 :            : {
      37                 :        172 :         int size = vq->vq_nentries;
      38                 :        172 :         struct vring *vr = &vq->vq_ring;
      39                 :        172 :         uint8_t *ring_mem = vq->vq_ring_virt_mem;
      40                 :            : 
      41                 :            :         /*
      42                 :            :          * Reinitialise since virtio port might have been stopped and restarted
      43                 :            :          */
      44         [ -  + ]:        172 :         memset(ring_mem, 0, vq->vq_ring_size);
      45                 :        172 :         vring_init(vr, size, ring_mem, VIRTIO_PCI_VRING_ALIGN);
      46                 :        172 :         vq->vq_used_cons_idx = 0;
      47                 :        172 :         vq->vq_desc_head_idx = 0;
      48                 :        172 :         vq->vq_avail_idx = 0;
      49                 :        172 :         vq->vq_desc_tail_idx = (uint16_t)(vq->vq_nentries - 1);
      50                 :        172 :         vq->vq_free_cnt = vq->vq_nentries;
      51                 :        172 :         vq->req_start = VQ_RING_DESC_CHAIN_END;
      52                 :        172 :         vq->req_end = VQ_RING_DESC_CHAIN_END;
      53                 :        172 :         vq->reqs_finished = 0;
      54         [ -  + ]:        172 :         memset(vq->vq_descx, 0, sizeof(struct vq_desc_extra) * vq->vq_nentries);
      55                 :            : 
      56                 :        172 :         vring_desc_init(vr->desc, size);
      57                 :            : 
      58                 :            :         /* Tell the backend not to interrupt us.
      59                 :            :          * If F_EVENT_IDX is negotiated, we will always set incredibly high
      60                 :            :          * used event idx, so that we will practically never receive an
      61                 :            :          * interrupt. See virtqueue_req_flush()
      62                 :            :          */
      63         [ -  + ]:        172 :         if (vq->vdev->negotiated_features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
      64                 :          0 :                 vring_used_event(&vq->vq_ring) = UINT16_MAX;
      65                 :            :         } else {
      66                 :        172 :                 vq->vq_ring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
      67                 :            :         }
      68                 :        172 : }
      69                 :            : 
      70                 :            : static int
      71                 :        172 : virtio_init_queue(struct virtio_dev *dev, uint16_t vtpci_queue_idx)
      72                 :            : {
      73                 :            :         unsigned int vq_size, size;
      74                 :          0 :         struct virtqueue *vq;
      75                 :            :         int rc;
      76                 :            : 
      77   [ -  +  -  + ]:        172 :         SPDK_DEBUGLOG(virtio_dev, "setting up queue: %"PRIu16"\n", vtpci_queue_idx);
      78                 :            : 
      79                 :            :         /*
      80                 :            :          * Read the virtqueue size from the Queue Size field
      81                 :            :          * Always power of 2 and if 0 virtqueue does not exist
      82                 :            :          */
      83                 :        172 :         vq_size = virtio_dev_backend_ops(dev)->get_queue_size(dev, vtpci_queue_idx);
      84   [ -  +  -  + ]:        172 :         SPDK_DEBUGLOG(virtio_dev, "vq_size: %u\n", vq_size);
      85         [ -  + ]:        172 :         if (vq_size == 0) {
      86                 :          0 :                 SPDK_ERRLOG("virtqueue %"PRIu16" does not exist\n", vtpci_queue_idx);
      87                 :          0 :                 return -EINVAL;
      88                 :            :         }
      89                 :            : 
      90         [ -  + ]:        172 :         if (!spdk_u32_is_pow2(vq_size)) {
      91                 :          0 :                 SPDK_ERRLOG("virtqueue %"PRIu16" size (%u) is not powerof 2\n",
      92                 :            :                             vtpci_queue_idx, vq_size);
      93                 :          0 :                 return -EINVAL;
      94                 :            :         }
      95                 :            : 
      96                 :        172 :         size = sizeof(*vq) + vq_size * sizeof(struct vq_desc_extra);
      97                 :            : 
      98   [ -  +  -  + ]:        172 :         if (posix_memalign((void **)&vq, SPDK_CACHE_LINE_SIZE, size)) {
      99                 :          0 :                 SPDK_ERRLOG("can not allocate vq\n");
     100                 :          0 :                 return -ENOMEM;
     101                 :            :         }
     102         [ -  + ]:        172 :         memset(vq, 0, size);
     103                 :        172 :         dev->vqs[vtpci_queue_idx] = vq;
     104                 :            : 
     105                 :        172 :         vq->vdev = dev;
     106                 :        172 :         vq->vq_queue_index = vtpci_queue_idx;
     107                 :        172 :         vq->vq_nentries = vq_size;
     108                 :            : 
     109                 :            :         /*
     110                 :            :          * Reserve a memzone for vring elements
     111                 :            :          */
     112                 :        172 :         size = vring_size(vq_size, VIRTIO_PCI_VRING_ALIGN);
     113                 :        172 :         vq->vq_ring_size = SPDK_ALIGN_CEIL(size, VIRTIO_PCI_VRING_ALIGN);
     114   [ -  +  -  + ]:        172 :         SPDK_DEBUGLOG(virtio_dev, "vring_size: %u, rounded_vring_size: %u\n",
     115                 :            :                       size, vq->vq_ring_size);
     116                 :            : 
     117                 :        172 :         vq->owner_thread = NULL;
     118                 :            : 
     119                 :        172 :         rc = virtio_dev_backend_ops(dev)->setup_queue(dev, vq);
     120         [ -  + ]:        172 :         if (rc < 0) {
     121                 :          0 :                 SPDK_ERRLOG("setup_queue failed\n");
     122                 :          0 :                 free(vq);
     123                 :          0 :                 dev->vqs[vtpci_queue_idx] = NULL;
     124                 :          0 :                 return rc;
     125                 :            :         }
     126                 :            : 
     127   [ -  +  -  + ]:        172 :         SPDK_DEBUGLOG(virtio_dev, "vq->vq_ring_mem:      0x%" PRIx64 "\n",
     128                 :            :                       vq->vq_ring_mem);
     129   [ -  +  -  + ]:        172 :         SPDK_DEBUGLOG(virtio_dev, "vq->vq_ring_virt_mem: 0x%" PRIx64 "\n",
     130                 :            :                       (uint64_t)(uintptr_t)vq->vq_ring_virt_mem);
     131                 :            : 
     132                 :        172 :         virtio_init_vring(vq);
     133                 :        172 :         return 0;
     134                 :            : }
     135                 :            : 
     136                 :            : static void
     137                 :         58 : virtio_free_queues(struct virtio_dev *dev)
     138                 :            : {
     139                 :         58 :         uint16_t nr_vq = dev->max_queues;
     140                 :            :         struct virtqueue *vq;
     141                 :            :         uint16_t i;
     142                 :            : 
     143         [ +  + ]:         58 :         if (dev->vqs == NULL) {
     144                 :         29 :                 return;
     145                 :            :         }
     146                 :            : 
     147         [ +  + ]:        201 :         for (i = 0; i < nr_vq; i++) {
     148                 :        172 :                 vq = dev->vqs[i];
     149         [ -  + ]:        172 :                 if (!vq) {
     150                 :          0 :                         continue;
     151                 :            :                 }
     152                 :            : 
     153                 :        172 :                 virtio_dev_backend_ops(dev)->del_queue(dev, vq);
     154                 :            : 
     155                 :        172 :                 free(vq);
     156                 :        172 :                 dev->vqs[i] = NULL;
     157                 :            :         }
     158                 :            : 
     159                 :         29 :         free(dev->vqs);
     160                 :         29 :         dev->vqs = NULL;
     161                 :            : }
     162                 :            : 
     163                 :            : static int
     164                 :         29 : virtio_alloc_queues(struct virtio_dev *dev, uint16_t max_queues, uint16_t fixed_vq_num)
     165                 :            : {
     166                 :            :         uint16_t i;
     167                 :            :         int ret;
     168                 :            : 
     169         [ -  + ]:         29 :         if (max_queues == 0) {
     170                 :            :                 /* perfectly fine to have a device with no virtqueues. */
     171                 :          0 :                 return 0;
     172                 :            :         }
     173                 :            : 
     174         [ -  + ]:         29 :         assert(dev->vqs == NULL);
     175                 :         29 :         dev->vqs = calloc(1, sizeof(struct virtqueue *) * max_queues);
     176         [ -  + ]:         29 :         if (!dev->vqs) {
     177                 :          0 :                 SPDK_ERRLOG("failed to allocate %"PRIu16" vqs\n", max_queues);
     178                 :          0 :                 return -ENOMEM;
     179                 :            :         }
     180                 :            : 
     181         [ +  + ]:        201 :         for (i = 0; i < max_queues; i++) {
     182                 :        172 :                 ret = virtio_init_queue(dev, i);
     183         [ -  + ]:        172 :                 if (ret < 0) {
     184                 :          0 :                         virtio_free_queues(dev);
     185                 :          0 :                         return ret;
     186                 :            :                 }
     187                 :            :         }
     188                 :            : 
     189                 :         29 :         dev->max_queues = max_queues;
     190                 :         29 :         dev->fixed_queues_num = fixed_vq_num;
     191                 :         29 :         return 0;
     192                 :            : }
     193                 :            : 
     194                 :            : /**
     195                 :            :  * Negotiate virtio features. For virtio_user this will also set
     196                 :            :  * dev->modern flag if VIRTIO_F_VERSION_1 flag is negotiated.
     197                 :            :  */
     198                 :            : static int
     199                 :         29 : virtio_negotiate_features(struct virtio_dev *dev, uint64_t req_features)
     200                 :            : {
     201                 :         29 :         uint64_t host_features = virtio_dev_backend_ops(dev)->get_features(dev);
     202                 :            :         int rc;
     203                 :            : 
     204   [ -  +  -  + ]:         29 :         SPDK_DEBUGLOG(virtio_dev, "guest features = %" PRIx64 "\n", req_features);
     205   [ -  +  -  + ]:         29 :         SPDK_DEBUGLOG(virtio_dev, "device features = %" PRIx64 "\n", host_features);
     206                 :            : 
     207                 :         29 :         rc = virtio_dev_backend_ops(dev)->set_features(dev, req_features & host_features);
     208         [ -  + ]:         29 :         if (rc != 0) {
     209                 :          0 :                 SPDK_ERRLOG("failed to negotiate device features.\n");
     210                 :          0 :                 return rc;
     211                 :            :         }
     212                 :            : 
     213   [ -  +  -  + ]:         29 :         SPDK_DEBUGLOG(virtio_dev, "negotiated features = %" PRIx64 "\n",
     214                 :            :                       dev->negotiated_features);
     215                 :            : 
     216                 :         29 :         virtio_dev_set_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
     217         [ -  + ]:         29 :         if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_FEATURES_OK)) {
     218                 :          0 :                 SPDK_ERRLOG("failed to set FEATURES_OK status!\n");
     219                 :            :                 /* either the device failed, or we offered some features that
     220                 :            :                  * depend on other, not offered features.
     221                 :            :                  */
     222                 :          0 :                 return -EINVAL;
     223                 :            :         }
     224                 :            : 
     225                 :         29 :         return 0;
     226                 :            : }
     227                 :            : 
     228                 :            : int
     229                 :         29 : virtio_dev_construct(struct virtio_dev *vdev, const char *name,
     230                 :            :                      const struct virtio_dev_ops *ops, void *ctx)
     231                 :            : {
     232                 :            :         int rc;
     233                 :            : 
     234         [ -  + ]:         29 :         vdev->name = strdup(name);
     235         [ -  + ]:         29 :         if (vdev->name == NULL) {
     236                 :          0 :                 return -ENOMEM;
     237                 :            :         }
     238                 :            : 
     239         [ -  + ]:         29 :         rc = pthread_mutex_init(&vdev->mutex, NULL);
     240         [ -  + ]:         29 :         if (rc != 0) {
     241                 :          0 :                 free(vdev->name);
     242                 :          0 :                 return -rc;
     243                 :            :         }
     244                 :            : 
     245                 :         29 :         vdev->backend_ops = ops;
     246                 :         29 :         vdev->ctx = ctx;
     247                 :            : 
     248                 :         29 :         return 0;
     249                 :            : }
     250                 :            : 
     251                 :            : int
     252                 :         29 : virtio_dev_reset(struct virtio_dev *dev, uint64_t req_features)
     253                 :            : {
     254                 :         29 :         req_features |= (1ULL << VIRTIO_F_VERSION_1);
     255                 :            : 
     256                 :         29 :         virtio_dev_stop(dev);
     257                 :            : 
     258                 :         29 :         virtio_dev_set_status(dev, VIRTIO_CONFIG_S_ACKNOWLEDGE);
     259         [ -  + ]:         29 :         if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_ACKNOWLEDGE)) {
     260                 :          0 :                 SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_ACKNOWLEDGE status.\n");
     261                 :          0 :                 return -EIO;
     262                 :            :         }
     263                 :            : 
     264                 :         29 :         virtio_dev_set_status(dev, VIRTIO_CONFIG_S_DRIVER);
     265         [ -  + ]:         29 :         if (!(virtio_dev_get_status(dev) & VIRTIO_CONFIG_S_DRIVER)) {
     266                 :          0 :                 SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_DRIVER status.\n");
     267                 :          0 :                 return -EIO;
     268                 :            :         }
     269                 :            : 
     270                 :         29 :         return virtio_negotiate_features(dev, req_features);
     271                 :            : }
     272                 :            : 
     273                 :            : int
     274                 :         29 : virtio_dev_start(struct virtio_dev *vdev, uint16_t max_queues, uint16_t fixed_queue_num)
     275                 :            : {
     276                 :            :         int ret;
     277                 :            : 
     278                 :         29 :         ret = virtio_alloc_queues(vdev, max_queues, fixed_queue_num);
     279         [ -  + ]:         29 :         if (ret < 0) {
     280                 :          0 :                 return ret;
     281                 :            :         }
     282                 :            : 
     283                 :         29 :         virtio_dev_set_status(vdev, VIRTIO_CONFIG_S_DRIVER_OK);
     284         [ -  + ]:         29 :         if (!(virtio_dev_get_status(vdev) & VIRTIO_CONFIG_S_DRIVER_OK)) {
     285                 :          0 :                 SPDK_ERRLOG("Failed to set VIRTIO_CONFIG_S_DRIVER_OK status.\n");
     286                 :          0 :                 return -1;
     287                 :            :         }
     288                 :            : 
     289                 :         29 :         return 0;
     290                 :            : }
     291                 :            : 
     292                 :            : void
     293                 :         29 : virtio_dev_destruct(struct virtio_dev *dev)
     294                 :            : {
     295                 :         29 :         virtio_dev_backend_ops(dev)->destruct_dev(dev);
     296         [ -  + ]:         29 :         pthread_mutex_destroy(&dev->mutex);
     297                 :         29 :         free(dev->name);
     298                 :         29 : }
     299                 :            : 
     300                 :            : static void
     301                 :    2693119 : vq_ring_free_chain(struct virtqueue *vq, uint16_t desc_idx)
     302                 :            : {
     303                 :            :         struct vring_desc *dp, *dp_tail;
     304                 :            :         struct vq_desc_extra *dxp;
     305                 :    2693119 :         uint16_t desc_idx_last = desc_idx;
     306                 :            : 
     307                 :    2693119 :         dp  = &vq->vq_ring.desc[desc_idx];
     308                 :    2693119 :         dxp = &vq->vq_descx[desc_idx];
     309                 :    2693119 :         vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt + dxp->ndescs);
     310         [ +  - ]:    2693119 :         if ((dp->flags & VRING_DESC_F_INDIRECT) == 0) {
     311         [ +  + ]:    8079324 :                 while (dp->flags & VRING_DESC_F_NEXT) {
     312                 :    5386205 :                         desc_idx_last = dp->next;
     313                 :    5386205 :                         dp = &vq->vq_ring.desc[dp->next];
     314                 :            :                 }
     315                 :            :         }
     316                 :    2693119 :         dxp->ndescs = 0;
     317                 :            : 
     318                 :            :         /*
     319                 :            :          * We must append the existing free chain, if any, to the end of
     320                 :            :          * newly freed chain. If the virtqueue was completely used, then
     321                 :            :          * head would be VQ_RING_DESC_CHAIN_END (ASSERTed above).
     322                 :            :          */
     323         [ -  + ]:    2693119 :         if (vq->vq_desc_tail_idx == VQ_RING_DESC_CHAIN_END) {
     324                 :          0 :                 vq->vq_desc_head_idx = desc_idx;
     325                 :            :         } else {
     326                 :    2693119 :                 dp_tail = &vq->vq_ring.desc[vq->vq_desc_tail_idx];
     327                 :    2693119 :                 dp_tail->next = desc_idx;
     328                 :            :         }
     329                 :            : 
     330                 :    2693119 :         vq->vq_desc_tail_idx = desc_idx_last;
     331                 :    2693119 :         dp->next = VQ_RING_DESC_CHAIN_END;
     332                 :    2693119 : }
     333                 :            : 
     334                 :            : static uint16_t
     335                 :   43929824 : virtqueue_dequeue_burst_rx(struct virtqueue *vq, void **rx_pkts,
     336                 :            :                            uint32_t *len, uint16_t num)
     337                 :            : {
     338                 :            :         struct vring_used_elem *uep;
     339                 :            :         void *cookie;
     340                 :            :         uint16_t used_idx, desc_idx;
     341                 :            :         uint16_t i;
     342                 :            : 
     343                 :            :         /*  Caller does the check */
     344         [ +  + ]:   46622943 :         for (i = 0; i < num ; i++) {
     345                 :    2693119 :                 used_idx = (uint16_t)(vq->vq_used_cons_idx & (vq->vq_nentries - 1));
     346                 :    2693119 :                 uep = &vq->vq_ring.used->ring[used_idx];
     347                 :    2693119 :                 desc_idx = (uint16_t) uep->id;
     348                 :    2693119 :                 len[i] = uep->len;
     349                 :    2693119 :                 cookie = vq->vq_descx[desc_idx].cookie;
     350                 :            : 
     351         [ -  + ]:    2693119 :                 if (spdk_unlikely(cookie == NULL)) {
     352                 :          0 :                         SPDK_WARNLOG("vring descriptor with no mbuf cookie at %"PRIu16"\n",
     353                 :            :                                      vq->vq_used_cons_idx);
     354                 :          0 :                         break;
     355                 :            :                 }
     356                 :            : 
     357                 :    2693119 :                 __builtin_prefetch(cookie);
     358                 :            : 
     359                 :    2693119 :                 rx_pkts[i]  = cookie;
     360                 :    2693119 :                 vq->vq_used_cons_idx++;
     361                 :    2693119 :                 vq_ring_free_chain(vq, desc_idx);
     362                 :    2693119 :                 vq->vq_descx[desc_idx].cookie = NULL;
     363                 :            :         }
     364                 :            : 
     365                 :   43929824 :         return i;
     366                 :            : }
     367                 :            : 
     368                 :            : static void
     369                 :    2693311 : finish_req(struct virtqueue *vq)
     370                 :            : {
     371                 :            :         struct vring_desc *desc;
     372                 :            :         uint16_t avail_idx;
     373                 :            : 
     374                 :    2693311 :         desc = &vq->vq_ring.desc[vq->req_end];
     375                 :    2693311 :         desc->flags &= ~VRING_DESC_F_NEXT;
     376                 :            : 
     377                 :            :         /*
     378                 :            :          * Place the head of the descriptor chain into the next slot and make
     379                 :            :          * it usable to the host. The chain is made available now rather than
     380                 :            :          * deferring to virtqueue_req_flush() in the hopes that if the host is
     381                 :            :          * currently running on another CPU, we can keep it processing the new
     382                 :            :          * descriptor.
     383                 :            :          */
     384                 :    2693311 :         avail_idx = (uint16_t)(vq->vq_avail_idx & (vq->vq_nentries - 1));
     385                 :    2693311 :         vq->vq_ring.avail->ring[avail_idx] = vq->req_start;
     386                 :    2693311 :         vq->vq_avail_idx++;
     387                 :    2693311 :         vq->req_end = VQ_RING_DESC_CHAIN_END;
     388                 :    2693311 :         virtio_wmb();
     389                 :    2693311 :         vq->vq_ring.avail->idx = vq->vq_avail_idx;
     390                 :    2693311 :         vq->reqs_finished++;
     391                 :    2693311 : }
     392                 :            : 
     393                 :            : int
     394                 :    2693311 : virtqueue_req_start(struct virtqueue *vq, void *cookie, int iovcnt)
     395                 :            : {
     396                 :            :         struct vq_desc_extra *dxp;
     397                 :            : 
     398                 :            :         /* Reserve enough entries to handle iov split */
     399         [ -  + ]:    2693311 :         if (2 * iovcnt > vq->vq_free_cnt) {
     400         [ #  # ]:          0 :                 return iovcnt > vq->vq_nentries ? -EINVAL : -ENOMEM;
     401                 :            :         }
     402                 :            : 
     403         [ -  + ]:    2693311 :         if (vq->req_end != VQ_RING_DESC_CHAIN_END) {
     404                 :          0 :                 finish_req(vq);
     405                 :            :         }
     406                 :            : 
     407                 :    2693311 :         vq->req_start = vq->vq_desc_head_idx;
     408                 :    2693311 :         dxp = &vq->vq_descx[vq->req_start];
     409                 :    2693311 :         dxp->cookie = cookie;
     410                 :    2693311 :         dxp->ndescs = 0;
     411                 :            : 
     412                 :    2693311 :         return 0;
     413                 :            : }
     414                 :            : 
     415                 :            : void
     416                 :    2693311 : virtqueue_req_flush(struct virtqueue *vq)
     417                 :            : {
     418                 :            :         uint16_t reqs_finished;
     419                 :            : 
     420         [ -  + ]:    2693311 :         if (vq->req_end == VQ_RING_DESC_CHAIN_END) {
     421                 :            :                 /* no non-empty requests have been started */
     422                 :          0 :                 return;
     423                 :            :         }
     424                 :            : 
     425                 :    2693311 :         finish_req(vq);
     426                 :    2693311 :         virtio_mb();
     427                 :            : 
     428                 :    2693311 :         reqs_finished = vq->reqs_finished;
     429                 :    2693311 :         vq->reqs_finished = 0;
     430                 :            : 
     431         [ -  + ]:    2693311 :         if (vq->vdev->negotiated_features & (1ULL << VIRTIO_RING_F_EVENT_IDX)) {
     432                 :            :                 /* Set used event idx to a value the device will never reach.
     433                 :            :                  * This effectively disables interrupts.
     434                 :            :                  */
     435                 :          0 :                 vring_used_event(&vq->vq_ring) = vq->vq_used_cons_idx - vq->vq_nentries - 1;
     436                 :            : 
     437         [ #  # ]:          0 :                 if (!vring_need_event(vring_avail_event(&vq->vq_ring),
     438                 :          0 :                                       vq->vq_avail_idx,
     439                 :          0 :                                       vq->vq_avail_idx - reqs_finished)) {
     440                 :          0 :                         return;
     441                 :            :                 }
     442         [ +  + ]:    2693311 :         } else if (vq->vq_ring.used->flags & VRING_USED_F_NO_NOTIFY) {
     443                 :    2693117 :                 return;
     444                 :            :         }
     445                 :            : 
     446                 :        194 :         virtio_dev_backend_ops(vq->vdev)->notify_queue(vq->vdev, vq);
     447   [ -  +  -  + ]:        194 :         SPDK_DEBUGLOG(virtio_dev, "Notified backend after xmit\n");
     448                 :            : }
     449                 :            : 
     450                 :            : void
     451                 :          0 : virtqueue_req_abort(struct virtqueue *vq)
     452                 :            : {
     453                 :            :         struct vring_desc *desc;
     454                 :            : 
     455         [ #  # ]:          0 :         if (vq->req_start == VQ_RING_DESC_CHAIN_END) {
     456                 :            :                 /* no requests have been started */
     457                 :          0 :                 return;
     458                 :            :         }
     459                 :            : 
     460                 :          0 :         desc = &vq->vq_ring.desc[vq->req_end];
     461                 :          0 :         desc->flags &= ~VRING_DESC_F_NEXT;
     462                 :            : 
     463                 :          0 :         vq_ring_free_chain(vq, vq->req_start);
     464                 :          0 :         vq->req_start = VQ_RING_DESC_CHAIN_END;
     465                 :            : }
     466                 :            : 
     467                 :            : void
     468                 :    8079549 : virtqueue_req_add_iovs(struct virtqueue *vq, struct iovec *iovs, uint16_t iovcnt,
     469                 :            :                        enum spdk_virtio_desc_type desc_type)
     470                 :            : {
     471                 :            :         struct vring_desc *desc;
     472                 :            :         struct vq_desc_extra *dxp;
     473                 :            :         uint16_t i, prev_head, new_head;
     474                 :          0 :         uint64_t processed_length, iovec_length, current_length;
     475                 :            :         void *current_base;
     476                 :    8079549 :         uint16_t used_desc_count = 0;
     477                 :            : 
     478         [ -  + ]:    8079549 :         assert(vq->req_start != VQ_RING_DESC_CHAIN_END);
     479         [ -  + ]:    8079549 :         assert(iovcnt <= vq->vq_free_cnt);
     480                 :            : 
     481                 :            :         /* TODO use indirect descriptors if iovcnt is high enough
     482                 :            :          * or the caller specifies SPDK_VIRTIO_DESC_F_INDIRECT
     483                 :            :          */
     484                 :            : 
     485                 :    8079549 :         prev_head = vq->req_end;
     486                 :    8079549 :         new_head = vq->vq_desc_head_idx;
     487         [ +  + ]:   16159075 :         for (i = 0; i < iovcnt; ++i) {
     488                 :    8079526 :                 processed_length = 0;
     489                 :    8079526 :                 iovec_length = iovs[i].iov_len;
     490                 :    8079526 :                 current_base = iovs[i].iov_base;
     491                 :            : 
     492         [ +  + ]:   16159042 :                 while (processed_length < iovec_length) {
     493                 :    8079516 :                         desc = &vq->vq_ring.desc[new_head];
     494                 :    8079516 :                         current_length = iovec_length - processed_length;
     495                 :            : 
     496         [ +  - ]:    8079516 :                         if (!vq->vdev->is_hw) {
     497                 :    8079516 :                                 desc->addr  = (uintptr_t)current_base;
     498                 :            :                         } else {
     499                 :          0 :                                 desc->addr = spdk_vtophys(current_base, &current_length);
     500                 :            :                         }
     501                 :            : 
     502                 :    8079516 :                         desc->len = current_length;
     503                 :            :                         /* always set NEXT flag. unset it on the last descriptor
     504                 :            :                          * in the request-ending function.
     505                 :            :                          */
     506                 :    8079516 :                         desc->flags = desc_type | VRING_DESC_F_NEXT;
     507                 :            : 
     508                 :    8079516 :                         prev_head = new_head;
     509                 :    8079516 :                         new_head = desc->next;
     510                 :    8079516 :                         used_desc_count++;
     511                 :            : 
     512                 :    8079516 :                         processed_length += current_length;
     513                 :    8079516 :                         current_base += current_length;
     514                 :            :                 }
     515                 :            :         }
     516                 :            : 
     517                 :    8079549 :         dxp = &vq->vq_descx[vq->req_start];
     518                 :    8079549 :         dxp->ndescs += used_desc_count;
     519                 :            : 
     520                 :    8079549 :         vq->req_end = prev_head;
     521                 :    8079549 :         vq->vq_desc_head_idx = new_head;
     522                 :    8079549 :         vq->vq_free_cnt = (uint16_t)(vq->vq_free_cnt - used_desc_count);
     523         [ -  + ]:    8079549 :         if (vq->vq_desc_head_idx == VQ_RING_DESC_CHAIN_END) {
     524         [ #  # ]:          0 :                 assert(vq->vq_free_cnt == 0);
     525                 :          0 :                 vq->vq_desc_tail_idx = VQ_RING_DESC_CHAIN_END;
     526                 :            :         }
     527                 :    8079549 : }
     528                 :            : 
     529                 :            : #define DESC_PER_CACHELINE (SPDK_CACHE_LINE_SIZE / sizeof(struct vring_desc))
     530                 :            : uint16_t
     531                 :   43929824 : virtio_recv_pkts(struct virtqueue *vq, void **io, uint32_t *len, uint16_t nb_pkts)
     532                 :            : {
     533                 :            :         uint16_t nb_used, num;
     534                 :            : 
     535                 :   43929824 :         nb_used = vq->vq_ring.used->idx - vq->vq_used_cons_idx;
     536                 :   43929824 :         virtio_rmb();
     537                 :            : 
     538         [ +  + ]:   43929824 :         num = (uint16_t)(spdk_likely(nb_used <= nb_pkts) ? nb_used : nb_pkts);
     539         [ +  + ]:   43929824 :         if (spdk_likely(num > DESC_PER_CACHELINE)) {
     540                 :     194777 :                 num = num - ((vq->vq_used_cons_idx + num) % DESC_PER_CACHELINE);
     541                 :            :         }
     542                 :            : 
     543                 :   43929824 :         return virtqueue_dequeue_burst_rx(vq, io, len, num);
     544                 :            : }
     545                 :            : 
     546                 :            : int
     547                 :         38 : virtio_dev_acquire_queue(struct virtio_dev *vdev, uint16_t index)
     548                 :            : {
     549                 :         38 :         struct virtqueue *vq = NULL;
     550                 :            : 
     551         [ -  + ]:         38 :         if (index >= vdev->max_queues) {
     552                 :          0 :                 SPDK_ERRLOG("requested vq index %"PRIu16" exceeds max queue count %"PRIu16".\n",
     553                 :            :                             index, vdev->max_queues);
     554                 :          0 :                 return -1;
     555                 :            :         }
     556                 :            : 
     557         [ -  + ]:         38 :         pthread_mutex_lock(&vdev->mutex);
     558                 :         38 :         vq = vdev->vqs[index];
     559   [ +  -  -  + ]:         38 :         if (vq == NULL || vq->owner_thread != NULL) {
     560         [ #  # ]:          0 :                 pthread_mutex_unlock(&vdev->mutex);
     561                 :          0 :                 return -1;
     562                 :            :         }
     563                 :            : 
     564                 :         38 :         vq->owner_thread = spdk_get_thread();
     565         [ -  + ]:         38 :         pthread_mutex_unlock(&vdev->mutex);
     566                 :         38 :         return 0;
     567                 :            : }
     568                 :            : 
     569                 :            : int32_t
     570                 :         44 : virtio_dev_find_and_acquire_queue(struct virtio_dev *vdev, uint16_t start_index)
     571                 :            : {
     572                 :         44 :         struct virtqueue *vq = NULL;
     573                 :            :         uint16_t i;
     574                 :            : 
     575         [ -  + ]:         44 :         pthread_mutex_lock(&vdev->mutex);
     576         [ +  - ]:         74 :         for (i = start_index; i < vdev->max_queues; ++i) {
     577                 :         74 :                 vq = vdev->vqs[i];
     578   [ +  -  +  + ]:         74 :                 if (vq != NULL && vq->owner_thread == NULL) {
     579                 :         44 :                         break;
     580                 :            :                 }
     581                 :            :         }
     582                 :            : 
     583   [ +  -  -  + ]:         44 :         if (vq == NULL || i == vdev->max_queues) {
     584                 :          0 :                 SPDK_ERRLOG("no more unused virtio queues with idx >= %"PRIu16".\n", start_index);
     585         [ #  # ]:          0 :                 pthread_mutex_unlock(&vdev->mutex);
     586                 :          0 :                 return -1;
     587                 :            :         }
     588                 :            : 
     589                 :         44 :         vq->owner_thread = spdk_get_thread();
     590         [ -  + ]:         44 :         pthread_mutex_unlock(&vdev->mutex);
     591                 :         44 :         return i;
     592                 :            : }
     593                 :            : 
     594                 :            : struct spdk_thread *
     595                 :         12 : virtio_dev_queue_get_thread(struct virtio_dev *vdev, uint16_t index)
     596                 :            : {
     597                 :         12 :         struct spdk_thread *thread = NULL;
     598                 :            : 
     599         [ -  + ]:         12 :         if (index >= vdev->max_queues) {
     600                 :          0 :                 SPDK_ERRLOG("given vq index %"PRIu16" exceeds max queue count %"PRIu16"\n",
     601                 :            :                             index, vdev->max_queues);
     602                 :          0 :                 abort(); /* This is not recoverable */
     603                 :            :         }
     604                 :            : 
     605         [ -  + ]:         12 :         pthread_mutex_lock(&vdev->mutex);
     606                 :         12 :         thread = vdev->vqs[index]->owner_thread;
     607         [ -  + ]:         12 :         pthread_mutex_unlock(&vdev->mutex);
     608                 :            : 
     609                 :         12 :         return thread;
     610                 :            : }
     611                 :            : 
     612                 :            : bool
     613                 :          0 : virtio_dev_queue_is_acquired(struct virtio_dev *vdev, uint16_t index)
     614                 :            : {
     615                 :          0 :         return virtio_dev_queue_get_thread(vdev, index) != NULL;
     616                 :            : }
     617                 :            : 
     618                 :            : void
     619                 :         82 : virtio_dev_release_queue(struct virtio_dev *vdev, uint16_t index)
     620                 :            : {
     621                 :         82 :         struct virtqueue *vq = NULL;
     622                 :            : 
     623         [ -  + ]:         82 :         if (index >= vdev->max_queues) {
     624                 :          0 :                 SPDK_ERRLOG("given vq index %"PRIu16" exceeds max queue count %"PRIu16".\n",
     625                 :            :                             index, vdev->max_queues);
     626                 :          0 :                 return;
     627                 :            :         }
     628                 :            : 
     629         [ -  + ]:         82 :         pthread_mutex_lock(&vdev->mutex);
     630                 :         82 :         vq = vdev->vqs[index];
     631         [ -  + ]:         82 :         if (vq == NULL) {
     632                 :          0 :                 SPDK_ERRLOG("virtqueue at index %"PRIu16" is not initialized.\n", index);
     633         [ #  # ]:          0 :                 pthread_mutex_unlock(&vdev->mutex);
     634                 :          0 :                 return;
     635                 :            :         }
     636                 :            : 
     637         [ -  + ]:         82 :         assert(vq->owner_thread == spdk_get_thread());
     638                 :         82 :         vq->owner_thread = NULL;
     639         [ -  + ]:         82 :         pthread_mutex_unlock(&vdev->mutex);
     640                 :            : }
     641                 :            : 
     642                 :            : int
     643                 :         55 : virtio_dev_read_dev_config(struct virtio_dev *dev, size_t offset,
     644                 :            :                            void *dst, int length)
     645                 :            : {
     646                 :         55 :         return virtio_dev_backend_ops(dev)->read_dev_cfg(dev, offset, dst, length);
     647                 :            : }
     648                 :            : 
     649                 :            : int
     650                 :          0 : virtio_dev_write_dev_config(struct virtio_dev *dev, size_t offset,
     651                 :            :                             const void *src, int length)
     652                 :            : {
     653                 :          0 :         return virtio_dev_backend_ops(dev)->write_dev_cfg(dev, offset, src, length);
     654                 :            : }
     655                 :            : 
     656                 :            : void
     657                 :         58 : virtio_dev_stop(struct virtio_dev *dev)
     658                 :            : {
     659                 :         58 :         virtio_dev_backend_ops(dev)->set_status(dev, VIRTIO_CONFIG_S_RESET);
     660                 :            :         /* flush status write */
     661                 :         58 :         virtio_dev_backend_ops(dev)->get_status(dev);
     662                 :         58 :         virtio_free_queues(dev);
     663                 :         58 : }
     664                 :            : 
     665                 :            : void
     666                 :        116 : virtio_dev_set_status(struct virtio_dev *dev, uint8_t status)
     667                 :            : {
     668         [ +  - ]:        116 :         if (status != VIRTIO_CONFIG_S_RESET) {
     669                 :        116 :                 status |= virtio_dev_backend_ops(dev)->get_status(dev);
     670                 :            :         }
     671                 :            : 
     672                 :        116 :         virtio_dev_backend_ops(dev)->set_status(dev, status);
     673                 :        116 : }
     674                 :            : 
     675                 :            : uint8_t
     676                 :        116 : virtio_dev_get_status(struct virtio_dev *dev)
     677                 :            : {
     678                 :        116 :         return virtio_dev_backend_ops(dev)->get_status(dev);
     679                 :            : }
     680                 :            : 
     681                 :            : const struct virtio_dev_ops *
     682                 :       1497 : virtio_dev_backend_ops(struct virtio_dev *dev)
     683                 :            : {
     684                 :       1497 :         return dev->backend_ops;
     685                 :            : }
     686                 :            : 
     687                 :            : void
     688                 :         85 : virtio_dev_dump_json_info(struct virtio_dev *hw, struct spdk_json_write_ctx *w)
     689                 :            : {
     690                 :         85 :         spdk_json_write_named_object_begin(w, "virtio");
     691                 :            : 
     692                 :         85 :         spdk_json_write_named_uint32(w, "vq_count", hw->max_queues);
     693                 :            : 
     694                 :         85 :         spdk_json_write_named_uint32(w, "vq_size",
     695                 :         85 :                                      virtio_dev_backend_ops(hw)->get_queue_size(hw, 0));
     696                 :            : 
     697                 :         85 :         virtio_dev_backend_ops(hw)->dump_json_info(hw, w);
     698                 :            : 
     699                 :         85 :         spdk_json_write_object_end(w);
     700                 :         85 : }
     701                 :            : 
     702                 :       2050 : SPDK_LOG_REGISTER_COMPONENT(virtio_dev)

Generated by: LCOV version 1.14